17#include "llvm/ADT/MapVector.h"
18#include "llvm/ADT/StringRef.h"
19#include "llvm/ADT/TypeSwitch.h"
23#include "mlir/Dialect/DLTI/DLTIOpInterfaces.cpp.inc"
25#include "mlir/Dialect/DLTI/DLTIDialect.cpp.inc"
27#define GET_ATTRDEF_CLASSES
28#include "mlir/Dialect/DLTI/DLTIAttrs.cpp.inc"
30#define DEBUG_TYPE "dlti"
41 DataLayoutEntryInterface &entry,
42 bool tryType =
false) {
49 if (failed(parsedType.
value()))
51 <<
"error while parsing type DLTI key";
56 entry = DataLayoutEntryAttr::get(type, value);
57 return ParseResult::success();
67 entry = DataLayoutEntryAttr::get(
68 StringAttr::get(parser.
getContext(), ident), value);
69 return ParseResult::success();
74 if (succeeded(parsedEntry.
value()))
75 return parsedEntry.
value();
79 <<
"failed to parse DLTI entry";
91 bool allowEmpty =
false) {
95 return parseKeyValuePair(parser, entries.emplace_back(), tryType);
99 if (entries.empty() && !allowEmpty) {
116 .Case<StringAttr,
Type>(
117 [&](
auto key) { llvm::raw_string_ostream(buf) << key; });
125 llvm::interleaveComma(std::forward<T>(entries), os, [&](
auto entry) {
126 os <<
keyToStr(entry.getKey()) <<
" = " << entry.getValue();
138 bool allowTypes =
true) {
140 for (DataLayoutEntryInterface entry : entries) {
142 return emitError() <<
"contained invalid DLTI entry";
145 return emitError() <<
"contained invalid DLTI key";
146 if (!allowTypes && dyn_cast<Type>(key))
147 return emitError() <<
"type as DLTI key is not allowed";
148 if (
auto strKey = dyn_cast<StringAttr>(key))
149 if (strKey.getValue().empty())
150 return emitError() <<
"empty string as DLTI key is not allowed";
151 if (!keys.insert(key).second)
153 if (!entry.getValue())
167 using KeyTy = std::pair<DataLayoutEntryKey, Attribute>;
188DataLayoutEntryAttr DataLayoutEntryAttr::get(StringAttr key,
Attribute value) {
189 return Base::get(key.getContext(), key, value);
192DataLayoutEntryAttr DataLayoutEntryAttr::get(
Type key,
Attribute value) {
193 return Base::get(key.
getContext(), key, value);
197 return getImpl()->entryKey;
200Attribute DataLayoutEntryAttr::getValue()
const {
return getImpl()->value; }
209 Type typeKey =
nullptr;
210 std::string identifier;
218 parser.
emitError(idLoc) <<
"expected a type or a quoted string";
228 return typeKey ?
get(typeKey, value)
229 :
get(parser.getBuilder().getStringAttr(identifier), value);
232void DataLayoutEntryAttr::print(
AsmPrinter &printer)
const {
233 printer <<
"<" <<
keyToStr(getKey()) <<
", " << getValue() <<
">";
249void MapAttr::print(
AsmPrinter &printer)
const {
274 unsigned oldEntriesSize = oldEntries.size();
275 for (DataLayoutEntryInterface entry : newEntries) {
280 bool replaced =
false;
281 for (
unsigned i = 0; i < oldEntriesSize; ++i) {
282 if (oldEntries[i].getKey() == entry.getKey()) {
283 oldEntries[i] = entry;
289 oldEntries.push_back(entry);
297 DataLayoutSpecInterface spec,
306 spec.bucketEntriesByType(newEntriesForType, newEntriesForID);
310 for (
const auto &kvp : newEntriesForID) {
311 StringAttr
id = cast<StringAttr>(kvp.second.getKey());
312 Dialect *dialect =
id.getReferencedDialect();
313 if (!entriesForID.count(
id)) {
314 entriesForID[id] = kvp.second;
322 dialect ? cast<DataLayoutDialectInterface>(dialect)->combine(
323 entriesForID[
id], kvp.second)
324 : DataLayoutDialectInterface::defaultCombine(entriesForID[
id],
326 if (!entriesForID[
id])
331 for (
auto &kvp : newEntriesForType) {
332 if (!entriesForType.count(kvp.first)) {
333 entriesForType[kvp.first] = std::move(kvp.second);
337 Type typeSample = cast<Type>(kvp.second.front().getKey());
340 "unexpected data layout entry for built-in type");
342 auto interface = cast<DataLayoutTypeInterface>(typeSample);
345 if (!interface.areCompatible(entriesForType.lookup(kvp.first), kvp.second,
359 if (any_of(specs, [](DataLayoutSpecInterface spec) {
360 return !llvm::isa<DataLayoutSpecAttr>(spec);
367 for (DataLayoutSpecInterface spec : specs)
375 llvm::append_range(entries, llvm::make_second_range(entriesForID));
376 for (
const auto &kvp : entriesForType)
377 llvm::append_range(entries, kvp.second);
379 return DataLayoutSpecAttr::get(
getContext(), entries);
383DataLayoutSpecAttr::getEndiannessIdentifier(
MLIRContext *context)
const {
387StringAttr DataLayoutSpecAttr::getDefaultMemorySpaceIdentifier(
390 DLTIDialect::kDataLayoutDefaultMemorySpaceKey);
394DataLayoutSpecAttr::getAllocaMemorySpaceIdentifier(
MLIRContext *context)
const {
396 DLTIDialect::kDataLayoutAllocaMemorySpaceKey);
399StringAttr DataLayoutSpecAttr::getProgramMemorySpaceIdentifier(
402 DLTIDialect::kDataLayoutProgramMemorySpaceKey);
406DataLayoutSpecAttr::getGlobalMemorySpaceIdentifier(
MLIRContext *context)
const {
408 DLTIDialect::kDataLayoutGlobalMemorySpaceKey);
412DataLayoutSpecAttr::getManglingModeIdentifier(
MLIRContext *context)
const {
414 DLTIDialect::kDataLayoutManglingModeKey);
418DataLayoutSpecAttr::getStackAlignmentIdentifier(
MLIRContext *context)
const {
420 DLTIDialect::kDataLayoutStackAlignmentKey);
423StringAttr DataLayoutSpecAttr::getFunctionPointerAlignmentIdentifier(
426 DLTIDialect::kDataLayoutFunctionPointerAlignmentKey);
430DataLayoutSpecAttr::getLegalIntWidthsIdentifier(
MLIRContext *context)
const {
432 DLTIDialect::kDataLayoutLegalIntWidthsKey);
445void DataLayoutSpecAttr::print(
AsmPrinter &printer)
const {
467void TargetDeviceSpecAttr::print(
AsmPrinter &printer)
const {
480 for (
const auto &entry : entries) {
482 llvm::dyn_cast<TargetSystemSpecInterface::DeviceID>(entry.getKey());
484 return emitError() <<
"non-string key of DLTI system spec";
486 if (
auto targetDeviceSpec =
487 llvm::dyn_cast<TargetDeviceSpecInterface>(entry.getValue())) {
489 targetDeviceSpec.getEntries())))
492 return emitError() <<
"value associated with key " << deviceId
493 <<
" is not a DLTI device spec";
497 if (!deviceIds.insert(deviceId).second)
498 return emitError() <<
"repeated device ID in dlti.target_system_spec: "
513void TargetSystemSpecAttr::print(
AsmPrinter &printer)
const {
528 return queryable.query(key);
535 if (
auto stringKey = dyn_cast<StringAttr>(key);
536 stringKey && stringKey.getValue().empty())
542 auto current = dyn_cast_or_null<DLTIQueryInterface>(*inherent);
543 if (current && !isa<MapAttr>(current))
547 if (
auto map = dyn_cast_or_null<MapAttr>(current))
548 llvm::append_range(entries, map.getEntries());
550 auto makeEntry = [&]() -> DataLayoutEntryInterface {
551 if (
auto type = dyn_cast<Type>(key))
552 return DataLayoutEntryAttr::get(type, value);
553 return DataLayoutEntryAttr::get(cast<StringAttr>(key), value);
555 auto entry = llvm::find_if(entries, [&](DataLayoutEntryInterface entry) {
556 return entry.getKey() == key;
558 if (entry != entries.end()) {
560 *entry = makeEntry();
562 entries.erase(entry);
564 entries.push_back(makeEntry());
570 if (entries.empty()) {
585 auto diag = op->
emitError() <<
"target op of failed DLTI query";
586 diag.attachNote(op->
getLoc()) <<
"no keys provided to attempt query with";
593 for (; queryOp; queryOp = queryOp->
getParentOp()) {
594 auto queryable = dyn_cast<DLTIQueryOpInterface>(queryOp);
597 FailureOr<Attribute>
result = queryable.queryDlti(keys.front());
606 auto diag = op->
emitError() <<
"target op of failed DLTI query";
608 <<
"no DLTI-queryable operation on the target or any of its "
609 "ancestors could answer key "
615 for (
auto &&[idx, key] : llvm::enumerate(keys.drop_front())) {
616 if (
auto map = dyn_cast<DLTIQueryInterface>(currentAttr)) {
617 auto maybeAttr = map.query(key);
618 if (failed(maybeAttr)) {
620 auto diag = op->
emitError() <<
"target op of failed DLTI query";
623 <<
" has no DLTI-mapping per attr: " << map;
627 currentAttr = *maybeAttr;
630 std::string commaSeparatedKeys;
632 keys.take_front(idx + 1),
633 [&](
auto key) { commaSeparatedKeys += keyToStr(key); },
634 [&]() { commaSeparatedKeys +=
","; });
636 auto diag = op->
emitError() <<
"target op of failed DLTI query";
638 <<
"got non-DLTI-queryable attribute upon looking up keys ["
639 << commaSeparatedKeys <<
"] at op";
655 entryKeys.reserve(keys.size());
656 for (StringRef key : keys)
657 entryKeys.push_back(StringAttr::get(ctx, key));
663struct ModuleDLTIQueryOpInterface
664 : DLTIQueryOpInterface::ExternalModel<ModuleDLTIQueryOpInterface,
667class TargetDataLayoutInterface :
public DataLayoutDialectInterface {
669 using DataLayoutDialectInterface::DataLayoutDialectInterface;
671 LogicalResult verifyEntry(DataLayoutEntryInterface entry,
673 StringRef entryName = cast<StringAttr>(entry.getKey()).strref();
674 if (entryName == DLTIDialect::kDataLayoutEndiannessKey) {
675 auto value = dyn_cast<StringAttr>(entry.getValue());
677 (value.getValue() == DLTIDialect::kDataLayoutEndiannessBig ||
678 value.getValue() == DLTIDialect::kDataLayoutEndiannessLittle))
680 return emitError(loc) <<
"'" << entryName
681 <<
"' data layout entry is expected to be either '"
682 << DLTIDialect::kDataLayoutEndiannessBig <<
"' or '"
683 << DLTIDialect::kDataLayoutEndiannessLittle <<
"'";
685 if (entryName == DLTIDialect::kDataLayoutDefaultMemorySpaceKey ||
686 entryName == DLTIDialect::kDataLayoutAllocaMemorySpaceKey ||
687 entryName == DLTIDialect::kDataLayoutProgramMemorySpaceKey ||
688 entryName == DLTIDialect::kDataLayoutGlobalMemorySpaceKey ||
689 entryName == DLTIDialect::kDataLayoutStackAlignmentKey ||
690 entryName == DLTIDialect::kDataLayoutFunctionPointerAlignmentKey ||
691 entryName == DLTIDialect::kDataLayoutLegalIntWidthsKey ||
692 entryName == DLTIDialect::kDataLayoutManglingModeKey)
694 return emitError(loc) <<
"unknown data layout entry name: " << entryName;
699void DLTIDialect::initialize() {
701#define GET_ATTRDEF_LIST
702#include "mlir/Dialect/DLTI/DLTIAttrs.cpp.inc"
704 addInterfaces<TargetDataLayoutInterface>();
705 ModuleOp::attachInterface<ModuleDLTIQueryOpInterface>(*
getContext());
708LogicalResult DLTIDialect::verifyOperationAttribute(
Operation *op,
710 if (attr.
getName() == DLTIDialect::kDataLayoutAttrName) {
711 if (!llvm::isa<DataLayoutSpecAttr>(attr.
getValue())) {
712 return op->
emitError() <<
"'" << DLTIDialect::kDataLayoutAttrName
713 <<
"' is expected to be a #dlti.dl_spec attribute";
715 if (isa<ModuleOp>(op))
720 if (attr.
getName() == DLTIDialect::kTargetSystemDescAttrName) {
721 if (!llvm::isa<TargetSystemSpecAttr>(attr.
getValue())) {
723 <<
"'" << DLTIDialect::kTargetSystemDescAttrName
724 <<
"' is expected to be a #dlti.target_system_spec attribute";
729 if (attr.
getName() == DLTIDialect::kMapAttrName) {
730 if (!llvm::isa<MapAttr>(attr.
getValue())) {
731 return op->
emitError() <<
"'" << DLTIDialect::kMapAttrName
732 <<
"' is expected to be a #dlti.map attribute";
738 <<
"' not supported by dialect";
static LogicalResult verifyEntries(function_ref< InFlightDiagnostic()> emitError, ArrayRef< DataLayoutEntryInterface > entries, bool allowTypes=true)
Verify entries, with the option to disallow types as keys.
static void printAngleBracketedEntries(AsmPrinter &os, T &&entries)
Pretty-print entries, each in key = value format, separated by commas.
static constexpr llvm::StringLiteral kDltiAttrName
static std::string keyToStr(DataLayoutEntryKey key)
Convert pointer-union keys to strings.
static void overwriteDuplicateEntries(SmallVectorImpl< DataLayoutEntryInterface > &oldEntries, ArrayRef< DataLayoutEntryInterface > newEntries)
Given a list of old and a list of new entries, overwrites old entries with new ones if they have matc...
static Attribute parseAngleBracketedEntries(AsmParser &parser, Type ty, bool tryType=false, bool allowEmpty=false)
Construct a requested attribute by parsing list of entries occurring within a pair of < and >,...
static LogicalResult combineOneSpec(DataLayoutSpecInterface spec, llvm::MapVector< TypeID, DataLayoutEntryList > &entriesForType, llvm::MapVector< StringAttr, DataLayoutEntryInterface > &entriesForID)
Combines a data layout spec into the given lists of entries organized by type class and identifier,...
static ParseResult parseKeyValuePair(AsmParser &parser, DataLayoutEntryInterface &entry, bool tryType=false)
Parse an entry which can either be of the form key = value or a dlti.dl_entry attribute.
This base class exposes generic asm parser hooks, usable across the various derived parsers.
@ LessGreater
<> brackets surrounding zero or more operands.
virtual ParseResult parseCommaSeparatedList(Delimiter delimiter, function_ref< ParseResult()> parseElementFn, StringRef contextMessage=StringRef())=0
Parse a list of comma-separated items with an optional delimiter.
virtual OptionalParseResult parseOptionalType(Type &result)=0
Parse an optional type.
MLIRContext * getContext() const
virtual InFlightDiagnostic emitError(SMLoc loc, const Twine &message={})=0
Emit a diagnostic at the specified location and return failure.
virtual ParseResult parseLess()=0
Parse a '<' token.
virtual ParseResult parseEqual()=0
Parse a = token.
virtual SMLoc getCurrentLocation()=0
Get the location of the next token and store it into the argument.
virtual SMLoc getNameLoc() const =0
Return the location of the original name token.
virtual ParseResult parseOptionalString(std::string *string)=0
Parse a quoted string token if present.
virtual ParseResult parseGreater()=0
Parse a '>' token.
virtual ParseResult parseComma()=0
Parse a , token.
virtual ParseResult parseAttribute(Attribute &result, Type type={})=0
Parse an arbitrary attribute of a given type and return it in result.
This base class exposes generic asm printer hooks, usable across the various derived printers.
Base storage class appearing in an attribute.
Attributes are known-constant values of operations.
This class is a general helper class for creating context-global objects like types,...
StringAttr getStringAttr(const Twine &bytes)
Dialects are groups of MLIR operations, types and attributes, as well as behavior associated with the...
This class represents a diagnostic that is inflight and set to be reported.
This class defines the main interface for locations in MLIR and acts as a non-nullable wrapper around...
MLIRContext is the top-level object for a collection of MLIR operations.
Dialect * getLoadedDialect(StringRef name)
Get a registered IR dialect with the given namespace.
NamedAttribute represents a combination of a name and an Attribute value.
StringAttr getName() const
Return the name of the attribute.
Attribute getValue() const
Return the value of the attribute.
Operation is the basic unit of execution within MLIR.
void setInherentAttr(StringAttr name, Attribute value)
Set an inherent attribute by name.
std::optional< Attribute > getInherentAttr(StringRef name)
Access an inherent attribute by name: returns an empty optional if there is no inherent attribute wit...
AttrClass getInherentAttrOfType(StringRef name)
Access an inherent attribute by name and cast it to AttrClass.
Location getLoc()
The source location the operation was defined or derived from.
Operation * getParentOp()
Returns the closest surrounding operation that contains this operation or nullptr if this is a top-le...
InFlightDiagnostic emitError(const Twine &message={})
Emit an error about fatal conditions with this operation, reporting up to any diagnostic handlers tha...
MLIRContext * getContext()
Return the context this operation is associated with.
This class implements Optional functionality for ParseResult.
ParseResult value() const
Access the internal ParseResult value.
bool has_value() const
Returns true if we contain a valid ParseResult value.
T * allocate()
Allocate an instance of the provided type.
Instances of the Type class are uniqued, have an immutable identifier and an optional mutable compone...
Dialect & getDialect() const
Get the dialect this type is registered to.
MLIRContext * getContext() const
Return the MLIRContext in which this type was uniqued.
static DataLayoutEntryAttrStorage * construct(AttributeStorageAllocator &allocator, const KeyTy &key)
DataLayoutEntryKey entryKey
DataLayoutEntryAttrStorage(DataLayoutEntryKey entryKey, Attribute value)
bool operator==(const KeyTy &other) const
std::pair< DataLayoutEntryKey, Attribute > KeyTy
LogicalResult verifyDataLayoutOp(Operation *op)
Verifies that the operation implementing the data layout interface, or a module operation,...
LogicalResult setDlti(Operation *op, DataLayoutEntryKey key, Attribute value)
FailureOr< Attribute > queryDlti(Operation *op, DataLayoutEntryKey key)
FailureOr< Attribute > query(Operation *op, ArrayRef< DataLayoutEntryKey > keys, bool emitError=false)
Query the first key at op or the nearest ancestor that can answer it.
Include the generated interface declarations.
llvm::PointerUnion< Type, StringAttr > DataLayoutEntryKey
llvm::DenseSet< ValueT, ValueInfoT > DenseSet
InFlightDiagnostic emitError(Location loc)
Utility method to emit an error message using this location.
StorageUniquer::StorageAllocator AttributeStorageAllocator
llvm::TypeSwitch< T, ResultT > TypeSwitch
auto get(MLIRContext *context, Ts &&...params)
Helper method that injects context only if needed, this helps unify some of the attribute constructio...
llvm::function_ref< Fn > function_ref