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