1 //===- LLVMAttrs.cpp - LLVM Attributes registration -----------------------===//
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
7 //===----------------------------------------------------------------------===//
9 // This file defines the attribute details for the LLVM IR dialect in MLIR.
11 //===----------------------------------------------------------------------===//
13 #include "mlir/Dialect/LLVMIR/LLVMAttrs.h"
14 #include "mlir/Dialect/LLVMIR/LLVMDialect.h"
15 #include "mlir/IR/Builders.h"
16 #include "mlir/IR/DialectImplementation.h"
17 #include "mlir/Interfaces/FunctionInterfaces.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"
25 using namespace mlir::LLVM
;
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 LogicalResult
parseExpressionArg(AsmParser
&parser
, uint64_t opcode
,
31 SmallVector
<uint64_t> &args
);
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
);
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"
43 //===----------------------------------------------------------------------===//
44 // LLVMDialect registration
45 //===----------------------------------------------------------------------===//
47 void LLVMDialect::registerAttributes() {
49 #define GET_ATTRDEF_LIST
50 #include "mlir/Dialect/LLVMIR/LLVMOpsAttrDefs.cpp.inc"
54 //===----------------------------------------------------------------------===//
56 //===----------------------------------------------------------------------===//
58 bool DINodeAttr::classof(Attribute attr
) {
60 DIBasicTypeAttr
, DICommonBlockAttr
, DICompileUnitAttr
,
61 DICompositeTypeAttr
, DIDerivedTypeAttr
, DIFileAttr
, DIGenericSubrangeAttr
,
62 DIGlobalVariableAttr
, DIImportedEntityAttr
, DILabelAttr
,
63 DILexicalBlockAttr
, DILexicalBlockFileAttr
, DILocalVariableAttr
,
64 DIModuleAttr
, DINamespaceAttr
, DINullTypeAttr
, DIAnnotationAttr
,
65 DIStringTypeAttr
, DISubprogramAttr
, DISubrangeAttr
, DISubroutineTypeAttr
>(
69 //===----------------------------------------------------------------------===//
71 //===----------------------------------------------------------------------===//
73 bool DIScopeAttr::classof(Attribute attr
) {
74 return llvm::isa
<DICommonBlockAttr
, DICompileUnitAttr
, DICompositeTypeAttr
,
75 DIFileAttr
, DILocalScopeAttr
, DIModuleAttr
, DINamespaceAttr
>(
79 //===----------------------------------------------------------------------===//
81 //===----------------------------------------------------------------------===//
83 bool DILocalScopeAttr::classof(Attribute attr
) {
84 return llvm::isa
<DILexicalBlockAttr
, DILexicalBlockFileAttr
,
85 DISubprogramAttr
>(attr
);
88 //===----------------------------------------------------------------------===//
90 //===----------------------------------------------------------------------===//
92 bool DIVariableAttr::classof(Attribute attr
) {
93 return llvm::isa
<DILocalVariableAttr
, DIGlobalVariableAttr
>(attr
);
96 //===----------------------------------------------------------------------===//
98 //===----------------------------------------------------------------------===//
100 bool DITypeAttr::classof(Attribute attr
) {
101 return llvm::isa
<DINullTypeAttr
, DIBasicTypeAttr
, DICompositeTypeAttr
,
102 DIDerivedTypeAttr
, DIStringTypeAttr
, DISubroutineTypeAttr
>(
106 //===----------------------------------------------------------------------===//
108 //===----------------------------------------------------------------------===//
110 bool TBAANodeAttr::classof(Attribute attr
) {
111 return llvm::isa
<TBAATypeDescriptorAttr
, TBAARootAttr
>(attr
);
114 //===----------------------------------------------------------------------===//
116 //===----------------------------------------------------------------------===//
118 MemoryEffectsAttr
MemoryEffectsAttr::get(MLIRContext
*context
,
119 ArrayRef
<ModRefInfo
> memInfoArgs
) {
120 if (memInfoArgs
.empty())
121 return MemoryEffectsAttr::get(context
, ModRefInfo::ModRef
,
122 ModRefInfo::ModRef
, ModRefInfo::ModRef
);
123 if (memInfoArgs
.size() == 3)
124 return MemoryEffectsAttr::get(context
, memInfoArgs
[0], memInfoArgs
[1],
129 bool MemoryEffectsAttr::isReadWrite() {
130 if (this->getArgMem() != ModRefInfo::ModRef
)
132 if (this->getInaccessibleMem() != ModRefInfo::ModRef
)
134 if (this->getOther() != ModRefInfo::ModRef
)
139 //===----------------------------------------------------------------------===//
141 //===----------------------------------------------------------------------===//
143 DIExpressionAttr
DIExpressionAttr::get(MLIRContext
*context
) {
144 return get(context
, ArrayRef
<DIExpressionElemAttr
>({}));
147 LogicalResult
parseExpressionArg(AsmParser
&parser
, uint64_t opcode
,
148 SmallVector
<uint64_t> &args
) {
149 auto operandParser
= [&]() -> LogicalResult
{
150 uint64_t operand
= 0;
151 if (!args
.empty() && opcode
== llvm::dwarf::DW_OP_LLVM_convert
) {
152 // Attempt to parse a keyword.
154 if (succeeded(parser
.parseOptionalKeyword(&keyword
))) {
155 operand
= llvm::dwarf::getAttributeEncoding(keyword
);
157 // The keyword is invalid.
158 return parser
.emitError(parser
.getCurrentLocation())
159 << "encountered unknown attribute encoding \"" << keyword
165 // operand should be non-zero if a keyword was parsed. Otherwise, the
166 // operand MUST be an integer.
168 // Parse the next operand as an integer.
169 if (parser
.parseInteger(operand
)) {
170 return parser
.emitError(parser
.getCurrentLocation())
171 << "expected integer operand";
175 args
.push_back(operand
);
179 // Parse operands as a comma-separated list.
180 return parser
.parseCommaSeparatedList(operandParser
);
183 void printExpressionArg(AsmPrinter
&printer
, uint64_t opcode
,
184 ArrayRef
<uint64_t> args
) {
186 llvm::interleaveComma(args
, printer
, [&](uint64_t operand
) {
187 if (i
> 0 && opcode
== llvm::dwarf::DW_OP_LLVM_convert
) {
188 if (const StringRef keyword
=
189 llvm::dwarf::AttributeEncodingString(operand
);
195 // All operands are expected to be printed as integers.
201 //===----------------------------------------------------------------------===//
202 // DICompositeTypeAttr
203 //===----------------------------------------------------------------------===//
205 DIRecursiveTypeAttrInterface
206 DICompositeTypeAttr::withRecId(DistinctAttr recId
) {
207 return DICompositeTypeAttr::get(
208 getContext(), recId
, getIsRecSelf(), getTag(), getName(), getFile(),
209 getLine(), getScope(), getBaseType(), getFlags(), getSizeInBits(),
210 getAlignInBits(), getElements(), getDataLocation(), getRank(),
211 getAllocated(), getAssociated());
214 DIRecursiveTypeAttrInterface
215 DICompositeTypeAttr::getRecSelf(DistinctAttr recId
) {
216 return DICompositeTypeAttr::get(recId
.getContext(), recId
, /*isRecSelf=*/true,
217 0, {}, {}, 0, {}, {}, DIFlags(), 0, 0, {}, {},
221 //===----------------------------------------------------------------------===//
223 //===----------------------------------------------------------------------===//
225 DIRecursiveTypeAttrInterface
DISubprogramAttr::withRecId(DistinctAttr recId
) {
226 return DISubprogramAttr::get(getContext(), recId
, getIsRecSelf(), getId(),
227 getCompileUnit(), getScope(), getName(),
228 getLinkageName(), getFile(), getLine(),
229 getScopeLine(), getSubprogramFlags(), getType(),
230 getRetainedNodes(), getAnnotations());
233 DIRecursiveTypeAttrInterface
DISubprogramAttr::getRecSelf(DistinctAttr recId
) {
234 return DISubprogramAttr::get(recId
.getContext(), recId
, /*isRecSelf=*/true,
235 {}, {}, {}, {}, {}, 0, 0, {}, {}, {}, {}, {});
238 //===----------------------------------------------------------------------===//
240 //===----------------------------------------------------------------------===//
242 Attribute
ConstantRangeAttr::parse(AsmParser
&parser
, Type odsType
) {
243 llvm::SMLoc loc
= parser
.getCurrentLocation();
244 IntegerType widthType
;
245 if (parser
.parseLess() || parser
.parseType(widthType
) ||
246 parser
.parseComma()) {
249 unsigned bitWidth
= widthType
.getWidth();
250 APInt
lower(bitWidth
, 0);
251 APInt
upper(bitWidth
, 0);
252 if (parser
.parseInteger(lower
) || parser
.parseComma() ||
253 parser
.parseInteger(upper
) || parser
.parseGreater())
255 // For some reason, 0 is always parsed as 64-bits, fix that if needed.
257 lower
= lower
.sextOrTrunc(bitWidth
);
259 upper
= upper
.sextOrTrunc(bitWidth
);
260 return parser
.getChecked
<ConstantRangeAttr
>(loc
, parser
.getContext(), lower
,
264 void ConstantRangeAttr::print(AsmPrinter
&printer
) const {
265 printer
<< "<i" << getLower().getBitWidth() << ", " << getLower() << ", "
266 << getUpper() << ">";
270 ConstantRangeAttr::verify(llvm::function_ref
<InFlightDiagnostic()> emitError
,
271 APInt lower
, APInt upper
) {
272 if (lower
.getBitWidth() != upper
.getBitWidth())
274 << "expected lower and upper to have matching bitwidths but got "
275 << lower
.getBitWidth() << " vs. " << upper
.getBitWidth();
279 //===----------------------------------------------------------------------===//
280 // TargetFeaturesAttr
281 //===----------------------------------------------------------------------===//
283 TargetFeaturesAttr
TargetFeaturesAttr::get(MLIRContext
*context
,
284 llvm::ArrayRef
<StringRef
> features
) {
285 return Base::get(context
,
286 llvm::map_to_vector(features
, [&](StringRef feature
) {
287 return StringAttr::get(context
, feature
);
291 TargetFeaturesAttr
TargetFeaturesAttr::get(MLIRContext
*context
,
292 StringRef targetFeatures
) {
293 SmallVector
<StringRef
> features
;
294 targetFeatures
.split(features
, ',', /*MaxSplit=*/-1,
295 /*KeepEmpty=*/false);
296 return get(context
, features
);
300 TargetFeaturesAttr::verify(function_ref
<InFlightDiagnostic()> emitError
,
301 llvm::ArrayRef
<StringAttr
> features
) {
302 for (StringAttr featureAttr
: features
) {
303 if (!featureAttr
|| featureAttr
.empty())
304 return emitError() << "target features can not be null or empty";
305 auto feature
= featureAttr
.strref();
306 if (feature
[0] != '+' && feature
[0] != '-')
307 return emitError() << "target features must start with '+' or '-'";
308 if (feature
.contains(','))
309 return emitError() << "target features can not contain ','";
314 bool TargetFeaturesAttr::contains(StringAttr feature
) const {
317 // Note: Using StringAttr does pointer comparisons.
318 return llvm::is_contained(getFeatures(), feature
);
321 bool TargetFeaturesAttr::contains(StringRef feature
) const {
324 return llvm::is_contained(getFeatures(), feature
);
327 std::string
TargetFeaturesAttr::getFeaturesString() const {
328 std::string featuresString
;
329 llvm::raw_string_ostream
ss(featuresString
);
331 getFeatures(), ss
, [&](auto &feature
) { ss
<< feature
.strref(); }, ",");
332 return featuresString
;
335 TargetFeaturesAttr
TargetFeaturesAttr::featuresAt(Operation
*op
) {
336 auto parentFunction
= op
->getParentOfType
<FunctionOpInterface
>();
339 return parentFunction
.getOperation()->getAttrOfType
<TargetFeaturesAttr
>(