clang 22.0.0git
CIRAttrs.cpp
Go to the documentation of this file.
1//===- CIRAttrs.cpp - MLIR CIR Attributes ---------------------------------===//
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 attributes in the CIR dialect.
10//
11//===----------------------------------------------------------------------===//
12
14
15#include "mlir/IR/DialectImplementation.h"
16#include "llvm/ADT/TypeSwitch.h"
17
18//===-----------------------------------------------------------------===//
19// RecordMembers
20//===-----------------------------------------------------------------===//
21
22static void printRecordMembers(mlir::AsmPrinter &p, mlir::ArrayAttr members);
23static mlir::ParseResult parseRecordMembers(mlir::AsmParser &parser,
24 mlir::ArrayAttr &members);
25
26//===-----------------------------------------------------------------===//
27// IntLiteral
28//===-----------------------------------------------------------------===//
29
30static void printIntLiteral(mlir::AsmPrinter &p, llvm::APInt value,
31 cir::IntTypeInterface ty);
32static mlir::ParseResult parseIntLiteral(mlir::AsmParser &parser,
33 llvm::APInt &value,
34 cir::IntTypeInterface ty);
35//===-----------------------------------------------------------------===//
36// FloatLiteral
37//===-----------------------------------------------------------------===//
38
39static void printFloatLiteral(mlir::AsmPrinter &p, llvm::APFloat value,
40 mlir::Type ty);
41static mlir::ParseResult
42parseFloatLiteral(mlir::AsmParser &parser,
43 mlir::FailureOr<llvm::APFloat> &value,
44 cir::FPTypeInterface fpType);
45
46static mlir::ParseResult parseConstPtr(mlir::AsmParser &parser,
47 mlir::IntegerAttr &value);
48
49static void printConstPtr(mlir::AsmPrinter &p, mlir::IntegerAttr value);
50
51#define GET_ATTRDEF_CLASSES
52#include "clang/CIR/Dialect/IR/CIROpsAttributes.cpp.inc"
53
54using namespace mlir;
55using namespace cir;
56
57//===----------------------------------------------------------------------===//
58// General CIR parsing / printing
59//===----------------------------------------------------------------------===//
60
61Attribute CIRDialect::parseAttribute(DialectAsmParser &parser,
62 Type type) const {
63 llvm::SMLoc typeLoc = parser.getCurrentLocation();
64 llvm::StringRef mnemonic;
65 Attribute genAttr;
66 OptionalParseResult parseResult =
67 generatedAttributeParser(parser, &mnemonic, type, genAttr);
68 if (parseResult.has_value())
69 return genAttr;
70 parser.emitError(typeLoc, "unknown attribute in CIR dialect");
71 return Attribute();
72}
73
74void CIRDialect::printAttribute(Attribute attr, DialectAsmPrinter &os) const {
75 if (failed(generatedAttributePrinter(attr, os)))
76 llvm_unreachable("unexpected CIR type kind");
77}
78
79static void printRecordMembers(mlir::AsmPrinter &printer,
80 mlir::ArrayAttr members) {
81 printer << '{';
82 llvm::interleaveComma(members, printer);
83 printer << '}';
84}
85
86static ParseResult parseRecordMembers(mlir::AsmParser &parser,
87 mlir::ArrayAttr &members) {
89
90 auto delimiter = AsmParser::Delimiter::Braces;
91 auto result = parser.parseCommaSeparatedList(delimiter, [&]() {
92 mlir::TypedAttr attr;
93 if (parser.parseAttribute(attr).failed())
94 return mlir::failure();
95 elts.push_back(attr);
96 return mlir::success();
97 });
98
99 if (result.failed())
100 return mlir::failure();
101
102 members = mlir::ArrayAttr::get(parser.getContext(), elts);
103 return mlir::success();
104}
105
106//===----------------------------------------------------------------------===//
107// ConstRecordAttr definitions
108//===----------------------------------------------------------------------===//
109
110LogicalResult
111ConstRecordAttr::verify(function_ref<InFlightDiagnostic()> emitError,
112 mlir::Type type, ArrayAttr members) {
113 auto sTy = mlir::dyn_cast_if_present<cir::RecordType>(type);
114 if (!sTy)
115 return emitError() << "expected !cir.record type";
116
117 if (sTy.getMembers().size() != members.size())
118 return emitError() << "number of elements must match";
119
120 unsigned attrIdx = 0;
121 for (auto &member : sTy.getMembers()) {
122 auto m = mlir::cast<mlir::TypedAttr>(members[attrIdx]);
123 if (member != m.getType())
124 return emitError() << "element at index " << attrIdx << " has type "
125 << m.getType()
126 << " but the expected type for this element is "
127 << member;
128 attrIdx++;
129 }
130
131 return success();
132}
133
134//===----------------------------------------------------------------------===//
135// OptInfoAttr definitions
136//===----------------------------------------------------------------------===//
137
138LogicalResult OptInfoAttr::verify(function_ref<InFlightDiagnostic()> emitError,
139 unsigned level, unsigned size) {
140 if (level > 3)
141 return emitError()
142 << "optimization level must be between 0 and 3 inclusive";
143 if (size > 2)
144 return emitError()
145 << "size optimization level must be between 0 and 2 inclusive";
146 return success();
147}
148
149//===----------------------------------------------------------------------===//
150// ConstPtrAttr definitions
151//===----------------------------------------------------------------------===//
152
153// TODO(CIR): Consider encoding the null value differently and use conditional
154// assembly format instead of custom parsing/printing.
155static ParseResult parseConstPtr(AsmParser &parser, mlir::IntegerAttr &value) {
156
157 if (parser.parseOptionalKeyword("null").succeeded()) {
158 value = parser.getBuilder().getI64IntegerAttr(0);
159 return success();
160 }
161
162 return parser.parseAttribute(value);
163}
164
165static void printConstPtr(AsmPrinter &p, mlir::IntegerAttr value) {
166 if (!value.getInt())
167 p << "null";
168 else
169 p << value;
170}
171
172//===----------------------------------------------------------------------===//
173// IntAttr definitions
174//===----------------------------------------------------------------------===//
175
176template <typename IntT>
177static bool isTooLargeForType(const mlir::APInt &value, IntT expectedValue) {
178 if constexpr (std::is_signed_v<IntT>) {
179 return value.getSExtValue() != expectedValue;
180 } else {
181 return value.getZExtValue() != expectedValue;
182 }
183}
184
185template <typename IntT>
186static mlir::ParseResult parseIntLiteralImpl(mlir::AsmParser &p,
187 llvm::APInt &value,
188 cir::IntTypeInterface ty) {
189 IntT ivalue;
190 const bool isSigned = ty.isSigned();
191 if (p.parseInteger(ivalue))
192 return p.emitError(p.getCurrentLocation(), "expected integer value");
193
194 value = mlir::APInt(ty.getWidth(), ivalue, isSigned, /*implicitTrunc=*/true);
195 if (isTooLargeForType(value, ivalue))
196 return p.emitError(p.getCurrentLocation(),
197 "integer value too large for the given type");
198
199 return success();
200}
201
202mlir::ParseResult parseIntLiteral(mlir::AsmParser &parser, llvm::APInt &value,
203 cir::IntTypeInterface ty) {
204 if (ty.isSigned())
205 return parseIntLiteralImpl<int64_t>(parser, value, ty);
206 return parseIntLiteralImpl<uint64_t>(parser, value, ty);
207}
208
209void printIntLiteral(mlir::AsmPrinter &p, llvm::APInt value,
210 cir::IntTypeInterface ty) {
211 if (ty.isSigned())
212 p << value.getSExtValue();
213 else
214 p << value.getZExtValue();
215}
216
217LogicalResult IntAttr::verify(function_ref<InFlightDiagnostic()> emitError,
218 cir::IntTypeInterface type, llvm::APInt value) {
219 if (value.getBitWidth() != type.getWidth())
220 return emitError() << "type and value bitwidth mismatch: "
221 << type.getWidth() << " != " << value.getBitWidth();
222 return success();
223}
224
225//===----------------------------------------------------------------------===//
226// FPAttr definitions
227//===----------------------------------------------------------------------===//
228
229static void printFloatLiteral(AsmPrinter &p, APFloat value, Type ty) {
230 p << value;
231}
232
233static ParseResult parseFloatLiteral(AsmParser &parser,
234 FailureOr<APFloat> &value,
235 cir::FPTypeInterface fpType) {
236
237 APFloat parsedValue(0.0);
238 if (parser.parseFloat(fpType.getFloatSemantics(), parsedValue))
239 return failure();
240
241 value.emplace(parsedValue);
242 return success();
243}
244
245FPAttr FPAttr::getZero(Type type) {
246 return get(type,
247 APFloat::getZero(
248 mlir::cast<cir::FPTypeInterface>(type).getFloatSemantics()));
249}
250
251LogicalResult FPAttr::verify(function_ref<InFlightDiagnostic()> emitError,
252 cir::FPTypeInterface fpType, APFloat value) {
253 if (APFloat::SemanticsToEnum(fpType.getFloatSemantics()) !=
254 APFloat::SemanticsToEnum(value.getSemantics()))
255 return emitError() << "floating-point semantics mismatch";
256
257 return success();
258}
259
260//===----------------------------------------------------------------------===//
261// ConstComplexAttr definitions
262//===----------------------------------------------------------------------===//
263
264LogicalResult
265ConstComplexAttr::verify(function_ref<InFlightDiagnostic()> emitError,
266 cir::ComplexType type, mlir::TypedAttr real,
267 mlir::TypedAttr imag) {
268 mlir::Type elemType = type.getElementType();
269 if (real.getType() != elemType)
270 return emitError()
271 << "type of the real part does not match the complex type";
272
273 if (imag.getType() != elemType)
274 return emitError()
275 << "type of the imaginary part does not match the complex type";
276
277 return success();
278}
279
280//===----------------------------------------------------------------------===//
281// CIR ConstArrayAttr
282//===----------------------------------------------------------------------===//
283
284LogicalResult
285ConstArrayAttr::verify(function_ref<InFlightDiagnostic()> emitError, Type type,
286 Attribute elts, int trailingZerosNum) {
287
288 if (!(mlir::isa<ArrayAttr, StringAttr>(elts)))
289 return emitError() << "constant array expects ArrayAttr or StringAttr";
290
291 if (auto strAttr = mlir::dyn_cast<StringAttr>(elts)) {
292 const auto arrayTy = mlir::cast<ArrayType>(type);
293 const auto intTy = mlir::dyn_cast<IntType>(arrayTy.getElementType());
294
295 // TODO: add CIR type for char.
296 if (!intTy || intTy.getWidth() != 8)
297 return emitError()
298 << "constant array element for string literals expects "
299 "!cir.int<u, 8> element type";
300 return success();
301 }
302
303 assert(mlir::isa<ArrayAttr>(elts));
304 const auto arrayAttr = mlir::cast<mlir::ArrayAttr>(elts);
305 const auto arrayTy = mlir::cast<ArrayType>(type);
306
307 // Make sure both number of elements and subelement types match type.
308 if (arrayTy.getSize() != arrayAttr.size() + trailingZerosNum)
309 return emitError() << "constant array size should match type size";
310 return success();
311}
312
313Attribute ConstArrayAttr::parse(AsmParser &parser, Type type) {
314 mlir::FailureOr<Type> resultTy;
315 mlir::FailureOr<Attribute> resultVal;
316
317 // Parse literal '<'
318 if (parser.parseLess())
319 return {};
320
321 // Parse variable 'value'
322 resultVal = FieldParser<Attribute>::parse(parser);
323 if (failed(resultVal)) {
324 parser.emitError(
325 parser.getCurrentLocation(),
326 "failed to parse ConstArrayAttr parameter 'value' which is "
327 "to be a `Attribute`");
328 return {};
329 }
330
331 // ArrayAttrrs have per-element type, not the type of the array...
332 if (mlir::isa<ArrayAttr>(*resultVal)) {
333 // Array has implicit type: infer from const array type.
334 if (parser.parseOptionalColon().failed()) {
335 resultTy = type;
336 } else { // Array has explicit type: parse it.
337 resultTy = FieldParser<Type>::parse(parser);
338 if (failed(resultTy)) {
339 parser.emitError(
340 parser.getCurrentLocation(),
341 "failed to parse ConstArrayAttr parameter 'type' which is "
342 "to be a `::mlir::Type`");
343 return {};
344 }
345 }
346 } else {
347 auto ta = mlir::cast<TypedAttr>(*resultVal);
348 resultTy = ta.getType();
349 if (mlir::isa<mlir::NoneType>(*resultTy)) {
350 parser.emitError(parser.getCurrentLocation(),
351 "expected type declaration for string literal");
352 return {};
353 }
354 }
355
356 unsigned zeros = 0;
357 if (parser.parseOptionalComma().succeeded()) {
358 if (parser.parseOptionalKeyword("trailing_zeros").succeeded()) {
359 unsigned typeSize =
360 mlir::cast<cir::ArrayType>(resultTy.value()).getSize();
361 mlir::Attribute elts = resultVal.value();
362 if (auto str = mlir::dyn_cast<mlir::StringAttr>(elts))
363 zeros = typeSize - str.size();
364 else
365 zeros = typeSize - mlir::cast<mlir::ArrayAttr>(elts).size();
366 } else {
367 return {};
368 }
369 }
370
371 // Parse literal '>'
372 if (parser.parseGreater())
373 return {};
374
375 return parser.getChecked<ConstArrayAttr>(
376 parser.getCurrentLocation(), parser.getContext(), resultTy.value(),
377 resultVal.value(), zeros);
378}
379
380void ConstArrayAttr::print(AsmPrinter &printer) const {
381 printer << "<";
382 printer.printStrippedAttrOrType(getElts());
383 if (getTrailingZerosNum())
384 printer << ", trailing_zeros";
385 printer << ">";
386}
387
388//===----------------------------------------------------------------------===//
389// CIR ConstVectorAttr
390//===----------------------------------------------------------------------===//
391
392LogicalResult
393cir::ConstVectorAttr::verify(function_ref<InFlightDiagnostic()> emitError,
394 Type type, ArrayAttr elts) {
395
396 if (!mlir::isa<cir::VectorType>(type))
397 return emitError() << "type of cir::ConstVectorAttr is not a "
398 "cir::VectorType: "
399 << type;
400
401 const auto vecType = mlir::cast<cir::VectorType>(type);
402
403 if (vecType.getSize() != elts.size())
404 return emitError()
405 << "number of constant elements should match vector size";
406
407 // Check if the types of the elements match
408 LogicalResult elementTypeCheck = success();
409 elts.walkImmediateSubElements(
410 [&](Attribute element) {
411 if (elementTypeCheck.failed()) {
412 // An earlier element didn't match
413 return;
414 }
415 auto typedElement = mlir::dyn_cast<TypedAttr>(element);
416 if (!typedElement ||
417 typedElement.getType() != vecType.getElementType()) {
418 elementTypeCheck = failure();
419 emitError() << "constant type should match vector element type";
420 }
421 },
422 [&](Type) {});
423
424 return elementTypeCheck;
425}
426
427//===----------------------------------------------------------------------===//
428// CIR VTableAttr
429//===----------------------------------------------------------------------===//
430
431LogicalResult cir::VTableAttr::verify(
432 llvm::function_ref<mlir::InFlightDiagnostic()> emitError, mlir::Type type,
433 mlir::ArrayAttr data) {
434 auto sTy = mlir::dyn_cast_if_present<cir::RecordType>(type);
435 if (!sTy)
436 return emitError() << "expected !cir.record type result";
437 if (sTy.getMembers().empty() || data.empty())
438 return emitError() << "expected record type with one or more subtype";
439
440 if (cir::ConstRecordAttr::verify(emitError, type, data).failed())
441 return failure();
442
443 for (const auto &element : data.getAsRange<mlir::Attribute>()) {
444 const auto &constArrayAttr = mlir::dyn_cast<cir::ConstArrayAttr>(element);
445 if (!constArrayAttr)
446 return emitError() << "expected constant array subtype";
447
448 LogicalResult eltTypeCheck = success();
449 auto arrayElts = mlir::cast<ArrayAttr>(constArrayAttr.getElts());
450 arrayElts.walkImmediateSubElements(
451 [&](mlir::Attribute attr) {
452 if (mlir::isa<ConstPtrAttr, GlobalViewAttr>(attr))
453 return;
454
455 eltTypeCheck = emitError()
456 << "expected GlobalViewAttr or ConstPtrAttr";
457 },
458 [&](mlir::Type type) {});
459 if (eltTypeCheck.failed())
460 return eltTypeCheck;
461 }
462 return success();
463}
464
465//===----------------------------------------------------------------------===//
466// CIR Dialect
467//===----------------------------------------------------------------------===//
468
469void CIRDialect::registerAttributes() {
470 addAttributes<
471#define GET_ATTRDEF_LIST
472#include "clang/CIR/Dialect/IR/CIROpsAttributes.cpp.inc"
473 >();
474}
static mlir::ParseResult parseFloatLiteral(mlir::AsmParser &parser, mlir::FailureOr< llvm::APFloat > &value, cir::FPTypeInterface fpType)
static mlir::ParseResult parseIntLiteralImpl(mlir::AsmParser &p, llvm::APInt &value, cir::IntTypeInterface ty)
Definition CIRAttrs.cpp:186
static void printConstPtr(mlir::AsmPrinter &p, mlir::IntegerAttr value)
static void printRecordMembers(mlir::AsmPrinter &p, mlir::ArrayAttr members)
Definition CIRAttrs.cpp:79
static mlir::ParseResult parseIntLiteral(mlir::AsmParser &parser, llvm::APInt &value, cir::IntTypeInterface ty)
Definition CIRAttrs.cpp:202
static void printIntLiteral(mlir::AsmPrinter &p, llvm::APInt value, cir::IntTypeInterface ty)
Definition CIRAttrs.cpp:209
static mlir::ParseResult parseConstPtr(mlir::AsmParser &parser, mlir::IntegerAttr &value)
static bool isTooLargeForType(const mlir::APInt &value, IntT expectedValue)
Definition CIRAttrs.cpp:177
static void printFloatLiteral(mlir::AsmPrinter &p, llvm::APFloat value, mlir::Type ty)
static mlir::ParseResult parseRecordMembers(mlir::AsmParser &parser, mlir::ArrayAttr &members)
Definition CIRAttrs.cpp:86
RangeSelector member(std::string ID)
Given a MemberExpr, selects the member token. ID is the node's binding in the match result.