-
Notifications
You must be signed in to change notification settings - Fork 15.1k
[CIR] Upstream Exception ThrowOp with subexpr #161818
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -31,11 +31,36 @@ void CIRGenFunction::emitCXXThrowExpr(const CXXThrowExpr *e) { | |
| if (throwType->isObjCObjectPointerType()) { | ||
| cgm.errorNYI("emitCXXThrowExpr ObjCObjectPointerType"); | ||
| return; | ||
| } else { | ||
| cgm.errorNYI("emitCXXThrowExpr with subExpr"); | ||
| return; | ||
| } | ||
| } else { | ||
| cgm.getCXXABI().emitRethrow(*this, /*isNoReturn=*/true); | ||
|
|
||
| cgm.getCXXABI().emitThrow(*this, e); | ||
| return; | ||
| } | ||
|
|
||
| cgm.getCXXABI().emitRethrow(*this, /*isNoReturn=*/true); | ||
| } | ||
|
|
||
| void CIRGenFunction::emitAnyExprToExn(const Expr *e, Address addr) { | ||
| // Make sure the exception object is cleaned up if there's an | ||
| // exception during initialization. | ||
| assert(!cir::MissingFeatures::ehCleanupScope()); | ||
|
|
||
| // __cxa_allocate_exception returns a void*; we need to cast this | ||
| // to the appropriate type for the object. | ||
| mlir::Type ty = convertTypeForMem(e->getType()); | ||
| Address typedAddr = addr.withElementType(builder, ty); | ||
|
|
||
| // From LLVM's codegen: | ||
| // FIXME: this isn't quite right! If there's a final unelided call | ||
| // to a copy constructor, then according to [except.terminate]p1 we | ||
| // must call std::terminate() if that constructor throws, because | ||
| // technically that copy occurs after the exception expression is | ||
| // evaluated but before the exception is caught. But the best way | ||
| // to handle that is to teach EmitAggExpr to do the final copy | ||
| // differently if it can't be elided. | ||
| emitAnyExprToMem(e, typedAddr, e->getType().getQualifiers(), | ||
| /*isInitializer=*/true); | ||
|
|
||
| // Deactivate the cleanup block. | ||
| assert(!cir::MissingFeatures::ehCleanupScope()); | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It's not clear to me why you aren't calling There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Without |
||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -5,7 +5,7 @@ | |
| // 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() { | ||
| void rethrow() { | ||
| throw; | ||
| } | ||
|
|
||
|
|
@@ -18,7 +18,7 @@ void foo() { | |
| // OGCG: call void @__cxa_rethrow() | ||
| // OGCG: unreachable | ||
|
|
||
| int foo1(int a, int b) { | ||
| int rethrow_from_block(int a, int b) { | ||
| if (b == 0) | ||
| throw; | ||
| return a / b; | ||
|
|
@@ -83,3 +83,43 @@ int foo1(int a, int b) { | |
| // 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]] | ||
|
|
||
| void throw_scalar() { | ||
| throw 1; | ||
| } | ||
|
|
||
| // CIR: %[[EXCEPTION_ADDR:.*]] = cir.alloc.exception 4 -> !cir.ptr<!s32i> | ||
| // CIR: %[[EXCEPTION_VALUE:.*]] = cir.const #cir.int<1> : !s32i | ||
| // CIR: cir.store{{.*}} %[[EXCEPTION_VALUE]], %[[EXCEPTION_ADDR]] : !s32i, !cir.ptr<!s32i> | ||
| // CIR: cir.throw %[[EXCEPTION_ADDR]] : !cir.ptr<!s32i>, @_ZTIi | ||
| // CIR: cir.unreachable | ||
|
|
||
| // LLVM: %[[EXCEPTION_ADDR:.*]] = call ptr @__cxa_allocate_exception(i64 4) | ||
| // LLVM: store i32 1, ptr %[[EXCEPTION_ADDR]], align 16 | ||
| // LLVM: call void @__cxa_throw(ptr %[[EXCEPTION_ADDR]], ptr @_ZTIi, ptr null) | ||
| // LLVM: unreachable | ||
|
|
||
| // OGCG: %[[EXCEPTION_ADDR:.*]] = call ptr @__cxa_allocate_exception(i64 4) | ||
| // OGCG: store i32 1, ptr %[[EXCEPTION_ADDR]], align 16 | ||
| // OGCG: call void @__cxa_throw(ptr %[[EXCEPTION_ADDR]], ptr @_ZTIi, ptr null) | ||
| // OGCG: unreachable | ||
|
|
||
| void paren_expr() { (throw 0, 1 + 2); } | ||
|
|
||
| // CIR: %[[EXCEPTION_ADDR:.*]] = cir.alloc.exception 4 -> !cir.ptr<!s32i> | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
| // CIR: %[[EXCEPTION_VALUE:.*]] = cir.const #cir.int<0> : !s32i | ||
| // CIR: cir.store{{.*}} %[[EXCEPTION_VALUE]], %[[EXCEPTION_ADDR]] : !s32i, !cir.ptr<!s32i> | ||
| // CIR: cir.throw %[[EXCEPTION_ADDR]] : !cir.ptr<!s32i>, @_ZTIi | ||
| // CIR: cir.unreachable | ||
| // CIR: ^bb1: | ||
| // CIR: %[[CONST_1:.*]] = cir.const #cir.int<1> : !s32i | ||
| // CIR: %[[CONST_2:.*]] = cir.const #cir.int<2> : !s32i | ||
| // CIR: %[[ADD:.*]] = cir.binop(add, %[[CONST_1]], %[[CONST_2]]) nsw : !s32i | ||
|
|
||
| // LLVM: %[[EXCEPTION_ADDR:.*]] = call ptr @__cxa_allocate_exception(i64 4) | ||
| // LLVM: store i32 0, ptr %[[EXCEPTION_ADDR]], align 16 | ||
| // LLVM: call void @__cxa_throw(ptr %[[EXCEPTION_ADDR]], ptr @_ZTIi, ptr null) | ||
|
|
||
| // OGCG: %[[EXCEPTION_ADDR:.*]] = call ptr @__cxa_allocate_exception(i64 4) | ||
| // OGCG: store i32 0, ptr %[[EXCEPTION_ADDR]], align 16 | ||
| // OGCG: call void @__cxa_throw(ptr %[[EXCEPTION_ADDR]], ptr @_ZTIi, ptr null) | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we be more specific about the return type? For instance, is the return type always ptr-to-ptr-to-ui8?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
From the CIR code, yes, it can be
Ptr<Ptr<UI8>>, I will double check OGCG and add constraints, also we can add one for ThrowOp operandThere was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I see now. We're allocating an exception for a throw expression, and since we know the throw type, we allocate the exception accordingly. OGCG is just emitting a call to __cxa_allocate_exception, which it "casts" to the correct type, but since OGCG uses opaque types the cast is never visible.