MLIR  22.0.0git
LLVMAttrs.cpp
Go to the documentation of this file.
1 //===- LLVMAttrs.cpp - LLVM Attributes registration -----------------------===//
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 //
9 // This file defines the attribute details for the LLVM IR dialect in MLIR.
10 //
11 //===----------------------------------------------------------------------===//
12 
15 #include "mlir/IR/Builders.h"
18 #include "llvm/ADT/StringExtras.h"
19 #include "llvm/ADT/TypeSwitch.h"
20 #include "llvm/BinaryFormat/Dwarf.h"
21 
22 using namespace mlir;
23 using namespace mlir::LLVM;
24 
25 /// Parses DWARF expression arguments with respect to the DWARF operation
26 /// opcode. Some DWARF expression operations have a specific number of operands
27 /// and may appear in a textual form.
28 static ParseResult parseExpressionArg(AsmParser &parser, uint64_t opcode,
29  SmallVector<uint64_t> &args);
30 
31 /// Prints DWARF expression arguments with respect to the specific DWARF
32 /// operation. Some operands are printed in their textual form.
33 static void printExpressionArg(AsmPrinter &printer, uint64_t opcode,
34  ArrayRef<uint64_t> args);
35 
36 #include "mlir/Dialect/LLVMIR/LLVMAttrInterfaces.cpp.inc"
37 #include "mlir/Dialect/LLVMIR/LLVMOpsEnums.cpp.inc"
38 #define GET_ATTRDEF_CLASSES
39 #include "mlir/Dialect/LLVMIR/LLVMOpsAttrDefs.cpp.inc"
40 
41 //===----------------------------------------------------------------------===//
42 // LLVMDialect registration
43 //===----------------------------------------------------------------------===//
44 
45 void LLVMDialect::registerAttributes() {
46  addAttributes<
47 #define GET_ATTRDEF_LIST
48 #include "mlir/Dialect/LLVMIR/LLVMOpsAttrDefs.cpp.inc"
49 
50  >();
51 }
52 
53 //===----------------------------------------------------------------------===//
54 // AliasScopeAttr
55 //===----------------------------------------------------------------------===//
56 
57 LogicalResult
59  Attribute id, AliasScopeDomainAttr domain,
60  StringAttr description) {
61  (void)domain;
62  (void)description;
63  if (!llvm::isa<StringAttr, DistinctAttr>(id))
64  return emitError()
65  << "id of an alias scope must be a StringAttr or a DistrinctAttr";
66 
67  return success();
68 }
69 
70 //===----------------------------------------------------------------------===//
71 // DINodeAttr
72 //===----------------------------------------------------------------------===//
73 
75  return llvm::isa<
76  DIBasicTypeAttr, DICommonBlockAttr, DICompileUnitAttr,
77  DICompositeTypeAttr, DIDerivedTypeAttr, DIFileAttr, DIGenericSubrangeAttr,
78  DIGlobalVariableAttr, DIImportedEntityAttr, DILabelAttr,
79  DILexicalBlockAttr, DILexicalBlockFileAttr, DILocalVariableAttr,
80  DIModuleAttr, DINamespaceAttr, DINullTypeAttr, DIAnnotationAttr,
81  DIStringTypeAttr, DISubprogramAttr, DISubrangeAttr, DISubroutineTypeAttr>(
82  attr);
83 }
84 
85 //===----------------------------------------------------------------------===//
86 // DIScopeAttr
87 //===----------------------------------------------------------------------===//
88 
90  return llvm::isa<DICommonBlockAttr, DICompileUnitAttr, DICompositeTypeAttr,
91  DIDerivedTypeAttr, DIFileAttr, DILocalScopeAttr,
92  DIModuleAttr, DINamespaceAttr>(attr);
93 }
94 
95 //===----------------------------------------------------------------------===//
96 // DILocalScopeAttr
97 //===----------------------------------------------------------------------===//
98 
100  return llvm::isa<DILexicalBlockAttr, DILexicalBlockFileAttr,
101  DISubprogramAttr>(attr);
102 }
103 
104 //===----------------------------------------------------------------------===//
105 // DIVariableAttr
106 //===----------------------------------------------------------------------===//
107 
109  return llvm::isa<DILocalVariableAttr, DIGlobalVariableAttr>(attr);
110 }
111 
112 //===----------------------------------------------------------------------===//
113 // DITypeAttr
114 //===----------------------------------------------------------------------===//
115 
117  return llvm::isa<DINullTypeAttr, DIBasicTypeAttr, DICompositeTypeAttr,
118  DIDerivedTypeAttr, DIStringTypeAttr, DISubroutineTypeAttr>(
119  attr);
120 }
121 
122 //===----------------------------------------------------------------------===//
123 // TBAANodeAttr
124 //===----------------------------------------------------------------------===//
125 
127  return llvm::isa<TBAATypeDescriptorAttr, TBAARootAttr>(attr);
128 }
129 
130 //===----------------------------------------------------------------------===//
131 // MemoryEffectsAttr
132 //===----------------------------------------------------------------------===//
133 
134 MemoryEffectsAttr MemoryEffectsAttr::get(MLIRContext *context,
135  ArrayRef<ModRefInfo> memInfoArgs) {
136  if (memInfoArgs.empty())
137  return MemoryEffectsAttr::get(context, ModRefInfo::ModRef,
138  ModRefInfo::ModRef, ModRefInfo::ModRef);
139  if (memInfoArgs.size() == 3)
140  return MemoryEffectsAttr::get(context, memInfoArgs[0], memInfoArgs[1],
141  memInfoArgs[2]);
142  return {};
143 }
144 
145 bool MemoryEffectsAttr::isReadWrite() {
146  if (this->getArgMem() != ModRefInfo::ModRef)
147  return false;
148  if (this->getInaccessibleMem() != ModRefInfo::ModRef)
149  return false;
150  if (this->getOther() != ModRefInfo::ModRef)
151  return false;
152  return true;
153 }
154 
155 //===----------------------------------------------------------------------===//
156 // DIExpression
157 //===----------------------------------------------------------------------===//
158 
159 DIExpressionAttr DIExpressionAttr::get(MLIRContext *context) {
160  return get(context, ArrayRef<DIExpressionElemAttr>({}));
161 }
162 
163 ParseResult parseExpressionArg(AsmParser &parser, uint64_t opcode,
164  SmallVector<uint64_t> &args) {
165  auto operandParser = [&]() -> LogicalResult {
166  uint64_t operand = 0;
167  if (!args.empty() && opcode == llvm::dwarf::DW_OP_LLVM_convert) {
168  // Attempt to parse a keyword.
169  StringRef keyword;
170  if (succeeded(parser.parseOptionalKeyword(&keyword))) {
171  operand = llvm::dwarf::getAttributeEncoding(keyword);
172  if (operand == 0) {
173  // The keyword is invalid.
174  return parser.emitError(parser.getCurrentLocation())
175  << "encountered unknown attribute encoding \"" << keyword
176  << "\"";
177  }
178  }
179  }
180 
181  // operand should be non-zero if a keyword was parsed. Otherwise, the
182  // operand MUST be an integer.
183  if (operand == 0) {
184  // Parse the next operand as an integer.
185  if (parser.parseInteger(operand)) {
186  return parser.emitError(parser.getCurrentLocation())
187  << "expected integer operand";
188  }
189  }
190 
191  args.push_back(operand);
192  return success();
193  };
194 
195  // Parse operands as a comma-separated list.
196  return parser.parseCommaSeparatedList(operandParser);
197 }
198 
199 void printExpressionArg(AsmPrinter &printer, uint64_t opcode,
200  ArrayRef<uint64_t> args) {
201  size_t i = 0;
202  llvm::interleaveComma(args, printer, [&](uint64_t operand) {
203  if (i > 0 && opcode == llvm::dwarf::DW_OP_LLVM_convert) {
204  if (const StringRef keyword =
205  llvm::dwarf::AttributeEncodingString(operand);
206  !keyword.empty()) {
207  printer << keyword;
208  return;
209  }
210  }
211  // All operands are expected to be printed as integers.
212  printer << operand;
213  i++;
214  });
215 }
216 
217 //===----------------------------------------------------------------------===//
218 // DICompositeTypeAttr
219 //===----------------------------------------------------------------------===//
220 
221 DIRecursiveTypeAttrInterface
222 DICompositeTypeAttr::withRecId(DistinctAttr recId) {
224  getContext(), recId, getIsRecSelf(), getTag(), getName(), getFile(),
225  getLine(), getScope(), getBaseType(), getFlags(), getSizeInBits(),
226  getAlignInBits(), getElements(), getDataLocation(), getRank(),
227  getAllocated(), getAssociated());
228 }
229 
230 DIRecursiveTypeAttrInterface
231 DICompositeTypeAttr::getRecSelf(DistinctAttr recId) {
232  return DICompositeTypeAttr::get(recId.getContext(), recId, /*isRecSelf=*/true,
233  0, {}, {}, 0, {}, {}, DIFlags(), 0, 0, {}, {},
234  {}, {}, {});
235 }
236 
237 //===----------------------------------------------------------------------===//
238 // DISubprogramAttr
239 //===----------------------------------------------------------------------===//
240 
241 DIRecursiveTypeAttrInterface DISubprogramAttr::withRecId(DistinctAttr recId) {
242  return DISubprogramAttr::get(getContext(), recId, getIsRecSelf(), getId(),
243  getCompileUnit(), getScope(), getName(),
244  getLinkageName(), getFile(), getLine(),
245  getScopeLine(), getSubprogramFlags(), getType(),
246  getRetainedNodes(), getAnnotations());
247 }
248 
249 DIRecursiveTypeAttrInterface DISubprogramAttr::getRecSelf(DistinctAttr recId) {
250  return DISubprogramAttr::get(recId.getContext(), recId, /*isRecSelf=*/true,
251  {}, {}, {}, {}, {}, {}, 0, 0, {}, {}, {}, {});
252 }
253 
254 //===----------------------------------------------------------------------===//
255 // ConstantRangeAttr
256 //===----------------------------------------------------------------------===//
257 
259  llvm::SMLoc loc = parser.getCurrentLocation();
260  IntegerType widthType;
261  if (parser.parseLess() || parser.parseType(widthType) ||
262  parser.parseComma()) {
263  return Attribute{};
264  }
265  unsigned bitWidth = widthType.getWidth();
266  APInt lower(bitWidth, 0);
267  APInt upper(bitWidth, 0);
268  if (parser.parseInteger(lower) || parser.parseComma() ||
269  parser.parseInteger(upper) || parser.parseGreater())
270  return Attribute{};
271  // Non-positive numbers may use more bits than `bitWidth`
272  lower = lower.sextOrTrunc(bitWidth);
273  upper = upper.sextOrTrunc(bitWidth);
274  return parser.getChecked<ConstantRangeAttr>(loc, parser.getContext(), lower,
275  upper);
276 }
277 
278 void ConstantRangeAttr::print(AsmPrinter &printer) const {
279  printer << "<i" << getLower().getBitWidth() << ", " << getLower() << ", "
280  << getUpper() << ">";
281 }
282 
283 LogicalResult
285  APInt lower, APInt upper) {
286  if (lower.getBitWidth() != upper.getBitWidth())
287  return emitError()
288  << "expected lower and upper to have matching bitwidths but got "
289  << lower.getBitWidth() << " vs. " << upper.getBitWidth();
290  return success();
291 }
292 
293 //===----------------------------------------------------------------------===//
294 // TargetFeaturesAttr
295 //===----------------------------------------------------------------------===//
296 
297 TargetFeaturesAttr TargetFeaturesAttr::get(MLIRContext *context,
298  llvm::ArrayRef<StringRef> features) {
299  return Base::get(context,
300  llvm::map_to_vector(features, [&](StringRef feature) {
301  return StringAttr::get(context, feature);
302  }));
303 }
304 
305 TargetFeaturesAttr
306 TargetFeaturesAttr::getChecked(function_ref<InFlightDiagnostic()> emitError,
307  MLIRContext *context,
308  llvm::ArrayRef<StringRef> features) {
309  return Base::getChecked(emitError, context,
310  llvm::map_to_vector(features, [&](StringRef feature) {
311  return StringAttr::get(context, feature);
312  }));
313 }
314 
315 TargetFeaturesAttr TargetFeaturesAttr::get(MLIRContext *context,
316  StringRef targetFeatures) {
317  SmallVector<StringRef> features;
318  targetFeatures.split(features, ',', /*MaxSplit=*/-1,
319  /*KeepEmpty=*/false);
320  return get(context, features);
321 }
322 
323 TargetFeaturesAttr
324 TargetFeaturesAttr::getChecked(function_ref<InFlightDiagnostic()> emitError,
325  MLIRContext *context, StringRef targetFeatures) {
326  SmallVector<StringRef> features;
327  targetFeatures.split(features, ',', /*MaxSplit=*/-1,
328  /*KeepEmpty=*/false);
329  ArrayRef featuresRef(features);
330  return getChecked(emitError, context, featuresRef);
331 }
332 
333 LogicalResult
335  llvm::ArrayRef<StringAttr> features) {
336  for (StringAttr featureAttr : features) {
337  if (!featureAttr || featureAttr.empty())
338  return emitError() << "target features can not be null or empty";
339  auto feature = featureAttr.strref();
340  if (feature[0] != '+' && feature[0] != '-')
341  return emitError() << "target features must start with '+' or '-'";
342  if (feature.contains(','))
343  return emitError() << "target features can not contain ','";
344  }
345  return success();
346 }
347 
348 bool TargetFeaturesAttr::contains(StringAttr feature) const {
349  if (nullOrEmpty())
350  return false;
351  // Note: Using StringAttr does pointer comparisons.
352  return llvm::is_contained(getFeatures(), feature);
353 }
354 
355 bool TargetFeaturesAttr::contains(StringRef feature) const {
356  if (nullOrEmpty())
357  return false;
358  return llvm::is_contained(getFeatures(), feature);
359 }
360 
361 std::string TargetFeaturesAttr::getFeaturesString() const {
362  std::string featuresString;
363  llvm::raw_string_ostream ss(featuresString);
364  llvm::interleave(
365  getFeatures(), ss, [&](auto &feature) { ss << feature.strref(); }, ",");
366  return featuresString;
367 }
368 
369 TargetFeaturesAttr TargetFeaturesAttr::featuresAt(Operation *op) {
370  auto parentFunction = op->getParentOfType<FunctionOpInterface>();
371  if (!parentFunction)
372  return {};
373  return parentFunction.getOperation()->getAttrOfType<TargetFeaturesAttr>(
374  getAttributeName());
375 }
376 
377 LogicalResult
379  LLVM::ModFlagBehavior flagBehavior, StringAttr key,
380  Attribute value) {
381  if (key == LLVMDialect::getModuleFlagKeyCGProfileName()) {
382  auto arrayAttr = dyn_cast<ArrayAttr>(value);
383  if ((!arrayAttr) || (!llvm::all_of(arrayAttr, [](Attribute attr) {
384  return isa<ModuleFlagCGProfileEntryAttr>(attr);
385  })))
386  return emitError()
387  << "'CG Profile' key expects an array of '#llvm.cgprofile_entry'";
388  return success();
389  }
390 
391  if (key == LLVMDialect::getModuleFlagKeyProfileSummaryName()) {
392  if (!isa<ModuleFlagProfileSummaryAttr>(value))
393  return emitError() << "'ProfileSummary' key expects a "
394  "'#llvm.profile_summary' attribute";
395  return success();
396  }
397 
398  if (isa<IntegerAttr, StringAttr>(value))
399  return success();
400 
401  return emitError() << "only integer and string values are currently "
402  "supported for unknown key '"
403  << key << "'";
404 }
static MLIRContext * getContext(OpFoldResult val)
static void printExpressionArg(AsmPrinter &printer, uint64_t opcode, ArrayRef< uint64_t > args)
Prints DWARF expression arguments with respect to the specific DWARF operation.
Definition: LLVMAttrs.cpp:199
static ParseResult parseExpressionArg(AsmParser &parser, uint64_t opcode, SmallVector< uint64_t > &args)
Parses DWARF expression arguments with respect to the DWARF operation opcode.
Definition: LLVMAttrs.cpp:163
static bool contains(SMRange range, SMLoc loc)
Returns true if the given range contains the given source location.
Definition: MLIRServer.cpp:111
static void print(spirv::VerCapExtAttr triple, DialectAsmPrinter &printer)
This base class exposes generic asm parser hooks, usable across the various derived parsers.
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 ParseResult parseOptionalKeyword(StringRef keyword)=0
Parse the given keyword if present.
MLIRContext * getContext() const
Definition: AsmPrinter.cpp:72
virtual InFlightDiagnostic emitError(SMLoc loc, const Twine &message={})=0
Emit a diagnostic at the specified location and return failure.
ParseResult parseInteger(IntT &result)
Parse an integer value from the stream.
virtual ParseResult parseLess()=0
Parse a '<' token.
virtual SMLoc getCurrentLocation()=0
Get the location of the next token and store it into the argument.
auto getChecked(SMLoc loc, ParamsT &&...params)
Invoke the getChecked method of the given Attribute or Type class, using the provided location to emi...
virtual ParseResult parseGreater()=0
Parse a '>' token.
virtual ParseResult parseType(Type &result)=0
Parse a type.
virtual ParseResult parseComma()=0
Parse a , token.
This base class exposes generic asm printer hooks, usable across the various derived printers.
Attributes are known-constant values of operations.
Definition: Attributes.h:25
MLIRContext * getContext() const
Return the context this attribute belongs to.
Definition: Attributes.cpp:37
An attribute that associates a referenced attribute with a unique identifier.
This class represents a diagnostic that is inflight and set to be reported.
Definition: Diagnostics.h:314
This class represents a LLVM attribute that describes a local debug info scope.
Definition: LLVMAttrs.h:46
static bool classof(Attribute attr)
Support LLVM type casting.
Definition: LLVMAttrs.cpp:99
static bool classof(Attribute attr)
Definition: LLVMAttrs.cpp:74
static bool classof(Attribute attr)
Support LLVM type casting.
Definition: LLVMAttrs.cpp:89
static bool classof(Attribute attr)
Support LLVM type casting.
Definition: LLVMAttrs.cpp:116
static bool classof(Attribute attr)
Support LLVM type casting.
Definition: LLVMAttrs.cpp:108
static bool classof(Attribute attr)
Support LLVM type casting.
Definition: LLVMAttrs.cpp:126
MLIRContext is the top-level object for a collection of MLIR operations.
Definition: MLIRContext.h:60
Operation is the basic unit of execution within MLIR.
Definition: Operation.h:88
OpTy getParentOfType()
Return the closest surrounding parent operation that is of type 'OpTy'.
Definition: Operation.h:238
Instances of the Type class are uniqued, have an immutable identifier and an optional mutable compone...
Definition: Types.h:74
QueryRef parse(llvm::StringRef line, const QuerySession &qs)
Definition: Query.cpp:21
Include the generated interface declarations.
Type getType(OpFoldResult ofr)
Returns the int type of the integer in ofr.
Definition: Utils.cpp:305
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,...
Definition: Verifier.cpp:423