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

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