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