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
17#include "mlir/IR/Builders.h"
20#include "llvm/ADT/StringExtras.h"
21#include "llvm/ADT/TypeSwitch.h"
22#include "llvm/BinaryFormat/Dwarf.h"
23
24using namespace mlir;
25using 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.
30static ParseResult parseExpressionArg(AsmParser &parser, uint64_t opcode,
32
33/// Prints DWARF expression arguments with respect to the specific DWARF
34/// operation. Some operands are printed in their textual form.
35static void printExpressionArg(AsmPrinter &printer, uint64_t opcode,
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
47void LLVMDialect::registerAttributes() {
48 addAttributes<
49#define GET_ATTRDEF_LIST
50#include "mlir/Dialect/LLVMIR/LLVMOpsAttrDefs.cpp.inc"
51
52 >();
53}
54
55//===----------------------------------------------------------------------===//
56// AddressSpaceAttr
57//===----------------------------------------------------------------------===//
58
59/// Checks whether the given type is an LLVM type that can be loaded or stored.
61 Type type, ptr::AtomicOrdering ordering, std::optional<int64_t> alignment,
62 const ::mlir::DataLayout *dataLayout,
64 if (!isLoadableType(type)) {
65 if (emitError)
66 emitError() << "type must be LLVM type with size, but got " << type;
67 return false;
68 }
69 if (ordering == ptr::AtomicOrdering::not_atomic)
70 return true;
71
72 // To check atomic validity we need a datalayout.
73 if (!dataLayout) {
74 if (emitError)
75 emitError() << "expected a valid data layout";
76 return false;
77 }
78 if (!isTypeCompatibleWithAtomicOp(type, *dataLayout)) {
79 if (emitError)
80 emitError() << "unsupported type " << type << " for atomic access";
81 return false;
82 }
83 return true;
84}
85
86bool AddressSpaceAttr::isValidLoad(
87 Type type, ptr::AtomicOrdering ordering, std::optional<int64_t> alignment,
88 const ::mlir::DataLayout *dataLayout,
90 return detail::isValidLoadStoreImpl(type, ordering, alignment, dataLayout,
91 emitError);
92}
93
94bool AddressSpaceAttr::isValidStore(
95 Type type, ptr::AtomicOrdering ordering, std::optional<int64_t> alignment,
96 const ::mlir::DataLayout *dataLayout,
98 return detail::isValidLoadStoreImpl(type, ordering, alignment, dataLayout,
99 emitError);
100}
101
102bool AddressSpaceAttr::isValidAtomicOp(
103 ptr::AtomicBinOp op, Type type, ptr::AtomicOrdering ordering,
104 std::optional<int64_t> alignment, const ::mlir::DataLayout *dataLayout,
106 // TODO: update this method once `ptr.atomic_rmw` is implemented.
107 assert(false && "unimplemented, see TODO in the source.");
108 return false;
109}
110
111bool AddressSpaceAttr::isValidAtomicXchg(
112 Type type, ptr::AtomicOrdering successOrdering,
113 ptr::AtomicOrdering failureOrdering, std::optional<int64_t> alignment,
114 const ::mlir::DataLayout *dataLayout,
116 // TODO: update this method once `ptr.atomic_cmpxchg` is implemented.
117 assert(false && "unimplemented, see TODO in the source.");
118 return false;
119}
120
121bool AddressSpaceAttr::isValidAddrSpaceCast(
123 // TODO: update this method once the `ptr.addrspace_cast` op is added to the
124 // dialect.
125 assert(false && "unimplemented, see TODO in the source.");
126 return false;
127}
128
129bool AddressSpaceAttr::isValidPtrIntCast(
130 Type intLikeTy, Type ptrLikeTy,
132 // TODO: update this method once the int-cast ops are added to the `ptr`
133 // dialect.
134 assert(false && "unimplemented, see TODO in the source.");
135 return false;
136}
137
138//===----------------------------------------------------------------------===//
139// AliasScopeAttr
140//===----------------------------------------------------------------------===//
141
142LogicalResult
143AliasScopeAttr::verify(function_ref<InFlightDiagnostic()> emitError,
144 Attribute id, AliasScopeDomainAttr domain,
145 StringAttr description) {
146 (void)domain;
147 (void)description;
148 if (!llvm::isa<StringAttr, DistinctAttr>(id))
149 return emitError()
150 << "id of an alias scope must be a StringAttr or a DistrinctAttr";
151
152 return success();
153}
154
155//===----------------------------------------------------------------------===//
156// DINodeAttr
157//===----------------------------------------------------------------------===//
158
160 return llvm::isa<
161 DIBasicTypeAttr, DICommonBlockAttr, DICompileUnitAttr,
162 DICompositeTypeAttr, DIDerivedTypeAttr, DIFileAttr, DIGenericSubrangeAttr,
163 DIGlobalVariableAttr, DIImportedEntityAttr, DILabelAttr,
164 DILexicalBlockAttr, DILexicalBlockFileAttr, DILocalVariableAttr,
165 DIModuleAttr, DINamespaceAttr, DINullTypeAttr, DIAnnotationAttr,
166 DIStringTypeAttr, DISubprogramAttr, DISubrangeAttr, DISubroutineTypeAttr>(
167 attr);
168}
169
170//===----------------------------------------------------------------------===//
171// DIScopeAttr
172//===----------------------------------------------------------------------===//
173
175 return llvm::isa<DICommonBlockAttr, DICompileUnitAttr, DICompositeTypeAttr,
176 DIDerivedTypeAttr, DIFileAttr, DILocalScopeAttr,
177 DIModuleAttr, DINamespaceAttr>(attr);
178}
179
180//===----------------------------------------------------------------------===//
181// DILocalScopeAttr
182//===----------------------------------------------------------------------===//
183
185 return llvm::isa<DILexicalBlockAttr, DILexicalBlockFileAttr,
186 DISubprogramAttr>(attr);
187}
188
189//===----------------------------------------------------------------------===//
190// DIVariableAttr
191//===----------------------------------------------------------------------===//
192
194 return llvm::isa<DILocalVariableAttr, DIGlobalVariableAttr>(attr);
195}
196
197//===----------------------------------------------------------------------===//
198// DITypeAttr
199//===----------------------------------------------------------------------===//
200
202 return llvm::isa<DINullTypeAttr, DIBasicTypeAttr, DICompositeTypeAttr,
203 DIDerivedTypeAttr, DIStringTypeAttr, DISubroutineTypeAttr>(
204 attr);
205}
206
207//===----------------------------------------------------------------------===//
208// TBAANodeAttr
209//===----------------------------------------------------------------------===//
210
212 return llvm::isa<TBAATypeDescriptorAttr, TBAARootAttr>(attr);
213}
214
215//===----------------------------------------------------------------------===//
216// MemoryEffectsAttr
217//===----------------------------------------------------------------------===//
218
219MemoryEffectsAttr MemoryEffectsAttr::get(MLIRContext *context,
220 ArrayRef<ModRefInfo> memInfoArgs) {
221 if (memInfoArgs.empty())
222 return MemoryEffectsAttr::get(context, /*other=*/ModRefInfo::ModRef,
223 /*argMem=*/ModRefInfo::ModRef,
224 /*inaccessibleMem=*/ModRefInfo::ModRef,
225 /*errnoMem=*/ModRefInfo::ModRef,
226 /*targetMem0=*/ModRefInfo::ModRef,
227 /*targetMem1=*/ModRefInfo::ModRef);
228 if (memInfoArgs.size() == 6)
229 return MemoryEffectsAttr::get(context, memInfoArgs[0], memInfoArgs[1],
230 memInfoArgs[2], memInfoArgs[3],
231 memInfoArgs[4], memInfoArgs[5]);
232 return {};
233}
234
235bool MemoryEffectsAttr::isReadWrite() {
236 if (this->getArgMem() != ModRefInfo::ModRef)
237 return false;
238 if (this->getInaccessibleMem() != ModRefInfo::ModRef)
239 return false;
240 if (this->getOther() != ModRefInfo::ModRef)
241 return false;
242 if (this->getErrnoMem() != ModRefInfo::ModRef)
243 return false;
244 if (this->getTargetMem0() != ModRefInfo::ModRef)
245 return false;
246 if (this->getTargetMem1() != ModRefInfo::ModRef)
247 return false;
248 return true;
249}
250
251//===----------------------------------------------------------------------===//
252// DIExpression
253//===----------------------------------------------------------------------===//
254
255DIExpressionAttr DIExpressionAttr::get(MLIRContext *context) {
256 return get(context, ArrayRef<DIExpressionElemAttr>({}));
257}
258
259ParseResult parseExpressionArg(AsmParser &parser, uint64_t opcode,
260 SmallVector<uint64_t> &args) {
261 auto operandParser = [&]() -> LogicalResult {
262 uint64_t operand = 0;
263 if (!args.empty() && opcode == llvm::dwarf::DW_OP_LLVM_convert) {
264 // Attempt to parse a keyword.
265 StringRef keyword;
266 if (succeeded(parser.parseOptionalKeyword(&keyword))) {
267 operand = llvm::dwarf::getAttributeEncoding(keyword);
268 if (operand == 0) {
269 // The keyword is invalid.
270 return parser.emitError(parser.getCurrentLocation())
271 << "encountered unknown attribute encoding \"" << keyword
272 << "\"";
273 }
274 }
275 }
276
277 // operand should be non-zero if a keyword was parsed. Otherwise, the
278 // operand MUST be an integer.
279 if (operand == 0) {
280 // Parse the next operand as an integer.
281 if (parser.parseInteger(operand)) {
282 return parser.emitError(parser.getCurrentLocation())
283 << "expected integer operand";
284 }
285 }
286
287 args.push_back(operand);
288 return success();
289 };
290
291 // Parse operands as a comma-separated list.
292 return parser.parseCommaSeparatedList(operandParser);
293}
294
295void printExpressionArg(AsmPrinter &printer, uint64_t opcode,
296 ArrayRef<uint64_t> args) {
297 size_t i = 0;
298 llvm::interleaveComma(args, printer, [&](uint64_t operand) {
299 if (i > 0 && opcode == llvm::dwarf::DW_OP_LLVM_convert) {
300 if (const StringRef keyword =
301 llvm::dwarf::AttributeEncodingString(operand);
302 !keyword.empty()) {
303 printer << keyword;
304 return;
305 }
306 }
307 // All operands are expected to be printed as integers.
308 printer << operand;
309 i++;
310 });
311}
312
313//===----------------------------------------------------------------------===//
314// DICompositeTypeAttr
315//===----------------------------------------------------------------------===//
316
317DIRecursiveTypeAttrInterface
318DICompositeTypeAttr::withRecId(DistinctAttr recId) {
319 return DICompositeTypeAttr::get(
320 getContext(), recId, getIsRecSelf(), getTag(), getName(), getFile(),
321 getLine(), getScope(), getBaseType(), getFlags(), getSizeInBits(),
322 getAlignInBits(), getDataLocation(), getRank(), getAllocated(),
323 getAssociated(), getElements());
324}
325
326DIRecursiveTypeAttrInterface
327DICompositeTypeAttr::getRecSelf(DistinctAttr recId) {
328 return DICompositeTypeAttr::get(recId.getContext(), recId, /*isRecSelf=*/true,
329 0, {}, {}, 0, {}, {}, DIFlags(), 0, 0, {}, {},
330 {}, {}, {});
331}
332
333//===----------------------------------------------------------------------===//
334// DISubprogramAttr
335//===----------------------------------------------------------------------===//
336
337DIRecursiveTypeAttrInterface DISubprogramAttr::withRecId(DistinctAttr recId) {
338 return DISubprogramAttr::get(getContext(), recId, getIsRecSelf(), getId(),
339 getCompileUnit(), getScope(), getName(),
340 getLinkageName(), getFile(), getLine(),
341 getScopeLine(), getSubprogramFlags(), getType(),
342 getRetainedNodes(), getAnnotations());
343}
344
345DIRecursiveTypeAttrInterface DISubprogramAttr::getRecSelf(DistinctAttr recId) {
346 return DISubprogramAttr::get(recId.getContext(), recId, /*isRecSelf=*/true,
347 {}, {}, {}, {}, {}, {}, 0, 0, {}, {}, {}, {});
348}
349
350//===----------------------------------------------------------------------===//
351// ConstantRangeAttr
352//===----------------------------------------------------------------------===//
353
354Attribute ConstantRangeAttr::parse(AsmParser &parser, Type odsType) {
355 llvm::SMLoc loc = parser.getCurrentLocation();
356 IntegerType widthType;
357 if (parser.parseLess() || parser.parseType(widthType) ||
358 parser.parseComma()) {
359 return Attribute{};
360 }
361 unsigned bitWidth = widthType.getWidth();
362 APInt lower(bitWidth, 0);
363 APInt upper(bitWidth, 0);
364 if (parser.parseInteger(lower) || parser.parseComma() ||
365 parser.parseInteger(upper) || parser.parseGreater())
366 return Attribute{};
367 // Non-positive numbers may use more bits than `bitWidth`
368 lower = lower.sextOrTrunc(bitWidth);
369 upper = upper.sextOrTrunc(bitWidth);
370 return parser.getChecked<ConstantRangeAttr>(loc, parser.getContext(), lower,
371 upper);
372}
373
374void ConstantRangeAttr::print(AsmPrinter &printer) const {
375 printer << "<i" << getLower().getBitWidth() << ", " << getLower() << ", "
376 << getUpper() << ">";
377}
378
379LogicalResult
380ConstantRangeAttr::verify(llvm::function_ref<InFlightDiagnostic()> emitError,
381 APInt lower, APInt upper) {
382 if (lower.getBitWidth() != upper.getBitWidth())
383 return emitError()
384 << "expected lower and upper to have matching bitwidths but got "
385 << lower.getBitWidth() << " vs. " << upper.getBitWidth();
386 return success();
387}
388
389//===----------------------------------------------------------------------===//
390// TargetFeaturesAttr
391//===----------------------------------------------------------------------===//
392
393TargetFeaturesAttr TargetFeaturesAttr::get(MLIRContext *context,
394 llvm::ArrayRef<StringRef> features) {
395 return Base::get(context,
396 llvm::map_to_vector(features, [&](StringRef feature) {
397 return StringAttr::get(context, feature);
398 }));
399}
400
401TargetFeaturesAttr
402TargetFeaturesAttr::getChecked(function_ref<InFlightDiagnostic()> emitError,
403 MLIRContext *context,
404 llvm::ArrayRef<StringRef> features) {
405 return Base::getChecked(emitError, context,
406 llvm::map_to_vector(features, [&](StringRef feature) {
407 return StringAttr::get(context, feature);
408 }));
409}
410
411TargetFeaturesAttr TargetFeaturesAttr::get(MLIRContext *context,
412 StringRef targetFeatures) {
413 SmallVector<StringRef> features;
414 targetFeatures.split(features, ',', /*MaxSplit=*/-1,
415 /*KeepEmpty=*/false);
416 return get(context, features);
417}
418
419TargetFeaturesAttr
420TargetFeaturesAttr::getChecked(function_ref<InFlightDiagnostic()> emitError,
421 MLIRContext *context, StringRef targetFeatures) {
422 SmallVector<StringRef> features;
423 targetFeatures.split(features, ',', /*MaxSplit=*/-1,
424 /*KeepEmpty=*/false);
425 ArrayRef featuresRef(features);
426 return getChecked(emitError, context, featuresRef);
427}
428
429LogicalResult
430TargetFeaturesAttr::verify(function_ref<InFlightDiagnostic()> emitError,
431 llvm::ArrayRef<StringAttr> features) {
432 for (StringAttr featureAttr : features) {
433 if (!featureAttr || featureAttr.empty())
434 return emitError() << "target features can not be null or empty";
435 auto feature = featureAttr.strref();
436 if (feature[0] != '+' && feature[0] != '-')
437 return emitError() << "target features must start with '+' or '-'";
438 if (feature.contains(','))
439 return emitError() << "target features can not contain ','";
440 }
441 return success();
442}
443
444bool TargetFeaturesAttr::contains(StringAttr feature) const {
445 if (nullOrEmpty())
446 return false;
447 // Note: Using StringAttr does pointer comparisons.
448 return llvm::is_contained(getFeatures(), feature);
449}
450
451bool TargetFeaturesAttr::contains(StringRef feature) const {
452 if (nullOrEmpty())
453 return false;
454 return llvm::is_contained(getFeatures(), feature);
455}
456
457std::string TargetFeaturesAttr::getFeaturesString() const {
458 std::string featuresString;
459 llvm::raw_string_ostream ss(featuresString);
460 llvm::interleave(
461 getFeatures(), ss, [&](auto &feature) { ss << feature.strref(); }, ",");
462 return featuresString;
463}
464
465TargetFeaturesAttr TargetFeaturesAttr::featuresAt(Operation *op) {
466 auto parentFunction = op->getParentOfType<FunctionOpInterface>();
467 if (!parentFunction)
468 return {};
469 return parentFunction.getOperation()->getAttrOfType<TargetFeaturesAttr>(
470 getAttributeName());
471}
472
473FailureOr<Attribute> TargetFeaturesAttr::query(DataLayoutEntryKey key) {
474 auto stringKey = dyn_cast<StringAttr>(key);
475 if (!stringKey)
476 return failure();
477
478 if (contains(stringKey))
479 return UnitAttr::get(getContext());
480
481 if (contains((std::string("+") + stringKey.strref()).str()))
482 return BoolAttr::get(getContext(), true);
483
484 if (contains((std::string("-") + stringKey.strref()).str()))
485 return BoolAttr::get(getContext(), false);
486
487 return failure();
488}
489
490//===----------------------------------------------------------------------===//
491// TargetAttr
492//===----------------------------------------------------------------------===//
493
494FailureOr<::mlir::Attribute> TargetAttr::query(DataLayoutEntryKey key) {
495 if (auto stringAttrKey = dyn_cast<StringAttr>(key)) {
496 if (stringAttrKey.getValue() == "triple")
497 return getTriple();
498 if (stringAttrKey.getValue() == "chip")
499 return getChip();
500 if (stringAttrKey.getValue() == "features" && getFeatures())
501 return getFeatures();
502 }
503 return failure();
504}
505
506//===----------------------------------------------------------------------===//
507// ModuleFlagAttr
508//===----------------------------------------------------------------------===//
509
510LogicalResult
511ModuleFlagAttr::verify(function_ref<InFlightDiagnostic()> emitError,
512 LLVM::ModFlagBehavior flagBehavior, StringAttr key,
513 Attribute value) {
514 if (key == LLVMDialect::getModuleFlagKeyCGProfileName()) {
515 auto arrayAttr = dyn_cast<ArrayAttr>(value);
516 if ((!arrayAttr) || (!llvm::all_of(arrayAttr, [](Attribute attr) {
517 return isa<ModuleFlagCGProfileEntryAttr>(attr);
518 })))
519 return emitError()
520 << "'CG Profile' key expects an array of '#llvm.cgprofile_entry'";
521 return success();
522 }
523
524 if (key == LLVMDialect::getModuleFlagKeyProfileSummaryName()) {
525 if (!isa<ModuleFlagProfileSummaryAttr>(value))
526 return emitError() << "'ProfileSummary' key expects a "
527 "'#llvm.profile_summary' attribute";
528 return success();
529 }
530
531 if (isa<IntegerAttr, StringAttr>(value))
532 return success();
533
534 return emitError() << "only integer and string values are currently "
535 "supported for unknown key '"
536 << key << "'";
537}
return success()
static void printExpressionArg(AsmPrinter &printer, uint64_t opcode, ArrayRef< uint64_t > args)
Prints DWARF expression arguments with respect to the specific DWARF operation.
static ParseResult parseExpressionArg(AsmParser &parser, uint64_t opcode, SmallVector< uint64_t > &args)
Parses DWARF expression arguments with respect to the DWARF operation opcode.
b getContext())
static bool contains(SMRange range, SMLoc loc)
Returns true if the given range contains the given source location.
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
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.
static BoolAttr get(MLIRContext *context, bool value)
This class represents a diagnostic that is inflight and set to be reported.
This class represents a LLVM attribute that describes a local debug info scope.
Definition LLVMAttrs.h:48
static bool classof(Attribute attr)
Support LLVM type casting.
constexpr Attribute()=default
static bool classof(Attribute attr)
static bool classof(Attribute attr)
Support LLVM type casting.
static bool classof(Attribute attr)
Support LLVM type casting.
static bool classof(Attribute attr)
Support LLVM type casting.
static bool classof(Attribute attr)
Support LLVM type casting.
constexpr Attribute()=default
MLIRContext is the top-level object for a collection of MLIR operations.
Definition MLIRContext.h:63
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
bool isValidLoadStoreImpl(Type type, ptr::AtomicOrdering ordering, std::optional< int64_t > alignment, const ::mlir::DataLayout *dataLayout, function_ref< InFlightDiagnostic()> emitError)
Checks whether the given type is an LLVM type that can be loaded or stored.
Definition LLVMAttrs.cpp:60
bool isLoadableType(Type type)
Returns true if the given type is a loadable type compatible with the LLVM dialect.
bool isTypeCompatibleWithAtomicOp(Type type, const DataLayout &dataLayout)
Returns true if the given type is supported by atomic operations.
Include the generated interface declarations.
llvm::PointerUnion< Type, StringAttr > DataLayoutEntryKey
Type getType(OpFoldResult ofr)
Returns the int type of the integer in ofr.
Definition Utils.cpp:304
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...
llvm::function_ref< Fn > function_ref
Definition LLVM.h:152