MLIR  20.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 #include "llvm/IR/DebugInfoMetadata.h"
22 #include <optional>
23 
24 using namespace mlir;
25 using namespace mlir::LLVM;
26 
27 /// Parses DWARF expression arguments with respect to the DWARF operation
28 /// opcode. Some DWARF expression operations have a specific number of operands
29 /// and may appear in a textual form.
30 static ParseResult parseExpressionArg(AsmParser &parser, uint64_t opcode,
31  SmallVector<uint64_t> &args);
32 
33 /// Prints DWARF expression arguments with respect to the specific DWARF
34 /// operation. Some operands are printed in their textual form.
35 static void printExpressionArg(AsmPrinter &printer, uint64_t opcode,
36  ArrayRef<uint64_t> args);
37 
38 #include "mlir/Dialect/LLVMIR/LLVMAttrInterfaces.cpp.inc"
39 #include "mlir/Dialect/LLVMIR/LLVMOpsEnums.cpp.inc"
40 #define GET_ATTRDEF_CLASSES
41 #include "mlir/Dialect/LLVMIR/LLVMOpsAttrDefs.cpp.inc"
42 
43 //===----------------------------------------------------------------------===//
44 // LLVMDialect registration
45 //===----------------------------------------------------------------------===//
46 
47 void LLVMDialect::registerAttributes() {
48  addAttributes<
49 #define GET_ATTRDEF_LIST
50 #include "mlir/Dialect/LLVMIR/LLVMOpsAttrDefs.cpp.inc"
51 
52  >();
53 }
54 
55 //===----------------------------------------------------------------------===//
56 // DINodeAttr
57 //===----------------------------------------------------------------------===//
58 
60  return llvm::isa<
61  DIBasicTypeAttr, DICommonBlockAttr, DICompileUnitAttr,
62  DICompositeTypeAttr, DIDerivedTypeAttr, DIFileAttr, DIGenericSubrangeAttr,
63  DIGlobalVariableAttr, DIImportedEntityAttr, DILabelAttr,
64  DILexicalBlockAttr, DILexicalBlockFileAttr, DILocalVariableAttr,
65  DIModuleAttr, DINamespaceAttr, DINullTypeAttr, DIAnnotationAttr,
66  DIStringTypeAttr, DISubprogramAttr, DISubrangeAttr, DISubroutineTypeAttr>(
67  attr);
68 }
69 
70 //===----------------------------------------------------------------------===//
71 // DIScopeAttr
72 //===----------------------------------------------------------------------===//
73 
75  return llvm::isa<DICommonBlockAttr, DICompileUnitAttr, DICompositeTypeAttr,
76  DIFileAttr, DILocalScopeAttr, DIModuleAttr, DINamespaceAttr>(
77  attr);
78 }
79 
80 //===----------------------------------------------------------------------===//
81 // DILocalScopeAttr
82 //===----------------------------------------------------------------------===//
83 
85  return llvm::isa<DILexicalBlockAttr, DILexicalBlockFileAttr,
86  DISubprogramAttr>(attr);
87 }
88 
89 //===----------------------------------------------------------------------===//
90 // DIVariableAttr
91 //===----------------------------------------------------------------------===//
92 
94  return llvm::isa<DILocalVariableAttr, DIGlobalVariableAttr>(attr);
95 }
96 
97 //===----------------------------------------------------------------------===//
98 // DITypeAttr
99 //===----------------------------------------------------------------------===//
100 
102  return llvm::isa<DINullTypeAttr, DIBasicTypeAttr, DICompositeTypeAttr,
103  DIDerivedTypeAttr, DIStringTypeAttr, DISubroutineTypeAttr>(
104  attr);
105 }
106 
107 //===----------------------------------------------------------------------===//
108 // TBAANodeAttr
109 //===----------------------------------------------------------------------===//
110 
112  return llvm::isa<TBAATypeDescriptorAttr, TBAARootAttr>(attr);
113 }
114 
115 //===----------------------------------------------------------------------===//
116 // MemoryEffectsAttr
117 //===----------------------------------------------------------------------===//
118 
119 MemoryEffectsAttr MemoryEffectsAttr::get(MLIRContext *context,
120  ArrayRef<ModRefInfo> memInfoArgs) {
121  if (memInfoArgs.empty())
122  return MemoryEffectsAttr::get(context, ModRefInfo::ModRef,
123  ModRefInfo::ModRef, ModRefInfo::ModRef);
124  if (memInfoArgs.size() == 3)
125  return MemoryEffectsAttr::get(context, memInfoArgs[0], memInfoArgs[1],
126  memInfoArgs[2]);
127  return {};
128 }
129 
130 bool MemoryEffectsAttr::isReadWrite() {
131  if (this->getArgMem() != ModRefInfo::ModRef)
132  return false;
133  if (this->getInaccessibleMem() != ModRefInfo::ModRef)
134  return false;
135  if (this->getOther() != ModRefInfo::ModRef)
136  return false;
137  return true;
138 }
139 
140 //===----------------------------------------------------------------------===//
141 // DIExpression
142 //===----------------------------------------------------------------------===//
143 
144 DIExpressionAttr DIExpressionAttr::get(MLIRContext *context) {
145  return get(context, ArrayRef<DIExpressionElemAttr>({}));
146 }
147 
148 ParseResult parseExpressionArg(AsmParser &parser, uint64_t opcode,
149  SmallVector<uint64_t> &args) {
150  auto operandParser = [&]() -> LogicalResult {
151  uint64_t operand = 0;
152  if (!args.empty() && opcode == llvm::dwarf::DW_OP_LLVM_convert) {
153  // Attempt to parse a keyword.
154  StringRef keyword;
155  if (succeeded(parser.parseOptionalKeyword(&keyword))) {
156  operand = llvm::dwarf::getAttributeEncoding(keyword);
157  if (operand == 0) {
158  // The keyword is invalid.
159  return parser.emitError(parser.getCurrentLocation())
160  << "encountered unknown attribute encoding \"" << keyword
161  << "\"";
162  }
163  }
164  }
165 
166  // operand should be non-zero if a keyword was parsed. Otherwise, the
167  // operand MUST be an integer.
168  if (operand == 0) {
169  // Parse the next operand as an integer.
170  if (parser.parseInteger(operand)) {
171  return parser.emitError(parser.getCurrentLocation())
172  << "expected integer operand";
173  }
174  }
175 
176  args.push_back(operand);
177  return success();
178  };
179 
180  // Parse operands as a comma-separated list.
181  return parser.parseCommaSeparatedList(operandParser);
182 }
183 
184 void printExpressionArg(AsmPrinter &printer, uint64_t opcode,
185  ArrayRef<uint64_t> args) {
186  size_t i = 0;
187  llvm::interleaveComma(args, printer, [&](uint64_t operand) {
188  if (i > 0 && opcode == llvm::dwarf::DW_OP_LLVM_convert) {
189  if (const StringRef keyword =
190  llvm::dwarf::AttributeEncodingString(operand);
191  !keyword.empty()) {
192  printer << keyword;
193  return;
194  }
195  }
196  // All operands are expected to be printed as integers.
197  printer << operand;
198  i++;
199  });
200 }
201 
202 //===----------------------------------------------------------------------===//
203 // DICompositeTypeAttr
204 //===----------------------------------------------------------------------===//
205 
206 DIRecursiveTypeAttrInterface
207 DICompositeTypeAttr::withRecId(DistinctAttr recId) {
209  getContext(), recId, getIsRecSelf(), getTag(), getName(), getFile(),
210  getLine(), getScope(), getBaseType(), getFlags(), getSizeInBits(),
211  getAlignInBits(), getElements(), getDataLocation(), getRank(),
212  getAllocated(), getAssociated());
213 }
214 
215 DIRecursiveTypeAttrInterface
216 DICompositeTypeAttr::getRecSelf(DistinctAttr recId) {
217  return DICompositeTypeAttr::get(recId.getContext(), recId, /*isRecSelf=*/true,
218  0, {}, {}, 0, {}, {}, DIFlags(), 0, 0, {}, {},
219  {}, {}, {});
220 }
221 
222 //===----------------------------------------------------------------------===//
223 // DISubprogramAttr
224 //===----------------------------------------------------------------------===//
225 
226 DIRecursiveTypeAttrInterface DISubprogramAttr::withRecId(DistinctAttr recId) {
227  return DISubprogramAttr::get(getContext(), recId, getIsRecSelf(), getId(),
228  getCompileUnit(), getScope(), getName(),
229  getLinkageName(), getFile(), getLine(),
230  getScopeLine(), getSubprogramFlags(), getType(),
231  getRetainedNodes(), getAnnotations());
232 }
233 
234 DIRecursiveTypeAttrInterface DISubprogramAttr::getRecSelf(DistinctAttr recId) {
235  return DISubprogramAttr::get(recId.getContext(), recId, /*isRecSelf=*/true,
236  {}, {}, {}, {}, {}, 0, 0, {}, {}, {}, {}, {});
237 }
238 
239 //===----------------------------------------------------------------------===//
240 // ConstantRangeAttr
241 //===----------------------------------------------------------------------===//
242 
244  llvm::SMLoc loc = parser.getCurrentLocation();
245  IntegerType widthType;
246  if (parser.parseLess() || parser.parseType(widthType) ||
247  parser.parseComma()) {
248  return Attribute{};
249  }
250  unsigned bitWidth = widthType.getWidth();
251  APInt lower(bitWidth, 0);
252  APInt upper(bitWidth, 0);
253  if (parser.parseInteger(lower) || parser.parseComma() ||
254  parser.parseInteger(upper) || parser.parseGreater())
255  return Attribute{};
256  // For some reason, 0 is always parsed as 64-bits, fix that if needed.
257  if (lower.isZero())
258  lower = lower.sextOrTrunc(bitWidth);
259  if (upper.isZero())
260  upper = upper.sextOrTrunc(bitWidth);
261  return parser.getChecked<ConstantRangeAttr>(loc, parser.getContext(), lower,
262  upper);
263 }
264 
265 void ConstantRangeAttr::print(AsmPrinter &printer) const {
266  printer << "<i" << getLower().getBitWidth() << ", " << getLower() << ", "
267  << getUpper() << ">";
268 }
269 
270 LogicalResult
272  APInt lower, APInt upper) {
273  if (lower.getBitWidth() != upper.getBitWidth())
274  return emitError()
275  << "expected lower and upper to have matching bitwidths but got "
276  << lower.getBitWidth() << " vs. " << upper.getBitWidth();
277  return success();
278 }
279 
280 //===----------------------------------------------------------------------===//
281 // TargetFeaturesAttr
282 //===----------------------------------------------------------------------===//
283 
284 TargetFeaturesAttr TargetFeaturesAttr::get(MLIRContext *context,
285  llvm::ArrayRef<StringRef> features) {
286  return Base::get(context,
287  llvm::map_to_vector(features, [&](StringRef feature) {
288  return StringAttr::get(context, feature);
289  }));
290 }
291 
292 TargetFeaturesAttr
293 TargetFeaturesAttr::getChecked(function_ref<InFlightDiagnostic()> emitError,
294  MLIRContext *context,
295  llvm::ArrayRef<StringRef> features) {
296  return Base::getChecked(emitError, context,
297  llvm::map_to_vector(features, [&](StringRef feature) {
298  return StringAttr::get(context, feature);
299  }));
300 }
301 
302 TargetFeaturesAttr TargetFeaturesAttr::get(MLIRContext *context,
303  StringRef targetFeatures) {
304  SmallVector<StringRef> features;
305  targetFeatures.split(features, ',', /*MaxSplit=*/-1,
306  /*KeepEmpty=*/false);
307  return get(context, features);
308 }
309 
310 TargetFeaturesAttr
311 TargetFeaturesAttr::getChecked(function_ref<InFlightDiagnostic()> emitError,
312  MLIRContext *context, StringRef targetFeatures) {
313  SmallVector<StringRef> features;
314  targetFeatures.split(features, ',', /*MaxSplit=*/-1,
315  /*KeepEmpty=*/false);
316  ArrayRef featuresRef(features);
317  return getChecked(emitError, context, featuresRef);
318 }
319 
320 LogicalResult
322  llvm::ArrayRef<StringAttr> features) {
323  for (StringAttr featureAttr : features) {
324  if (!featureAttr || featureAttr.empty())
325  return emitError() << "target features can not be null or empty";
326  auto feature = featureAttr.strref();
327  if (feature[0] != '+' && feature[0] != '-')
328  return emitError() << "target features must start with '+' or '-'";
329  if (feature.contains(','))
330  return emitError() << "target features can not contain ','";
331  }
332  return success();
333 }
334 
335 bool TargetFeaturesAttr::contains(StringAttr feature) const {
336  if (nullOrEmpty())
337  return false;
338  // Note: Using StringAttr does pointer comparisons.
339  return llvm::is_contained(getFeatures(), feature);
340 }
341 
342 bool TargetFeaturesAttr::contains(StringRef feature) const {
343  if (nullOrEmpty())
344  return false;
345  return llvm::is_contained(getFeatures(), feature);
346 }
347 
348 std::string TargetFeaturesAttr::getFeaturesString() const {
349  std::string featuresString;
350  llvm::raw_string_ostream ss(featuresString);
351  llvm::interleave(
352  getFeatures(), ss, [&](auto &feature) { ss << feature.strref(); }, ",");
353  return featuresString;
354 }
355 
356 TargetFeaturesAttr TargetFeaturesAttr::featuresAt(Operation *op) {
357  auto parentFunction = op->getParentOfType<FunctionOpInterface>();
358  if (!parentFunction)
359  return {};
360  return parentFunction.getOperation()->getAttrOfType<TargetFeaturesAttr>(
361  getAttributeName());
362 }
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:184
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:148
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:73
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:84
static bool classof(Attribute attr)
Definition: LLVMAttrs.cpp:59
static bool classof(Attribute attr)
Support LLVM type casting.
Definition: LLVMAttrs.cpp:74
static bool classof(Attribute attr)
Support LLVM type casting.
Definition: LLVMAttrs.cpp:101
static bool classof(Attribute attr)
Support LLVM type casting.
Definition: LLVMAttrs.cpp:93
static bool classof(Attribute attr)
Support LLVM type casting.
Definition: LLVMAttrs.cpp:111
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:20
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:425