17 #include "llvm/ADT/TypeSwitch.h"
19 #include "llvm/ADT/TypeSwitch.h"
20 #include "llvm/Support/Debug.h"
21 #include "llvm/Support/MathExtras.h"
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";
57 return ParseResult::success();
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>;
189 return Base::get(key.getContext(), key, value);
197 return getImpl()->entryKey;
200 Attribute 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);
233 printer <<
"<" <<
keyToStr(getKey()) <<
", " << getValue() <<
">";
245 return parseAngleBracketedEntries<MapAttr>(parser, type,
true,
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);
306 spec.bucketEntriesByType(newEntriesForType, newEntriesForID);
309 for (
auto &kvp : newEntriesForType) {
310 if (!entriesForType.count(kvp.first)) {
311 entriesForType[kvp.first] = std::move(kvp.second);
315 Type typeSample = kvp.second.front().getKey().get<
Type>();
318 "unexpected data layout entry for built-in type");
320 auto interface = cast<DataLayoutTypeInterface>(typeSample);
321 if (!interface.areCompatible(entriesForType.lookup(kvp.first), kvp.second))
327 for (
const auto &kvp : newEntriesForID) {
328 StringAttr
id = kvp.second.getKey().get<StringAttr>();
329 Dialect *dialect =
id.getReferencedDialect();
330 if (!entriesForID.count(
id)) {
331 entriesForID[id] = kvp.second;
339 dialect ? cast<DataLayoutDialectInterface>(dialect)->combine(
340 entriesForID[
id], kvp.second)
343 if (!entriesForID[
id])
354 if (any_of(specs, [](DataLayoutSpecInterface spec) {
355 return !llvm::isa<DataLayoutSpecAttr>(spec);
362 for (DataLayoutSpecInterface spec : specs)
370 llvm::append_range(entries, llvm::make_second_range(entriesForID));
371 for (
const auto &kvp : entriesForType)
372 llvm::append_range(entries, kvp.getSecond());
378 DataLayoutSpecAttr::getEndiannessIdentifier(
MLIRContext *context)
const {
383 DataLayoutSpecAttr::getAllocaMemorySpaceIdentifier(
MLIRContext *context)
const {
385 DLTIDialect::kDataLayoutAllocaMemorySpaceKey);
388 StringAttr DataLayoutSpecAttr::getProgramMemorySpaceIdentifier(
391 DLTIDialect::kDataLayoutProgramMemorySpaceKey);
395 DataLayoutSpecAttr::getGlobalMemorySpaceIdentifier(
MLIRContext *context)
const {
397 DLTIDialect::kDataLayoutGlobalMemorySpaceKey);
401 DataLayoutSpecAttr::getStackAlignmentIdentifier(
MLIRContext *context)
const {
403 DLTIDialect::kDataLayoutStackAlignmentKey);
411 return parseAngleBracketedEntries<DataLayoutSpecAttr>(parser, type,
435 return parseAngleBracketedEntries<TargetDeviceSpecAttr>(parser, type);
451 for (
const auto &entry : entries) {
453 llvm::dyn_cast<TargetSystemSpecInterface::DeviceID>(entry.getKey());
455 return emitError() <<
"non-string key of DLTI system spec";
457 if (
auto targetDeviceSpec =
458 llvm::dyn_cast<TargetDeviceSpecInterface>(entry.getValue())) {
460 targetDeviceSpec.getEntries())))
463 return emitError() <<
"value associated with key " << deviceId
464 <<
" is not a DLTI device spec";
468 if (!deviceIds.insert(deviceId).second)
469 return emitError() <<
"repeated device ID in dlti.target_system_spec: "
481 return parseAngleBracketedEntries<TargetSystemSpecAttr>(parser, type);
495 static std::pair<DLTIQueryInterface, Operation *>
497 DLTIQueryInterface queryable = {};
502 if ((queryable = dyn_cast<DLTIQueryInterface>(attr.getValue())))
506 return std::pair(queryable, op);
513 auto diag = op->
emitError() <<
"target op of failed DLTI query";
514 diag.attachNote(op->
getLoc()) <<
"no keys provided to attempt query with";
520 Operation *reportOp = (queryOp ? queryOp : op);
524 auto diag = op->
emitError() <<
"target op of failed DLTI query";
526 <<
"no DLTI-queryable attrs on target op or any of its ancestors";
533 if (
auto map = dyn_cast<DLTIQueryInterface>(currentAttr)) {
534 auto maybeAttr = map.query(key);
535 if (failed(maybeAttr)) {
537 auto diag = op->
emitError() <<
"target op of failed DLTI query";
540 <<
" has no DLTI-mapping per attr: " << map;
544 currentAttr = *maybeAttr;
547 std::string commaSeparatedKeys;
549 keys.take_front(idx),
550 [&](
auto key) { commaSeparatedKeys += keyToStr(key); },
551 [&]() { commaSeparatedKeys +=
","; });
553 auto diag = op->
emitError() <<
"target op of failed DLTI query";
555 <<
"got non-DLTI-queryable attribute upon looking up keys ["
556 << commaSeparatedKeys <<
"] at op";
565 constexpr
const StringLiteral mlir::DLTIDialect::kDataLayoutAttrName;
566 constexpr
const StringLiteral mlir::DLTIDialect::kDataLayoutEndiannessKey;
567 constexpr
const StringLiteral mlir::DLTIDialect::kDataLayoutEndiannessBig;
568 constexpr
const StringLiteral mlir::DLTIDialect::kDataLayoutEndiannessLittle;
575 LogicalResult verifyEntry(DataLayoutEntryInterface entry,
577 StringRef entryName = entry.getKey().get<StringAttr>().strref();
578 if (entryName == DLTIDialect::kDataLayoutEndiannessKey) {
579 auto value = dyn_cast<StringAttr>(entry.getValue());
581 (value.getValue() == DLTIDialect::kDataLayoutEndiannessBig ||
582 value.getValue() == DLTIDialect::kDataLayoutEndiannessLittle))
584 return emitError(loc) <<
"'" << entryName
585 <<
"' data layout entry is expected to be either '"
586 << DLTIDialect::kDataLayoutEndiannessBig <<
"' or '"
587 << DLTIDialect::kDataLayoutEndiannessLittle <<
"'";
589 if (entryName == DLTIDialect::kDataLayoutAllocaMemorySpaceKey ||
590 entryName == DLTIDialect::kDataLayoutProgramMemorySpaceKey ||
591 entryName == DLTIDialect::kDataLayoutGlobalMemorySpaceKey ||
592 entryName == DLTIDialect::kDataLayoutStackAlignmentKey)
594 return emitError(loc) <<
"unknown data layout entry name: " << entryName;
599 void DLTIDialect::initialize() {
601 #define GET_ATTRDEF_LIST
602 #include "mlir/Dialect/DLTI/DLTIAttrs.cpp.inc"
604 addInterfaces<TargetDataLayoutInterface>();
607 LogicalResult DLTIDialect::verifyOperationAttribute(
Operation *op,
609 if (attr.
getName() == DLTIDialect::kDataLayoutAttrName) {
610 if (!llvm::isa<DataLayoutSpecAttr>(attr.
getValue())) {
611 return op->
emitError() <<
"'" << DLTIDialect::kDataLayoutAttrName
612 <<
"' is expected to be a #dlti.dl_spec attribute";
614 if (isa<ModuleOp>(op))
619 if (attr.
getName() == DLTIDialect::kTargetSystemDescAttrName) {
620 if (!llvm::isa<TargetSystemSpecAttr>(attr.
getValue())) {
622 <<
"'" << DLTIDialect::kTargetSystemDescAttrName
623 <<
"' is expected to be a #dlti.target_system_spec attribute";
628 if (attr.
getName() == DLTIDialect::kMapAttrName) {
629 if (!llvm::isa<MapAttr>(attr.
getValue())) {
630 return op->
emitError() <<
"'" << DLTIDialect::kMapAttrName
631 <<
"' is expected to be a #dlti.map attribute";
637 <<
"' 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 std::pair< DLTIQueryInterface, Operation * > getClosestQueryable(Operation *op)
Retrieve the first DLTIQueryInterface-implementing attribute that is attached to op or such an attr o...
static std::string keyToStr(DataLayoutEntryKey key)
Convert pointer-union keys to strings.
static LogicalResult combineOneSpec(DataLayoutSpecInterface spec, DenseMap< TypeID, DataLayoutEntryList > &entriesForType, DenseMap< StringAttr, DataLayoutEntryInterface > &entriesForID)
Combines a data layout spec into the given lists of entries organized by type class and identifier,...
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 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.
static MLIRContext * getContext(OpFoldResult val)
static std::string diag(const llvm::Value &value)
static void print(spirv::VerCapExtAttr triple, DialectAsmPrinter &printer)
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)
An interface to be implemented by dialects that can have identifiers in the data layout specification...
DataLayoutDialectInterface(Dialect *dialect)
static DataLayoutEntryInterface defaultCombine(DataLayoutEntryInterface outer, DataLayoutEntryInterface inner)
Default implementation of entry combination that combines identical entries and returns null otherwis...
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.
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...
ArrayRef< NamedAttribute > getAttrs()
Return all of the attributes on this operation.
InFlightDiagnostic emitError(const Twine &message={})
Emit an error about fatal conditions with this operation, reporting up to any diagnostic handlers tha...
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.
This is a utility allocator used to allocate memory for instances of derived types.
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.
DataLayoutEntryKey entryKey
DataLayoutEntryAttrStorage(DataLayoutEntryKey entryKey, Attribute value)
bool operator==(const KeyTy &other) const
std::pair< DataLayoutEntryKey, Attribute > KeyTy
static DataLayoutEntryAttrStorage * construct(AttributeStorageAllocator &allocator, const KeyTy &key)
constexpr void enumerate(std::tuple< Tys... > &tuple, CallbackT &&callback)
LogicalResult verifyDataLayoutOp(Operation *op)
Verifies that the operation implementing the data layout interface, or a module operation,...
FailureOr< Attribute > query(Operation *op, ArrayRef< DataLayoutEntryKey > keys, bool emitError=false)
Perform a DLTI-query at op, recursively querying each key of keys on query interface-implementing att...
QueryRef parse(llvm::StringRef line, const QuerySession &qs)
Include the generated interface declarations.
InFlightDiagnostic emitError(Location loc)
Utility method to emit an error message using this location.
auto get(MLIRContext *context, Ts &&...params)
Helper method that injects context only if needed, this helps unify some of the attribute constructio...
LogicalResult verify(Operation *op, bool verifyRecursively=true)
Perform (potentially expensive) checks of invariants, used to detect compiler bugs,...