Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 0 additions & 8 deletions clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2565,10 +2565,6 @@ mlir::Value ScalarExprEmitter::VisitAbstractConditionalOperator(
.create<cir::TernaryOp>(
loc, condV, /*trueBuilder=*/
[&](mlir::OpBuilder &b, mlir::Location loc) {
CIRGenFunction::LexicalScope lexScope{CGF, loc,
b.getInsertionBlock()};
CGF.currLexScope->setAsTernary();

assert(!cir::MissingFeatures::incrementProfileCounter());
eval.begin(CGF);
auto lhs = Visit(lhsExpr);
Expand All @@ -2585,10 +2581,6 @@ mlir::Value ScalarExprEmitter::VisitAbstractConditionalOperator(
},
/*falseBuilder=*/
[&](mlir::OpBuilder &b, mlir::Location loc) {
CIRGenFunction::LexicalScope lexScope{CGF, loc,
b.getInsertionBlock()};
CGF.currLexScope->setAsTernary();

assert(!cir::MissingFeatures::incrementProfileCounter());
eval.begin(CGF);
auto rhs = Visit(rhsExpr);
Expand Down
67 changes: 34 additions & 33 deletions clang/lib/CIR/CodeGen/CIRGenItaniumCXXABI.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2263,44 +2263,46 @@ mlir::Value CIRGenItaniumCXXABI::getCXXDestructorImplicitParam(
return CGF.GetVTTParameter(GD, ForVirtualBase, Delegating);
}

// 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.
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()) {
builder.create<cir::ThrowOp>(loc, exceptionPtr, typeInfo, dtor);
builder.create<cir::UnreachableOp>(loc);
} else {
mlir::Block *throwBlock = builder.createBlock(region);
builder.create<cir::ThrowOp>(loc, exceptionPtr, typeInfo, dtor);
builder.create<cir::UnreachableOp>(loc);

builder.setInsertionPointToEnd(currentBlock);
builder.create<cir::BrOp>(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)
builder.create<cir::ScopeOp>(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) {
auto &builder = CGF.getBuilder();
assert(CGF.currSrcLoc && "expected source location");
auto loc = *CGF.currSrcLoc;

// 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.

mlir::Block *currentBlock = builder.getInsertionBlock();
mlir::Region *region = currentBlock->getParent();

if (currentBlock->empty()) {
builder.create<cir::ThrowOp>(loc, mlir::Value{},
mlir::FlatSymbolRefAttr{},
mlir::FlatSymbolRefAttr{});
builder.create<cir::UnreachableOp>(loc);
} else {
mlir::Block *rethrowBlock = builder.createBlock(region);
builder.create<cir::ThrowOp>(loc, mlir::Value{},
mlir::FlatSymbolRefAttr{},
mlir::FlatSymbolRefAttr{});
builder.create<cir::UnreachableOp>(loc);

builder.setInsertionPointToEnd(currentBlock);
builder.create<cir::BrOp>(loc, rethrowBlock);
}

(void)builder.createBlock(region);
// This will be erased during codegen, it acts as a placeholder for the
// operations to be inserted (if any)
builder.create<cir::ScopeOp>(loc, /*scopeBuilder=*/
[&](mlir::OpBuilder &b, mlir::Location loc) {
b.create<cir::YieldOp>(loc);
});
insertThrowAndSplit(builder, loc, mlir::Value{}, mlir::FlatSymbolRefAttr{},
mlir::FlatSymbolRefAttr{});
} else {
llvm_unreachable("NYI");
}
Expand Down Expand Up @@ -2366,8 +2368,7 @@ void CIRGenItaniumCXXABI::emitThrow(CIRGenFunction &CGF,

// Now throw the exception.
mlir::Location loc = CGF.getLoc(E->getSourceRange());
builder.create<cir::ThrowOp>(loc, exceptionPtr, typeInfo.getSymbol(), dtor);
builder.create<cir::UnreachableOp>(loc);
insertThrowAndSplit(builder, loc, exceptionPtr, typeInfo.getSymbol(), dtor);
}

mlir::Value CIRGenItaniumCXXABI::getVirtualBaseClassOffset(
Expand Down
4 changes: 2 additions & 2 deletions clang/lib/CIR/Dialect/IR/CIRDialect.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1556,13 +1556,13 @@ void cir::TernaryOp::build(
result.addOperands(cond);
OpBuilder::InsertionGuard guard(builder);
Region *trueRegion = result.addRegion();
auto *block = builder.createBlock(trueRegion);
builder.createBlock(trueRegion);
trueBuilder(builder, result.location);
Region *falseRegion = result.addRegion();
builder.createBlock(falseRegion);
falseBuilder(builder, result.location);

auto yield = dyn_cast<YieldOp>(block->getTerminator());
auto yield = dyn_cast<YieldOp>(trueRegion->back().getTerminator());
assert((yield && yield.getNumOperands() <= 1) &&
"expected zero or one result type");
if (yield.getNumOperands() == 1)
Expand Down
139 changes: 139 additions & 0 deletions clang/test/CIR/CodeGen/throw.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ double d(int a, int b) {
// CIR-NEXT: cir.store{{.*}} %[[STR_ADD]], %[[ADDR]] : !cir.ptr<!s8i>, !cir.ptr<!cir.ptr<!s8i>>
// CIR-NEXT: cir.throw %[[ADDR]] : !cir.ptr<!cir.ptr<!s8i>>, @_ZTIPKc
// CIR-NEXT: cir.unreachable
// CIR-NEXT: ^bb1: // no predecessors
// CIR-NEXT: cir.yield
// CIR-NEXT: }

// LLVM: %[[ADDR:.*]] = call ptr @__cxa_allocate_exception(i64 8)
Expand Down Expand Up @@ -293,3 +295,140 @@ void refoo4() {
// LLVM: invoke void @__cxa_rethrow
// LLVM: unreachable
// LLVM: invoke void @_ZN1SC2Ev

void statements() {
throw 0;
123 + 456;
}

// CIR: cir.func @_Z10statementsv()
// CIR-NEXT: %[[V0:.*]] = cir.alloc.exception 4 -> !cir.ptr<!s32i>
// CIR-NEXT: %[[V1:.*]] = cir.const #cir.int<0> : !s32i
// CIR-NEXT: cir.store align(16) %[[V1]], %[[V0]] : !s32i, !cir.ptr<!s32i>
// CIR-NEXT: cir.throw %[[V0]] : !cir.ptr<!s32i>, @_ZTIi
// CIR-NEXT: cir.unreachable
// CIR-NEXT: ^bb1:
// CIR-NEXT: %[[V2:.*]] = cir.const #cir.int<123> : !s32i
// CIR-NEXT: %[[V3:.*]] = cir.const #cir.int<456> : !s32i
// CIR-NEXT: %[[V4:.*]] = cir.binop(add, %[[V2]], %[[V3]]) nsw : !s32i
// CIR-NEXT: cir.return
// CIR-NEXT: }

// LLVM: call void @__cxa_throw
// LLVM: unreachable

void paren_expr() { (throw 0, 123 + 456); }

// CIR: cir.func @_Z10paren_exprv()
// CIR-NEXT: %[[V0:.*]] = cir.alloc.exception 4 -> !cir.ptr<!s32i>
// CIR-NEXT: %[[V1:.*]] = cir.const #cir.int<0> : !s32i
// CIR-NEXT: cir.store align(16) %[[V1]], %[[V0]] : !s32i, !cir.ptr<!s32i>
// CIR-NEXT: cir.throw %[[V0]] : !cir.ptr<!s32i>, @_ZTIi
// CIR-NEXT: cir.unreachable
// CIR-NEXT: ^bb1:
// CIR-NEXT: %[[V2:.*]] = cir.const #cir.int<123> : !s32i
// CIR-NEXT: %[[V3:.*]] = cir.const #cir.int<456> : !s32i
// CIR-NEXT: %[[V4:.*]] = cir.binop(add, %[[V2]], %[[V3]]) nsw : !s32i
// CIR-NEXT: cir.return
// CIR-NEXT: }

// LLVM: call void @__cxa_throw
// LLVM: unreachable

int ternary_throw1(bool condition, int x) {
return condition ? throw x : x;
}

// CIR: cir.func @_Z14ternary_throw1bi(%arg0: !cir.bool
// CIR-NEXT: %[[V0:.*]] = cir.alloca !cir.bool, !cir.ptr<!cir.bool>, ["condition", init] {alignment = 1 : i64}
// CIR-NEXT: %[[V1:.*]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["x", init] {alignment = 4 : i64}
// CIR-NEXT: %[[V2:.*]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["__retval"] {alignment = 4 : i64}
// CIR-NEXT: %[[V3:.*]] = cir.alloca !cir.bool, !cir.ptr<!cir.bool>, ["cleanup.cond"] {alignment = 1 : i64}
// CIR-NEXT: %[[V4:.*]] = cir.const #false
// CIR-NEXT: %[[V5:.*]] = cir.const #true
// CIR-NEXT: cir.store %arg0, %[[V0]] : !cir.bool, !cir.ptr<!cir.bool>
// CIR-NEXT: cir.store %arg1, %[[V1]] : !s32i, !cir.ptr<!s32i>
// CIR-NEXT: %[[V6:.*]] = cir.load align(1) %[[V0]] : !cir.ptr<!cir.bool>, !cir.bool
// CIR-NEXT: cir.store align(1) %[[V4]], %[[V3]] : !cir.bool, !cir.ptr<!cir.bool>
// CIR-NEXT: %[[V7:.*]] = cir.ternary(%[[V6]], true {
// CIR-NEXT: %[[V9:.*]] = cir.alloc.exception 4 -> !cir.ptr<!s32i>
// CIR-NEXT: cir.store align(1) %[[V5]], %[[V3]] : !cir.bool, !cir.ptr<!cir.bool>
// CIR-NEXT: %[[V10:.*]] = cir.load align(4) %[[V1]] : !cir.ptr<!s32i>, !s32i
// CIR-NEXT: cir.store align(16) %[[V10]], %[[V9]] : !s32i, !cir.ptr<!s32i>
// CIR-NEXT: cir.throw %[[V9]] : !cir.ptr<!s32i>, @_ZTIi
// CIR-NEXT: cir.unreachable
// CIR-NEXT: ^bb1: // no predecessors
// CIR-NEXT: %[[V11:.*]] = cir.const #cir.int<0> : !s32i loc(#loc173)
// CIR-NEXT: cir.yield %[[V11]] : !s32i
// CIR-NEXT: }, false {
// CIR-NEXT: %[[V9:.*]] = cir.load align(4) %[[V1]] : !cir.ptr<!s32i>, !s32i
// CIR-NEXT: cir.yield %[[V9]] : !s32i
// CIR-NEXT: }) : (!cir.bool) -> !s32i
// CIR-NEXT: cir.store %[[V7]], %[[V2]] : !s32i, !cir.ptr<!s32i>
// CIR-NEXT: %[[V8:.*]] = cir.load %[[V2]] : !cir.ptr<!s32i>, !s32i
// CIR-NEXT: cir.return %[[V8]] : !s32i
// CIR-NEXT: }

// LLVM: @_Z14ternary_throw1bi
// LLVM: %[[V3:.*]] = alloca i8, i64 1, align 1
// LLVM: %[[V4:.*]] = alloca i32, i64 1, align 4
// LLVM: %[[V5:.*]] = alloca i32, i64 1, align 4
// LLVM: %[[V6:.*]] = alloca i8, i64 1, align 1
// LLVM: %[[V7:.*]] = zext i1 %[[V0:.*]] to i8
// LLVM: store i8 %[[V7]], ptr %[[V3]], align 1
// LLVM: store i32 %[[V1:.*]], ptr %[[V4]], align 4
// LLVM: %[[V8:.*]] = load i8, ptr %[[V3]], align 1
// LLVM: %[[V9:.*]] = trunc i8 %[[V8]] to i1
// LLVM: store i8 0, ptr %[[V6]], align 1
// LLVM: br i1 %[[V9]], label %[[B10:.*]], label %[[B14:.*]]
// LLVM: [[B10]]:
// LLVM: %[[V11:.*]] = call ptr @__cxa_allocate_exception(i64 4)
// LLVM: store i8 1, ptr %[[V6]], align 1
// LLVM: %[[V12:.*]] = load i32, ptr %[[V4]], align 4
// LLVM: store i32 %[[V12]], ptr %[[V11]], align 16
// LLVM: call void @__cxa_throw(ptr %[[V11]], ptr @_ZTIi, ptr null)
// LLVM: unreachable
// LLVM: [[B13]]:
// LLVM: br label %[[B16:.*]]
// LLVM: [[B14]]:
// LLVM: %[[V15:.*]] = load i32, ptr %[[V4]], align 4
// LLVM: br label %[[B16]]
// LLVM: [[B16]]:
// LLVM: %[[V17:.*]] = phi i32 [ 0, %[[V13]] ], [ %[[V15]], %[[V14]] ]
// LLVM: store i32 %[[V17]], ptr %[[V5]], align 4
// LLVM: %[[V18:.*]] = load i32, ptr %[[V5]], align 4
// LLVM: ret i32 %[[V18]]

int ternary_throw2(bool condition, int x) {
return condition ? x : throw x;
}

// LLVM: @_Z14ternary_throw2bi
// LLVM: %[[V3:.*]] = alloca i8, i64 1, align 1
// LLVM: %[[V4:.*]] = alloca i32, i64 1, align 4
// LLVM: %[[V5:.*]] = alloca i32, i64 1, align 4
// LLVM: %[[V6:.*]] = alloca i8, i64 1, align 1
// LLVM: %[[V7:.*]] = zext i1 %[[V0:.*]] to i8
// LLVM: store i8 %[[V7]], ptr %[[V3]], align 1
// LLVM: store i32 %[[V1]], ptr %[[V4]], align 4
// LLVM: %[[V8:.*]] = load i8, ptr %[[V3]], align 1
// LLVM: %[[V9:.*]] = trunc i8 %[[V8]] to i1
// LLVM: store i8 0, ptr %[[V6]], align 1
// LLVM: br i1 %[[V9]], label %[[B10:.*]], label %[[B12:.*]]
// LLVM: [[B10]]:
// LLVM: %[[V11:.*]] = load i32, ptr %[[V4]], align 4
// LLVM: br label %[[B16:.*]]
// LLVM: [[B12]]:
// LLVM: %[[V13:.*]] = call ptr @__cxa_allocate_exception(i64 4)
// LLVM: store i8 1, ptr %[[V6]], align 1
// LLVM: %[[V14:.*]] = load i32, ptr %[[V4]], align 4
// LLVM: store i32 %[[V14]], ptr %[[V13]], align 16
// LLVM: call void @__cxa_throw(ptr %[[V13]], ptr @_ZTIi, ptr null)
// LLVM: unreachable
// LLVM: [[B15:.*]]:
// LLVM: br label %[[B16:.*]]
// LLVM: [[B16]]:
// LLVM: %[[V17:.*]] = phi i32 [ 0, %[[V15]] ], [ %[[V11]], %[[V10]] ]
// LLVM: store i32 %[[V17]], ptr %[[V5]], align 4
// LLVM: %[[V18:.*]] = load i32, ptr %[[V5]], align 4
// LLVM: ret i32 %[[V18]]
Loading