aboutsummaryrefslogtreecommitdiff
path: root/clang/lib/CIR/Dialect
diff options
context:
space:
mode:
Diffstat (limited to 'clang/lib/CIR/Dialect')
-rw-r--r--clang/lib/CIR/Dialect/IR/CIRDialect.cpp220
-rw-r--r--clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp37
-rw-r--r--clang/lib/CIR/Dialect/Transforms/LoweringPrepareItaniumCXXABI.cpp48
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> &regions) {
+ // 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