18#include "llvm/ADT/MapVector.h"
19#include "llvm/ADT/TypeSwitch.h"
23#include "mlir/Dialect/DLTI/DLTIDialect.cpp.inc"
25#define GET_ATTRDEF_CLASSES
26#include "mlir/Dialect/DLTI/DLTIAttrs.cpp.inc"
28#define DEBUG_TYPE "dlti"
39 DataLayoutEntryInterface &entry,
40 bool tryType =
false) {
47 if (failed(parsedType.
value()))
49 <<
"error while parsing type DLTI key";
54 entry = DataLayoutEntryAttr::get(type, value);
55 return ParseResult::success();
65 entry = DataLayoutEntryAttr::get(
66 StringAttr::get(parser.
getContext(), ident), value);
67 return ParseResult::success();
72 if (succeeded(parsedEntry.
value()))
73 return parsedEntry.
value();
77 <<
"failed to parse DLTI entry";
89 bool allowEmpty =
false) {
93 return parseKeyValuePair(parser, entries.emplace_back(), tryType);
97 if (entries.empty() && !allowEmpty) {
114 .Case<StringAttr,
Type>(
115 [&](
auto key) { llvm::raw_string_ostream(buf) << key; });
123 llvm::interleaveComma(std::forward<T>(entries), os, [&](
auto entry) {
124 os <<
keyToStr(entry.getKey()) <<
" = " << entry.getValue();
136 bool allowTypes =
true) {
138 for (DataLayoutEntryInterface entry : entries) {
140 return emitError() <<
"contained invalid DLTI entry";
143 return emitError() <<
"contained invalid DLTI key";
144 if (!allowTypes && dyn_cast<Type>(key))
145 return emitError() <<
"type as DLTI key is not allowed";
146 if (
auto strKey = dyn_cast<StringAttr>(key))
147 if (strKey.getValue().empty())
148 return emitError() <<
"empty string as DLTI key is not allowed";
149 if (!keys.insert(key).second)
151 if (!entry.getValue())
165 using KeyTy = std::pair<DataLayoutEntryKey, Attribute>;
186DataLayoutEntryAttr DataLayoutEntryAttr::get(StringAttr key,
Attribute value) {
187 return Base::get(key.getContext(), key, value);
190DataLayoutEntryAttr DataLayoutEntryAttr::get(
Type key,
Attribute value) {
191 return Base::get(key.
getContext(), key, value);
195 return getImpl()->entryKey;
198Attribute DataLayoutEntryAttr::getValue()
const {
return getImpl()->value; }
207 Type typeKey =
nullptr;
208 std::string identifier;
216 parser.
emitError(idLoc) <<
"expected a type or a quoted string";
226 return typeKey ?
get(typeKey, value)
227 :
get(parser.getBuilder().getStringAttr(identifier), value);
230void DataLayoutEntryAttr::print(
AsmPrinter &printer)
const {
231 printer <<
"<" <<
keyToStr(getKey()) <<
", " << getValue() <<
">";
247void MapAttr::print(
AsmPrinter &printer)
const {
272 unsigned oldEntriesSize = oldEntries.size();
273 for (DataLayoutEntryInterface entry : newEntries) {
278 bool replaced =
false;
279 for (
unsigned i = 0; i < oldEntriesSize; ++i) {
280 if (oldEntries[i].getKey() == entry.getKey()) {
281 oldEntries[i] = entry;
287 oldEntries.push_back(entry);
295 DataLayoutSpecInterface spec,
296 llvm::MapVector<TypeID, DataLayoutEntryList> &entriesForType,
297 llvm::MapVector<StringAttr, DataLayoutEntryInterface> &entriesForID) {
302 llvm::MapVector<TypeID, DataLayoutEntryList> newEntriesForType;
303 llvm::MapVector<StringAttr, DataLayoutEntryInterface> newEntriesForID;
304 spec.bucketEntriesByType(newEntriesForType, newEntriesForID);
308 for (
const auto &kvp : newEntriesForID) {
309 StringAttr
id = cast<StringAttr>(kvp.second.getKey());
310 Dialect *dialect =
id.getReferencedDialect();
311 if (!entriesForID.count(
id)) {
312 entriesForID[id] = kvp.second;
320 dialect ? cast<DataLayoutDialectInterface>(dialect)->combine(
321 entriesForID[
id], kvp.second)
324 if (!entriesForID[
id])
329 for (
auto &kvp : newEntriesForType) {
330 if (!entriesForType.count(kvp.first)) {
331 entriesForType[kvp.first] = std::move(kvp.second);
335 Type typeSample = cast<Type>(kvp.second.front().getKey());
338 "unexpected data layout entry for built-in type");
340 auto interface = cast<DataLayoutTypeInterface>(typeSample);
343 if (!interface.areCompatible(entriesForType.lookup(kvp.first), kvp.second,
357 if (any_of(specs, [](DataLayoutSpecInterface spec) {
358 return !llvm::isa<DataLayoutSpecAttr>(spec);
363 llvm::MapVector<TypeID, DataLayoutEntryList> entriesForType;
364 llvm::MapVector<StringAttr, DataLayoutEntryInterface> entriesForID;
365 for (DataLayoutSpecInterface spec : specs)
373 llvm::append_range(entries, llvm::make_second_range(entriesForID));
374 for (
const auto &kvp : entriesForType)
375 llvm::append_range(entries, kvp.second);
377 return DataLayoutSpecAttr::get(
getContext(), entries);
381DataLayoutSpecAttr::getEndiannessIdentifier(
MLIRContext *context)
const {
385StringAttr DataLayoutSpecAttr::getDefaultMemorySpaceIdentifier(
388 DLTIDialect::kDataLayoutDefaultMemorySpaceKey);
392DataLayoutSpecAttr::getAllocaMemorySpaceIdentifier(
MLIRContext *context)
const {
394 DLTIDialect::kDataLayoutAllocaMemorySpaceKey);
397StringAttr DataLayoutSpecAttr::getProgramMemorySpaceIdentifier(
400 DLTIDialect::kDataLayoutProgramMemorySpaceKey);
404DataLayoutSpecAttr::getGlobalMemorySpaceIdentifier(
MLIRContext *context)
const {
406 DLTIDialect::kDataLayoutGlobalMemorySpaceKey);
410DataLayoutSpecAttr::getManglingModeIdentifier(
MLIRContext *context)
const {
412 DLTIDialect::kDataLayoutManglingModeKey);
416DataLayoutSpecAttr::getStackAlignmentIdentifier(
MLIRContext *context)
const {
418 DLTIDialect::kDataLayoutStackAlignmentKey);
421StringAttr DataLayoutSpecAttr::getFunctionPointerAlignmentIdentifier(
424 DLTIDialect::kDataLayoutFunctionPointerAlignmentKey);
428DataLayoutSpecAttr::getLegalIntWidthsIdentifier(
MLIRContext *context)
const {
430 DLTIDialect::kDataLayoutLegalIntWidthsKey);
443void DataLayoutSpecAttr::print(
AsmPrinter &printer)
const {
465void TargetDeviceSpecAttr::print(
AsmPrinter &printer)
const {
478 for (
const auto &entry : entries) {
480 llvm::dyn_cast<TargetSystemSpecInterface::DeviceID>(entry.getKey());
482 return emitError() <<
"non-string key of DLTI system spec";
484 if (
auto targetDeviceSpec =
485 llvm::dyn_cast<TargetDeviceSpecInterface>(entry.getValue())) {
487 targetDeviceSpec.getEntries())))
490 return emitError() <<
"value associated with key " << deviceId
491 <<
" is not a DLTI device spec";
495 if (!deviceIds.insert(deviceId).second)
496 return emitError() <<
"repeated device ID in dlti.target_system_spec: "
511void TargetSystemSpecAttr::print(
AsmPrinter &printer)
const {
522static std::pair<DLTIQueryInterface, Operation *>
524 DLTIQueryInterface queryable = {};
529 if ((queryable = dyn_cast<DLTIQueryInterface>(attr.getValue())))
533 return std::pair(queryable, op);
543 auto diag = op->
emitError() <<
"target op of failed DLTI query";
544 diag.attachNote(op->
getLoc()) <<
"no keys provided to attempt query with";
550 Operation *reportOp = (queryOp ? queryOp : op);
554 auto diag = op->
emitError() <<
"target op of failed DLTI query";
556 <<
"no DLTI-queryable attrs on target op or any of its ancestors";
562 for (
auto &&[idx, key] : llvm::enumerate(keys)) {
563 if (
auto map = dyn_cast<DLTIQueryInterface>(currentAttr)) {
564 auto maybeAttr = map.query(key);
565 if (failed(maybeAttr)) {
567 auto diag = op->
emitError() <<
"target op of failed DLTI query";
570 <<
" has no DLTI-mapping per attr: " << map;
574 currentAttr = *maybeAttr;
577 std::string commaSeparatedKeys;
579 keys.take_front(idx),
580 [&](
auto key) { commaSeparatedKeys += keyToStr(key); },
581 [&]() { commaSeparatedKeys +=
","; });
583 auto diag = op->
emitError() <<
"target op of failed DLTI query";
585 <<
"got non-DLTI-queryable attribute upon looking up keys ["
586 << commaSeparatedKeys <<
"] at op";
602 entryKeys.reserve(keys.size());
603 for (StringRef key : keys)
604 entryKeys.push_back(StringAttr::get(ctx, key));
614 LogicalResult verifyEntry(DataLayoutEntryInterface entry,
616 StringRef entryName = cast<StringAttr>(entry.getKey()).strref();
617 if (entryName == DLTIDialect::kDataLayoutEndiannessKey) {
618 auto value = dyn_cast<StringAttr>(entry.getValue());
620 (value.getValue() == DLTIDialect::kDataLayoutEndiannessBig ||
621 value.getValue() == DLTIDialect::kDataLayoutEndiannessLittle))
623 return emitError(loc) <<
"'" << entryName
624 <<
"' data layout entry is expected to be either '"
625 << DLTIDialect::kDataLayoutEndiannessBig <<
"' or '"
626 << DLTIDialect::kDataLayoutEndiannessLittle <<
"'";
628 if (entryName == DLTIDialect::kDataLayoutDefaultMemorySpaceKey ||
629 entryName == DLTIDialect::kDataLayoutAllocaMemorySpaceKey ||
630 entryName == DLTIDialect::kDataLayoutProgramMemorySpaceKey ||
631 entryName == DLTIDialect::kDataLayoutGlobalMemorySpaceKey ||
632 entryName == DLTIDialect::kDataLayoutStackAlignmentKey ||
633 entryName == DLTIDialect::kDataLayoutFunctionPointerAlignmentKey ||
634 entryName == DLTIDialect::kDataLayoutLegalIntWidthsKey ||
635 entryName == DLTIDialect::kDataLayoutManglingModeKey)
637 return emitError(loc) <<
"unknown data layout entry name: " << entryName;
642void DLTIDialect::initialize() {
644#define GET_ATTRDEF_LIST
645#include "mlir/Dialect/DLTI/DLTIAttrs.cpp.inc"
647 addInterfaces<TargetDataLayoutInterface>();
650LogicalResult DLTIDialect::verifyOperationAttribute(
Operation *op,
652 if (attr.
getName() == DLTIDialect::kDataLayoutAttrName) {
653 if (!llvm::isa<DataLayoutSpecAttr>(attr.
getValue())) {
654 return op->
emitError() <<
"'" << DLTIDialect::kDataLayoutAttrName
655 <<
"' is expected to be a #dlti.dl_spec attribute";
657 if (isa<ModuleOp>(op))
662 if (attr.
getName() == DLTIDialect::kTargetSystemDescAttrName) {
663 if (!llvm::isa<TargetSystemSpecAttr>(attr.
getValue())) {
665 <<
"'" << DLTIDialect::kTargetSystemDescAttrName
666 <<
"' is expected to be a #dlti.target_system_spec attribute";
671 if (attr.
getName() == DLTIDialect::kMapAttrName) {
672 if (!llvm::isa<MapAttr>(attr.
getValue())) {
673 return op->
emitError() <<
"'" << DLTIDialect::kMapAttrName
674 <<
"' is expected to be a #dlti.map attribute";
680 <<
"' 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 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.
static std::string diag(const llvm::Value &value)
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.
ArrayRef< NamedAttribute > getAttrs()
Return all of the attributes on this operation.
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,...
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...
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