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