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
4 changes: 2 additions & 2 deletions clang/include/clang/CIR/Dialect/IR/CIROps.td
Original file line number Diff line number Diff line change
Expand Up @@ -7779,11 +7779,11 @@ def CIR_ConstructCatchParamOp : CIR_Op<"construct_catch_param", [
CIR_EhTokenType:$eh_token,
CIR_PointerType:$param_addr,
CIR_InitCatchKind:$kind,
FlatSymbolRefAttr:$copy_fn
OptionalAttr<FlatSymbolRefAttr>:$copy_fn
);

let assemblyFormat = [{
$kind $eh_token `to` $param_addr `using` $copy_fn `:`
$kind $eh_token `to` $param_addr `using` ($copy_fn^)? `:`
qualified(type($param_addr)) attr-dict
}];

Expand Down
1 change: 1 addition & 0 deletions clang/include/clang/CIR/MissingFeatures.h
Original file line number Diff line number Diff line change
Expand Up @@ -372,6 +372,7 @@ struct MissingFeatures {

// Maybe only needed for Windows exception handling
static bool currentFuncletPad() { return false; }
static bool sizeOfUnwindException() { return false; }
};

} // namespace cir
Expand Down
24 changes: 17 additions & 7 deletions clang/lib/CIR/CodeGen/CIRGenException.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -387,10 +387,15 @@ static void initCatchParam(CIRGenFunction &cgf, CIRGenBuilderTy &builder,
CanQualType catchType =
cgf.cgm.getASTContext().getCanonicalType(catchParam.getType());
cir::InitCatchKind kind;
bool shouldInitFromExnDirectly;

// If we're catching by reference, we can just cast the object
// pointer to the appropriate pointer.
if (isa<ReferenceType>(catchType)) {
QualType caughtType = cast<ReferenceType>(catchType)->getPointeeType();
if (const PointerType *ptr = dyn_cast<PointerType>(caughtType)) {
shouldInitFromExnDirectly = !ptr->getPointeeType()->isRecordType();
}
kind = cir::InitCatchKind::Reference;
} else {
cir::TypeEvaluationKind tek = cgf.getEvaluationKind(catchType);
Expand Down Expand Up @@ -424,19 +429,24 @@ static void initCatchParam(CIRGenFunction &cgf, CIRGenBuilderTy &builder,
Address paramAddr = var.getAllocatedAddress();
mlir::Location mloc = cgf.getLoc(loc);

if (kind == cir::InitCatchKind::NonTrivialCopy) {
if (kind == cir::InitCatchKind::NonTrivialCopy ||
(kind == cir::InitCatchKind::Reference && shouldInitFromExnDirectly)) {
// Sanitizer-checked construction (UBSan vptr/derived-class checks, etc.)
// would require additional adornments that cir.construct_catch_param does
// not yet carry.
assert(!cir::MissingFeatures::sanitizers());

auto paramAddrType =
mlir::cast<cir::PointerType>(paramAddr.getPointer().getType());
cir::FuncOp thunk =
getOrCreateCopyThunk(cgf, catchParam, paramAddrType, mloc);
mlir::FlatSymbolRefAttr copyFun{};
if (kind == cir::InitCatchKind::NonTrivialCopy) {
auto paramAddrType =
mlir::cast<cir::PointerType>(paramAddr.getPointer().getType());
cir::FuncOp thunk =
getOrCreateCopyThunk(cgf, catchParam, paramAddrType, mloc);
copyFun = mlir::FlatSymbolRefAttr::get(thunk.getSymNameAttr());
}

cir::ConstructCatchParamOp::create(builder, mloc, ehToken,
paramAddr.getPointer(), kind,
thunk.getSymName());
paramAddr.getPointer(), kind, copyFun);
}

mlir::Value exnPtr = callBeginCatch(cgf, ehToken, builder.getVoidPtrTy());
Expand Down
5 changes: 4 additions & 1 deletion clang/lib/CIR/Dialect/IR/CIRDialect.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4294,11 +4294,14 @@ cir::EhTypeIdOp::verifySymbolUses(SymbolTableCollection &symbolTable) {

LogicalResult cir::ConstructCatchParamOp::verifySymbolUses(
SymbolTableCollection &symbolTable) {
auto copyFnAttr = getCopyFnAttr();
if (!copyFnAttr)
return success();
auto fn =
symbolTable.lookupNearestSymbolFrom<cir::FuncOp>(*this, getCopyFnAttr());
if (!fn)
return emitOpError("'")
<< getCopyFn() << "' does not reference a valid cir.func";
<< *getCopyFn() << "' does not reference a valid cir.func";

if (!fn->hasAttr(cir::CIRDialect::getCatchCopyThunkAttrName()))
return emitOpError("catch-init copy_fn must be tagged with the ")
Expand Down
35 changes: 28 additions & 7 deletions clang/lib/CIR/Dialect/Transforms/EHABILowering.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
#include "clang/CIR/Dialect/IR/CIRTypes.h"
#include "clang/CIR/Dialect/Passes.h"
#include "clang/CIR/Dialect/Transforms/CIRTransformUtils.h"
#include "clang/CIR/MissingFeatures.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/TargetParser/Triple.h"
Expand Down Expand Up @@ -621,18 +622,37 @@ ItaniumEHLowering::resolveCatchCopyThunk(cir::ConstructCatchParamOp op) {
mlir::LogicalResult
ItaniumEHLowering::lowerConstructCatchParam(cir::ConstructCatchParamOp op,
mlir::Value exnPtr) {
mlir::Location loc = op.getLoc();
mlir::Value paramAddr = op.getParamAddr();
cir::PointerType paramAddrType =
mlir::cast<cir::PointerType>(paramAddr.getType());

if (op.getKind() == cir::InitCatchKind::Reference) {
assert(!MissingFeatures::sizeOfUnwindException());
constexpr unsigned headerSize = 32;

builder.setInsertionPoint(op);
auto index = cir::ConstantOp::create(
builder, loc, cir::IntAttr::get(u32Type, headerSize));
assert((exnPtr.getType() == voidPtrType || exnPtr.getType() == u8PtrType) &&
"lowerConstructCatchParam exn ptr not void* or i8*");
auto exnObj =
cir::PtrStrideOp::create(builder, loc, exnPtr.getType(), exnPtr, index);
Comment thread
AmrDeveloper marked this conversation as resolved.
mlir::Value casted =
cir::CastOp::create(builder, loc, paramAddrType.getPointee(),
cir::CastKind::bitcast, exnObj);
cir::StoreOp::create(builder, loc, casted, paramAddr, {}, {}, {}, {});
op.erase();
return success();
}

if (op.getKind() != cir::InitCatchKind::NonTrivialCopy)
return op.emitError(
"ConstructCatchParam: only non_trivial_copy is supported");

mlir::Location loc = op.getLoc();
ensureRuntimeDecls(loc);
ensureClangCallTerminate(loc);

mlir::Value paramAddr = op.getParamAddr();
cir::PointerType paramAddrType =
mlir::cast<cir::PointerType>(paramAddr.getType());

// Call __cxa_get_exception_ptr to get the in-flight exception.
builder.setInsertionPoint(op);
cir::CallOp getExnCall = cir::CallOp::create(
Expand Down Expand Up @@ -723,8 +743,9 @@ void ItaniumEHLowering::lowerInitCatchParam(cir::InitCatchParamOp op) {
// this by-value pointer and use the exception object instead.
if (auto ptr = mlir::dyn_cast<cir::PointerType>(ref.getPointee()))
if (!mlir::isa<cir::RecordType>(ptr.getPointee()))
llvm_unreachable(
"InitCatchParam: reference of pointer or non-record is NYI");
// Extracting and storing the actual exception object was performed by
// cir.construct_catch_param before cir.begin_catch.
break;
}

mlir::Value casted = cir::CastOp::create(builder, loc, elementType,
Expand Down
147 changes: 147 additions & 0 deletions clang/test/CIR/CodeGen/try-catch.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1615,3 +1615,150 @@ int init_catch_param_with_type_int_ptr() {
// OGCG: %[[TMP_EXCEPTION_INFO:.*]] = insertvalue { ptr, i32 } poison, ptr %[[TMP_EXCEPTION]], 0
// OGCG: %[[EXCEPTION_INFO:.*]] = insertvalue { ptr, i32 } %[[TMP_EXCEPTION_INFO]], i32 %[[TMP_EH_TYPE_ID]], 1
// OGCG: resume { ptr, i32 } %[[EXCEPTION_INFO]]

int init_catch_param_with_ref_to_ptr_to_non_record() {
int rv = 0;
try {
division();
} catch (int *&p) {
rv = *p;
}
return rv;
}

// CIR: cir.func {{.*}} @_Z46init_catch_param_with_ref_to_ptr_to_non_recordv() {{.*}} personality(@__gxx_personality_v0)
// CIR: %[[RET_ADDR:.*]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["__retval"]
// CIR: %[[RV_ADDR:.*]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["rv", init]
// CIR: cir.scope {
// CIR: %[[P_ADDR:.*]] = cir.alloca !cir.ptr<!cir.ptr<!s32i>>, !cir.ptr<!cir.ptr<!cir.ptr<!s32i>>>, ["p", const]
// CIR: cir.try {
// CIR: %[[CALL:.*]] = cir.call @_Z8divisionv() : () -> (!s32i {llvm.noundef})
// CIR: cir.yield
// CIR: } catch [type #cir.global_view<@_ZTIPi> : !cir.ptr<!u8i>] (%[[TOKEN:.*]]: !cir.eh_token {{.*}}) {
// CIR: cir.construct_catch_param reference %[[TOKEN]] to %[[P_ADDR]] using : !cir.ptr<!cir.ptr<!cir.ptr<!s32i>>>
// CIR: %[[CATCH_TOKEN:.*]], %[[EXN_PTR:.*]] = cir.begin_catch %{{.*}} : !cir.eh_token -> (!cir.catch_token, !cir.ptr<!void>)
// CIR: cir.cleanup.scope {
// CIR: cir.init_catch_param reference %[[EXN_PTR]] to %[[P_ADDR]] : !cir.ptr<!void>, !cir.ptr<!cir.ptr<!cir.ptr<!s32i>>>
// CIR: %[[TMP_P:.*]] = cir.load %[[P_ADDR]] : !cir.ptr<!cir.ptr<!cir.ptr<!s32i>>>, !cir.ptr<!cir.ptr<!s32i>>
// CIR: %[[DEREF_P:.*]] = cir.load deref {{.*}} %[[TMP_P]] : !cir.ptr<!cir.ptr<!s32i>>, !cir.ptr<!s32i>
// CIR: %[[P_VAL:.*]] = cir.load {{.*}} %[[DEREF_P]] : !cir.ptr<!s32i>, !s32i
// CIR: cir.store {{.*}} %[[P_VAL]], %[[RV_ADDR]] : !s32i, !cir.ptr<!s32i>
// CIR: cir.yield
// CIR: } cleanup all {
// CIR: cir.end_catch %catch_token : !cir.catch_token
// CIR: cir.yield
// CIR: }
// CIR: cir.yield
// CIR: } unwind (%{{.*}}: !cir.eh_token {{.*}}) {
// CIR: cir.resume %{{.*}} : !cir.eh_token
// CIR: }
// CIR: }
// CIR: %[[TMP_RV:.*]] = cir.load {{.*}} %[[RV_ADDR]] : !cir.ptr<!s32i>, !s32i
// CIR: cir.store %[[TMP_RV]], %[[RET_ADDR]] : !s32i, !cir.ptr<!s32i>
// CIR: %[[TMP_RET:.*]] = cir.load %[[RET_ADDR]] : !cir.ptr<!s32i>, !s32i
// CIR: cir.return %[[TMP_RET]] : !s32i

// LLVM: define {{.*}} i32 @_Z46init_catch_param_with_ref_to_ptr_to_non_recordv() {{.*}} personality ptr @__gxx_personality_v0
// LLVM: %[[P_ADDR:.*]] = alloca ptr, i64 1, align 8
// LLVM: %[[RET_ADDR:.*]] = alloca i32, i64 1, align 4
// LLVM: %[[RV_ADDR:.*]] = alloca i32, i64 1, align 4
// LLVM: br label %[[TRY_SCOPE:.*]]
// LLVM: [[TRY_SCOPE]]:
// LLVM: br label %[[TRY_BEGIN:.*]]
// LLVM: [[TRY_BEGIN]]:
// LLVM: %[[CALL:.*]] = invoke noundef i32 @_Z8divisionv()
// LLVM: to label %[[INVOKE_CONT:.*]] unwind label %[[LANDING_PAD:.*]]
// LLVM: [[INVOKE_CONT]]:
// LLVM: br label %[[TRY_CONT:.*]]
// LLVM: [[LANDING_PAD]]:
// LLVM: %[[LP:.*]] = landingpad { ptr, i32 }
// LLVM: catch ptr @_ZTIPi
// LLVM: %[[EXN_OBJ:.*]] = extractvalue { ptr, i32 } %[[LP]], 0
// LLVM: %[[EH_SELECTOR_VAL:.*]] = extractvalue { ptr, i32 } %[[LP]], 1
// LLVM: br label %[[CATCH:.*]]
// LLVM: [[CATCH]]:
// LLVM: %[[EXN_OBJ_PHI:.*]] = phi ptr [ %[[EXN_OBJ:.*]], %[[LANDING_PAD:.*]] ]
// LLVM: %[[EH_SELECTOR_PHI:.*]] = phi i32 [ %[[EH_SELECTOR_VAL:.*]], %[[LANDING_PAD:.*]] ]
// LLVM: br label %[[DISPATCH:.*]]
// LLVM: [[DISPATCH]]:
// LLVM: %[[EXN_OBJ_PHI1:.*]] = phi ptr [ %[[EXN_OBJ_PHI:.*]], %[[CATCH:.*]] ]
// LLVM: %[[EH_SELECTOR_PHI1:.*]] = phi i32 [ %[[EH_SELECTOR_PHI:.*]], %[[CATCH]] ]
// LLVM: %[[EH_TYPE_ID:.*]] = call i32 @llvm.eh.typeid.for.p0(ptr @_ZTIPi)
// LLVM: %[[TYPE_ID_EQ:.*]] = icmp eq i32 %[[EH_SELECTOR_PHI1]], %[[EH_TYPE_ID]]
// LLVM: br i1 %[[TYPE_ID_EQ]], label %[[BEGIN_CATCH:.*]], label %[[RESUME:.*]]
// LLVM: [[BEGIN_CATCH]]:
// LLVM: %[[EXN_OBJ_PHI2:.*]] = phi ptr [ %[[EXN_OBJ_PHI1:.*]], %[[DISPATCH:.*]] ]
// LLVM: %[[EH_SELECTOR_PHI2:.*]] = phi i32 [ %[[EH_SELECTOR_PHI1:.*]], %[[DISPATCH:.*]] ]
// LLVM: %[[EXN_OBJ:.*]] = getelementptr i8, ptr %[[EXN_OBJ_PHI2]], i64 32
// LLVM: store ptr %[[EXN_OBJ]], ptr %[[P_ADDR]], align 8
// LLVM: %[[EXN_PTR:.*]] = call ptr @__cxa_begin_catch(ptr %[[EXN_OBJ_PHI2]])
// LLVM: br label %[[CATCH_BODY:.*]]
// LLVM: [[CATCH_BODY]]:
// LLVM: %[[TMP_P:.*]] = load ptr, ptr %[[P_ADDR]], align 8
// LLVM: %[[DEREF_P:.*]] = load ptr, ptr %[[TMP_P]], align 8
// LLVM: %[[P_VAL:.*]] = load i32, ptr %[[DEREF_P]], align 4
// LLVM: store i32 %[[P_VAL]], ptr %[[RV_ADDR]], align 4
// LLVM: br label %[[END_CATCH:.*]]
// LLVM: [[END_CATCH]]:
// LLVM: call void @__cxa_end_catch()
// LLVM: br label %[[END_DISPATCH:.*]]
// LLVM: [[END_DISPATCH]]:
// LLVM: br label %[[END_TRY:.*]]
// LLVM: [[END_TRY]]:
// LLVM: br label %[[TRY_CONT:.*]]
// LLVM: [[RESUME]]:
// LLVM: %[[EXN_OBJ_PHI3:.*]] = phi ptr [ %[[EXN_OBJ_PHI1:.*]], %[[DISPATCH:.*]] ]
// LLVM: %[[EH_SELECTOR_PHI3:.*]] = phi i32 [ %[[EH_SELECTOR_PHI1:.*]], %[[DISPATCH:.*]] ]
// LLVM: %[[TMP_EXCEPTION_INFO:.*]] = insertvalue { ptr, i32 } poison, ptr %[[EXN_OBJ_PHI3]], 0
// LLVM: %[[EXCEPTION_INFO:.*]] = insertvalue { ptr, i32 } %[[TMP_EXCEPTION_INFO]], i32 %[[EH_SELECTOR_PHI3]], 1
// LLVM: resume { ptr, i32 } %[[EXCEPTION_INFO]]
// LLVM: [[TRY_CONT]]:
// LLVM: br label %[[DONE:.*]]
// LLVM: [[DONE]]:
// LLVM: %[[TMP_RV:.*]] = load i32, ptr %[[RV_ADDR]], align 4
// LLVM: store i32 %[[TMP_RV]], ptr %[[RET_ADDR]], align 4
// LLVM: %[[TMP_RET:.*]] = load i32, ptr %[[RET_ADDR]], align 4
// LLVM: ret i32 %[[TMP_RET]]

// OGCG: define {{.*}} i32 @_Z46init_catch_param_with_ref_to_ptr_to_non_recordv() {{.*}} personality ptr @__gxx_personality_v0
// OGCG: %[[RV_ADDR:.*]] = alloca i32, align 4
// OGCG: %[[EXCEPTION_ADDR:.*]] = alloca ptr, align 8
// OGCG: %[[EH_TYPE_ID_ADDR:.*]] = alloca i32, align 4
// OGCG: %[[P_ADDR:.*]] = alloca ptr, align 8
// OGCG: %[[CALL:.*]] = invoke noundef i32 @_Z8divisionv()
// OGCG: to label %[[INVOKE_NORMAL:.*]] unwind label %[[INVOKE_UNWIND:.*]]
// OGCG: [[INVOKE_NORMAL]]:
// OGCG: br label %[[TRY_CONT:.*]]
// OGCG: [[INVOKE_UNWIND]]:
// OGCG: %[[LANDING_PAD:.*]] = landingpad { ptr, i32 }
// OGCG: catch ptr @_ZTIPi
// OGCG: %[[EXCEPTION:.*]] = extractvalue { ptr, i32 } %[[LANDING_PAD]], 0
// OGCG: store ptr %[[EXCEPTION]], ptr %[[EXCEPTION_ADDR]], align 8
// OGCG: %[[EH_TYPE_ID:.*]] = extractvalue { ptr, i32 } %[[LANDING_PAD]], 1
// OGCG: store i32 %[[EH_TYPE_ID]], ptr %[[EH_TYPE_ID_ADDR]], align 4
// OGCG: br label %[[CATCH_DISPATCH]]
// OGCG: [[CATCH_DISPATCH]]:
// OGCG: %[[TMP_EH_TYPE_ID:.*]] = load i32, ptr %[[EH_TYPE_ID_ADDR]], align 4
// OGCG: %[[EH_TYPE_ID:.*]] = call i32 @llvm.eh.typeid.for.p0(ptr @_ZTIPi)
// OGCG: %[[TYPE_ID_EQ:.*]] = icmp eq i32 %[[TMP_EH_TYPE_ID]], %[[EH_TYPE_ID]]
// OGCG: br i1 %[[TYPE_ID_EQ]], label %[[CATCH_EXCEPTION:.*]], label %[[EH_RESUME:.*]]
// OGCG: [[CATCH_EXCEPTION]]:
// OGCG: %[[TMP_EXCEPTION:.*]] = load ptr, ptr %[[EXCEPTION_ADDR]], align 8
// OGCG: %[[BEGIN_CATCH:.*]] = call ptr @__cxa_begin_catch(ptr %[[TMP_EXCEPTION]])
// OGCG: %[[EXN_OBJ:.*]] = getelementptr i8, ptr %[[TMP_EXCEPTION]], i32 32
// OGCG: store ptr %[[EXN_OBJ]], ptr %[[P_ADDR]], align 8
// OGCG: %[[TMP_P:.*]] = load ptr, ptr %[[P_ADDR]], align 8
// OGCG: %[[DEREF_P:.*]] = load ptr, ptr %[[TMP_P]], align 8
// OGCG: %[[P_VAL:.*]] = load i32, ptr %[[DEREF_P]], align 4
// OGCG: store i32 %[[P_VAL]], ptr %[[RV_ADDR]], align 4
// OGCG: call void @__cxa_end_catch()
// OGCG: br label %[[TRY_CONT]]
// OGCG: [[TRY_CONT]]:
// OGCG: %[[TMP_RV:.*]] = load i32, ptr %[[RV_ADDR]], align 4
// OGCG: ret i32 %[[TMP_RV]]
// OGCG: [[EH_RESUME]]:
// OGCG: %[[TMP_EXCEPTION:.*]] = load ptr, ptr %[[EXCEPTION_ADDR]], align 8
// OGCG: %[[TMP_EH_TYPE_ID:.*]] = load i32, ptr %[[EH_TYPE_ID_ADDR]], align 4
// OGCG: %[[TMP_EXCEPTION_INFO:.*]] = insertvalue { ptr, i32 } poison, ptr %[[TMP_EXCEPTION]], 0
// OGCG: %[[EXCEPTION_INFO:.*]] = insertvalue { ptr, i32 } %[[TMP_EXCEPTION_INFO]], i32 %[[TMP_EH_TYPE_ID]], 1
// OGCG: resume { ptr, i32 } %[[EXCEPTION_INFO]]