18#include "llvm/ADT/MapVector.h"
19#include "llvm/ADT/StringRef.h"
20#include "llvm/ADT/TypeSwitch.h"
24#include "mlir/Dialect/DLTI/DLTIOpInterfaces.cpp.inc"
26#include "mlir/Dialect/DLTI/DLTIDialect.cpp.inc"
28#define GET_ATTRDEF_CLASSES
29#include "mlir/Dialect/DLTI/DLTIAttrs.cpp.inc"
31#define DEBUG_TYPE "dlti"
42 DataLayoutEntryInterface &entry,
43 bool tryType =
false) {
50 if (failed(parsedType.
value()))
52 <<
"error while parsing type DLTI key";
57 entry = DataLayoutEntryAttr::get(type, value);
58 return ParseResult::success();
68 entry = DataLayoutEntryAttr::get(
69 StringAttr::get(parser.
getContext(), ident), value);
70 return ParseResult::success();
75 if (succeeded(parsedEntry.
value()))
76 return parsedEntry.
value();
80 <<
"failed to parse DLTI entry";
92 bool allowEmpty =
false) {
96 return parseKeyValuePair(parser, entries.emplace_back(), tryType);
100 if (entries.empty() && !allowEmpty) {
117 .Case<StringAttr,
Type>(
118 [&](
auto key) { llvm::raw_string_ostream(buf) << key; });
126 llvm::interleaveComma(std::forward<T>(entries), os, [&](
auto entry) {
127 os <<
keyToStr(entry.getKey()) <<
" = " << entry.getValue();
139 bool allowTypes =
true) {
141 for (DataLayoutEntryInterface entry : entries) {
143 return emitError() <<
"contained invalid DLTI entry";
146 return emitError() <<
"contained invalid DLTI key";
147 if (!allowTypes && dyn_cast<Type>(key))
148 return emitError() <<
"type as DLTI key is not allowed";
149 if (
auto strKey = dyn_cast<StringAttr>(key))
150 if (strKey.getValue().empty())
151 return emitError() <<
"empty string as DLTI key is not allowed";
152 if (!keys.insert(key).second)
154 if (!entry.getValue())
168 using KeyTy = std::pair<DataLayoutEntryKey, Attribute>;
189DataLayoutEntryAttr DataLayoutEntryAttr::get(StringAttr key,
Attribute value) {
190 return Base::get(key.getContext(), key, value);
193DataLayoutEntryAttr DataLayoutEntryAttr::get(
Type key,
Attribute value) {
194 return Base::get(key.
getContext(), key, value);
198 return getImpl()->entryKey;
201Attribute DataLayoutEntryAttr::getValue()
const {
return getImpl()->value; }
210 Type typeKey =
nullptr;
211 std::string identifier;
219 parser.
emitError(idLoc) <<
"expected a type or a quoted string";
229 return typeKey ?
get(typeKey, value)
230 :
get(parser.getBuilder().getStringAttr(identifier), value);
233void DataLayoutEntryAttr::print(
AsmPrinter &printer)
const {
234 printer <<
"<" <<
keyToStr(getKey()) <<
", " << getValue() <<
">";
250void MapAttr::print(
AsmPrinter &printer)
const {
275 unsigned oldEntriesSize = oldEntries.size();
276 for (DataLayoutEntryInterface entry : newEntries) {
281 bool replaced =
false;
282 for (
unsigned i = 0; i < oldEntriesSize; ++i) {
283 if (oldEntries[i].getKey() == entry.getKey()) {
284 oldEntries[i] = entry;
290 oldEntries.push_back(entry);
298 DataLayoutSpecInterface spec,
307 spec.bucketEntriesByType(newEntriesForType, newEntriesForID);
311 for (
const auto &kvp : newEntriesForID) {
312 StringAttr
id = cast<StringAttr>(kvp.second.getKey());
313 Dialect *dialect =
id.getReferencedDialect();
314 if (!entriesForID.count(
id)) {
315 entriesForID[id] = kvp.second;
323 dialect ? cast<DataLayoutDialectInterface>(dialect)->combine(
324 entriesForID[
id], kvp.second)
325 : DataLayoutDialectInterface::defaultCombine(entriesForID[
id],
327 if (!entriesForID[
id])
332 for (
auto &kvp : newEntriesForType) {
333 if (!entriesForType.count(kvp.first)) {
334 entriesForType[kvp.first] = std::move(kvp.second);
338 Type typeSample = cast<Type>(kvp.second.front().getKey());
341 "unexpected data layout entry for built-in type");
343 auto interface = cast<DataLayoutTypeInterface>(typeSample);
346 if (!interface.areCompatible(entriesForType.lookup(kvp.first), kvp.second,
360 if (any_of(specs, [](DataLayoutSpecInterface spec) {
361 return !llvm::isa<DataLayoutSpecAttr>(spec);
368 for (DataLayoutSpecInterface spec : specs)
376 llvm::append_range(entries, llvm::make_second_range(entriesForID));
377 for (
const auto &kvp : entriesForType)
378 llvm::append_range(entries, kvp.second);
380 return DataLayoutSpecAttr::get(
getContext(), entries);
384DataLayoutSpecAttr::getEndiannessIdentifier(
MLIRContext *context)
const {
388StringAttr DataLayoutSpecAttr::getDefaultMemorySpaceIdentifier(
391 DLTIDialect::kDataLayoutDefaultMemorySpaceKey);
395DataLayoutSpecAttr::getAllocaMemorySpaceIdentifier(
MLIRContext *context)
const {
397 DLTIDialect::kDataLayoutAllocaMemorySpaceKey);
400StringAttr DataLayoutSpecAttr::getProgramMemorySpaceIdentifier(
403 DLTIDialect::kDataLayoutProgramMemorySpaceKey);
407DataLayoutSpecAttr::getGlobalMemorySpaceIdentifier(
MLIRContext *context)
const {
409 DLTIDialect::kDataLayoutGlobalMemorySpaceKey);
413DataLayoutSpecAttr::getManglingModeIdentifier(
MLIRContext *context)
const {
415 DLTIDialect::kDataLayoutManglingModeKey);
419DataLayoutSpecAttr::getStackAlignmentIdentifier(
MLIRContext *context)
const {
421 DLTIDialect::kDataLayoutStackAlignmentKey);
424StringAttr DataLayoutSpecAttr::getFunctionPointerAlignmentIdentifier(
427 DLTIDialect::kDataLayoutFunctionPointerAlignmentKey);
431DataLayoutSpecAttr::getLegalIntWidthsIdentifier(
MLIRContext *context)
const {
433 DLTIDialect::kDataLayoutLegalIntWidthsKey);
446void DataLayoutSpecAttr::print(
AsmPrinter &printer)
const {
468void TargetDeviceSpecAttr::print(
AsmPrinter &printer)
const {
481 for (
const auto &entry : entries) {
483 llvm::dyn_cast<TargetSystemSpecInterface::DeviceID>(entry.getKey());
485 return emitError() <<
"non-string key of DLTI system spec";
487 if (
auto targetDeviceSpec =
488 llvm::dyn_cast<TargetDeviceSpecInterface>(entry.getValue())) {
490 targetDeviceSpec.getEntries())))
493 return emitError() <<
"value associated with key " << deviceId
494 <<
" is not a DLTI device spec";
498 if (!deviceIds.insert(deviceId).second)
499 return emitError() <<
"repeated device ID in dlti.target_system_spec: "
514void TargetSystemSpecAttr::print(
AsmPrinter &printer)
const {
529 return queryable.query(key);
536 if (
auto stringKey = dyn_cast<StringAttr>(key);
537 stringKey && stringKey.getValue().empty())
543 auto current = dyn_cast_or_null<DLTIQueryInterface>(*inherent);
544 if (current && !isa<MapAttr>(current))
548 if (
auto map = dyn_cast_or_null<MapAttr>(current))
549 llvm::append_range(entries, map.getEntries());
551 auto makeEntry = [&]() -> DataLayoutEntryInterface {
552 if (
auto type = dyn_cast<Type>(key))
553 return DataLayoutEntryAttr::get(type, value);
554 return DataLayoutEntryAttr::get(cast<StringAttr>(key), value);
556 auto entry = llvm::find_if(entries, [&](DataLayoutEntryInterface entry) {
557 return entry.getKey() == key;
559 if (entry != entries.end()) {
561 *entry = makeEntry();
563 entries.erase(entry);
565 entries.push_back(makeEntry());
571 if (entries.empty()) {
586 auto diag = op->
emitError() <<
"target op of failed DLTI query";
587 diag.attachNote(op->
getLoc()) <<
"no keys provided to attempt query with";
594 for (; queryOp; queryOp = queryOp->
getParentOp()) {
595 auto queryable = dyn_cast<DLTIQueryOpInterface>(queryOp);
598 FailureOr<Attribute>
result = queryable.queryDlti(keys.front());
607 auto diag = op->
emitError() <<
"target op of failed DLTI query";
609 <<
"no DLTI-queryable operation on the target or any of its "
610 "ancestors could answer key "
616 for (
auto &&[idx, key] : llvm::enumerate(keys.drop_front())) {
617 if (
auto map = dyn_cast<DLTIQueryInterface>(currentAttr)) {
618 auto maybeAttr = map.query(key);
619 if (failed(maybeAttr)) {
621 auto diag = op->
emitError() <<
"target op of failed DLTI query";
624 <<
" has no DLTI-mapping per attr: " << map;
628 currentAttr = *maybeAttr;
631 std::string commaSeparatedKeys;
633 keys.take_front(idx + 1),
634 [&](
auto key) { commaSeparatedKeys += keyToStr(key); },
635 [&]() { commaSeparatedKeys +=
","; });
637 auto diag = op->
emitError() <<
"target op of failed DLTI query";
639 <<
"got non-DLTI-queryable attribute upon looking up keys ["
640 << commaSeparatedKeys <<
"] at op";
656 entryKeys.reserve(keys.size());
657 for (StringRef key : keys)
658 entryKeys.push_back(StringAttr::get(ctx, key));
664struct ModuleDLTIQueryOpInterface
665 : DLTIQueryOpInterface::ExternalModel<ModuleDLTIQueryOpInterface,
668class TargetDataLayoutInterface :
public DataLayoutDialectInterface {
670 using DataLayoutDialectInterface::DataLayoutDialectInterface;
672 LogicalResult verifyEntry(DataLayoutEntryInterface entry,
674 StringRef entryName = cast<StringAttr>(entry.getKey()).strref();
675 if (entryName == DLTIDialect::kDataLayoutEndiannessKey) {
676 auto value = dyn_cast<StringAttr>(entry.getValue());
678 (value.getValue() == DLTIDialect::kDataLayoutEndiannessBig ||
679 value.getValue() == DLTIDialect::kDataLayoutEndiannessLittle))
681 return emitError(loc) <<
"'" << entryName
682 <<
"' data layout entry is expected to be either '"
683 << DLTIDialect::kDataLayoutEndiannessBig <<
"' or '"
684 << DLTIDialect::kDataLayoutEndiannessLittle <<
"'";
686 if (entryName == DLTIDialect::kDataLayoutDefaultMemorySpaceKey ||
687 entryName == DLTIDialect::kDataLayoutAllocaMemorySpaceKey ||
688 entryName == DLTIDialect::kDataLayoutProgramMemorySpaceKey ||
689 entryName == DLTIDialect::kDataLayoutGlobalMemorySpaceKey ||
690 entryName == DLTIDialect::kDataLayoutStackAlignmentKey ||
691 entryName == DLTIDialect::kDataLayoutFunctionPointerAlignmentKey ||
692 entryName == DLTIDialect::kDataLayoutLegalIntWidthsKey ||
693 entryName == DLTIDialect::kDataLayoutManglingModeKey)
695 return emitError(loc) <<
"unknown data layout entry name: " << entryName;
700void DLTIDialect::initialize() {
702#define GET_ATTRDEF_LIST
703#include "mlir/Dialect/DLTI/DLTIAttrs.cpp.inc"
705 addInterfaces<TargetDataLayoutInterface>();
706 ModuleOp::attachInterface<ModuleDLTIQueryOpInterface>(*
getContext());
709LogicalResult DLTIDialect::verifyOperationAttribute(
Operation *op,
711 if (attr.
getName() == DLTIDialect::kDataLayoutAttrName) {
712 if (!llvm::isa<DataLayoutSpecAttr>(attr.
getValue())) {
713 return op->
emitError() <<
"'" << DLTIDialect::kDataLayoutAttrName
714 <<
"' is expected to be a #dlti.dl_spec attribute";
716 if (isa<ModuleOp>(op))
721 if (attr.
getName() == DLTIDialect::kTargetSystemDescAttrName) {
722 if (!llvm::isa<TargetSystemSpecAttr>(attr.
getValue())) {
724 <<
"'" << DLTIDialect::kTargetSystemDescAttrName
725 <<
"' is expected to be a #dlti.target_system_spec attribute";
730 if (attr.
getName() == DLTIDialect::kMapAttrName) {
731 if (!llvm::isa<MapAttr>(attr.
getValue())) {
732 return op->
emitError() <<
"'" << DLTIDialect::kMapAttrName
733 <<
"' is expected to be a #dlti.map attribute";
739 <<
"' 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