aboutsummaryrefslogtreecommitdiff
path: root/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp')
-rw-r--r--clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp140
1 files changed, 131 insertions, 9 deletions
diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
index 3a3c631..a80a295 100644
--- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
+++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
@@ -2413,6 +2413,73 @@ static void prepareTypeConverter(mlir::LLVMTypeConverter &converter,
});
}
+static void buildCtorDtorList(
+ mlir::ModuleOp module, StringRef globalXtorName, StringRef llvmXtorName,
+ llvm::function_ref<std::pair<StringRef, int>(mlir::Attribute)> createXtor) {
+ llvm::SmallVector<std::pair<StringRef, int>> globalXtors;
+ for (const mlir::NamedAttribute namedAttr : module->getAttrs()) {
+ if (namedAttr.getName() == globalXtorName) {
+ for (auto attr : mlir::cast<mlir::ArrayAttr>(namedAttr.getValue()))
+ globalXtors.emplace_back(createXtor(attr));
+ break;
+ }
+ }
+
+ if (globalXtors.empty())
+ return;
+
+ mlir::OpBuilder builder(module.getContext());
+ builder.setInsertionPointToEnd(&module.getBodyRegion().back());
+
+ // Create a global array llvm.global_ctors with element type of
+ // struct { i32, ptr, ptr }
+ auto ctorPFTy = mlir::LLVM::LLVMPointerType::get(builder.getContext());
+ llvm::SmallVector<mlir::Type> ctorStructFields;
+ ctorStructFields.push_back(builder.getI32Type());
+ ctorStructFields.push_back(ctorPFTy);
+ ctorStructFields.push_back(ctorPFTy);
+
+ auto ctorStructTy = mlir::LLVM::LLVMStructType::getLiteral(
+ builder.getContext(), ctorStructFields);
+ auto ctorStructArrayTy =
+ mlir::LLVM::LLVMArrayType::get(ctorStructTy, globalXtors.size());
+
+ mlir::Location loc = module.getLoc();
+ auto newGlobalOp = mlir::LLVM::GlobalOp::create(
+ builder, loc, ctorStructArrayTy, /*constant=*/false,
+ mlir::LLVM::Linkage::Appending, llvmXtorName, mlir::Attribute());
+
+ builder.createBlock(&newGlobalOp.getRegion());
+ builder.setInsertionPointToEnd(newGlobalOp.getInitializerBlock());
+
+ mlir::Value result =
+ mlir::LLVM::UndefOp::create(builder, loc, ctorStructArrayTy);
+
+ for (auto [index, fn] : llvm::enumerate(globalXtors)) {
+ mlir::Value structInit =
+ mlir::LLVM::UndefOp::create(builder, loc, ctorStructTy);
+ mlir::Value initPriority = mlir::LLVM::ConstantOp::create(
+ builder, loc, ctorStructFields[0], fn.second);
+ mlir::Value initFuncAddr = mlir::LLVM::AddressOfOp::create(
+ builder, loc, ctorStructFields[1], fn.first);
+ mlir::Value initAssociate =
+ mlir::LLVM::ZeroOp::create(builder, loc, ctorStructFields[2]);
+ // Literal zero makes the InsertValueOp::create ambiguous.
+ llvm::SmallVector<int64_t> zero{0};
+ structInit = mlir::LLVM::InsertValueOp::create(builder, loc, structInit,
+ initPriority, zero);
+ structInit = mlir::LLVM::InsertValueOp::create(builder, loc, structInit,
+ initFuncAddr, 1);
+ // TODO: handle associated data for initializers.
+ structInit = mlir::LLVM::InsertValueOp::create(builder, loc, structInit,
+ initAssociate, 2);
+ result = mlir::LLVM::InsertValueOp::create(builder, loc, result, structInit,
+ index);
+ }
+
+ builder.create<mlir::LLVM::ReturnOp>(loc, result);
+}
+
// The applyPartialConversion function traverses blocks in the dominance order,
// so it does not lower and operations that are not reachachable from the
// operations passed in as arguments. Since we do need to lower such code in
@@ -2519,6 +2586,14 @@ void ConvertCIRToLLVMPass::runOnOperation() {
if (failed(applyPartialConversion(ops, target, std::move(patterns))))
signalPassFailure();
+
+ // Emit the llvm.global_ctors array.
+ buildCtorDtorList(module, cir::CIRDialect::getGlobalCtorsAttrName(),
+ "llvm.global_ctors", [](mlir::Attribute attr) {
+ auto ctorAttr = mlir::cast<cir::GlobalCtorAttr>(attr);
+ return std::make_pair(ctorAttr.getName(),
+ ctorAttr.getPriority());
+ });
}
mlir::LogicalResult CIRToLLVMBrOpLowering::matchAndRewrite(
@@ -2581,22 +2656,69 @@ void createLLVMFuncOpIfNotExist(mlir::ConversionPatternRewriter &rewriter,
mlir::LogicalResult CIRToLLVMThrowOpLowering::matchAndRewrite(
cir::ThrowOp op, OpAdaptor adaptor,
mlir::ConversionPatternRewriter &rewriter) const {
- if (op.rethrows()) {
- auto voidTy = mlir::LLVM::LLVMVoidType::get(getContext());
- auto funcTy =
- mlir::LLVM::LLVMFunctionType::get(getContext(), voidTy, {}, false);
+ mlir::Location loc = op.getLoc();
+ auto voidTy = mlir::LLVM::LLVMVoidType::get(getContext());
- auto mlirModule = op->getParentOfType<mlir::ModuleOp>();
- rewriter.setInsertionPointToStart(&mlirModule.getBodyRegion().front());
+ if (op.rethrows()) {
+ auto funcTy = mlir::LLVM::LLVMFunctionType::get(voidTy, {});
+ // Get or create `declare void @__cxa_rethrow()`
const llvm::StringRef functionName = "__cxa_rethrow";
createLLVMFuncOpIfNotExist(rewriter, op, functionName, funcTy);
- rewriter.setInsertionPointAfter(op.getOperation());
- rewriter.replaceOpWithNewOp<mlir::LLVM::CallOp>(
- op, mlir::TypeRange{}, functionName, mlir::ValueRange{});
+ auto cxaRethrow = mlir::LLVM::CallOp::create(
+ rewriter, loc, mlir::TypeRange{}, functionName);
+
+ rewriter.replaceOp(op, cxaRethrow);
+ return mlir::success();
}
+ auto llvmPtrTy = mlir::LLVM::LLVMPointerType::get(rewriter.getContext());
+ auto fnTy = mlir::LLVM::LLVMFunctionType::get(
+ voidTy, {llvmPtrTy, llvmPtrTy, llvmPtrTy});
+
+ // Get or create `declare void @__cxa_throw(ptr, ptr, ptr)`
+ const llvm::StringRef fnName = "__cxa_throw";
+ createLLVMFuncOpIfNotExist(rewriter, op, fnName, fnTy);
+
+ mlir::Value typeInfo = mlir::LLVM::AddressOfOp::create(
+ rewriter, loc, mlir::LLVM::LLVMPointerType::get(rewriter.getContext()),
+ adaptor.getTypeInfoAttr());
+
+ mlir::Value dtor;
+ if (op.getDtor()) {
+ dtor = mlir::LLVM::AddressOfOp::create(rewriter, loc, llvmPtrTy,
+ adaptor.getDtorAttr());
+ } else {
+ dtor = mlir::LLVM::ZeroOp::create(rewriter, loc, llvmPtrTy);
+ }
+
+ auto cxaThrowCall = mlir::LLVM::CallOp::create(
+ rewriter, loc, mlir::TypeRange{}, fnName,
+ mlir::ValueRange{adaptor.getExceptionPtr(), typeInfo, dtor});
+
+ rewriter.replaceOp(op, cxaThrowCall);
+ return mlir::success();
+}
+
+mlir::LogicalResult CIRToLLVMAllocExceptionOpLowering::matchAndRewrite(
+ cir::AllocExceptionOp op, OpAdaptor adaptor,
+ mlir::ConversionPatternRewriter &rewriter) const {
+ // Get or create `declare ptr @__cxa_allocate_exception(i64)`
+ StringRef fnName = "__cxa_allocate_exception";
+ auto llvmPtrTy = mlir::LLVM::LLVMPointerType::get(rewriter.getContext());
+ auto int64Ty = mlir::IntegerType::get(rewriter.getContext(), 64);
+ auto fnTy = mlir::LLVM::LLVMFunctionType::get(llvmPtrTy, {int64Ty});
+
+ createLLVMFuncOpIfNotExist(rewriter, op, fnName, fnTy);
+ auto exceptionSize = mlir::LLVM::ConstantOp::create(rewriter, op.getLoc(),
+ adaptor.getSizeAttr());
+
+ auto allocaExceptionCall = mlir::LLVM::CallOp::create(
+ rewriter, op.getLoc(), mlir::TypeRange{llvmPtrTy}, fnName,
+ mlir::ValueRange{exceptionSize});
+
+ rewriter.replaceOp(op, allocaExceptionCall);
return mlir::success();
}