MLIR  14.0.0git
DLTI.cpp
Go to the documentation of this file.
1 //===- DLTI.cpp - Data Layout And Target Info MLIR Dialect Implementation -===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
10 #include "mlir/IR/Builders.h"
11 #include "mlir/IR/BuiltinDialect.h"
12 #include "mlir/IR/BuiltinOps.h"
13 #include "mlir/IR/Dialect.h"
15 #include "llvm/ADT/TypeSwitch.h"
16 
17 using namespace mlir;
18 
19 #include "mlir/Dialect/DLTI/DLTIDialect.cpp.inc"
20 
21 //===----------------------------------------------------------------------===//
22 // DataLayoutEntryAttr
23 //===----------------------------------------------------------------------===//
24 //
25 constexpr const StringLiteral mlir::DataLayoutEntryAttr::kAttrKeyword;
26 
27 namespace mlir {
28 namespace impl {
30 public:
31  using KeyTy = std::pair<DataLayoutEntryKey, Attribute>;
32 
34  : entryKey(entryKey), value(value) {}
35 
37  const KeyTy &key) {
38  return new (allocator.allocate<DataLayoutEntryStorage>())
39  DataLayoutEntryStorage(key.first, key.second);
40  }
41 
42  bool operator==(const KeyTy &other) const {
43  return other.first == entryKey && other.second == value;
44  }
45 
48 };
49 } // namespace impl
50 } // namespace mlir
51 
53  return Base::get(key.getContext(), key, value);
54 }
55 
57  return Base::get(key.getContext(), key, value);
58 }
59 
61  return getImpl()->entryKey;
62 }
63 
64 Attribute DataLayoutEntryAttr::getValue() const { return getImpl()->value; }
65 
66 /// Parses an attribute with syntax:
67 /// attr ::= `#target.` `dl_entry` `<` (type | quoted-string) `,` attr `>`
69  if (failed(parser.parseLess()))
70  return {};
71 
72  Type type = nullptr;
73  std::string identifier;
74  llvm::SMLoc idLoc = parser.getCurrentLocation();
75  OptionalParseResult parsedType = parser.parseOptionalType(type);
76  if (parsedType.hasValue() && failed(parsedType.getValue()))
77  return {};
78  if (!parsedType.hasValue()) {
79  OptionalParseResult parsedString = parser.parseOptionalString(&identifier);
80  if (!parsedString.hasValue() || failed(parsedString.getValue())) {
81  parser.emitError(idLoc) << "expected a type or a quoted string";
82  return {};
83  }
84  }
85 
87  if (failed(parser.parseComma()) || failed(parser.parseAttribute(value)) ||
88  failed(parser.parseGreater()))
89  return {};
90 
91  return type ? get(type, value)
92  : get(parser.getBuilder().getStringAttr(identifier), value);
93 }
94 
97  if (auto type = getKey().dyn_cast<Type>())
98  os << type;
99  else
100  os << "\"" << getKey().get<StringAttr>().strref() << "\"";
101  os << ", " << getValue() << ">";
102 }
103 
104 //===----------------------------------------------------------------------===//
105 // DataLayoutSpecAttr
106 //===----------------------------------------------------------------------===//
107 //
108 constexpr const StringLiteral mlir::DataLayoutSpecAttr::kAttrKeyword;
109 
110 namespace mlir {
111 namespace impl {
113 public:
115 
117  : entries(entries) {}
118 
119  bool operator==(const KeyTy &key) const { return key == entries; }
120 
122  const KeyTy &key) {
123  return new (allocator.allocate<DataLayoutSpecStorage>())
124  DataLayoutSpecStorage(allocator.copyInto(key));
125  }
126 
128 };
129 } // namespace impl
130 } // namespace mlir
131 
135  return Base::get(ctx, entries);
136 }
137 
140  MLIRContext *context,
142  return Base::getChecked(emitError, context, entries);
143 }
144 
148  DenseSet<Type> types;
150  for (DataLayoutEntryInterface entry : entries) {
151  if (auto type = entry.getKey().dyn_cast<Type>()) {
152  if (!types.insert(type).second)
153  return emitError() << "repeated layout entry key: " << type;
154  } else {
155  auto id = entry.getKey().get<StringAttr>();
156  if (!ids.insert(id).second)
157  return emitError() << "repeated layout entry key: " << id.getValue();
158  }
159  }
160  return success();
161 }
162 
163 /// Given a list of old and a list of new entries, overwrites old entries with
164 /// new ones if they have matching keys, appends new entries to the old entry
165 /// list otherwise.
166 static void
169  unsigned oldEntriesSize = oldEntries.size();
170  for (DataLayoutEntryInterface entry : newEntries) {
171  // We expect a small (dozens) number of entries, so it is practically
172  // cheaper to iterate over the list linearly rather than to create an
173  // auxiliary hashmap to avoid duplication. Also note that we never need to
174  // check for duplicate keys the values that were added from `newEntries`.
175  bool replaced = false;
176  for (unsigned i = 0; i < oldEntriesSize; ++i) {
177  if (oldEntries[i].getKey() == entry.getKey()) {
178  oldEntries[i] = entry;
179  replaced = true;
180  break;
181  }
182  }
183  if (!replaced)
184  oldEntries.push_back(entry);
185  }
186 }
187 
188 /// Combines a data layout spec into the given lists of entries organized by
189 /// type class and identifier, overwriting them if necessary. Fails to combine
190 /// if the two entries with identical keys are not compatible.
191 static LogicalResult
192 combineOneSpec(DataLayoutSpecInterface spec,
195  // A missing spec should be fine.
196  if (!spec)
197  return success();
198 
199  DenseMap<TypeID, DataLayoutEntryList> newEntriesForType;
201  spec.bucketEntriesByType(newEntriesForType, newEntriesForID);
202 
203  // Try overwriting the old entries with the new ones.
204  for (auto &kvp : newEntriesForType) {
205  if (!entriesForType.count(kvp.first)) {
206  entriesForType[kvp.first] = std::move(kvp.second);
207  continue;
208  }
209 
210  Type typeSample = kvp.second.front().getKey().get<Type>();
211  assert(&typeSample.getDialect() !=
212  typeSample.getContext()->getLoadedDialect<BuiltinDialect>() &&
213  "unexpected data layout entry for built-in type");
214 
215  auto interface = typeSample.cast<DataLayoutTypeInterface>();
216  if (!interface.areCompatible(entriesForType.lookup(kvp.first), kvp.second))
217  return failure();
218 
219  overwriteDuplicateEntries(entriesForType[kvp.first], kvp.second);
220  }
221 
222  for (const auto &kvp : newEntriesForID) {
223  StringAttr id = kvp.second.getKey().get<StringAttr>();
224  Dialect *dialect = id.getReferencedDialect();
225  if (!entriesForID.count(id)) {
226  entriesForID[id] = kvp.second;
227  continue;
228  }
229 
230  // Attempt to combine the enties using the dialect interface. If the
231  // dialect is not loaded for some reason, use the default combinator
232  // that conservatively accepts identical entries only.
233  entriesForID[id] =
234  dialect ? dialect->getRegisteredInterface<DataLayoutDialectInterface>()
235  ->combine(entriesForID[id], kvp.second)
237  kvp.second);
238  if (!entriesForID[id])
239  return failure();
240  }
241 
242  return success();
243 }
244 
247  // Only combine with attributes of the same kind.
248  // TODO: reconsider this when the need arises.
249  if (llvm::any_of(specs, [](DataLayoutSpecInterface spec) {
250  return !spec.isa<DataLayoutSpecAttr>();
251  }))
252  return {};
253 
254  // Combine all specs in order, with `this` being the last one.
257  for (DataLayoutSpecInterface spec : specs)
258  if (failed(combineOneSpec(spec, entriesForType, entriesForID)))
259  return nullptr;
260  if (failed(combineOneSpec(*this, entriesForType, entriesForID)))
261  return nullptr;
262 
263  // Rebuild the linear list of entries.
265  llvm::append_range(entries, llvm::make_second_range(entriesForID));
266  for (const auto &kvp : entriesForType)
267  llvm::append_range(entries, kvp.getSecond());
268 
269  return DataLayoutSpecAttr::get(getContext(), entries);
270 }
271 
273  return getImpl()->entries;
274 }
275 
276 /// Parses an attribute with syntax
277 /// attr ::= `#target.` `dl_spec` `<` attr-list? `>`
278 /// attr-list ::= attr
279 /// | attr `,` attr-list
281  if (failed(parser.parseLess()))
282  return {};
283 
284  // Empty spec.
285  if (succeeded(parser.parseOptionalGreater()))
286  return get(parser.getContext(), {});
287 
289  do {
290  entries.emplace_back();
291  if (failed(parser.parseAttribute(entries.back())))
292  return {};
293  } while (succeeded(parser.parseOptionalComma()));
294 
295  if (failed(parser.parseGreater()))
296  return {};
297  return getChecked([&] { return parser.emitError(parser.getNameLoc()); },
298  parser.getContext(), entries);
299 }
300 
303  llvm::interleaveComma(getEntries(), os);
304  os << ">";
305 }
306 
307 //===----------------------------------------------------------------------===//
308 // DLTIDialect
309 //===----------------------------------------------------------------------===//
310 
311 constexpr const StringLiteral mlir::DLTIDialect::kDataLayoutAttrName;
312 constexpr const StringLiteral mlir::DLTIDialect::kDataLayoutEndiannessKey;
313 constexpr const StringLiteral mlir::DLTIDialect::kDataLayoutEndiannessBig;
314 constexpr const StringLiteral mlir::DLTIDialect::kDataLayoutEndiannessLittle;
315 
316 namespace {
317 class TargetDataLayoutInterface : public DataLayoutDialectInterface {
318 public:
320 
321  LogicalResult verifyEntry(DataLayoutEntryInterface entry,
322  Location loc) const final {
323  StringRef entryName = entry.getKey().get<StringAttr>().strref();
324  if (entryName == DLTIDialect::kDataLayoutEndiannessKey) {
325  auto value = entry.getValue().dyn_cast<StringAttr>();
326  if (value &&
327  (value.getValue() == DLTIDialect::kDataLayoutEndiannessBig ||
328  value.getValue() == DLTIDialect::kDataLayoutEndiannessLittle))
329  return success();
330  return emitError(loc) << "'" << entryName
331  << "' data layout entry is expected to be either '"
332  << DLTIDialect::kDataLayoutEndiannessBig << "' or '"
333  << DLTIDialect::kDataLayoutEndiannessLittle << "'";
334  }
335  return emitError(loc) << "unknown data layout entry name: " << entryName;
336  }
337 };
338 } // namespace
339 
340 void DLTIDialect::initialize() {
341  addAttributes<DataLayoutEntryAttr, DataLayoutSpecAttr>();
342  addInterfaces<TargetDataLayoutInterface>();
343 }
344 
346  Type type) const {
347  StringRef attrKind;
348  if (parser.parseKeyword(&attrKind))
349  return {};
350 
351  if (attrKind == DataLayoutEntryAttr::kAttrKeyword)
352  return DataLayoutEntryAttr::parse(parser);
353  if (attrKind == DataLayoutSpecAttr::kAttrKeyword)
354  return DataLayoutSpecAttr::parse(parser);
355 
356  parser.emitError(parser.getNameLoc(), "unknown attrribute type: ")
357  << attrKind;
358  return {};
359 }
360 
361 void DLTIDialect::printAttribute(Attribute attr, DialectAsmPrinter &os) const {
363  .Case<DataLayoutEntryAttr, DataLayoutSpecAttr>(
364  [&](auto a) { a.print(os); })
365  .Default([](Attribute) { llvm_unreachable("unknown attribute kind"); });
366 }
367 
368 LogicalResult DLTIDialect::verifyOperationAttribute(Operation *op,
369  NamedAttribute attr) {
370  if (attr.getName() == DLTIDialect::kDataLayoutAttrName) {
371  if (!attr.getValue().isa<DataLayoutSpecAttr>()) {
372  return op->emitError() << "'" << DLTIDialect::kDataLayoutAttrName
373  << "' is expected to be a #dlti.dl_spec attribute";
374  }
375  if (isa<ModuleOp>(op))
376  return detail::verifyDataLayoutOp(op);
377  return success();
378  }
379 
380  return op->emitError() << "attribute '" << attr.getName().getValue()
381  << "' not supported by dialect";
382 }
Include the generated interface declarations.
A data layout entry attribute is a key-value pair where the key is a type or an identifier and the va...
Definition: DLTI.h:33
Attribute parseAttribute(llvm::StringRef attrStr, MLIRContext *context)
This parses a single MLIR attribute to an MLIR context if it was valid.
Dialect & getDialect() const
Get the dialect this type is registered to.
Definition: Types.h:114
static DataLayoutEntryAttr parse(AsmParser &parser)
Parses an instance of this attribute.
Definition: DLTI.cpp:68
Operation is a basic unit of execution within MLIR.
Definition: Operation.h:28
Attribute getValue() const
Return the value of the attribute.
Definition: Attributes.h:151
This class represents a diagnostic that is inflight and set to be reported.
Definition: Diagnostics.h:301
bool isa() const
Definition: Attributes.h:107
bool failed(LogicalResult result)
Utility function that returns true if the provided LogicalResult corresponds to a failure value...
Definition: LogicalResult.h:72
This is a utility allocator used to allocate memory for instances of derived types.
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...
Definition: DLTI.cpp:192
DataLayoutSpecAttr combineWith(ArrayRef< DataLayoutSpecInterface > specs) const
Combines this specification with specs, enclosing specifications listed from outermost to innermost...
Definition: DLTI.cpp:246
bool operator==(const KeyTy &key) const
Definition: DLTI.cpp:119
bool succeeded(LogicalResult result)
Utility function that returns true if the provided LogicalResult corresponds to a success value...
Definition: LogicalResult.h:68
virtual Builder & getBuilder() const =0
Return a builder which provides useful access to MLIRContext, global objects like types and attribute...
virtual ParseResult parseOptionalString(std::string *string)=0
Parse a quoted string token if present.
static DataLayoutEntryStorage * construct(AttributeStorageAllocator &allocator, const KeyTy &key)
Definition: DLTI.cpp:36
DataLayoutEntryStorage(DataLayoutEntryKey entryKey, Attribute value)
Definition: DLTI.cpp:33
virtual ParseResult parseComma()=0
Parse a , token.
virtual llvm::SMLoc getNameLoc() const =0
Return the location of the original name token.
DataLayoutSpecStorage(ArrayRef< DataLayoutEntryInterface > entries)
Definition: DLTI.cpp:116
DataLayoutEntryListRef getEntries() const
Returns the list of entries.
Definition: DLTI.cpp:272
A data layout specification is a list of entries that specify (partial) data layout information...
Definition: DLTI.h:67
virtual ParseResult parseOptionalComma()=0
Parse a , token if present.
This class defines the main interface for locations in MLIR and acts as a non-nullable wrapper around...
Definition: Location.h:48
NamedAttribute represents a combination of a name and an Attribute value.
Definition: Attributes.h:137
void print(AsmPrinter &os) const
Prints this attribute.
Definition: DLTI.cpp:301
bool operator==(const KeyTy &other) const
Definition: DLTI.cpp:42
static DataLayoutEntryAttr get(StringAttr key, Attribute value)
Returns the entry with the given key and value.
Definition: DLTI.cpp:52
T * allocate()
Allocate an instance of the provided type.
LogicalResult success(bool isSuccess=true)
Utility function to generate a LogicalResult.
Definition: LogicalResult.h:56
This class represents an efficient way to signal success or failure.
Definition: LogicalResult.h:26
LogicalResult failure(bool isFailure=true)
Utility function to generate a LogicalResult.
Definition: LogicalResult.h:62
constexpr static const llvm::StringLiteral kAttrKeyword
The keyword used for this attribute in custom syntax.
Definition: DLTI.h:41
virtual ParseResult parseGreater()=0
Parse a &#39;>&#39; token.
virtual llvm::SMLoc getCurrentLocation()=0
Get the location of the next token and store it into the argument.
ArrayRef< DataLayoutEntryInterface > entries
Definition: DLTI.cpp:127
void print(AsmPrinter &os) const
Prints this attribute.
Definition: DLTI.cpp:95
static LogicalResult verify(function_ref< InFlightDiagnostic()> emitError, ArrayRef< DataLayoutEntryInterface > entries)
Checks that the given list of entries does not contain duplicate keys.
Definition: DLTI.cpp:146
Attributes are known-constant values of operations.
Definition: Attributes.h:24
DataLayoutEntryKey getKey() const
Returns the key of this entry.
Definition: DLTI.cpp:60
StringAttr getName() const
Return the name of the attribute.
Definition: Attributes.cpp:32
Attribute getValue() const
Returns the value of this entry.
Definition: DLTI.cpp:64
Dialects are groups of MLIR operations, types and attributes, as well as behavior associated with the...
Definition: Dialect.h:42
ParseResult parseKeyword(StringRef keyword, const Twine &msg="")
Parse a given keyword.
virtual ParseResult parseLess()=0
Parse a &#39;<&#39; token.
This base class exposes generic asm parser hooks, usable across the various derived parsers...
DataLayoutEntryKey entryKey
Definition: DLTI.cpp:46
Instances of the Type class are uniqued, have an immutable identifier and an optional mutable compone...
Definition: Types.h:72
static DataLayoutEntryInterface defaultCombine(DataLayoutEntryInterface outer, DataLayoutEntryInterface inner)
Default implementation of entry combination that combines identical entries and returns null otherwis...
MLIRContext * getContext() const
Return the MLIRContext in which this type was uniqued.
Definition: Types.cpp:19
static DataLayoutSpecAttr parse(AsmParser &parser)
Parses an instance of this attribute.
Definition: DLTI.cpp:280
constexpr static const StringLiteral kAttrKeyword
The keyword used for this attribute in custom syntax.
Definition: DLTI.h:75
ParseResult getValue() const
Access the internal ParseResult value.
Definition: OpDefinition.h:65
This class implements Optional functionality for ParseResult.
Definition: OpDefinition.h:52
virtual InFlightDiagnostic emitError(llvm::SMLoc loc, const Twine &message={})=0
Emit a diagnostic at the specified location and return failure.
static DataLayoutSpecStorage * construct(AttributeStorageAllocator &allocator, const KeyTy &key)
Definition: DLTI.cpp:121
InFlightDiagnostic emitError(Location loc)
Utility method to emit an error message using this location.
virtual ParseResult parseOptionalGreater()=0
Parse a &#39;>&#39; token if present.
LogicalResult verifyDataLayoutOp(Operation *op)
Verifies that the operation implementing the data layout interface, or a module operation, is valid.
OwningOpRef< spirv::ModuleOp > combine(ArrayRef< spirv::ModuleOp > inputModules, OpBuilder &combinedModuleBuilder, SymbolRenameListener symRenameListener)
Combines a list of SPIR-V inputModules into one.
U dyn_cast() const
Definition: Attributes.h:117
This is a pure-virtual base class that exposes the asmprinter hooks necessary to implement a custom p...
MLIRContext is the top-level object for a collection of MLIR operations.
Definition: MLIRContext.h:55
Base storage class appearing in an attribute.
This base class exposes generic asm printer hooks, usable across the various derived printers...
bool hasValue() const
Returns true if we contain a valid ParseResult value.
Definition: OpDefinition.h:62
ArrayRef< T > copyInto(ArrayRef< T > elements)
Copy the specified array of elements into memory managed by our bump pointer allocator.
static DataLayoutSpecAttr get(MLIRContext *ctx, ArrayRef< DataLayoutEntryInterface > entries)
Returns the specification containing the given list of keys.
Definition: DLTI.cpp:133
static DataLayoutSpecAttr getChecked(function_ref< InFlightDiagnostic()> emitError, MLIRContext *context, ArrayRef< DataLayoutEntryInterface > entries)
Returns the specification containing the given list of keys.
Definition: DLTI.cpp:139
An interface to be implemented by dialects that can have identifiers in the data layout specification...
InFlightDiagnostic emitError(const Twine &message={})
Emit an error about fatal conditions with this operation, reporting up to any diagnostic handlers tha...
Definition: Operation.cpp:231
MLIRContext * getContext() const
Definition: AsmPrinter.cpp:61
virtual ParseResult parseAttribute(Attribute &result, Type type={})=0
Parse an arbitrary attribute of a given type and return it in result.
Dialect * getLoadedDialect(StringRef name)
Get a registered IR dialect with the given namespace.
virtual OptionalParseResult parseOptionalType(Type &result)=0
Parse an optional type.
StringAttr getStringAttr(const Twine &bytes)
Definition: Builders.cpp:201
The DialectAsmParser has methods for interacting with the asm parser when parsing attributes and type...
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...
Definition: DLTI.cpp:167
std::pair< DataLayoutEntryKey, Attribute > KeyTy
Definition: DLTI.cpp:31