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 LogicalResult 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 | // DINodeAttr |
56 | //===----------------------------------------------------------------------===// |
57 | |
58 | bool DINodeAttr::classof(Attribute attr) { |
59 | return llvm::isa<DIBasicTypeAttr, DICompileUnitAttr, DICompositeTypeAttr, |
60 | DIDerivedTypeAttr, DIFileAttr, DIGlobalVariableAttr, |
61 | DILabelAttr, DILexicalBlockAttr, DILexicalBlockFileAttr, |
62 | DILocalVariableAttr, DIModuleAttr, DINamespaceAttr, |
63 | DINullTypeAttr, DISubprogramAttr, DISubrangeAttr, |
64 | DISubroutineTypeAttr>(attr); |
65 | } |
66 | |
67 | //===----------------------------------------------------------------------===// |
68 | // DIScopeAttr |
69 | //===----------------------------------------------------------------------===// |
70 | |
71 | bool DIScopeAttr::classof(Attribute attr) { |
72 | return llvm::isa<DICompileUnitAttr, DICompositeTypeAttr, DIFileAttr, |
73 | DILocalScopeAttr, DIModuleAttr, DINamespaceAttr>(attr); |
74 | } |
75 | |
76 | //===----------------------------------------------------------------------===// |
77 | // DILocalScopeAttr |
78 | //===----------------------------------------------------------------------===// |
79 | |
80 | bool DILocalScopeAttr::classof(Attribute attr) { |
81 | return llvm::isa<DILexicalBlockAttr, DILexicalBlockFileAttr, |
82 | DISubprogramAttr>(attr); |
83 | } |
84 | |
85 | //===----------------------------------------------------------------------===// |
86 | // DITypeAttr |
87 | //===----------------------------------------------------------------------===// |
88 | |
89 | bool DITypeAttr::classof(Attribute attr) { |
90 | return llvm::isa<DINullTypeAttr, DIBasicTypeAttr, DICompositeTypeAttr, |
91 | DIDerivedTypeAttr, DISubroutineTypeAttr>(attr); |
92 | } |
93 | |
94 | //===----------------------------------------------------------------------===// |
95 | // TBAANodeAttr |
96 | //===----------------------------------------------------------------------===// |
97 | |
98 | bool TBAANodeAttr::classof(Attribute attr) { |
99 | return llvm::isa<TBAATypeDescriptorAttr, TBAARootAttr>(attr); |
100 | } |
101 | |
102 | //===----------------------------------------------------------------------===// |
103 | // MemoryEffectsAttr |
104 | //===----------------------------------------------------------------------===// |
105 | |
106 | MemoryEffectsAttr MemoryEffectsAttr::get(MLIRContext *context, |
107 | ArrayRef<ModRefInfo> memInfoArgs) { |
108 | if (memInfoArgs.empty()) |
109 | return MemoryEffectsAttr::get(context, ModRefInfo::ModRef, |
110 | ModRefInfo::ModRef, ModRefInfo::ModRef); |
111 | if (memInfoArgs.size() == 3) |
112 | return MemoryEffectsAttr::get(context, memInfoArgs[0], memInfoArgs[1], |
113 | memInfoArgs[2]); |
114 | return {}; |
115 | } |
116 | |
117 | bool MemoryEffectsAttr::isReadWrite() { |
118 | if (this->getArgMem() != ModRefInfo::ModRef) |
119 | return false; |
120 | if (this->getInaccessibleMem() != ModRefInfo::ModRef) |
121 | return false; |
122 | if (this->getOther() != ModRefInfo::ModRef) |
123 | return false; |
124 | return true; |
125 | } |
126 | |
127 | //===----------------------------------------------------------------------===// |
128 | // DIExpression |
129 | //===----------------------------------------------------------------------===// |
130 | |
131 | DIExpressionAttr DIExpressionAttr::get(MLIRContext *context) { |
132 | return get(context, ArrayRef<DIExpressionElemAttr>({})); |
133 | } |
134 | |
135 | LogicalResult parseExpressionArg(AsmParser &parser, uint64_t opcode, |
136 | SmallVector<uint64_t> &args) { |
137 | auto operandParser = [&]() -> LogicalResult { |
138 | uint64_t operand = 0; |
139 | if (!args.empty() && opcode == llvm::dwarf::DW_OP_LLVM_convert) { |
140 | // Attempt to parse a keyword. |
141 | StringRef keyword; |
142 | if (succeeded(result: parser.parseOptionalKeyword(keyword: &keyword))) { |
143 | operand = llvm::dwarf::getAttributeEncoding(EncodingString: keyword); |
144 | if (operand == 0) { |
145 | // The keyword is invalid. |
146 | return parser.emitError(loc: parser.getCurrentLocation()) |
147 | << "encountered unknown attribute encoding \"" << keyword |
148 | << "\"" ; |
149 | } |
150 | } |
151 | } |
152 | |
153 | // operand should be non-zero if a keyword was parsed. Otherwise, the |
154 | // operand MUST be an integer. |
155 | if (operand == 0) { |
156 | // Parse the next operand as an integer. |
157 | if (parser.parseInteger(result&: operand)) { |
158 | return parser.emitError(loc: parser.getCurrentLocation()) |
159 | << "expected integer operand" ; |
160 | } |
161 | } |
162 | |
163 | args.push_back(Elt: operand); |
164 | return success(); |
165 | }; |
166 | |
167 | // Parse operands as a comma-separated list. |
168 | return parser.parseCommaSeparatedList(parseElementFn: operandParser); |
169 | } |
170 | |
171 | void printExpressionArg(AsmPrinter &printer, uint64_t opcode, |
172 | ArrayRef<uint64_t> args) { |
173 | size_t i = 0; |
174 | llvm::interleaveComma(c: args, os&: printer, each_fn: [&](uint64_t operand) { |
175 | if (i > 0 && opcode == llvm::dwarf::DW_OP_LLVM_convert) { |
176 | if (const StringRef keyword = |
177 | llvm::dwarf::AttributeEncodingString(Encoding: operand); |
178 | !keyword.empty()) { |
179 | printer << keyword; |
180 | return; |
181 | } |
182 | } |
183 | // All operands are expected to be printed as integers. |
184 | printer << operand; |
185 | i++; |
186 | }); |
187 | } |
188 | |
189 | //===----------------------------------------------------------------------===// |
190 | // DICompositeTypeAttr |
191 | //===----------------------------------------------------------------------===// |
192 | |
193 | DIRecursiveTypeAttrInterface |
194 | DICompositeTypeAttr::withRecId(DistinctAttr recId) { |
195 | return DICompositeTypeAttr::get(getContext(), getTag(), recId, getName(), |
196 | getFile(), getLine(), getScope(), |
197 | getBaseType(), getFlags(), getSizeInBits(), |
198 | getAlignInBits(), getElements()); |
199 | } |
200 | |
201 | DIRecursiveTypeAttrInterface |
202 | DICompositeTypeAttr::getRecSelf(DistinctAttr recId) { |
203 | return DICompositeTypeAttr::get(recId.getContext(), 0, recId, {}, {}, 0, {}, |
204 | {}, DIFlags(), 0, 0, {}); |
205 | } |
206 | |
207 | //===----------------------------------------------------------------------===// |
208 | // TargetFeaturesAttr |
209 | //===----------------------------------------------------------------------===// |
210 | |
211 | TargetFeaturesAttr TargetFeaturesAttr::get(MLIRContext *context, |
212 | llvm::ArrayRef<StringRef> features) { |
213 | return Base::get(context, |
214 | llvm::map_to_vector(features, [&](StringRef feature) { |
215 | return StringAttr::get(context, feature); |
216 | })); |
217 | } |
218 | |
219 | TargetFeaturesAttr TargetFeaturesAttr::get(MLIRContext *context, |
220 | StringRef targetFeatures) { |
221 | SmallVector<StringRef> features; |
222 | targetFeatures.split(features, ',', /*MaxSplit=*/-1, |
223 | /*KeepEmpty=*/false); |
224 | return get(context, features); |
225 | } |
226 | |
227 | LogicalResult |
228 | TargetFeaturesAttr::verify(function_ref<InFlightDiagnostic()> emitError, |
229 | llvm::ArrayRef<StringAttr> features) { |
230 | for (StringAttr featureAttr : features) { |
231 | if (!featureAttr || featureAttr.empty()) |
232 | return emitError() << "target features can not be null or empty" ; |
233 | auto feature = featureAttr.strref(); |
234 | if (feature[0] != '+' && feature[0] != '-') |
235 | return emitError() << "target features must start with '+' or '-'" ; |
236 | if (feature.contains(',')) |
237 | return emitError() << "target features can not contain ','" ; |
238 | } |
239 | return success(); |
240 | } |
241 | |
242 | bool TargetFeaturesAttr::contains(StringAttr feature) const { |
243 | if (nullOrEmpty()) |
244 | return false; |
245 | // Note: Using StringAttr does pointer comparisons. |
246 | return llvm::is_contained(getFeatures(), feature); |
247 | } |
248 | |
249 | bool TargetFeaturesAttr::contains(StringRef feature) const { |
250 | if (nullOrEmpty()) |
251 | return false; |
252 | return llvm::is_contained(getFeatures(), feature); |
253 | } |
254 | |
255 | std::string TargetFeaturesAttr::getFeaturesString() const { |
256 | std::string featuresString; |
257 | llvm::raw_string_ostream ss(featuresString); |
258 | llvm::interleave( |
259 | getFeatures(), ss, [&](auto &feature) { ss << feature.strref(); }, "," ); |
260 | return ss.str(); |
261 | } |
262 | |
263 | TargetFeaturesAttr TargetFeaturesAttr::featuresAt(Operation *op) { |
264 | auto parentFunction = op->getParentOfType<FunctionOpInterface>(); |
265 | if (!parentFunction) |
266 | return {}; |
267 | return parentFunction.getOperation()->getAttrOfType<TargetFeaturesAttr>( |
268 | getAttributeName()); |
269 | } |
270 | |