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
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,
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.
35static 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
47void 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
59LogicalResult
60AliasScopeAttr::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
76bool 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
91bool DIScopeAttr::classof(Attribute attr) {
92 return llvm::isa<DICommonBlockAttr, DICompileUnitAttr, DICompositeTypeAttr,
93 DIDerivedTypeAttr, DIFileAttr, DILocalScopeAttr,
94 DIModuleAttr, DINamespaceAttr>(attr);
95}
96
97//===----------------------------------------------------------------------===//
98// DILocalScopeAttr
99//===----------------------------------------------------------------------===//
100
101bool DILocalScopeAttr::classof(Attribute attr) {
102 return llvm::isa<DILexicalBlockAttr, DILexicalBlockFileAttr,
103 DISubprogramAttr>(attr);
104}
105
106//===----------------------------------------------------------------------===//
107// DIVariableAttr
108//===----------------------------------------------------------------------===//
109
110bool DIVariableAttr::classof(Attribute attr) {
111 return llvm::isa<DILocalVariableAttr, DIGlobalVariableAttr>(attr);
112}
113
114//===----------------------------------------------------------------------===//
115// DITypeAttr
116//===----------------------------------------------------------------------===//
117
118bool DITypeAttr::classof(Attribute attr) {
119 return llvm::isa<DINullTypeAttr, DIBasicTypeAttr, DICompositeTypeAttr,
120 DIDerivedTypeAttr, DIStringTypeAttr, DISubroutineTypeAttr>(
121 attr);
122}
123
124//===----------------------------------------------------------------------===//
125// TBAANodeAttr
126//===----------------------------------------------------------------------===//
127
128bool TBAANodeAttr::classof(Attribute attr) {
129 return llvm::isa<TBAATypeDescriptorAttr, TBAARootAttr>(attr);
130}
131
132//===----------------------------------------------------------------------===//
133// MemoryEffectsAttr
134//===----------------------------------------------------------------------===//
135
136MemoryEffectsAttr 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
147bool 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
161DIExpressionAttr DIExpressionAttr::get(MLIRContext *context) {
162 return get(context, ArrayRef<DIExpressionElemAttr>({}));
163}
164
165ParseResult 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(Result: parser.parseOptionalKeyword(keyword: &keyword))) {
173 operand = llvm::dwarf::getAttributeEncoding(EncodingString: keyword);
174 if (operand == 0) {
175 // The keyword is invalid.
176 return parser.emitError(loc: 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(result&: operand)) {
188 return parser.emitError(loc: parser.getCurrentLocation())
189 << "expected integer operand";
190 }
191 }
192
193 args.push_back(Elt: operand);
194 return success();
195 };
196
197 // Parse operands as a comma-separated list.
198 return parser.parseCommaSeparatedList(parseElementFn: operandParser);
199}
200
201void printExpressionArg(AsmPrinter &printer, uint64_t opcode,
202 ArrayRef<uint64_t> args) {
203 size_t i = 0;
204 llvm::interleaveComma(c: args, os&: printer, each_fn: [&](uint64_t operand) {
205 if (i > 0 && opcode == llvm::dwarf::DW_OP_LLVM_convert) {
206 if (const StringRef keyword =
207 llvm::dwarf::AttributeEncodingString(Encoding: 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
223DIRecursiveTypeAttrInterface
224DICompositeTypeAttr::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
232DIRecursiveTypeAttrInterface
233DICompositeTypeAttr::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
243DIRecursiveTypeAttrInterface 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
251DIRecursiveTypeAttrInterface DISubprogramAttr::getRecSelf(DistinctAttr recId) {
252 return DISubprogramAttr::get(recId.getContext(), recId, /*isRecSelf=*/true,
253 {}, {}, {}, {}, {}, {}, 0, 0, {}, {}, {}, {});
254}
255
256//===----------------------------------------------------------------------===//
257// ConstantRangeAttr
258//===----------------------------------------------------------------------===//
259
260Attribute 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
280void ConstantRangeAttr::print(AsmPrinter &printer) const {
281 printer << "<i" << getLower().getBitWidth() << ", " << getLower() << ", "
282 << getUpper() << ">";
283}
284
285LogicalResult
286ConstantRangeAttr::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
299TargetFeaturesAttr 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
307TargetFeaturesAttr
308TargetFeaturesAttr::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
317TargetFeaturesAttr 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
325TargetFeaturesAttr
326TargetFeaturesAttr::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
335LogicalResult
336TargetFeaturesAttr::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
350bool 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
357bool TargetFeaturesAttr::contains(StringRef feature) const {
358 if (nullOrEmpty())
359 return false;
360 return llvm::is_contained(getFeatures(), feature);
361}
362
363std::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
371TargetFeaturesAttr 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
379LogicalResult
380ModuleFlagAttr::verify(function_ref<InFlightDiagnostic()> emitError,
381 LLVM::ModFlagBehavior flagBehavior, StringAttr key,
382 Attribute value) {
383 if (key == LLVMDialect::getModuleFlagKeyCGProfileName()) {
384 auto arrayAttr = dyn_cast<ArrayAttr>(value);
385 if ((!arrayAttr) || (!llvm::all_of(arrayAttr, [](Attribute attr) {
386 return isa<ModuleFlagCGProfileEntryAttr>(attr);
387 })))
388 return emitError()
389 << "'CG Profile' key expects an array of '#llvm.cgprofile_entry'";
390 return success();
391 }
392
393 if (key == LLVMDialect::getModuleFlagKeyProfileSummaryName()) {
394 if (!isa<ModuleFlagProfileSummaryAttr>(value))
395 return emitError() << "'ProfileSummary' key expects a "
396 "'#llvm.profile_summary' attribute";
397 return success();
398 }
399
400 if (isa<IntegerAttr, StringAttr>(value))
401 return success();
402
403 return emitError() << "only integer and string values are currently "
404 "supported for unknown key '"
405 << key << "'";
406}
407

Provided by KDAB

Privacy Policy
Improve your Profiling and Debugging skills
Find out more

source code of mlir/lib/Dialect/LLVMIR/IR/LLVMAttrs.cpp