From 7aec6bf51abf1f5a221ca70e6ce66f7315dab7ae Mon Sep 17 00:00:00 2001 From: bruteforceboy Date: Thu, 23 Jan 2025 16:01:57 +0300 Subject: [PATCH 1/7] add initial support for __cxa_rethrow --- clang/lib/CIR/CodeGen/CIRGenItaniumCXXABI.cpp | 25 ++++++++++++- clang/test/CIR/CodeGen/try-catch-dtors.cpp | 37 +++++++++++++++++++ 2 files changed, 61 insertions(+), 1 deletion(-) diff --git a/clang/lib/CIR/CodeGen/CIRGenItaniumCXXABI.cpp b/clang/lib/CIR/CodeGen/CIRGenItaniumCXXABI.cpp index fbf901c47a7c..d14336305952 100644 --- a/clang/lib/CIR/CodeGen/CIRGenItaniumCXXABI.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenItaniumCXXABI.cpp @@ -2261,7 +2261,30 @@ mlir::Value CIRGenItaniumCXXABI::getCXXDestructorImplicitParam( void CIRGenItaniumCXXABI::emitRethrow(CIRGenFunction &CGF, bool isNoReturn) { // void __cxa_rethrow(); - llvm_unreachable("NYI"); + + cir::FuncType FTy = + CGF.getBuilder().getFuncType({}, CGF.getBuilder().getVoidTy()); + + auto Fn = CGF.CGM.createRuntimeFunction(FTy, "__cxa_rethrow"); + + if (isNoReturn) { + auto &builder = CGF.getBuilder(); + + auto callOp = builder.createTryCallOp(Fn.getLoc(), Fn, {}); + + // The idea here is to create + // an unreachable continue block for the rethrow, but + // there is a YieldOp that terminates the TryOp already, so creating an + // UnreachableOp in-place causes us to have two terminators which isn't + // valid CIR. So, to make this valid CIR the UnreachableOp is created in a + // separate scope. + builder.create(Fn.getLoc(), /*scopeBuilder=*/ + [&](mlir::OpBuilder &b, mlir::Location loc) { + b.create(loc); + }); + } else { + llvm_unreachable("NYI"); + } } void CIRGenItaniumCXXABI::emitThrow(CIRGenFunction &CGF, diff --git a/clang/test/CIR/CodeGen/try-catch-dtors.cpp b/clang/test/CIR/CodeGen/try-catch-dtors.cpp index e212133e3e6f..8d628464518a 100644 --- a/clang/test/CIR/CodeGen/try-catch-dtors.cpp +++ b/clang/test/CIR/CodeGen/try-catch-dtors.cpp @@ -339,3 +339,40 @@ void bar() { // CIR: cir.store %[[V3]], %[[V1]] : !s32i, !cir.ptr // CIR: cir.call @_ZN1AD2Ev(%[[V0]]) : (!cir.ptr) -> () extra(#fn_attr) // CIR: cir.return + +struct S { + S() {} +}; + +void refoo() { + int r = 1; + try { + S s; + throw; + } catch (...) { + ++r; + } +} + +// CIR-LABEL: @_Z5refoov() +// 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.scope { +// CIR: cir.unreachable +// CIR: } +// 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 From fa80c8ca39b141ce2048fa2c19382ff8fd8128cf Mon Sep 17 00:00:00 2001 From: bruteforceboy Date: Wed, 5 Feb 2025 13:13:43 +0300 Subject: [PATCH 2/7] replace scope with blocks --- clang/lib/CIR/CodeGen/CIRGenItaniumCXXABI.cpp | 36 ++++-- clang/test/CIR/CodeGen/try-catch-dtors.cpp | 103 ++++++++++++++---- 2 files changed, 109 insertions(+), 30 deletions(-) diff --git a/clang/lib/CIR/CodeGen/CIRGenItaniumCXXABI.cpp b/clang/lib/CIR/CodeGen/CIRGenItaniumCXXABI.cpp index d14336305952..fceb1612cd73 100644 --- a/clang/lib/CIR/CodeGen/CIRGenItaniumCXXABI.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenItaniumCXXABI.cpp @@ -2266,21 +2266,41 @@ void CIRGenItaniumCXXABI::emitRethrow(CIRGenFunction &CGF, bool isNoReturn) { CGF.getBuilder().getFuncType({}, CGF.getBuilder().getVoidTy()); auto Fn = CGF.CGM.createRuntimeFunction(FTy, "__cxa_rethrow"); + auto loc = Fn.getLoc(); if (isNoReturn) { auto &builder = CGF.getBuilder(); - auto callOp = builder.createTryCallOp(Fn.getLoc(), Fn, {}); + // The idea here is creating a separate block for the rethrow with an + // `UnreachableOp` as the terminator. So, we branch from the current block + // to the rethrow block and create a block for the remaining operations. - // The idea here is to create - // an unreachable continue block for the rethrow, but - // there is a YieldOp that terminates the TryOp already, so creating an - // UnreachableOp in-place causes us to have two terminators which isn't - // valid CIR. So, to make this valid CIR the UnreachableOp is created in a - // separate scope. + auto currentBlock = builder.getInsertionBlock(); + auto reg = currentBlock->getParent(); + + bool branch = false; + if (currentBlock->empty()) + currentBlock->erase(); + else + branch = true; + + auto rethrowBlock = builder.createBlock(reg); + builder.setInsertionPointToStart(rethrowBlock); + builder.createTryCallOp(Fn.getLoc(), Fn, {}); + builder.create(loc); + + if (branch) { + builder.setInsertionPointToEnd(currentBlock); + builder.create(loc, rethrowBlock); + } + + auto remBlock = builder.createBlock(reg); + builder.setInsertionPointToEnd(remBlock); + // This will be erased during codegen, it acts as a placeholder for the + // operations to be inserted (if any) builder.create(Fn.getLoc(), /*scopeBuilder=*/ [&](mlir::OpBuilder &b, mlir::Location loc) { - b.create(loc); + b.create(loc); }); } else { llvm_unreachable("NYI"); diff --git a/clang/test/CIR/CodeGen/try-catch-dtors.cpp b/clang/test/CIR/CodeGen/try-catch-dtors.cpp index 8d628464518a..82b6c8ec0a8a 100644 --- a/clang/test/CIR/CodeGen/try-catch-dtors.cpp +++ b/clang/test/CIR/CodeGen/try-catch-dtors.cpp @@ -344,7 +344,7 @@ struct S { S() {} }; -void refoo() { +void refoo1() { int r = 1; try { S s; @@ -354,25 +354,84 @@ void refoo() { } } -// CIR-LABEL: @_Z5refoov() -// 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.scope { -// CIR: cir.unreachable -// CIR: } -// 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-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: ^bb1: // no predecessors +// 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: } -// CIR: cir.return + +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: ^bb1: // no predecessors +// CIR: cir.yield +// 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: } \ No newline at end of file From 75e11efc9a11edb2e47e953eb968cc4535739af4 Mon Sep 17 00:00:00 2001 From: bruteforceboy Date: Wed, 5 Feb 2025 13:16:03 +0300 Subject: [PATCH 3/7] add spacing --- clang/test/CIR/CodeGen/try-catch-dtors.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clang/test/CIR/CodeGen/try-catch-dtors.cpp b/clang/test/CIR/CodeGen/try-catch-dtors.cpp index 82b6c8ec0a8a..ec1105c66847 100644 --- a/clang/test/CIR/CodeGen/try-catch-dtors.cpp +++ b/clang/test/CIR/CodeGen/try-catch-dtors.cpp @@ -434,4 +434,4 @@ void refoo2() { // CIR: }] // CIR: } // CIR: cir.return -// CIR: } \ No newline at end of file +// CIR: } From 2b4a28a3816aaa121afe748d5a8339937a345c96 Mon Sep 17 00:00:00 2001 From: bruteforceboy Date: Thu, 6 Feb 2025 16:07:45 +0300 Subject: [PATCH 4/7] emit unreachable directly and llvm output --- clang/lib/CIR/CodeGen/CIRGenItaniumCXXABI.cpp | 32 +--- .../lib/CIR/Dialect/Transforms/FlattenCFG.cpp | 5 +- clang/test/CIR/CodeGen/throw.cpp | 179 +++++++++++++++++- clang/test/CIR/CodeGen/try-catch-dtors.cpp | 96 ---------- 4 files changed, 182 insertions(+), 130 deletions(-) diff --git a/clang/lib/CIR/CodeGen/CIRGenItaniumCXXABI.cpp b/clang/lib/CIR/CodeGen/CIRGenItaniumCXXABI.cpp index fceb1612cd73..5a40f351a973 100644 --- a/clang/lib/CIR/CodeGen/CIRGenItaniumCXXABI.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenItaniumCXXABI.cpp @@ -2270,38 +2270,8 @@ void CIRGenItaniumCXXABI::emitRethrow(CIRGenFunction &CGF, bool isNoReturn) { if (isNoReturn) { auto &builder = CGF.getBuilder(); - - // The idea here is creating a separate block for the rethrow with an - // `UnreachableOp` as the terminator. So, we branch from the current block - // to the rethrow block and create a block for the remaining operations. - - auto currentBlock = builder.getInsertionBlock(); - auto reg = currentBlock->getParent(); - - bool branch = false; - if (currentBlock->empty()) - currentBlock->erase(); - else - branch = true; - - auto rethrowBlock = builder.createBlock(reg); - builder.setInsertionPointToStart(rethrowBlock); - builder.createTryCallOp(Fn.getLoc(), Fn, {}); + builder.createTryCallOp(loc, Fn, {}); builder.create(loc); - - if (branch) { - builder.setInsertionPointToEnd(currentBlock); - builder.create(loc, rethrowBlock); - } - - auto remBlock = builder.createBlock(reg); - builder.setInsertionPointToEnd(remBlock); - // This will be erased during codegen, it acts as a placeholder for the - // operations to be inserted (if any) - builder.create(Fn.getLoc(), /*scopeBuilder=*/ - [&](mlir::OpBuilder &b, mlir::Location loc) { - b.create(loc); - }); } else { llvm_unreachable("NYI"); } diff --git a/clang/lib/CIR/Dialect/Transforms/FlattenCFG.cpp b/clang/lib/CIR/Dialect/Transforms/FlattenCFG.cpp index 2eb4b6134686..c86b252ab217 100644 --- a/clang/lib/CIR/Dialect/Transforms/FlattenCFG.cpp +++ b/clang/lib/CIR/Dialect/Transforms/FlattenCFG.cpp @@ -426,11 +426,12 @@ 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); + + 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/test/CIR/CodeGen/throw.cpp b/clang/test/CIR/CodeGen/throw.cpp index c2395c3725c3..1f9e7bdd8ba1 100644 --- a/clang/test/CIR/CodeGen/throw.cpp +++ b/clang/test/CIR/CodeGen/throw.cpp @@ -21,4 +21,181 @@ 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: @__cxa_rethrow() +// 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 {{.*}} diff --git a/clang/test/CIR/CodeGen/try-catch-dtors.cpp b/clang/test/CIR/CodeGen/try-catch-dtors.cpp index ec1105c66847..e212133e3e6f 100644 --- a/clang/test/CIR/CodeGen/try-catch-dtors.cpp +++ b/clang/test/CIR/CodeGen/try-catch-dtors.cpp @@ -339,99 +339,3 @@ void bar() { // CIR: cir.store %[[V3]], %[[V1]] : !s32i, !cir.ptr // CIR: cir.call @_ZN1AD2Ev(%[[V0]]) : (!cir.ptr) -> () extra(#fn_attr) // CIR: cir.return - -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: ^bb1: // no predecessors -// 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: } - -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: ^bb1: // no predecessors -// CIR: cir.yield -// 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: } From 02a9bb11307cca418b06248b9c26f3ac49467ea6 Mon Sep 17 00:00:00 2001 From: bruteforceboy Date: Thu, 6 Feb 2025 17:49:59 +0300 Subject: [PATCH 5/7] trigger tests From a626e1c14e48c2e49014991feee9133ca7704c80 Mon Sep 17 00:00:00 2001 From: bruteforceboy Date: Fri, 7 Feb 2025 14:32:05 +0300 Subject: [PATCH 6/7] add comment --- clang/lib/CIR/Dialect/Transforms/FlattenCFG.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/clang/lib/CIR/Dialect/Transforms/FlattenCFG.cpp b/clang/lib/CIR/Dialect/Transforms/FlattenCFG.cpp index c86b252ab217..e912a9aa6c8f 100644 --- a/clang/lib/CIR/Dialect/Transforms/FlattenCFG.cpp +++ b/clang/lib/CIR/Dialect/Transforms/FlattenCFG.cpp @@ -430,6 +430,8 @@ class CIRTryOpFlattening : public mlir::OpRewritePattern { mlir::Block *beforeCatch = rewriter.getInsertionBlock(); rewriter.setInsertionPointToEnd(beforeCatch); + // 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); From bf65b67ce7638ee4d4a8cd4708170a3615c36924 Mon Sep 17 00:00:00 2001 From: bruteforceboy Date: Mon, 10 Feb 2025 12:26:51 +0300 Subject: [PATCH 7/7] move lowering to loweringPrepare --- clang/lib/CIR/CodeGen/CIRGenItaniumCXXABI.cpp | 11 ++++----- .../Dialect/Transforms/LoweringPrepare.cpp | 24 ++++++++++++++++++- clang/test/CIR/CodeGen/throw.cpp | 1 - 3 files changed, 27 insertions(+), 9 deletions(-) diff --git a/clang/lib/CIR/CodeGen/CIRGenItaniumCXXABI.cpp b/clang/lib/CIR/CodeGen/CIRGenItaniumCXXABI.cpp index 5a40f351a973..7afa993f65de 100644 --- a/clang/lib/CIR/CodeGen/CIRGenItaniumCXXABI.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenItaniumCXXABI.cpp @@ -2262,15 +2262,12 @@ mlir::Value CIRGenItaniumCXXABI::getCXXDestructorImplicitParam( void CIRGenItaniumCXXABI::emitRethrow(CIRGenFunction &CGF, bool isNoReturn) { // void __cxa_rethrow(); - cir::FuncType FTy = - CGF.getBuilder().getFuncType({}, CGF.getBuilder().getVoidTy()); - - auto Fn = CGF.CGM.createRuntimeFunction(FTy, "__cxa_rethrow"); - auto loc = Fn.getLoc(); - if (isNoReturn) { auto &builder = CGF.getBuilder(); - builder.createTryCallOp(loc, Fn, {}); + 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"); 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 1f9e7bdd8ba1..87b34d231767 100644 --- a/clang/test/CIR/CodeGen/throw.cpp +++ b/clang/test/CIR/CodeGen/throw.cpp @@ -58,7 +58,6 @@ void refoo1() { // CIR: cir.return // CIR: } -// LLVM: @__cxa_rethrow() // LLVM: define dso_local void @_Z6refoo1v() // LLVM: %[[V1:.*]] = alloca %struct.S, i64 1, align 1 // LLVM: %[[V2:.*]] = alloca i32, i64 1, align 4