diff options
Diffstat (limited to 'clang/lib/CIR/Dialect')
-rw-r--r-- | clang/lib/CIR/Dialect/IR/CIRDialect.cpp | 220 | ||||
-rw-r--r-- | clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp | 37 | ||||
-rw-r--r-- | clang/lib/CIR/Dialect/Transforms/LoweringPrepareItaniumCXXABI.cpp | 48 |
3 files changed, 278 insertions, 27 deletions
diff --git a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp index 5f88590..f03b891 100644 --- a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp +++ b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp @@ -15,6 +15,7 @@ #include "clang/CIR/Dialect/IR/CIROpsEnums.h" #include "clang/CIR/Dialect/IR/CIRTypes.h" +#include "mlir/IR/DialectImplementation.h" #include "mlir/Interfaces/ControlFlowInterfaces.h" #include "mlir/Interfaces/FunctionImplementation.h" #include "mlir/Support/LLVM.h" @@ -1720,6 +1721,73 @@ ParseResult cir::FuncOp::parse(OpAsmParser &parser, OperationState &state) { hasAlias = true; } + auto parseGlobalDtorCtor = + [&](StringRef keyword, + llvm::function_ref<void(std::optional<int> prio)> createAttr) + -> mlir::LogicalResult { + if (mlir::succeeded(parser.parseOptionalKeyword(keyword))) { + std::optional<int> priority; + if (mlir::succeeded(parser.parseOptionalLParen())) { + auto parsedPriority = mlir::FieldParser<int>::parse(parser); + if (mlir::failed(parsedPriority)) + return parser.emitError(parser.getCurrentLocation(), + "failed to parse 'priority', of type 'int'"); + priority = parsedPriority.value_or(int()); + // Parse literal ')' + if (parser.parseRParen()) + return failure(); + } + createAttr(priority); + } + return success(); + }; + + if (parseGlobalDtorCtor("global_ctor", [&](std::optional<int> priority) { + mlir::IntegerAttr globalCtorPriorityAttr = + builder.getI32IntegerAttr(priority.value_or(65535)); + state.addAttribute(getGlobalCtorPriorityAttrName(state.name), + globalCtorPriorityAttr); + }).failed()) + return failure(); + + if (parseGlobalDtorCtor("global_dtor", [&](std::optional<int> priority) { + mlir::IntegerAttr globalDtorPriorityAttr = + builder.getI32IntegerAttr(priority.value_or(65535)); + state.addAttribute(getGlobalDtorPriorityAttrName(state.name), + globalDtorPriorityAttr); + }).failed()) + return failure(); + + // Parse optional inline kind: inline(never|always|hint) + if (parser.parseOptionalKeyword("inline").succeeded()) { + if (parser.parseLParen().failed()) + return failure(); + + llvm::StringRef inlineKindStr; + const std::array<llvm::StringRef, cir::getMaxEnumValForInlineKind()> + allowedInlineKindStrs{ + cir::stringifyInlineKind(cir::InlineKind::NoInline), + cir::stringifyInlineKind(cir::InlineKind::AlwaysInline), + cir::stringifyInlineKind(cir::InlineKind::InlineHint), + }; + if (parser.parseOptionalKeyword(&inlineKindStr, allowedInlineKindStrs) + .failed()) + return parser.emitError(parser.getCurrentLocation(), + "expected 'never', 'always', or 'hint'"); + + std::optional<InlineKind> inlineKind = + cir::symbolizeInlineKind(inlineKindStr); + if (!inlineKind) + return parser.emitError(parser.getCurrentLocation(), + "invalid inline kind"); + + state.addAttribute(getInlineKindAttrName(state.name), + cir::InlineAttr::get(builder.getContext(), *inlineKind)); + + if (parser.parseRParen().failed()) + return failure(); + } + // Parse the optional function body. auto *body = state.addRegion(); OptionalParseResult parseResult = parser.parseOptionalRegion( @@ -1801,6 +1869,22 @@ void cir::FuncOp::print(OpAsmPrinter &p) { p << ")"; } + if (auto globalCtorPriority = getGlobalCtorPriority()) { + p << " global_ctor"; + if (globalCtorPriority.value() != 65535) + p << "(" << globalCtorPriority.value() << ")"; + } + + if (auto globalDtorPriority = getGlobalDtorPriority()) { + p << " global_dtor"; + if (globalDtorPriority.value() != 65535) + p << "(" << globalDtorPriority.value() << ")"; + } + + if (cir::InlineAttr inlineAttr = getInlineKindAttr()) { + p << " inline(" << cir::stringifyInlineKind(inlineAttr.getValue()) << ")"; + } + // Print the body if this is not an external function. Region &body = getOperation()->getRegion(0); if (!body.empty()) { @@ -2851,31 +2935,141 @@ mlir::LogicalResult cir::ThrowOp::verify() { } //===----------------------------------------------------------------------===// -// AtomicCmpXchg +// TypeInfoAttr //===----------------------------------------------------------------------===// -LogicalResult cir::AtomicCmpXchg::verify() { - mlir::Type pointeeType = getPtr().getType().getPointee(); +LogicalResult cir::TypeInfoAttr::verify( + ::llvm::function_ref<::mlir::InFlightDiagnostic()> emitError, + ::mlir::Type type, ::mlir::ArrayAttr typeInfoData) { - if (pointeeType != getExpected().getType() || - pointeeType != getDesired().getType()) - return emitOpError("ptr, expected and desired types must match"); + if (cir::ConstRecordAttr::verify(emitError, type, typeInfoData).failed()) + return failure(); return success(); } //===----------------------------------------------------------------------===// -// TypeInfoAttr +// TryOp //===----------------------------------------------------------------------===// -LogicalResult cir::TypeInfoAttr::verify( - ::llvm::function_ref<::mlir::InFlightDiagnostic()> emitError, - ::mlir::Type type, ::mlir::ArrayAttr typeInfoData) { +void cir::TryOp::getSuccessorRegions( + mlir::RegionBranchPoint point, + llvm::SmallVectorImpl<mlir::RegionSuccessor> ®ions) { + // The `try` and the `catchers` region branch back to the parent operation. + if (!point.isParent()) { + regions.push_back(mlir::RegionSuccessor()); + return; + } - if (cir::ConstRecordAttr::verify(emitError, type, typeInfoData).failed()) - return failure(); + regions.push_back(mlir::RegionSuccessor(&getTryRegion())); - return success(); + // TODO(CIR): If we know a target function never throws a specific type, we + // can remove the catch handler. + for (mlir::Region &handlerRegion : this->getHandlerRegions()) + regions.push_back(mlir::RegionSuccessor(&handlerRegion)); +} + +static void +printTryHandlerRegions(mlir::OpAsmPrinter &printer, cir::TryOp op, + mlir::MutableArrayRef<mlir::Region> handlerRegions, + mlir::ArrayAttr handlerTypes) { + if (!handlerTypes) + return; + + for (const auto [typeIdx, typeAttr] : llvm::enumerate(handlerTypes)) { + if (typeIdx) + printer << " "; + + if (mlir::isa<cir::CatchAllAttr>(typeAttr)) { + printer << "catch all "; + } else if (mlir::isa<cir::UnwindAttr>(typeAttr)) { + printer << "unwind "; + } else { + printer << "catch [type "; + printer.printAttribute(typeAttr); + printer << "] "; + } + + printer.printRegion(handlerRegions[typeIdx], + /*printEntryBLockArgs=*/false, + /*printBlockTerminators=*/true); + } +} + +static mlir::ParseResult parseTryHandlerRegions( + mlir::OpAsmParser &parser, + llvm::SmallVectorImpl<std::unique_ptr<mlir::Region>> &handlerRegions, + mlir::ArrayAttr &handlerTypes) { + + auto parseCheckedCatcherRegion = [&]() -> mlir::ParseResult { + handlerRegions.emplace_back(new mlir::Region); + + mlir::Region &currRegion = *handlerRegions.back(); + mlir::SMLoc regionLoc = parser.getCurrentLocation(); + if (parser.parseRegion(currRegion)) { + handlerRegions.clear(); + return failure(); + } + + if (!currRegion.empty() && !(currRegion.back().mightHaveTerminator() && + currRegion.back().getTerminator())) + return parser.emitError( + regionLoc, "blocks are expected to be explicitly terminated"); + + return success(); + }; + + bool hasCatchAll = false; + llvm::SmallVector<mlir::Attribute, 4> catcherAttrs; + while (parser.parseOptionalKeyword("catch").succeeded()) { + bool hasLSquare = parser.parseOptionalLSquare().succeeded(); + + llvm::StringRef attrStr; + if (parser.parseOptionalKeyword(&attrStr, {"all", "type"}).failed()) + return parser.emitError(parser.getCurrentLocation(), + "expected 'all' or 'type' keyword"); + + bool isCatchAll = attrStr == "all"; + if (isCatchAll) { + if (hasCatchAll) + return parser.emitError(parser.getCurrentLocation(), + "can't have more than one catch all"); + hasCatchAll = true; + } + + mlir::Attribute exceptionRTTIAttr; + if (!isCatchAll && parser.parseAttribute(exceptionRTTIAttr).failed()) + return parser.emitError(parser.getCurrentLocation(), + "expected valid RTTI info attribute"); + + catcherAttrs.push_back(isCatchAll + ? cir::CatchAllAttr::get(parser.getContext()) + : exceptionRTTIAttr); + + if (hasLSquare && isCatchAll) + return parser.emitError(parser.getCurrentLocation(), + "catch all dosen't need RTTI info attribute"); + + if (hasLSquare && parser.parseRSquare().failed()) + return parser.emitError(parser.getCurrentLocation(), + "expected `]` after RTTI info attribute"); + + if (parseCheckedCatcherRegion().failed()) + return mlir::failure(); + } + + if (parser.parseOptionalKeyword("unwind").succeeded()) { + if (hasCatchAll) + return parser.emitError(parser.getCurrentLocation(), + "unwind can't be used with catch all"); + + catcherAttrs.push_back(cir::UnwindAttr::get(parser.getContext())); + if (parseCheckedCatcherRegion().failed()) + return mlir::failure(); + } + + handlerTypes = parser.getBuilder().getArrayAttr(catcherAttrs); + return mlir::success(); } //===----------------------------------------------------------------------===// diff --git a/clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp b/clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp index dbff0b9..d99c362 100644 --- a/clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp +++ b/clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp @@ -105,6 +105,8 @@ struct LoweringPreparePass : public LoweringPrepareBase<LoweringPreparePass> { /// List of ctors and their priorities to be called before main() llvm::SmallVector<std::pair<std::string, uint32_t>, 4> globalCtorList; + /// List of dtors and their priorities to be called when unloading module. + llvm::SmallVector<std::pair<std::string, uint32_t>, 4> globalDtorList; void setASTContext(clang::ASTContext *c) { astCtx = c; @@ -823,10 +825,13 @@ void LoweringPreparePass::buildGlobalCtorDtorList() { mlir::ArrayAttr::get(&getContext(), globalCtors)); } - // We will eventual need to populate a global_dtor list, but that's not - // needed for globals with destructors. It will only be needed for functions - // that are marked as global destructors with an attribute. - assert(!cir::MissingFeatures::opGlobalDtorList()); + if (!globalDtorList.empty()) { + llvm::SmallVector<mlir::Attribute> globalDtors = + prepareCtorDtorAttrList<cir::GlobalDtorAttr>(&getContext(), + globalDtorList); + mlirModule->setAttr(cir::CIRDialect::getGlobalDtorsAttrName(), + mlir::ArrayAttr::get(&getContext(), globalDtors)); + } } void LoweringPreparePass::buildCXXGlobalInitFunc() { @@ -975,22 +980,28 @@ void LoweringPreparePass::lowerArrayCtor(cir::ArrayCtor op) { } void LoweringPreparePass::runOnOp(mlir::Operation *op) { - if (auto arrayCtor = dyn_cast<ArrayCtor>(op)) + if (auto arrayCtor = dyn_cast<cir::ArrayCtor>(op)) { lowerArrayCtor(arrayCtor); - else if (auto arrayDtor = dyn_cast<cir::ArrayDtor>(op)) + } else if (auto arrayDtor = dyn_cast<cir::ArrayDtor>(op)) { lowerArrayDtor(arrayDtor); - else if (auto cast = mlir::dyn_cast<cir::CastOp>(op)) + } else if (auto cast = mlir::dyn_cast<cir::CastOp>(op)) { lowerCastOp(cast); - else if (auto complexDiv = mlir::dyn_cast<cir::ComplexDivOp>(op)) + } else if (auto complexDiv = mlir::dyn_cast<cir::ComplexDivOp>(op)) { lowerComplexDivOp(complexDiv); - else if (auto complexMul = mlir::dyn_cast<cir::ComplexMulOp>(op)) + } else if (auto complexMul = mlir::dyn_cast<cir::ComplexMulOp>(op)) { lowerComplexMulOp(complexMul); - else if (auto glob = mlir::dyn_cast<cir::GlobalOp>(op)) + } else if (auto glob = mlir::dyn_cast<cir::GlobalOp>(op)) { lowerGlobalOp(glob); - else if (auto dynamicCast = mlir::dyn_cast<cir::DynamicCastOp>(op)) + } else if (auto dynamicCast = mlir::dyn_cast<cir::DynamicCastOp>(op)) { lowerDynamicCastOp(dynamicCast); - else if (auto unary = mlir::dyn_cast<cir::UnaryOp>(op)) + } else if (auto unary = mlir::dyn_cast<cir::UnaryOp>(op)) { lowerUnaryOp(unary); + } else if (auto fnOp = dyn_cast<cir::FuncOp>(op)) { + if (auto globalCtor = fnOp.getGlobalCtorPriority()) + globalCtorList.emplace_back(fnOp.getName(), globalCtor.value()); + else if (auto globalDtor = fnOp.getGlobalDtorPriority()) + globalDtorList.emplace_back(fnOp.getName(), globalDtor.value()); + } } void LoweringPreparePass::runOnOperation() { @@ -1003,7 +1014,7 @@ void LoweringPreparePass::runOnOperation() { op->walk([&](mlir::Operation *op) { if (mlir::isa<cir::ArrayCtor, cir::ArrayDtor, cir::CastOp, cir::ComplexMulOp, cir::ComplexDivOp, cir::DynamicCastOp, - cir::GlobalOp, cir::UnaryOp>(op)) + cir::FuncOp, cir::GlobalOp, cir::UnaryOp>(op)) opsToTransform.push_back(op); }); diff --git a/clang/lib/CIR/Dialect/Transforms/LoweringPrepareItaniumCXXABI.cpp b/clang/lib/CIR/Dialect/Transforms/LoweringPrepareItaniumCXXABI.cpp index 7d3c711..11ce2a8 100644 --- a/clang/lib/CIR/Dialect/Transforms/LoweringPrepareItaniumCXXABI.cpp +++ b/clang/lib/CIR/Dialect/Transforms/LoweringPrepareItaniumCXXABI.cpp @@ -92,7 +92,53 @@ static mlir::Value buildDynamicCastToVoidAfterNullCheck(cir::CIRBaseBuilderTy &builder, clang::ASTContext &astCtx, cir::DynamicCastOp op) { - llvm_unreachable("dynamic cast to void is NYI"); + mlir::Location loc = op.getLoc(); + bool vtableUsesRelativeLayout = op.getRelativeLayout(); + + // TODO(cir): consider address space in this function. + assert(!cir::MissingFeatures::addressSpace()); + + mlir::Type vtableElemTy; + uint64_t vtableElemAlign; + if (vtableUsesRelativeLayout) { + vtableElemTy = builder.getSIntNTy(32); + vtableElemAlign = 4; + } else { + const auto &targetInfo = astCtx.getTargetInfo(); + auto ptrdiffTy = targetInfo.getPtrDiffType(clang::LangAS::Default); + bool ptrdiffTyIsSigned = clang::TargetInfo::isTypeSigned(ptrdiffTy); + uint64_t ptrdiffTyWidth = targetInfo.getTypeWidth(ptrdiffTy); + + vtableElemTy = cir::IntType::get(builder.getContext(), ptrdiffTyWidth, + ptrdiffTyIsSigned); + vtableElemAlign = + llvm::divideCeil(targetInfo.getPointerAlign(clang::LangAS::Default), 8); + } + + // Access vtable to get the offset from the given object to its containing + // complete object. + // TODO: Add a specialized operation to get the object offset? + auto vptrTy = cir::VPtrType::get(builder.getContext()); + cir::PointerType vptrPtrTy = builder.getPointerTo(vptrTy); + auto vptrPtr = + cir::VTableGetVPtrOp::create(builder, loc, vptrPtrTy, op.getSrc()); + mlir::Value vptr = builder.createLoad(loc, vptrPtr); + mlir::Value elementPtr = + builder.createBitcast(vptr, builder.getPointerTo(vtableElemTy)); + mlir::Value minusTwo = builder.getSignedInt(loc, -2, 64); + auto offsetToTopSlotPtr = cir::PtrStrideOp::create( + builder, loc, builder.getPointerTo(vtableElemTy), elementPtr, minusTwo); + mlir::Value offsetToTop = + builder.createAlignedLoad(loc, offsetToTopSlotPtr, vtableElemAlign); + + // Add the offset to the given pointer to get the cast result. + // Cast the input pointer to a uint8_t* to allow pointer arithmetic. + cir::PointerType u8PtrTy = builder.getPointerTo(builder.getUIntNTy(8)); + mlir::Value srcBytePtr = builder.createBitcast(op.getSrc(), u8PtrTy); + auto dstBytePtr = + cir::PtrStrideOp::create(builder, loc, u8PtrTy, srcBytePtr, offsetToTop); + // Cast the result to a void*. + return builder.createBitcast(dstBytePtr, builder.getVoidPtrTy()); } mlir::Value |