528 lines · cpp
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-exception6//7//===----------------------------------------------------------------------===//8//9// This file defines the attributes in the CIR dialect.10//11//===----------------------------------------------------------------------===//12 13#include "clang/CIR/Dialect/IR/CIRDialect.h"14 15#include "mlir/IR/DialectImplementation.h"16#include "llvm/ADT/TypeSwitch.h"17 18//===-----------------------------------------------------------------===//19// RecordMembers20//===-----------------------------------------------------------------===//21 22static void printRecordMembers(mlir::AsmPrinter &p, mlir::ArrayAttr members);23static mlir::ParseResult parseRecordMembers(mlir::AsmParser &parser,24 mlir::ArrayAttr &members);25 26//===-----------------------------------------------------------------===//27// IntLiteral28//===-----------------------------------------------------------------===//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// FloatLiteral37//===-----------------------------------------------------------------===//38 39static void printFloatLiteral(mlir::AsmPrinter &p, llvm::APFloat value,40 mlir::Type ty);41static mlir::ParseResult42parseFloatLiteral(mlir::AsmParser &parser,43 mlir::FailureOr<llvm::APFloat> &value,44 cir::FPTypeInterface fpType);45 46//===----------------------------------------------------------------------===//47// AddressSpaceAttr48//===----------------------------------------------------------------------===//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_CLASSES62#include "clang/CIR/Dialect/IR/CIROpsAttributes.cpp.inc"63 64using namespace mlir;65using namespace cir;66 67//===----------------------------------------------------------------------===//68// General CIR parsing / printing69//===----------------------------------------------------------------------===//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) {98 llvm::SmallVector<mlir::Attribute, 4> elts;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 definitions118//===----------------------------------------------------------------------===//119 120LogicalResult121ConstRecordAttr::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 definitions146//===----------------------------------------------------------------------===//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 definitions161//===----------------------------------------------------------------------===//162 163// TODO(CIR): Consider encoding the null value differently and use conditional164// 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 else179 p << value;180}181 182//===----------------------------------------------------------------------===//183// IntAttr definitions184//===----------------------------------------------------------------------===//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 else224 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 definitions237//===----------------------------------------------------------------------===//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 definitions272//===----------------------------------------------------------------------===//273 274LogicalResult275ConstComplexAttr::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 ConstArrayAttr292//===----------------------------------------------------------------------===//293 294LogicalResult295ConstArrayAttr::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 else375 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 ConstVectorAttr400//===----------------------------------------------------------------------===//401 402LogicalResult403cir::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 match418 LogicalResult elementTypeCheck = success();419 elts.walkImmediateSubElements(420 [&](Attribute element) {421 if (elementTypeCheck.failed()) {422 // An earlier element didn't match423 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 VTableAttr439//===----------------------------------------------------------------------===//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 definitions477//===----------------------------------------------------------------------===//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 Dialect520//===----------------------------------------------------------------------===//521 522void CIRDialect::registerAttributes() {523 addAttributes<524#define GET_ATTRDEF_LIST525#include "clang/CIR/Dialect/IR/CIROpsAttributes.cpp.inc"526 >();527}528