diff --git a/clang/lib/CIR/CodeGen/CIRGenItaniumCXXABI.cpp b/clang/lib/CIR/CodeGen/CIRGenItaniumCXXABI.cpp index fbf901c47a7c..7afa993f65de 100644 --- a/clang/lib/CIR/CodeGen/CIRGenItaniumCXXABI.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenItaniumCXXABI.cpp @@ -2261,7 +2261,17 @@ mlir::Value CIRGenItaniumCXXABI::getCXXDestructorImplicitParam( void CIRGenItaniumCXXABI::emitRethrow(CIRGenFunction &CGF, bool isNoReturn) { // void __cxa_rethrow(); - llvm_unreachable("NYI"); + + if (isNoReturn) { + auto &builder = CGF.getBuilder(); + assert(CGF.currSrcLoc && "expected source location"); + auto loc = *CGF.currSrcLoc; + builder.create(loc, mlir::Value{}, mlir::FlatSymbolRefAttr{}, + mlir::FlatSymbolRefAttr{}); + builder.create(loc); + } else { + llvm_unreachable("NYI"); + } } void CIRGenItaniumCXXABI::emitThrow(CIRGenFunction &CGF, diff --git a/clang/lib/CIR/Dialect/Transforms/FlattenCFG.cpp b/clang/lib/CIR/Dialect/Transforms/FlattenCFG.cpp index 2eb4b6134686..e912a9aa6c8f 100644 --- a/clang/lib/CIR/Dialect/Transforms/FlattenCFG.cpp +++ b/clang/lib/CIR/Dialect/Transforms/FlattenCFG.cpp @@ -426,11 +426,14 @@ class CIRTryOpFlattening : public mlir::OpRewritePattern { SmallVectorImpl &landingPads) const { // Replace the tryOp return with a branch that jumps out of the body. rewriter.setInsertionPointToEnd(afterBody); - auto tryBodyYield = cast(afterBody->getTerminator()); mlir::Block *beforeCatch = rewriter.getInsertionBlock(); rewriter.setInsertionPointToEnd(beforeCatch); - rewriter.replaceOpWithNewOp(tryBodyYield, afterTry); + + // Check if the terminator is a YieldOp because there could be another + // terminator, e.g. unreachable + if (auto tryBodyYield = dyn_cast(afterBody->getTerminator())) + rewriter.replaceOpWithNewOp(tryBodyYield, afterTry); // Start the landing pad by getting the inflight exception information. mlir::Block *nextDispatcher = diff --git a/clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp b/clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp index 20239d843d2d..f6f3e58e0322 100644 --- a/clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp +++ b/clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp @@ -86,6 +86,7 @@ struct LoweringPreparePass : public LoweringPrepareBase { void lowerToMemCpy(StoreOp op); void lowerArrayDtor(ArrayDtor op); void lowerArrayCtor(ArrayCtor op); + void lowerThrowOp(ThrowOp op); /// Collect annotations of global values in the module void addGlobalAnnotations(mlir::Operation *op, mlir::ArrayAttr annotations); @@ -1133,6 +1134,25 @@ void LoweringPreparePass::lowerIterEndOp(IterEndOp op) { op.erase(); } +void LoweringPreparePass::lowerThrowOp(ThrowOp op) { + CIRBaseBuilderTy builder(getContext()); + + if (op.rethrows()) { + auto voidTy = cir::VoidType::get(builder.getContext()); + auto fnType = cir::FuncType::get({}, voidTy); + auto fnName = "__cxa_rethrow"; + + builder.setInsertionPointToStart(&theModule.getBodyRegion().front()); + FuncOp f = buildRuntimeFunction(builder, fnName, op.getLoc(), fnType); + + builder.setInsertionPointAfter(op.getOperation()); + auto call = builder.createTryCallOp(op.getLoc(), f, {}); + + op->replaceAllUsesWith(call); + op->erase(); + } +} + void LoweringPreparePass::addGlobalAnnotations(mlir::Operation *op, mlir::ArrayAttr annotations) { auto globalValue = cast(op); @@ -1195,6 +1215,8 @@ void LoweringPreparePass::runOnOp(Operation *op) { } if (std::optional annotations = fnOp.getAnnotations()) addGlobalAnnotations(fnOp, annotations.value()); + } else if (auto throwOp = dyn_cast(op)) { + lowerThrowOp(throwOp); } } @@ -1211,7 +1233,7 @@ void LoweringPreparePass::runOnOperation() { op->walk([&](Operation *op) { if (isa(op)) + ArrayCtor, ArrayDtor, cir::FuncOp, StoreOp, ThrowOp>(op)) opsToTransform.push_back(op); }); diff --git a/clang/test/CIR/CodeGen/throw.cpp b/clang/test/CIR/CodeGen/throw.cpp index c2395c3725c3..87b34d231767 100644 --- a/clang/test/CIR/CodeGen/throw.cpp +++ b/clang/test/CIR/CodeGen/throw.cpp @@ -21,4 +21,180 @@ double d(int a, int b) { // LLVM: %[[ADDR:.*]] = call ptr @__cxa_allocate_exception(i64 8) // LLVM: store ptr @.str, ptr %[[ADDR]], align 8 // LLVM: call void @__cxa_throw(ptr %[[ADDR]], ptr @_ZTIPKc, ptr null) -// LLVM: unreachable \ No newline at end of file +// LLVM: unreachable + +struct S { + S() {} +}; + +void refoo1() { + int r = 1; + try { + S s; + throw; + } catch (...) { + ++r; + } +} + +// CIR-LABEL: @_Z6refoo1v() +// CIR: %[[V0:.*]] = cir.alloca !s32i, !cir.ptr, ["r", init] {alignment = 4 : i64} +// CIR: %[[V1:.*]] = cir.const #cir.int<1> : !s32i +// CIR: cir.store %[[V1]], %[[V0]] : !s32i, !cir.ptr +// CIR: cir.scope { +// CIR: %[[V2:.*]] = cir.alloca !ty_S, !cir.ptr, ["s", init] {alignment = 1 : i64} +// CIR: cir.try { +// CIR: cir.call exception @_ZN1SC2Ev(%[[V2]]) : (!cir.ptr) -> () +// CIR: cir.call exception @__cxa_rethrow() : () -> () +// CIR: cir.unreachable +// CIR: } catch [type #cir.all { +// CIR: %[[V3:.*]] = cir.catch_param -> !cir.ptr +// CIR: %[[V4:.*]] = cir.load %[[V0]] : !cir.ptr, !s32i +// CIR: %[[V5:.*]] = cir.unary(inc, %[[V4]]) : !s32i, !s32i +// CIR: cir.store %[[V5]], %[[V0]] : !s32i, !cir.ptr +// CIR: cir.yield +// CIR: }] +// CIR: } +// CIR: cir.return +// CIR: } + +// LLVM: define dso_local void @_Z6refoo1v() +// LLVM: %[[V1:.*]] = alloca %struct.S, i64 1, align 1 +// LLVM: %[[V2:.*]] = alloca i32, i64 1, align 4 +// LLVM: store i32 1, ptr %[[V2]], align 4 +// LLVM: br label %[[B3:.*]] +// LLVM: [[B3]]: +// LLVM: br label %[[B4:.*]] +// LLVM: [[B4]]: +// LLVM: invoke void @_ZN1SC2Ev(ptr %[[V1]]) +// LLVM: to label %[[B5:.*]] unwind label %[[B7:.*]] +// LLVM: [[B5]]: +// LLVM: invoke void @__cxa_rethrow() +// LLVM: to label %[[B6:.*]] unwind label %[[B11:.*]] +// LLVM: [[B6]]: +// LLVM: unreachable +// LLVM: [[B7]]: +// LLVM: %[[V8:.*]] = landingpad { ptr, i32 } +// LLVM: catch ptr null +// LLVM: %[[V9:.*]] = extractvalue { ptr, i32 } %[[V8]], 0 +// LLVM: %[[V10:.*]] = extractvalue { ptr, i32 } %[[V8]], 1 +// LLVM: br label %[[B15:.*]] +// LLVM: [[B11]]: +// LLVM: %[[V12:.*]] = landingpad { ptr, i32 } +// LLVM: catch ptr null +// LLVM: %[[V13:.*]] = extractvalue { ptr, i32 } %[[V12]], 0 +// LLVM: %[[V14:.*]] = extractvalue { ptr, i32 } %[[V12]], 1 +// LLVM: br label %[[B15:.*]] +// LLVM: [[B15]]: +// LLVM: %[[V16:.*]] = phi ptr [ %[[V9]], %[[B7]] ], [ %[[V13]], %[[B11]] ] +// LLVM: %[[V17:.*]] = call ptr @__cxa_begin_catch(ptr %[[V16]]) +// LLVM: %[[V18:.*]] = load i32, ptr %[[V2]], align 4 +// LLVM: %[[V19:.*]] = add i32 %[[V18]], 1 +// LLVM: store i32 %[[V19]], ptr %[[V2]], align 4 +// LLVM: call void @__cxa_end_catch() + +void refoo2() { + int r = 1; + try { + for (int i = 0; i < 5; i++) { + S s; + throw; + } + S s; + } catch (...) { + ++r; + } +} + +// CIR-LABEL: @_Z6refoo2v() +// CIR: %[[V0:.*]] = cir.alloca !s32i, !cir.ptr, ["r", init] {alignment = 4 : i64} +// CIR: %[[V1:.*]] = cir.const #cir.int<1> : !s32i +// CIR: cir.store %[[V1]], %[[V0]] : !s32i, !cir.ptr +// CIR: cir.scope { +// CIR: %[[V2:.*]] = cir.alloca !ty_S, !cir.ptr, ["s", init] {alignment = 1 : i64} +// CIR: cir.try { +// CIR: cir.scope { +// CIR: %[[V3:.*]] = cir.alloca !s32i, !cir.ptr, ["i", init] {alignment = 4 : i64} +// CIR: %[[V4:.*]] = cir.const #cir.int<0> : !s32i +// CIR: cir.store %[[V4]], %[[V3]] : !s32i, !cir.ptr +// CIR: cir.for : cond { +// CIR: %[[V5:.*]] = cir.load %[[V3]] : !cir.ptr, !s32i +// CIR: %[[V6:.*]] = cir.const #cir.int<5> : !s32i +// CIR: %[[V7:.*]] = cir.cmp(lt, %[[V5]], %[[V6]]) : !s32i, !cir.bool +// CIR: cir.condition(%[[V7]]) +// CIR: } body { +// CIR: cir.scope { +// CIR: %[[V5:.*]] = cir.alloca !ty_S, !cir.ptr, ["s", init] {alignment = 1 : i64} +// CIR: cir.call exception @_ZN1SC2Ev(%[[V5]]) : (!cir.ptr) -> () +// CIR: cir.call exception @__cxa_rethrow() : () -> () +// CIR: cir.unreachable +// CIR: } +// CIR: cir.yield +// CIR: } step { +// CIR: %[[V5:.*]] = cir.load %[[V3]] : !cir.ptr, !s32i +// CIR: %[[V6:.*]] = cir.unary(inc, %[[V5]]) : !s32i, !s32i +// CIR: cir.store %[[V6]], %[[V3]] : !s32i, !cir.ptr +// CIR: cir.yield +// CIR: } +// CIR: } +// CIR: cir.call exception @_ZN1SC2Ev(%[[V2]]) : (!cir.ptr) -> () +// CIR: cir.yield +// CIR: } catch [type #cir.all { +// CIR: %[[V3:.*]] = cir.catch_param -> !cir.ptr +// CIR: %[[V4:.*]] = cir.load %[[V0]] : !cir.ptr, !s32i +// CIR: %[[V5:.*]] = cir.unary(inc, %[[V4]]) : !s32i, !s32i +// CIR: cir.store %[[V5]], %[[V0]] : !s32i, !cir.ptr +// CIR: cir.yield +// CIR: }] +// CIR: } +// CIR: cir.return +// CIR: } + +// LLVM: {{.*}}: +// LLVM: invoke void @_ZN1SC2Ev(ptr %[[V3:.*]]) +// LLVM: to label %[[B13:.*]] unwind label %[[B22:.*]] +// LLVM: [[B13]]: +// LLVM: invoke void @__cxa_rethrow() +// LLVM: to label %[[B14:.*]] unwind label %[[B26:.*]] +// LLVM: [[B14]]: +// LLVM: unreachable +// LLVM: [[B15]]: +// LLVM: br label %[[B16:.*]] +// LLVM: [[B16]]: +// LLVM: %[[V17]] = load i32, ptr {{.*}}, align 4 +// LLVM: %[[V18]] = add i32 %[[V17]], 1 +// LLVM: store i32 %[[V18]], ptr {{.*}}, align 4 +// LLVM: br label {{.*}} +// LLVM: %[[B19:.*]] +// LLVM: br label %[[B20:.*]] +// LLVM: [[B20]]: +// LLVM: invoke void @_ZN1SC2Ev(ptr {{.*}}) +// LLVM: to label %[[B21:.*]] unwind label %[[B30:.*]] +// LLVM: [[B21]]: +// LLVM: br label {{.*}} +// LLVM: [[B22]]: +// LLVM: %[[V23:.*]] = landingpad { ptr, i32 } +// LLVM: catch ptr null +// LLVM: %[[V24:.*]] = extractvalue { ptr, i32 } %[[V23]], 0 +// LLVM: %[[V25:.*]] = extractvalue { ptr, i32 } %[[V23]], 1 +// LLVM: br label %[[B34:.*]] +// LLVM: [[B26]]: +// LLVM: %[[V27:.*]] = landingpad { ptr, i32 } +// LLVM: catch ptr null +// LLVM: %[[V28:.*]] = extractvalue { ptr, i32 } %[[V27]], 0 +// LLVM: %[[V29:.*]] = extractvalue { ptr, i32 } %[[V27]], 1 +// LLVM: br label %[[B34:.*]] +// LLVM: [[B30]]: +// LLVM: %[[V31:.*]] = landingpad { ptr, i32 } +// LLVM: catch ptr null +// LLVM: %[[V32:.*]] = extractvalue { ptr, i32 } %[[V31]], 0 +// LLVM: %[[V33:.*]] = extractvalue { ptr, i32 } %[[V31]], 1 +// LLVM: br label %[[B34:.*]] +// LLVM: [[B34]]: +// LLVM: %[[V35:.*]] = phi ptr [ %[[V32]], %[[B30]] ], [ %[[V24]], %[[B22]] ], [ %[[V28]], %[[B26]] ] +// LLVM: %[[V36:.*]] = call ptr @__cxa_begin_catch(ptr %[[V35]]) +// LLVM: %[[V37:.*]] = load i32, ptr {{.*}}, align 4 +// LLVM: %[[V38:.*]] = add i32 %[[V37]], 1 +// LLVM: store i32 %[[V38]], ptr {{.*}}, align 4 +// LLVM: call void @__cxa_end_catch() +// LLVM: br label {{.*}}