15#include "mlir/IR/DialectImplementation.h"
16#include "llvm/ADT/TypeSwitch.h"
24 mlir::ArrayAttr &members);
31 cir::IntTypeInterface ty);
34 cir::IntTypeInterface ty);
41static mlir::ParseResult
43 mlir::FailureOr<llvm::APFloat> &value,
44 cir::FPTypeInterface fpType);
51 cir::TargetAddressSpaceAttr &attr);
54 cir::TargetAddressSpaceAttr attr);
57 mlir::IntegerAttr &value);
61#define GET_ATTRDEF_CLASSES
62#include "clang/CIR/Dialect/IR/CIROpsAttributes.cpp.inc"
72 mlir::ArrayAttr members) {
74 llvm::interleaveComma(members, printer);
79 mlir::ArrayAttr &members) {
82 auto delimiter = AsmParser::Delimiter::Braces;
83 auto result = parser.parseCommaSeparatedList(delimiter, [&]() {
85 if (parser.parseAttribute(attr).failed())
86 return mlir::failure();
88 return mlir::success();
92 return mlir::failure();
94 members = mlir::ArrayAttr::get(parser.getContext(), elts);
95 return mlir::success();
103ConstRecordAttr::verify(function_ref<InFlightDiagnostic()> emitError,
104 mlir::Type type, ArrayAttr members) {
105 auto sTy = mlir::dyn_cast_if_present<cir::RecordType>(type);
107 return emitError() <<
"expected !cir.record type";
109 if (sTy.getMembers().size() != members.size())
110 return emitError() <<
"number of elements must match";
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 "
118 <<
" but the expected type for this element is "
130LogicalResult OptInfoAttr::verify(function_ref<InFlightDiagnostic()> emitError,
131 unsigned level,
unsigned size) {
134 <<
"optimization level must be between 0 and 3 inclusive";
137 <<
"size optimization level must be between 0 and 2 inclusive";
147static ParseResult
parseConstPtr(AsmParser &parser, mlir::IntegerAttr &value) {
149 if (parser.parseOptionalKeyword(
"null").succeeded()) {
150 value = parser.getBuilder().getI64IntegerAttr(0);
154 return parser.parseAttribute(value);
168template <
typename IntT>
170 if constexpr (std::is_signed_v<IntT>) {
171 return value.getSExtValue() != expectedValue;
173 return value.getZExtValue() != expectedValue;
177template <
typename IntT>
180 cir::IntTypeInterface ty) {
182 const bool isSigned = ty.isSigned();
183 if (p.parseInteger(ivalue))
184 return p.emitError(p.getCurrentLocation(),
"expected integer value");
186 value = mlir::APInt(ty.getWidth(), ivalue, isSigned,
true);
188 return p.emitError(p.getCurrentLocation(),
189 "integer value too large for the given type");
195 cir::IntTypeInterface ty) {
202 cir::IntTypeInterface ty) {
204 p << value.getSExtValue();
206 p << value.getZExtValue();
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();
226 FailureOr<APFloat> &value,
227 cir::FPTypeInterface fpType) {
229 APFloat parsedValue(0.0);
230 if (parser.parseFloat(fpType.getFloatSemantics(), parsedValue))
233 value.emplace(parsedValue);
237FPAttr FPAttr::getZero(Type type) {
240 mlir::cast<cir::FPTypeInterface>(type).getFloatSemantics()));
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";
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)
263 <<
"type of the real part does not match the complex type";
265 if (imag.getType() != elemType)
267 <<
"type of the imaginary part does not match the complex type";
277DataMemberAttr::verify(function_ref<InFlightDiagnostic()> emitError,
278 cir::DataMemberType ty,
279 std::optional<unsigned> memberIndex) {
281 if (!memberIndex.has_value())
284 cir::RecordType recTy = ty.getClassTy();
285 if (recTy.isIncomplete())
287 <<
"incomplete 'cir.record' cannot be used to build a non-null "
288 "data member pointer";
290 unsigned memberIndexValue = memberIndex.value();
291 if (memberIndexValue >= recTy.getNumElements())
293 <<
"member index of a #cir.data_member attribute is out of range";
295 mlir::Type memberTy = recTy.getMembers()[memberIndexValue];
296 if (memberTy != ty.getMemberTy())
298 <<
"member type of a #cir.data_member attribute must match the "
308LogicalResult MethodAttr::verify(function_ref<InFlightDiagnostic()> emitError,
309 cir::MethodType type,
310 std::optional<FlatSymbolRefAttr> symbol,
311 std::optional<uint64_t> vtable_offset) {
312 if (symbol.has_value() && vtable_offset.has_value())
314 <<
"at most one of symbol and vtable_offset can be present "
320Attribute MethodAttr::parse(AsmParser &parser, Type odsType) {
321 auto ty = mlir::cast<cir::MethodType>(odsType);
323 if (parser.parseLess().failed())
327 if (parser.parseOptionalKeyword(
"null").succeeded()) {
328 if (parser.parseGreater().failed())
335 FlatSymbolRefAttr symbol;
336 mlir::OptionalParseResult parseSymbolRefResult =
337 parser.parseOptionalAttribute(symbol);
338 if (parseSymbolRefResult.has_value()) {
339 if (parseSymbolRefResult.value().failed())
341 if (parser.parseGreater().failed())
343 return get(ty, symbol);
347 std::uint64_t vtableOffset = 0;
348 if (parser.parseKeyword(
"vtable_offset"))
350 if (parser.parseEqual())
352 if (parser.parseInteger(vtableOffset))
355 if (parser.parseGreater())
358 return get(ty, vtableOffset);
361void MethodAttr::print(AsmPrinter &printer)
const {
362 auto symbol = getSymbol();
363 auto vtableOffset = getVtableOffset();
366 if (symbol.has_value()) {
368 }
else if (vtableOffset.has_value()) {
369 printer <<
"vtable_offset = " << *vtableOffset;
381ConstArrayAttr::verify(function_ref<InFlightDiagnostic()> emitError, Type type,
382 Attribute elts,
int trailingZerosNum) {
384 if (!(mlir::isa<ArrayAttr, StringAttr>(elts)))
385 return emitError() <<
"constant array expects ArrayAttr or StringAttr";
387 if (
auto strAttr = mlir::dyn_cast<StringAttr>(elts)) {
388 const auto arrayTy = mlir::cast<ArrayType>(type);
389 const auto intTy = mlir::dyn_cast<IntType>(arrayTy.getElementType());
392 if (!intTy || intTy.getWidth() != 8)
394 <<
"constant array element for string literals expects "
395 "!cir.int<u, 8> element type";
399 assert(mlir::isa<ArrayAttr>(elts));
400 const auto arrayAttr = mlir::cast<mlir::ArrayAttr>(elts);
401 const auto arrayTy = mlir::cast<ArrayType>(type);
404 if (arrayTy.getSize() != arrayAttr.size() + trailingZerosNum)
405 return emitError() <<
"constant array size should match type size";
409Attribute ConstArrayAttr::parse(AsmParser &parser, Type type) {
410 mlir::FailureOr<Type> resultTy;
411 mlir::FailureOr<Attribute> resultVal;
414 if (parser.parseLess())
418 resultVal = FieldParser<Attribute>::parse(parser);
419 if (failed(resultVal)) {
421 parser.getCurrentLocation(),
422 "failed to parse ConstArrayAttr parameter 'value' which is "
423 "to be a `Attribute`");
428 if (mlir::isa<ArrayAttr>(*resultVal)) {
430 if (parser.parseOptionalColon().failed()) {
433 resultTy = FieldParser<Type>::parse(parser);
434 if (failed(resultTy)) {
436 parser.getCurrentLocation(),
437 "failed to parse ConstArrayAttr parameter 'type' which is "
438 "to be a `::mlir::Type`");
443 auto ta = mlir::cast<TypedAttr>(*resultVal);
444 resultTy = ta.getType();
445 if (mlir::isa<mlir::NoneType>(*resultTy)) {
446 parser.emitError(parser.getCurrentLocation(),
447 "expected type declaration for string literal");
453 if (parser.parseOptionalComma().succeeded()) {
454 if (parser.parseOptionalKeyword(
"trailing_zeros").succeeded()) {
456 mlir::cast<cir::ArrayType>(resultTy.value()).getSize();
457 mlir::Attribute elts = resultVal.value();
458 if (
auto str = mlir::dyn_cast<mlir::StringAttr>(elts))
459 zeros = typeSize - str.size();
461 zeros = typeSize - mlir::cast<mlir::ArrayAttr>(elts).size();
468 if (parser.parseGreater())
471 return parser.getChecked<ConstArrayAttr>(
472 parser.getCurrentLocation(), parser.getContext(), resultTy.value(),
473 resultVal.value(), zeros);
476void ConstArrayAttr::print(AsmPrinter &printer)
const {
478 printer.printStrippedAttrOrType(getElts());
479 if (getTrailingZerosNum())
480 printer <<
", trailing_zeros";
489cir::ConstVectorAttr::verify(function_ref<InFlightDiagnostic()> emitError,
490 Type type, ArrayAttr elts) {
492 if (!mlir::isa<cir::VectorType>(type))
493 return emitError() <<
"type of cir::ConstVectorAttr is not a "
497 const auto vecType = mlir::cast<cir::VectorType>(type);
499 if (vecType.getSize() != elts.size())
501 <<
"number of constant elements should match vector size";
504 LogicalResult elementTypeCheck =
success();
505 elts.walkImmediateSubElements(
506 [&](Attribute element) {
507 if (elementTypeCheck.failed()) {
511 auto typedElement = mlir::dyn_cast<TypedAttr>(element);
513 typedElement.getType() != vecType.getElementType()) {
514 elementTypeCheck = failure();
515 emitError() <<
"constant type should match vector element type";
520 return elementTypeCheck;
527LogicalResult cir::VTableAttr::verify(
528 llvm::function_ref<mlir::InFlightDiagnostic()> emitError, mlir::Type type,
529 mlir::ArrayAttr data) {
530 auto sTy = mlir::dyn_cast_if_present<cir::RecordType>(type);
532 return emitError() <<
"expected !cir.record type result";
533 if (sTy.getMembers().empty() || data.empty())
534 return emitError() <<
"expected record type with one or more subtype";
536 if (cir::ConstRecordAttr::verify(emitError, type, data).failed())
539 for (
const auto &element : data.getAsRange<mlir::Attribute>()) {
540 const auto &constArrayAttr = mlir::dyn_cast<cir::ConstArrayAttr>(element);
542 return emitError() <<
"expected constant array subtype";
544 LogicalResult eltTypeCheck =
success();
545 auto arrayElts = mlir::cast<ArrayAttr>(constArrayAttr.getElts());
546 arrayElts.walkImmediateSubElements(
547 [&](mlir::Attribute attr) {
548 if (mlir::isa<ConstPtrAttr, GlobalViewAttr>(attr))
551 eltTypeCheck = emitError()
552 <<
"expected GlobalViewAttr or ConstPtrAttr";
554 [&](mlir::Type type) {});
555 if (eltTypeCheck.failed())
565std::string DynamicCastInfoAttr::getAlias()
const {
568 std::string alias =
"dyn_cast_info_";
570 alias.append(getSrcRtti().getSymbol().getValue());
571 alias.push_back(
'_');
572 alias.append(getDestRtti().getSymbol().getValue());
577LogicalResult DynamicCastInfoAttr::verify(
578 function_ref<InFlightDiagnostic()> emitError, cir::GlobalViewAttr srcRtti,
579 cir::GlobalViewAttr destRtti, mlir::FlatSymbolRefAttr runtimeFunc,
580 mlir::FlatSymbolRefAttr badCastFunc, cir::IntAttr offsetHint) {
581 auto isRttiPtr = [](mlir::Type ty) {
584 auto ptrTy = mlir::dyn_cast<cir::PointerType>(ty);
588 auto pointeeIntTy = mlir::dyn_cast<cir::IntType>(ptrTy.getPointee());
592 return pointeeIntTy.isUnsigned() && pointeeIntTy.getWidth() == 8;
595 if (!isRttiPtr(srcRtti.getType()))
596 return emitError() <<
"srcRtti must be an RTTI pointer";
598 if (!isRttiPtr(destRtti.getType()))
599 return emitError() <<
"destRtti must be an RTTI pointer";
608void CIRDialect::registerAttributes() {
610#define GET_ATTRDEF_LIST
611#include "clang/CIR/Dialect/IR/CIROpsAttributes.cpp.inc"
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)
static void printConstPtr(mlir::AsmPrinter &p, mlir::IntegerAttr value)
static void printRecordMembers(mlir::AsmPrinter &p, mlir::ArrayAttr members)
static mlir::ParseResult parseIntLiteral(mlir::AsmParser &parser, llvm::APInt &value, cir::IntTypeInterface ty)
mlir::ParseResult parseTargetAddressSpace(mlir::AsmParser &p, cir::TargetAddressSpaceAttr &attr)
static void printIntLiteral(mlir::AsmPrinter &p, llvm::APInt value, cir::IntTypeInterface ty)
static mlir::ParseResult parseConstPtr(mlir::AsmParser &parser, mlir::IntegerAttr &value)
static bool isTooLargeForType(const mlir::APInt &value, IntT expectedValue)
static void printFloatLiteral(mlir::AsmPrinter &p, llvm::APFloat value, mlir::Type ty)
static mlir::ParseResult parseRecordMembers(mlir::AsmParser &parser, mlir::ArrayAttr &members)
void printTargetAddressSpace(mlir::AsmPrinter &p, cir::TargetAddressSpaceAttr attr)