https://github.com/AmrDeveloper updated https://github.com/llvm/llvm-project/pull/154994
>From 373d3c49c631955c9e4b50f7e9b9666fdb2faef4 Mon Sep 17 00:00:00 2001 From: AmrDeveloper <am...@programmer.net> Date: Fri, 22 Aug 2025 15:34:47 +0200 Subject: [PATCH 1/3] [CIR] Upstream Re-Throw with no return --- .../CIR/Dialect/Builder/CIRBaseBuilder.h | 21 +++++++- clang/include/clang/CIR/Dialect/IR/CIROps.td | 54 +++++++++++++++++++ clang/lib/CIR/CodeGen/CIRGenCXXABI.h | 4 +- clang/lib/CIR/CodeGen/CIRGenException.cpp | 41 ++++++++++++++ clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp | 5 ++ clang/lib/CIR/CodeGen/CIRGenFunction.h | 2 + clang/lib/CIR/CodeGen/CIRGenItaniumCXXABI.cpp | 50 ++++++++++++++++- clang/lib/CIR/CodeGen/CMakeLists.txt | 1 + clang/lib/CIR/Dialect/IR/CIRDialect.cpp | 18 +++++++ .../Dialect/Transforms/LoweringPrepare.cpp | 24 ++++++++- clang/test/CIR/CodeGen/exceptions.cpp | 19 +++++++ 11 files changed, 235 insertions(+), 4 deletions(-) create mode 100644 clang/lib/CIR/CodeGen/CIRGenException.cpp create mode 100644 clang/test/CIR/CodeGen/exceptions.cpp diff --git a/clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h b/clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h index d29e5687d2544..aba4615b2a7f4 100644 --- a/clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h +++ b/clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h @@ -19,7 +19,6 @@ #include "mlir/IR/Builders.h" #include "mlir/IR/BuiltinAttributes.h" -#include "mlir/IR/BuiltinTypes.h" #include "mlir/IR/Location.h" #include "mlir/IR/Types.h" @@ -313,6 +312,26 @@ class CIRBaseBuilderTy : public mlir::OpBuilder { resOperands, attrs); } + cir::CallOp + createTryCallOp(mlir::Location loc, + mlir::SymbolRefAttr callee = mlir::SymbolRefAttr(), + mlir::Type returnType = cir::VoidType(), + mlir::ValueRange operands = mlir::ValueRange(), + cir::SideEffect sideEffect = cir::SideEffect::All) { + assert(!cir::MissingFeatures::opCallCallConv()); + return createCallOp(loc, callee, returnType, operands); + } + + cir::CallOp + createTryCallOp(mlir::Location loc, cir::FuncOp callee, + mlir::ValueRange operands, + cir::SideEffect sideEffect = cir::SideEffect::All) { + assert(!cir::MissingFeatures::opCallCallConv()); + return createTryCallOp(loc, mlir::SymbolRefAttr::get(callee), + callee.getFunctionType().getReturnType(), operands, + sideEffect); + } + //===--------------------------------------------------------------------===// // Cast/Conversion Operators //===--------------------------------------------------------------------===// diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td b/clang/include/clang/CIR/Dialect/IR/CIROps.td index 8ab602000cc29..1a38e045dcf77 100644 --- a/clang/include/clang/CIR/Dialect/IR/CIROps.td +++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td @@ -3800,4 +3800,58 @@ def CIR_VAArgOp : CIR_Op<"va_arg"> { }]; } +//===----------------------------------------------------------------------===// +// ThrowOp +//===----------------------------------------------------------------------===// + +def CIR_ThrowOp : CIR_Op<"throw"> { + let summary = "(Re)Throws an exception"; + let description = [{ + Very similar to __cxa_throw: + + ``` + void __cxa_throw(void *thrown_exception, std::type_info *tinfo, + void (*dest) (void *)); + ``` + + The absense of arguments for `cir.throw` means it rethrows. + + For the no-rethrow version, it must have at least two operands, the RTTI + information, a pointer to the exception object (likely allocated via + `cir.cxa.allocate_exception`) and finally an optional dtor, which might + run as part of this operation. + + Example: + ```mlir + // throw; + cir.throw + + // if (b == 0) + // throw "Division by zero condition!"; + cir.if %cond { + %exception_addr = cir.alloc_exception 8 -> !cir.ptr<!void> + ... + cir.store %string_addr, %exception_addr : // Store string addr for "Division by zero condition!" + cir.throw %exception_addr : !cir.ptr<!cir.ptr<!u8i>>, @"typeinfo for char const*" + ``` + }]; + + let arguments = (ins Optional<CIR_PointerType>:$exception_ptr, + OptionalAttr<FlatSymbolRefAttr>:$type_info, + OptionalAttr<FlatSymbolRefAttr>:$dtor); + + let assemblyFormat = [{ + ($exception_ptr^ `:` type($exception_ptr))? + (`,` $type_info^)? + (`,` $dtor^)? + attr-dict + }]; + + let extraClassDeclaration = [{ + bool rethrows() { return getNumOperands() == 0; } + }]; + + let hasVerifier = 1; +} + #endif // CLANG_CIR_DIALECT_IR_CIROPS_TD diff --git a/clang/lib/CIR/CodeGen/CIRGenCXXABI.h b/clang/lib/CIR/CodeGen/CIRGenCXXABI.h index b5f2e1a067274..4ec6969aee7bf 100644 --- a/clang/lib/CIR/CodeGen/CIRGenCXXABI.h +++ b/clang/lib/CIR/CodeGen/CIRGenCXXABI.h @@ -47,9 +47,11 @@ class CIRGenCXXABI { } /// Emit the ABI-specific prolog for the function - virtual void emitInstanceFunctionProlog(SourceLocation Loc, + virtual void emitInstanceFunctionProlog(SourceLocation loc, CIRGenFunction &cgf) = 0; + virtual void emitRethrow(CIRGenFunction &cgf, bool isNoReturn) = 0; + /// Get the type of the implicit "this" parameter used by a method. May return /// zero if no specific type is applicable, e.g. if the ABI expects the "this" /// parameter to point to some artificial offset in a complete object due to diff --git a/clang/lib/CIR/CodeGen/CIRGenException.cpp b/clang/lib/CIR/CodeGen/CIRGenException.cpp new file mode 100644 index 0000000000000..7fcb39a2b74c4 --- /dev/null +++ b/clang/lib/CIR/CodeGen/CIRGenException.cpp @@ -0,0 +1,41 @@ +//===--- CIRGenException.cpp - Emit CIR Code for C++ exceptions -*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This contains code dealing with C++ exception related code generation. +// +//===----------------------------------------------------------------------===// + +#include "CIRGenCXXABI.h" +#include "CIRGenFunction.h" + +#include "clang/AST/StmtVisitor.h" + +using namespace clang; +using namespace clang::CIRGen; + +void CIRGenFunction::emitCXXThrowExpr(const CXXThrowExpr *e) { + const llvm::Triple &triple = getTarget().getTriple(); + if (cgm.getLangOpts().OpenMPIsTargetDevice && + (triple.isNVPTX() || triple.isAMDGCN())) { + cgm.errorNYI("emitCXXThrowExpr OpenMP with NVPTX or AMDGCN Triples"); + return; + } + + if (const Expr *subExpr = e->getSubExpr()) { + QualType throwType = subExpr->getType(); + if (throwType->isObjCObjectPointerType()) { + cgm.errorNYI("emitCXXThrowExpr ObjCObjectPointerType"); + return; + } else { + cgm.errorNYI("emitCXXThrowExpr with subExpr"); + return; + } + } else { + cgm.getCXXABI().emitRethrow(*this, /*isNoReturn=*/true); + } +} diff --git a/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp b/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp index 46934e7155adf..f0bebfeb19430 100644 --- a/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp @@ -657,6 +657,11 @@ class ScalarExprEmitter : public StmtVisitor<ScalarExprEmitter, mlir::Value> { return cgf.emitCXXNewExpr(e); } + mlir::Value VisitCXXThrowExpr(const CXXThrowExpr *e) { + cgf.emitCXXThrowExpr(e); + return nullptr; + } + /// Emit a conversion from the specified type to the specified destination /// type, both of which are CIR scalar types. /// TODO: do we need ScalarConversionOpts here? Should be done in another diff --git a/clang/lib/CIR/CodeGen/CIRGenFunction.h b/clang/lib/CIR/CodeGen/CIRGenFunction.h index 064b3c15a310b..6829ad63895eb 100644 --- a/clang/lib/CIR/CodeGen/CIRGenFunction.h +++ b/clang/lib/CIR/CodeGen/CIRGenFunction.h @@ -1140,6 +1140,8 @@ class CIRGenFunction : public CIRGenTypeCache { RValue emitCXXPseudoDestructorExpr(const CXXPseudoDestructorExpr *expr); + void emitCXXThrowExpr(const CXXThrowExpr *e); + void emitCtorPrologue(const clang::CXXConstructorDecl *ctor, clang::CXXCtorType ctorType, FunctionArgList &args); diff --git a/clang/lib/CIR/CodeGen/CIRGenItaniumCXXABI.cpp b/clang/lib/CIR/CodeGen/CIRGenItaniumCXXABI.cpp index aaf7dc767d888..1d98b801e90f8 100644 --- a/clang/lib/CIR/CodeGen/CIRGenItaniumCXXABI.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenItaniumCXXABI.cpp @@ -56,6 +56,8 @@ class CIRGenItaniumCXXABI : public CIRGenCXXABI { bool delegating, Address thisAddr, QualType thisTy) override; + void emitRethrow(CIRGenFunction &cgf, bool isNoReturn) override; + bool useThunkForDtorVariant(const CXXDestructorDecl *dtor, CXXDtorType dt) const override { // Itanium does not emit any destructor variant as an inline thunk. @@ -125,7 +127,7 @@ void CIRGenItaniumCXXABI::emitInstanceFunctionProlog(SourceLocation loc, // Find out how to cirgen the complete destructor and constructor namespace { enum class StructorCIRGen { Emit, RAUW, Alias, COMDAT }; -} +} // namespace static StructorCIRGen getCIRGenToUse(CIRGenModule &cgm, const CXXMethodDecl *md) { @@ -352,6 +354,52 @@ void CIRGenItaniumCXXABI::emitDestructorCall( vttTy, nullptr); } +// The idea here is creating a separate block for the throw with an +// `UnreachableOp` as the terminator. So, we branch from the current block +// to the throw block and create a block for the remaining operations. +static void insertThrowAndSplit(mlir::OpBuilder &builder, mlir::Location loc, + mlir::Value exceptionPtr = {}, + mlir::FlatSymbolRefAttr typeInfo = {}, + mlir::FlatSymbolRefAttr dtor = {}) { + mlir::Block *currentBlock = builder.getInsertionBlock(); + mlir::Region *region = currentBlock->getParent(); + + if (currentBlock->empty()) { + cir::ThrowOp::create(builder, loc, exceptionPtr, typeInfo, dtor); + cir::UnreachableOp::create(builder, loc); + } else { + mlir::Block *throwBlock = builder.createBlock(region); + + cir::ThrowOp::create(builder, loc, exceptionPtr, typeInfo, dtor); + cir::UnreachableOp::create(builder, loc); + + builder.setInsertionPointToEnd(currentBlock); + cir::BrOp::create(builder, loc, throwBlock); + } + + (void)builder.createBlock(region); + + // This will be erased during codegen, it acts as a placeholder for the + // operations to be inserted (if any) + cir::ScopeOp::create(builder, loc, /*scopeBuilder=*/ + [&](mlir::OpBuilder &b, mlir::Location loc) { + b.create<cir::YieldOp>(loc); + }); +} + +void CIRGenItaniumCXXABI::emitRethrow(CIRGenFunction &cgf, bool isNoReturn) { + // void __cxa_rethrow(); + + if (isNoReturn) { + CIRGenBuilderTy &builder = cgf.getBuilder(); + assert(cgf.currSrcLoc && "expected source location"); + mlir::Location loc = *cgf.currSrcLoc; + insertThrowAndSplit(builder, loc); + } else { + cgm.errorNYI("emitRethrow with isNoReturn false"); + } +} + CIRGenCXXABI *clang::CIRGen::CreateCIRGenItaniumCXXABI(CIRGenModule &cgm) { switch (cgm.getASTContext().getCXXABIKind()) { case TargetCXXABI::GenericItanium: diff --git a/clang/lib/CIR/CodeGen/CMakeLists.txt b/clang/lib/CIR/CodeGen/CMakeLists.txt index 7366446a33c6e..6d7072ad18696 100644 --- a/clang/lib/CIR/CodeGen/CMakeLists.txt +++ b/clang/lib/CIR/CodeGen/CMakeLists.txt @@ -20,6 +20,7 @@ add_clang_library(clangCIR CIRGenBuiltin.cpp CIRGenDecl.cpp CIRGenDeclOpenACC.cpp + CIRGenException.cpp CIRGenExpr.cpp CIRGenExprAggregate.cpp CIRGenExprComplex.cpp diff --git a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp index 8c53939e89d01..3f5bf799d2c9f 100644 --- a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp +++ b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp @@ -2650,6 +2650,24 @@ ParseResult cir::InlineAsmOp::parse(OpAsmParser &parser, return mlir::success(); } +//===----------------------------------------------------------------------===// +// ThrowOp +//===----------------------------------------------------------------------===// + +mlir::LogicalResult cir::ThrowOp::verify() { + // For the no-rethrow version, it must have at least the exception pointer. + if (rethrows()) + return success(); + + if (getNumOperands() == 1) { + if (getTypeInfo()) + return success(); + return emitOpError() << "'type_info' symbol attribute missing"; + } + + return failure(); +} + //===----------------------------------------------------------------------===// // TableGen'd op method definitions //===----------------------------------------------------------------------===// diff --git a/clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp b/clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp index c15637d297cd1..cccfe9b444a31 100644 --- a/clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp +++ b/clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp @@ -32,6 +32,7 @@ struct LoweringPreparePass : public LoweringPrepareBase<LoweringPreparePass> { void lowerUnaryOp(cir::UnaryOp op); void lowerArrayDtor(cir::ArrayDtor op); void lowerArrayCtor(cir::ArrayCtor op); + void lowerThrowOp(ThrowOp op); cir::FuncOp buildRuntimeFunction( mlir::OpBuilder &builder, llvm::StringRef name, mlir::Location loc, @@ -680,6 +681,24 @@ void LoweringPreparePass::lowerArrayCtor(cir::ArrayCtor op) { true); } +void LoweringPreparePass::lowerThrowOp(ThrowOp op) { + if (op.rethrows()) { + CIRBaseBuilderTy builder(getContext()); + auto voidTy = cir::VoidType::get(builder.getContext()); + auto fnType = cir::FuncType::get({}, voidTy); + + builder.setInsertionPointToStart(&mlirModule.getBodyRegion().front()); + FuncOp f = + buildRuntimeFunction(builder, "__cxa_rethrow", op.getLoc(), fnType); + + builder.setInsertionPointAfter(op.getOperation()); + cir::CallOp call = builder.createTryCallOp(op.getLoc(), f, {}); + + op->replaceAllUsesWith(call); + op->erase(); + } +} + void LoweringPreparePass::runOnOp(mlir::Operation *op) { if (auto arrayCtor = dyn_cast<ArrayCtor>(op)) lowerArrayCtor(arrayCtor); @@ -693,6 +712,8 @@ void LoweringPreparePass::runOnOp(mlir::Operation *op) { lowerComplexMulOp(complexMul); else if (auto unary = mlir::dyn_cast<cir::UnaryOp>(op)) lowerUnaryOp(unary); + else if (auto throwOp = mlir::dyn_cast<cir::ThrowOp>(op)) + lowerThrowOp(throwOp); } void LoweringPreparePass::runOnOperation() { @@ -704,7 +725,8 @@ void LoweringPreparePass::runOnOperation() { op->walk([&](mlir::Operation *op) { if (mlir::isa<cir::ArrayCtor, cir::ArrayDtor, cir::CastOp, - cir::ComplexMulOp, cir::ComplexDivOp, cir::UnaryOp>(op)) + cir::ComplexMulOp, cir::ComplexDivOp, cir::UnaryOp, + cir::ThrowOp>(op)) opsToTransform.push_back(op); }); diff --git a/clang/test/CIR/CodeGen/exceptions.cpp b/clang/test/CIR/CodeGen/exceptions.cpp new file mode 100644 index 0000000000000..a1a87bcb2f393 --- /dev/null +++ b/clang/test/CIR/CodeGen/exceptions.cpp @@ -0,0 +1,19 @@ +// RUN: %clang_cc1 -std=c++20 -triple x86_64-unknown-linux-gnu -fcxx-exceptions -fexceptions -fclangir -emit-cir %s -o %t.cir +// RUN: FileCheck --input-file=%t.cir %s -check-prefix=CIR +// RUN: %clang_cc1 -std=c++20 -triple x86_64-unknown-linux-gnu -fcxx-exceptions -fexceptions -fclangir -emit-llvm %s -o %t-cir.ll +// RUN: FileCheck --input-file=%t-cir.ll %s -check-prefix=LLVM +// RUN: %clang_cc1 -std=c++20 -triple x86_64-unknown-linux-gnu -fcxx-exceptions -fexceptions -emit-llvm %s -o %t.ll +// RUN: FileCheck --input-file=%t.ll %s -check-prefix=OGCG + +void foo() { + throw; +} + +// CIR: cir.call @__cxa_rethrow() : () -> () +// CIR: cir.unreachable + +// LLVM: call void @__cxa_rethrow() +// LLVM: unreachable + +// OGCG: call void @__cxa_rethrow() +// OGCG: unreachable >From 7a8f919fdcb7c706ad55738a33f4fbc3b28ec277 Mon Sep 17 00:00:00 2001 From: AmrDeveloper <am...@programmer.net> Date: Fri, 22 Aug 2025 20:46:26 +0200 Subject: [PATCH 2/3] Rename test file to throws to be alligned with incubator for now --- clang/test/CIR/CodeGen/{exceptions.cpp => throws.cpp} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename clang/test/CIR/CodeGen/{exceptions.cpp => throws.cpp} (100%) diff --git a/clang/test/CIR/CodeGen/exceptions.cpp b/clang/test/CIR/CodeGen/throws.cpp similarity index 100% rename from clang/test/CIR/CodeGen/exceptions.cpp rename to clang/test/CIR/CodeGen/throws.cpp >From 7091a4d1ec091586b585bf84fd4c2df47935f551 Mon Sep 17 00:00:00 2001 From: AmrDeveloper <am...@programmer.net> Date: Fri, 22 Aug 2025 23:53:41 +0200 Subject: [PATCH 3/3] Address code review comments --- .../CIR/Dialect/Builder/CIRBaseBuilder.h | 23 +++---- clang/include/clang/CIR/Dialect/IR/CIROps.td | 2 +- clang/include/clang/CIR/MissingFeatures.h | 1 + clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp | 2 +- clang/lib/CIR/CodeGen/CIRGenItaniumCXXABI.cpp | 10 +-- clang/lib/CIR/Dialect/IR/CIRDialect.cpp | 2 +- .../Dialect/Transforms/LoweringPrepare.cpp | 24 +------ .../CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp | 45 ++++++++++-- .../CIR/Lowering/DirectToLLVM/LowerToLLVM.h | 10 +++ clang/test/CIR/CodeGen/throws.cpp | 68 ++++++++++++++++++- clang/test/CIR/IR/invalid-throw.cir | 16 +++++ clang/test/CIR/IR/throw.cir | 63 +++++++++++++++++ 12 files changed, 214 insertions(+), 52 deletions(-) create mode 100644 clang/test/CIR/IR/invalid-throw.cir create mode 100644 clang/test/CIR/IR/throw.cir diff --git a/clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h b/clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h index aba4615b2a7f4..96f55f5c66071 100644 --- a/clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h +++ b/clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h @@ -312,24 +312,23 @@ class CIRBaseBuilderTy : public mlir::OpBuilder { resOperands, attrs); } - cir::CallOp - createTryCallOp(mlir::Location loc, - mlir::SymbolRefAttr callee = mlir::SymbolRefAttr(), - mlir::Type returnType = cir::VoidType(), - mlir::ValueRange operands = mlir::ValueRange(), - cir::SideEffect sideEffect = cir::SideEffect::All) { + cir::CallOp createTryCallOp( + mlir::Location loc, mlir::SymbolRefAttr callee = mlir::SymbolRefAttr(), + mlir::Type returnType = cir::VoidType(), + mlir::ValueRange operands = mlir::ValueRange(), + [[maybe_unused]] cir::SideEffect sideEffect = cir::SideEffect::All) { assert(!cir::MissingFeatures::opCallCallConv()); + assert(!cir::MissingFeatures::opCallSideEffect()); return createCallOp(loc, callee, returnType, operands); } - cir::CallOp - createTryCallOp(mlir::Location loc, cir::FuncOp callee, - mlir::ValueRange operands, - cir::SideEffect sideEffect = cir::SideEffect::All) { + cir::CallOp createTryCallOp( + mlir::Location loc, cir::FuncOp callee, mlir::ValueRange operands, + [[maybe_unused]] cir::SideEffect sideEffect = cir::SideEffect::All) { assert(!cir::MissingFeatures::opCallCallConv()); + assert(!cir::MissingFeatures::opCallSideEffect()); return createTryCallOp(loc, mlir::SymbolRefAttr::get(callee), - callee.getFunctionType().getReturnType(), operands, - sideEffect); + callee.getFunctionType().getReturnType(), operands); } //===--------------------------------------------------------------------===// diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td b/clang/include/clang/CIR/Dialect/IR/CIROps.td index 1a38e045dcf77..49db97efb3702 100644 --- a/clang/include/clang/CIR/Dialect/IR/CIROps.td +++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td @@ -3807,7 +3807,7 @@ def CIR_VAArgOp : CIR_Op<"va_arg"> { def CIR_ThrowOp : CIR_Op<"throw"> { let summary = "(Re)Throws an exception"; let description = [{ - Very similar to __cxa_throw: + It's equivalent __cxa_throw: ``` void __cxa_throw(void *thrown_exception, std::type_info *tinfo, diff --git a/clang/include/clang/CIR/MissingFeatures.h b/clang/include/clang/CIR/MissingFeatures.h index d7a2e49ec162a..e023d205df92e 100644 --- a/clang/include/clang/CIR/MissingFeatures.h +++ b/clang/include/clang/CIR/MissingFeatures.h @@ -93,6 +93,7 @@ struct MissingFeatures { static bool opCallReturn() { return false; } static bool opCallArgEvaluationOrder() { return false; } static bool opCallCallConv() { return false; } + static bool opCallSideEffect() { return false; } static bool opCallMustTail() { return false; } static bool opCallInAlloca() { return false; } static bool opCallAttrs() { return false; } diff --git a/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp b/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp index f0bebfeb19430..406d8398098b3 100644 --- a/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp @@ -659,7 +659,7 @@ class ScalarExprEmitter : public StmtVisitor<ScalarExprEmitter, mlir::Value> { mlir::Value VisitCXXThrowExpr(const CXXThrowExpr *e) { cgf.emitCXXThrowExpr(e); - return nullptr; + return {}; } /// Emit a conversion from the specified type to the specified destination diff --git a/clang/lib/CIR/CodeGen/CIRGenItaniumCXXABI.cpp b/clang/lib/CIR/CodeGen/CIRGenItaniumCXXABI.cpp index 1d98b801e90f8..c0f9148249f41 100644 --- a/clang/lib/CIR/CodeGen/CIRGenItaniumCXXABI.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenItaniumCXXABI.cpp @@ -127,7 +127,7 @@ void CIRGenItaniumCXXABI::emitInstanceFunctionProlog(SourceLocation loc, // Find out how to cirgen the complete destructor and constructor namespace { enum class StructorCIRGen { Emit, RAUW, Alias, COMDAT }; -} // namespace +} static StructorCIRGen getCIRGenToUse(CIRGenModule &cgm, const CXXMethodDecl *md) { @@ -378,18 +378,10 @@ static void insertThrowAndSplit(mlir::OpBuilder &builder, mlir::Location loc, } (void)builder.createBlock(region); - - // This will be erased during codegen, it acts as a placeholder for the - // operations to be inserted (if any) - cir::ScopeOp::create(builder, loc, /*scopeBuilder=*/ - [&](mlir::OpBuilder &b, mlir::Location loc) { - b.create<cir::YieldOp>(loc); - }); } void CIRGenItaniumCXXABI::emitRethrow(CIRGenFunction &cgf, bool isNoReturn) { // void __cxa_rethrow(); - if (isNoReturn) { CIRGenBuilderTy &builder = cgf.getBuilder(); assert(cgf.currSrcLoc && "expected source location"); diff --git a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp index 3f5bf799d2c9f..ee15618581cef 100644 --- a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp +++ b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp @@ -2659,7 +2659,7 @@ mlir::LogicalResult cir::ThrowOp::verify() { if (rethrows()) return success(); - if (getNumOperands() == 1) { + if (getNumOperands() != 0) { if (getTypeInfo()) return success(); return emitOpError() << "'type_info' symbol attribute missing"; diff --git a/clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp b/clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp index cccfe9b444a31..c15637d297cd1 100644 --- a/clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp +++ b/clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp @@ -32,7 +32,6 @@ struct LoweringPreparePass : public LoweringPrepareBase<LoweringPreparePass> { void lowerUnaryOp(cir::UnaryOp op); void lowerArrayDtor(cir::ArrayDtor op); void lowerArrayCtor(cir::ArrayCtor op); - void lowerThrowOp(ThrowOp op); cir::FuncOp buildRuntimeFunction( mlir::OpBuilder &builder, llvm::StringRef name, mlir::Location loc, @@ -681,24 +680,6 @@ void LoweringPreparePass::lowerArrayCtor(cir::ArrayCtor op) { true); } -void LoweringPreparePass::lowerThrowOp(ThrowOp op) { - if (op.rethrows()) { - CIRBaseBuilderTy builder(getContext()); - auto voidTy = cir::VoidType::get(builder.getContext()); - auto fnType = cir::FuncType::get({}, voidTy); - - builder.setInsertionPointToStart(&mlirModule.getBodyRegion().front()); - FuncOp f = - buildRuntimeFunction(builder, "__cxa_rethrow", op.getLoc(), fnType); - - builder.setInsertionPointAfter(op.getOperation()); - cir::CallOp call = builder.createTryCallOp(op.getLoc(), f, {}); - - op->replaceAllUsesWith(call); - op->erase(); - } -} - void LoweringPreparePass::runOnOp(mlir::Operation *op) { if (auto arrayCtor = dyn_cast<ArrayCtor>(op)) lowerArrayCtor(arrayCtor); @@ -712,8 +693,6 @@ void LoweringPreparePass::runOnOp(mlir::Operation *op) { lowerComplexMulOp(complexMul); else if (auto unary = mlir::dyn_cast<cir::UnaryOp>(op)) lowerUnaryOp(unary); - else if (auto throwOp = mlir::dyn_cast<cir::ThrowOp>(op)) - lowerThrowOp(throwOp); } void LoweringPreparePass::runOnOperation() { @@ -725,8 +704,7 @@ void LoweringPreparePass::runOnOperation() { op->walk([&](mlir::Operation *op) { if (mlir::isa<cir::ArrayCtor, cir::ArrayDtor, cir::CastOp, - cir::ComplexMulOp, cir::ComplexDivOp, cir::UnaryOp, - cir::ThrowOp>(op)) + cir::ComplexMulOp, cir::ComplexDivOp, cir::UnaryOp>(op)) opsToTransform.push_back(op); }); diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp index 9f0e4e6ecb8ce..fdae389d4edbf 100644 --- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp +++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp @@ -2435,6 +2435,7 @@ void ConvertCIRToLLVMPass::runOnOperation() { CIRToLLVMStackRestoreOpLowering, CIRToLLVMStackSaveOpLowering, CIRToLLVMSwitchFlatOpLowering, + CIRToLLVMThrowOpLowering, CIRToLLVMTrapOpLowering, CIRToLLVMUnaryOpLowering, CIRToLLVMUnreachableOpLowering, @@ -2514,6 +2515,42 @@ mlir::LogicalResult CIRToLLVMUnreachableOpLowering::matchAndRewrite( return mlir::success(); } +void createLLVMFuncOpIfNotExist(mlir::ConversionPatternRewriter &rewriter, + mlir::Operation *srcOp, llvm::StringRef fnName, + mlir::Type fnTy) { + auto modOp = srcOp->getParentOfType<mlir::ModuleOp>(); + auto enclosingFnOp = srcOp->getParentOfType<mlir::LLVM::LLVMFuncOp>(); + mlir::Operation *sourceSymbol = + mlir::SymbolTable::lookupSymbolIn(modOp, fnName); + if (!sourceSymbol) { + mlir::OpBuilder::InsertionGuard guard(rewriter); + rewriter.setInsertionPoint(enclosingFnOp); + rewriter.create<mlir::LLVM::LLVMFuncOp>(srcOp->getLoc(), fnName, fnTy); + } +} + +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); + + auto mlirModule = op->getParentOfType<mlir::ModuleOp>(); + rewriter.setInsertionPointToStart(&mlirModule.getBodyRegion().front()); + + 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{}); + } + + return mlir::success(); +} + mlir::LogicalResult CIRToLLVMTrapOpLowering::matchAndRewrite( cir::TrapOp op, OpAdaptor adaptor, mlir::ConversionPatternRewriter &rewriter) const { @@ -3129,7 +3166,7 @@ mlir::LogicalResult CIRToLLVMInlineAsmOpLowering::matchAndRewrite( SmallVector<mlir::Value> llvmOperands; SmallVector<mlir::Value> cirOperands; - for (auto const&[llvmOp, cirOp] : + for (auto const &[llvmOp, cirOp] : zip(adaptor.getAsmOperands(), op.getAsmOperands())) { append_range(llvmOperands, llvmOp); append_range(cirOperands, cirOp); @@ -3137,15 +3174,15 @@ mlir::LogicalResult CIRToLLVMInlineAsmOpLowering::matchAndRewrite( // so far we infer the llvm dialect element type attr from // CIR operand type. - for (auto const&[cirOpAttr, cirOp] : zip(op.getOperandAttrs(), cirOperands)) { + for (auto const &[cirOpAttr, cirOp] : + zip(op.getOperandAttrs(), cirOperands)) { if (!cirOpAttr) { opAttrs.push_back(mlir::Attribute()); continue; } llvm::SmallVector<mlir::NamedAttribute, 1> attrs; - cir::PointerType typ = - mlir::cast<cir::PointerType>(cirOp.getType()); + cir::PointerType typ = mlir::cast<cir::PointerType>(cirOp.getType()); mlir::TypeAttr typAttr = mlir::TypeAttr::get(convertTypeForMemory( *getTypeConverter(), dataLayout, typ.getPointee())); diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.h b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.h index 7b109c5cef9d3..173607c6a3ad5 100644 --- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.h +++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.h @@ -725,6 +725,16 @@ class CIRToLLVMInlineAsmOpLowering mlir::ConversionPatternRewriter &) const override; }; +class CIRToLLVMThrowOpLowering + : public mlir::OpConversionPattern<cir::ThrowOp> { +public: + using mlir::OpConversionPattern<cir::ThrowOp>::OpConversionPattern; + + mlir::LogicalResult + matchAndRewrite(cir::ThrowOp op, OpAdaptor, + mlir::ConversionPatternRewriter &) const override; +}; + class CIRToLLVMVAStartOpLowering : public mlir::OpConversionPattern<cir::VAStartOp> { public: diff --git a/clang/test/CIR/CodeGen/throws.cpp b/clang/test/CIR/CodeGen/throws.cpp index a1a87bcb2f393..0122f3088f0bf 100644 --- a/clang/test/CIR/CodeGen/throws.cpp +++ b/clang/test/CIR/CodeGen/throws.cpp @@ -9,7 +9,7 @@ void foo() { throw; } -// CIR: cir.call @__cxa_rethrow() : () -> () +// CIR: cir.throw // CIR: cir.unreachable // LLVM: call void @__cxa_rethrow() @@ -17,3 +17,69 @@ void foo() { // OGCG: call void @__cxa_rethrow() // OGCG: unreachable + +int foo1(int a, int b) { + if (b == 0) + throw; + return a / b; +} + +// CIR: %[[A_ADDR:.*]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["a", init] +// CIR: %[[B_ADDR:.*]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["b", init] +// CIR: %[[RES_ADDR:.*]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["__retval"] +// CIR: cir.store %{{.*}}, %[[A_ADDR]] : !s32i, !cir.ptr<!s32i> +// CIR: cir.store %{{.*}}, %[[B_ADDR]] : !s32i, !cir.ptr<!s32i> +// CIR: cir.scope { +// CIR: %[[TMP_B:.*]] = cir.load{{.*}} %[[B_ADDR]] : !cir.ptr<!s32i>, !s32i +// CIR: %[[CONST_0:.*]] = cir.const #cir.int<0> : !s32i +// CIR: %[[IS_B_ZERO:.*]] = cir.cmp(eq, %[[TMP_B]], %[[CONST_0]]) : !s32i, !cir.bool +// CIR: cir.if %[[IS_B_ZERO]] { +// CIR: cir.throw +// CIR: cir.unreachable +// CIR: } +// CIR: } +// CIR: %[[TMP_A:.*]] = cir.load{{.*}} %[[A_ADDR]] : !cir.ptr<!s32i>, !s32i +// CIR: %[[TMP_B:.*]] = cir.load{{.*}} %[[B_ADDR]] : !cir.ptr<!s32i>, !s32i +// CIR: %[[DIV_A_B:.*]] = cir.binop(div, %[[TMP_A:.*]], %[[TMP_B:.*]]) : !s32i +// CIR: cir.store %[[DIV_A_B]], %[[RES_ADDR]] : !s32i, !cir.ptr<!s32i> +// CIR: %[[RESULT:.*]] = cir.load %[[RES_ADDR]] : !cir.ptr<!s32i>, !s32i +// CIR: cir.return %[[RESULT]] : !s32i + +// LLVM: %[[A_ADDR:.*]] = alloca i32, i64 1, align 4 +// LLVM: %[[B_ADDR:.*]] = alloca i32, i64 1, align 4 +// LLVM: %[[RES_ADDR:.*]] = alloca i32, i64 1, align 4 +// LLVM: store i32 %{{.*}}, ptr %[[A_ADDR]], align 4 +// LLVM: store i32 %{{.*}}, ptr %[[B_ADDR]], align 4 +// LLVM: br label %[[CHECK_COND:.*]] +// LLVM: [[CHECK_COND]]: +// LLVM: %[[TMP_B:.*]] = load i32, ptr %[[B_ADDR]], align 4 +// LLVM: %[[IS_B_ZERO:.*]] = icmp eq i32 %[[TMP_B]], 0 +// LLVM: br i1 %[[IS_B_ZERO]], label %[[IF_THEN:.*]], label %[[IF_ELSE:.*]] +// LLVM: [[IF_THEN]]: +// LLVM: call void @__cxa_rethrow() +// LLVM: unreachable +// LLVM: [[IF_ELSE]]: +// LLVM: br label %[[IF_END:.*]] +// LLVM: [[IF_END]]: +// LLVM: %[[TMP_A:.*]] = load i32, ptr %[[A_ADDR]], align 4 +// LLVM: %[[TMP_B:.*]] = load i32, ptr %[[B_ADDR]], align 4 +// LLVM: %[[DIV_A_B:.*]] = sdiv i32 %[[TMP_A]], %[[TMP_B]] +// LLVM: store i32 %[[DIV_A_B]], ptr %[[RES_ADDR]], align 4 +// LLVM: %[[RESULT:.*]] = load i32, ptr %[[RES_ADDR]], align 4 +// LLVM: ret i32 %[[RESULT]] + +// OGCG: %[[A_ADDR:.*]] = alloca i32, align 4 +// OGCG: %[[B_ADDR:.*]] = alloca i32, align 4 +// OGCG: store i32 %{{.*}}, ptr %[[A_ADDR]], align 4 +// OGCG: store i32 %{{.*}}, ptr %[[B_ADDR]], align 4 +// OGCG: %[[TMP_B:.*]] = load i32, ptr %[[B_ADDR]], align 4 +// OGCG: %[[IS_B_ZERO:.*]] = icmp eq i32 %[[TMP_B]], 0 +// OGCG: br i1 %[[IS_B_ZERO]], label %[[IF_THEN:.*]], label %[[IF_END:.*]] +// OGCG: [[IF_THEN]]: +// OGCG: call void @__cxa_rethrow() +// OGCG: unreachable +// OGCG: [[IF_END]]: +// OGCG: %[[TMP_A:.*]] = load i32, ptr %[[A_ADDR]], align 4 +// OGCG: %[[TMP_B:.*]] = load i32, ptr %[[B_ADDR]], align 4 +// OGCG: %[[DIV_A_B:.*]] = sdiv i32 %[[TMP_A]], %[[TMP_B]] +// OGCG: ret i32 %[[DIV_A_B]] diff --git a/clang/test/CIR/IR/invalid-throw.cir b/clang/test/CIR/IR/invalid-throw.cir new file mode 100644 index 0000000000000..53582a11b285e --- /dev/null +++ b/clang/test/CIR/IR/invalid-throw.cir @@ -0,0 +1,16 @@ +// RUN: cir-opt %s -verify-diagnostics -split-input-file + +!s32i = !cir.int<s, 32> + +module { + +cir.func dso_local @throw_without_type_info() { + %0 = cir.alloca !s32i, !cir.ptr<!s32i>, ["a"] + // expected-error @below {{'cir.throw' op 'type_info' symbol attribute missing}} + cir.throw %0 : !cir.ptr<!s32i> + cir.unreachable + ^bb1: + cir.return +} + +} diff --git a/clang/test/CIR/IR/throw.cir b/clang/test/CIR/IR/throw.cir new file mode 100644 index 0000000000000..8b24b481057b1 --- /dev/null +++ b/clang/test/CIR/IR/throw.cir @@ -0,0 +1,63 @@ +// RUN: cir-opt %s | FileCheck %s + +!s32i = !cir.int<s, 32> + +module { + +cir.func @throw_with_no_return() { + cir.throw + cir.unreachable +} + +// CHECK: cir.func @throw_with_no_return() { +// CHECK: cir.throw +// CHECK: cir.unreachable +// CHECK: } + +cir.func @throw_with_no_return_2(%arg0: !s32i, %arg1: !s32i) -> !s32i { + %0 = cir.alloca !s32i, !cir.ptr<!s32i>, ["a", init] + %1 = cir.alloca !s32i, !cir.ptr<!s32i>, ["b", init] + %2 = cir.alloca !s32i, !cir.ptr<!s32i>, ["__retval"] + cir.store %arg0, %0 : !s32i, !cir.ptr<!s32i> + cir.store %arg1, %1 : !s32i, !cir.ptr<!s32i> + cir.scope { + %7 = cir.load align(4) %1 : !cir.ptr<!s32i>, !s32i + %8 = cir.const #cir.int<0> : !s32i + %9 = cir.cmp(eq, %7, %8) : !s32i, !cir.bool + cir.if %9 { + cir.throw + cir.unreachable + } + } + %3 = cir.load align(4) %0 : !cir.ptr<!s32i>, !s32i + %4 = cir.load align(4) %1 : !cir.ptr<!s32i>, !s32i + %5 = cir.binop(div, %3, %4) : !s32i + cir.store %5, %2 : !s32i, !cir.ptr<!s32i> + %6 = cir.load %2 : !cir.ptr<!s32i>, !s32i + cir.return %6 : !s32i +} + +// CHECK: cir.func @throw_with_no_return_2(%[[ARG_0:.*]]: !s32i, %[[ARG_1:.*]]: !s32i) -> !s32i { +// CHECK: %[[A_ADDR:.*]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["a", init] +// CHECK: %[[B_ADDR:.*]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["b", init] +// CHECK: %[[RES_ADDR:.*]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["__retval"] +// CHECK: cir.store %[[ARG_0]], %[[A_ADDR]] : !s32i, !cir.ptr<!s32i> +// CHECK: cir.store %[[ARG_1]], %[[B_ADDR]] : !s32i, !cir.ptr<!s32i> +// CHECK: cir.scope { +// CHECK: %[[TMP_B:.*]] = cir.load{{.*}} %[[B_ADDR]] : !cir.ptr<!s32i>, !s32i +// CHECK: %[[CONST_0:.*]] = cir.const #cir.int<0> : !s32i +// CHECK: %[[IS_B_ZERO:.*]] = cir.cmp(eq, %[[TMP_B]], %[[CONST_0]]) : !s32i, !cir.bool +// CHECK: cir.if %[[IS_B_ZERO]] { +// CHECK: cir.throw +// CHECK: cir.unreachable +// CHECK: } +// CHECK: } +// CHECK: %[[TMP_A:.*]] = cir.load{{.*}} %[[A_ADDR]] : !cir.ptr<!s32i>, !s32i +// CHECK: %[[TMP_B:.*]] = cir.load{{.*}} %[[B_ADDR]] : !cir.ptr<!s32i>, !s32i +// CHECK: %[[DIV_A_B:.*]] = cir.binop(div, %[[TMP_A:.*]], %[[TMP_B:.*]]) : !s32i +// CHECK: cir.store %[[DIV_A_B]], %[[RES_ADDR]] : !s32i, !cir.ptr<!s32i> +// CHECK: %[[RESULT:.*]] = cir.load %[[RES_ADDR]] : !cir.ptr<!s32i>, !s32i +// CHECK: cir.return %[[RESULT]] : !s32i +// CHECK: } + +} _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits