diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td b/clang/include/clang/CIR/Dialect/IR/CIROps.td index 73012187483e3..b30dd980f5569 100644 --- a/clang/include/clang/CIR/Dialect/IR/CIROps.td +++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td @@ -7631,6 +7631,59 @@ def CIR_EndCatchOp : CIR_Op<"end_catch"> { let hasLLVMLowering = false; } +//===----------------------------------------------------------------------===// +// EH Operations: InitCatchParamOp +//===----------------------------------------------------------------------===// + +def CIR_InitCatchKind : CIR_I32EnumAttr< + "InitCatchKind", "", [ + I32EnumAttrCase<"Reference", 0, "reference">, + I32EnumAttrCase<"Pointer", 1, "pointer">, + I32EnumAttrCase<"Scalar", 2, "scalar">, + I32EnumAttrCase<"Objc", 3, "objc">, + I32EnumAttrCase<"TrivialCopy", 4, "trivial_copy">, + I32EnumAttrCase<"NonTrivialCopy", 5, "non_trivial_copy">, +]>; + +def CIR_InitCatchParamOp : CIR_Op<"init_catch_param"> { + let summary = "Initialize a catch parameter from the exception pointer"; + let description = [{ + `cir.init_catch_param` represents copying or otherwise materializing the + caught exception object into the local catch parameter variable. It takes + the exception pointer returned by `cir.begin_catch` and the address of + the alloca created for the catch parameter, and has no result. + + This operation is target-independent. It is replaced during EHABI + lowering with the appropriate target/ABI-specific sequence (for example, + the Itanium C++ ABI may emit a load and store for scalar/pointer catch + types, an aggregate copy for record types, or a call to a copy + constructor when one is required). + + Example: + + ``` + %catch_token, %exn_ptr = cir.begin_catch %eh_token + : !cir.eh_token -> (!cir.catch_token, !cir.ptr) + %param_addr = cir.alloca !s32i, !cir.ptr, ["e", init] + cir.init_catch_param %exn_ptr to %param_addr + : !cir.ptr, !cir.ptr + ``` + }]; + + let arguments = (ins + CIR_PointerType:$exn_ptr, + CIR_PointerType:$param_addr, + CIR_InitCatchKind:$kind + ); + + let assemblyFormat = [{ + $kind $exn_ptr `to` $param_addr `:` + qualified(type($exn_ptr)) `,` qualified(type($param_addr)) attr-dict + }]; + + let hasLLVMLowering = false; +} + //===----------------------------------------------------------------------===// // Atomic operations //===----------------------------------------------------------------------===// diff --git a/clang/lib/CIR/CodeGen/CIRGenCXXABI.h b/clang/lib/CIR/CodeGen/CIRGenCXXABI.h index 614d62fda44a5..bb100f7afd929 100644 --- a/clang/lib/CIR/CodeGen/CIRGenCXXABI.h +++ b/clang/lib/CIR/CodeGen/CIRGenCXXABI.h @@ -134,10 +134,6 @@ class CIRGenCXXABI { virtual void emitBadCastCall(CIRGenFunction &cgf, mlir::Location loc) = 0; - virtual void emitBeginCatch(CIRGenFunction &cgf, - const CXXCatchStmt *catchStmt, - mlir::Value ehToken) = 0; - virtual mlir::Attribute getAddrOfRTTIDescriptor(mlir::Location loc, QualType ty) = 0; diff --git a/clang/lib/CIR/CodeGen/CIRGenException.cpp b/clang/lib/CIR/CodeGen/CIRGenException.cpp index c80f292553a1c..3c956801f6b52 100644 --- a/clang/lib/CIR/CodeGen/CIRGenException.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenException.cpp @@ -273,6 +273,108 @@ void CIRGenFunction::addCatchHandlerAttr( } } +namespace { +struct CallEndCatch final : EHScopeStack::Cleanup { + CallEndCatch(mlir::Value catchToken) : catchToken(catchToken) {} + mlir::Value catchToken; + + void emit(CIRGenFunction &cgf, Flags flags) override { + cir::EndCatchOp::create(cgf.getBuilder(), *cgf.currSrcLoc, catchToken); + cir::YieldOp::create(cgf.getBuilder(), *cgf.currSrcLoc); + } +}; +} // namespace + +static mlir::Value callBeginCatch(CIRGenFunction &cgf, mlir::Value ehToken, + mlir::Type exnPtrTy) { + auto catchTokenTy = cir::CatchTokenType::get(cgf.getBuilder().getContext()); + auto beginCatch = cir::BeginCatchOp::create(cgf.getBuilder(), + cgf.getBuilder().getUnknownLoc(), + catchTokenTy, exnPtrTy, ehToken); + + cgf.ehStack.pushCleanup(NormalAndEHCleanup, + beginCatch.getCatchToken()); + + return beginCatch.getExnPtr(); +} + +/// A "special initializer" callback for initializing a catch +/// parameter during catch initialization. +static void initCatchParam(CIRGenFunction &cgf, CIRGenBuilderTy &builder, + mlir::Value ehToken, const VarDecl &catchParam, + SourceLocation loc) { + CanQualType catchType = + cgf.cgm.getASTContext().getCanonicalType(catchParam.getType()); + cir::InitCatchKind kind; + + // If we're catching by reference, we can just cast the object + // pointer to the appropriate pointer. + if (isa(catchType)) { + kind = cir::InitCatchKind::Reference; + } else { + cir::TypeEvaluationKind tek = cgf.getEvaluationKind(catchType); + if (tek == cir::TEK_Aggregate) { + assert(isa(catchType) && "unexpected catch type!"); + const Expr *copyExpr = catchParam.getInit(); + kind = !copyExpr ? cir::InitCatchKind::TrivialCopy + : cir::InitCatchKind::NonTrivialCopy; + } else { + // Scalars and complexes. + if (catchType->hasPointerRepresentation()) { + switch (catchType.getQualifiers().getObjCLifetime()) { + case Qualifiers::OCL_Weak: + case Qualifiers::OCL_Strong: + kind = cir::InitCatchKind::Objc; + break; + + case Qualifiers::OCL_ExplicitNone: + case Qualifiers::OCL_Autoreleasing: + case Qualifiers::OCL_None: + kind = cir::InitCatchKind::Pointer; + break; + } + } else { + kind = cir::InitCatchKind::Scalar; + } + } + } + + mlir::Value exnPtr = callBeginCatch(cgf, ehToken, builder.getVoidPtrTy()); + CIRGenFunction::AutoVarEmission var = cgf.emitAutoVarAlloca(catchParam); + cir::InitCatchParamOp::create(builder, cgf.getLoc(loc), exnPtr, + var.getAllocatedAddress().getPointer(), kind); + cgf.emitAutoVarCleanups(var); +} + +/// Begins a catch statement by initializing the catch variable and +/// calling __cxa_begin_catch. +void CIRGenFunction::emitBeginCatch(const CXXCatchStmt *catchStmt, + mlir::Value ehToken) { + // We have to be very careful with the ordering of cleanups here: + // C++ [except.throw]p4: + // The destruction [of the exception temporary] occurs + // immediately after the destruction of the object declared in + // the exception-declaration in the handler. + // + // So the precise ordering is: + // 1. Construct catch variable. + // 2. begin_catch + // 3. Enter CallEndCatch cleanup + // 4. Enter dtor cleanup + // + VarDecl *catchParam = catchStmt->getExceptionDecl(); + if (!catchParam) { + callBeginCatch(*this, ehToken, builder.getVoidPtrTy()); + return; + } + + // Emit the local. Make sure the alloca's superseed the current scope, since + // these are going to be consumed by `cir.catch`, which is not within the + // current scope. + initCatchParam(*this, builder, ehToken, *catchParam, + catchStmt->getBeginLoc()); +} + mlir::LogicalResult CIRGenFunction::emitCXXTryStmt(const CXXTryStmt &s, cxxTryBodyEmitter &bodyCallback) { @@ -295,8 +397,8 @@ CIRGenFunction::emitCXXTryStmt(const CXXTryStmt &s, builder.restoreInsertionPoint(scopeIP); const llvm::Triple &t = getTarget().getTriple(); - // If we encounter a try statement on in an OpenMP target region offloaded to - // a GPU, we treat it as a basic block. + // If we encounter a try statement on in an OpenMP target region offloaded + // to a GPU, we treat it as a basic block. const bool isTargetDevice = (cgm.getLangOpts().OpenMPIsTargetDevice && (t.isNVPTX() || t.isAMDGCN())); if (isTargetDevice) { @@ -384,7 +486,7 @@ CIRGenFunction::emitCXXTryStmt(const CXXTryStmt &s, // Initialize the catch variable. // TODO(cir): Move this out of CXXABI. assert(!cir::MissingFeatures::currentFuncletPad()); - cgm.getCXXABI().emitBeginCatch(*this, catchStmt, ehToken); + emitBeginCatch(catchStmt, ehToken); // Emit the PGO counter increment. assert(!cir::MissingFeatures::incrementProfileCounter()); @@ -435,15 +537,16 @@ mlir::LogicalResult CIRGenFunction::emitCXXTryStmt(const CXXTryStmt &s) { return emitCXXTryStmt(s, emitter); } -// in classic codegen this function is mapping to `isInvokeDest` previously and -// currently it's mapping to the conditions that performs early returns in -// `getInvokeDestImpl`, in CIR we need the condition to know if the EH scope may -// throw exception or now. +// in classic codegen this function is mapping to `isInvokeDest` previously +// and currently it's mapping to the conditions that performs early returns in +// `getInvokeDestImpl`, in CIR we need the condition to know if the EH scope +// may throw exception or now. bool CIRGenFunction::isCatchOrCleanupRequired() { - // If exceptions are disabled/ignored and SEH is not in use, then there is no - // invoke destination. SEH "works" even if exceptions are off. In practice, - // this means that C++ destructors and other EH cleanups don't run, which is - // consistent with MSVC's behavior, except in the presence of -EHa + // If exceptions are disabled/ignored and SEH is not in use, then there is + // no invoke destination. SEH "works" even if exceptions are off. In + // practice, this means that C++ destructors and other EH cleanups don't + // run, which is consistent with MSVC's behavior, except in the presence of + // -EHa const LangOptions &lo = cgm.getLangOpts(); if (!lo.Exceptions || lo.IgnoreExceptions) { if (!lo.Borland && !lo.MicrosoftExt) diff --git a/clang/lib/CIR/CodeGen/CIRGenFunction.h b/clang/lib/CIR/CodeGen/CIRGenFunction.h index f3eb5982c041f..aadd2ff741650 100644 --- a/clang/lib/CIR/CodeGen/CIRGenFunction.h +++ b/clang/lib/CIR/CodeGen/CIRGenFunction.h @@ -1798,6 +1798,8 @@ class CIRGenFunction : public CIRGenTypeCache { virtual ~cxxTryBodyEmitter() = default; }; + void emitBeginCatch(const CXXCatchStmt *catchStmt, mlir::Value ehToken); + mlir::LogicalResult emitCXXTryStmt(const clang::CXXTryStmt &s, cxxTryBodyEmitter &bodyCallback); mlir::LogicalResult emitCXXTryStmt(const clang::CXXTryStmt &s); diff --git a/clang/lib/CIR/CodeGen/CIRGenItaniumCXXABI.cpp b/clang/lib/CIR/CodeGen/CIRGenItaniumCXXABI.cpp index b7b149923e78f..daff196b0355a 100644 --- a/clang/lib/CIR/CodeGen/CIRGenItaniumCXXABI.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenItaniumCXXABI.cpp @@ -82,9 +82,6 @@ class CIRGenItaniumCXXABI : public CIRGenCXXABI { void emitRethrow(CIRGenFunction &cgf, bool isNoReturn) override; void emitThrow(CIRGenFunction &cgf, const CXXThrowExpr *e) override; - void emitBeginCatch(CIRGenFunction &cgf, const CXXCatchStmt *catchStmt, - mlir::Value ehToken) override; - bool useThunkForDtorVariant(const CXXDestructorDecl *dtor, CXXDtorType dt) const override { // Itanium does not emit any destructor variant as an inline thunk. @@ -2483,242 +2480,6 @@ Address CIRGenItaniumCXXABI::initializeArrayCookie(CIRGenFunction &cgf, return Address(finalPtr, newPtr.getElementType(), finalAlignment); } -namespace { -/// From traditional LLVM, useful info for LLVM lowering support: -/// A cleanup to call __cxa_end_catch. In many cases, the caught -/// exception type lets us state definitively that the thrown exception -/// type does not have a destructor. In particular: -/// - Catch-alls tell us nothing, so we have to conservatively -/// assume that the thrown exception might have a destructor. -/// - Catches by reference behave according to their base types. -/// - Catches of non-record types will only trigger for exceptions -/// of non-record types, which never have destructors. -/// - Catches of record types can trigger for arbitrary subclasses -/// of the caught type, so we have to assume the actual thrown -/// exception type might have a throwing destructor, even if the -/// caught type's destructor is trivial or nothrow. -struct CallEndCatch final : EHScopeStack::Cleanup { - CallEndCatch(bool mightThrow, mlir::Value catchToken) - : mightThrow(mightThrow), catchToken(catchToken) {} - bool mightThrow; - mlir::Value catchToken; - - void emit(CIRGenFunction &cgf, Flags flags) override { - // Traditional LLVM codegen would emit a call to __cxa_end_catch - // here. For CIR, just let it pass since the cleanup is going - // to be emitted on a later pass when lowering the catch region. - // CGF.EmitRuntimeCallOrTryCall(getEndCatchFn(CGF.CGM)); - cir::EndCatchOp::create(cgf.getBuilder(), *cgf.currSrcLoc, catchToken); - cir::YieldOp::create(cgf.getBuilder(), *cgf.currSrcLoc); - } -}; -} // namespace - -static mlir::Value callBeginCatch(CIRGenFunction &cgf, mlir::Value ehToken, - mlir::Type exnPtrTy, bool endMightThrow) { - auto catchTokenTy = cir::CatchTokenType::get(cgf.getBuilder().getContext()); - auto beginCatch = cir::BeginCatchOp::create(cgf.getBuilder(), - cgf.getBuilder().getUnknownLoc(), - catchTokenTy, exnPtrTy, ehToken); - - cgf.ehStack.pushCleanup( - NormalAndEHCleanup, - endMightThrow && !cgf.cgm.getLangOpts().AssumeNothrowExceptionDtor, - beginCatch.getCatchToken()); - - return beginCatch.getExnPtr(); -} - -/// A "special initializer" callback for initializing a catch -/// parameter during catch initialization. -static void initCatchParam(CIRGenFunction &cgf, mlir::Value ehToken, - const VarDecl &catchParam, Address paramAddr, - SourceLocation loc) { - CanQualType catchType = - cgf.cgm.getASTContext().getCanonicalType(catchParam.getType()); - mlir::Type cirCatchTy = cgf.convertTypeForMem(catchType); - - // If we're catching by reference, we can just cast the object - // pointer to the appropriate pointer. - if (isa(catchType)) { - QualType caughtType = cast(catchType)->getPointeeType(); - bool endCatchMightThrow = caughtType->isRecordType(); - - mlir::Value adjustedExn = - callBeginCatch(cgf, ehToken, cirCatchTy, endCatchMightThrow); - - // We have no way to tell the personality function that we're - // catching by reference, so if we're catching a pointer, - // __cxa_begin_catch will actually return that pointer by value. - if (const PointerType *pt = dyn_cast(caughtType)) { - QualType pointeeType = pt->getPointeeType(); - // When catching by reference, generally we should just ignore - // this by-value pointer and use the exception object instead. - if (!pointeeType->isRecordType()) { - cgf.cgm.errorNYI(loc, - "initCatchParam: catching a pointer of non-record"); - } else { - // Pull the pointer for the reference type off. - mlir::Type ptrTy = cgf.convertTypeForMem(caughtType); - - // Create the temporary and write the adjusted pointer into it. - Address exnPtrTmp = cgf.createTempAlloca( - ptrTy, cgf.getPointerAlign(), cgf.getLoc(loc), "exn.byref.tmp"); - mlir::Value casted = cgf.getBuilder().createBitcast(adjustedExn, ptrTy); - cgf.getBuilder().createStore(cgf.getLoc(loc), casted, exnPtrTmp); - - // Bind the reference to the temporary. - adjustedExn = exnPtrTmp.emitRawPointer(); - } - } - - mlir::Value exnCast = - cgf.getBuilder().createBitcast(adjustedExn, cirCatchTy); - cgf.getBuilder().createStore(cgf.getLoc(loc), exnCast, paramAddr); - return; - } - - // Scalars and complexes. - cir::TypeEvaluationKind tek = cgf.getEvaluationKind(catchType); - if (tek != cir::TEK_Aggregate) { - // Notes for LLVM lowering: - // If the catch type is a pointer type, __cxa_begin_catch returns - // the pointer by value. - if (catchType->hasPointerRepresentation()) { - mlir::Value catchParam = - callBeginCatch(cgf, ehToken, cirCatchTy, /*endMightThrow=*/false); - switch (catchType.getQualifiers().getObjCLifetime()) { - case Qualifiers::OCL_Strong: - cgf.cgm.errorNYI(loc, - "initCatchParam: PointerRepresentation OCL_Strong"); - return; - - case Qualifiers::OCL_ExplicitNone: - case Qualifiers::OCL_Autoreleasing: - cgf.cgm.errorNYI(loc, "initCatchParam: PointerRepresentation " - "OCL_ExplicitNone & OCL_Autoreleasing"); - return; - - case Qualifiers::OCL_None: - cgf.getBuilder().createStore(cgf.getLoc(loc), catchParam, paramAddr); - return; - - case Qualifiers::OCL_Weak: - cgf.cgm.errorNYI(loc, "initCatchParam: PointerRepresentation OCL_Weak"); - return; - } - - llvm_unreachable("bad ownership qualifier!"); - } - - // Otherwise, it returns a pointer into the exception object. - mlir::Type cirCatchTy = cgf.convertTypeForMem(catchType); - mlir::Value catchParam = - callBeginCatch(cgf, ehToken, cgf.getBuilder().getPointerTo(cirCatchTy), - /*endMightThrow=*/false); - LValue srcLV = cgf.makeNaturalAlignAddrLValue(catchParam, catchType); - LValue destLV = cgf.makeAddrLValue(paramAddr, catchType); - switch (tek) { - case cir::TEK_Complex: { - mlir::Value load = cgf.emitLoadOfComplex(srcLV, loc); - cgf.emitStoreOfComplex(cgf.getLoc(loc), load, destLV, /*isInit=*/true); - return; - } - case cir::TEK_Scalar: { - mlir::Value exnLoad = cgf.emitLoadOfScalar(srcLV, loc); - cgf.emitStoreOfScalar(exnLoad, destLV, /*isInit=*/true); - return; - } - case cir::TEK_Aggregate: - llvm_unreachable("evaluation kind filtered out!"); - } - - llvm_unreachable("bad evaluation kind"); - } - - assert(isa(catchType) && "unexpected catch type!"); - auto *catchRD = catchType->getAsCXXRecordDecl(); - CharUnits caughtExnAlignment = cgf.cgm.getClassPointerAlignment(catchRD); - - // Check for a copy expression. If we don't have a copy expression, - // that means a trivial copy is okay. - const Expr *copyExpr = catchParam.getInit(); - if (!copyExpr) { - mlir::Type cirCatchPtrTy = cgf.getBuilder().getPointerTo(cirCatchTy); - mlir::Value rawAdjustedExn = - callBeginCatch(cgf, ehToken, cirCatchPtrTy, /*endMightThrow=*/true); - Address adjustedExn(rawAdjustedExn, cirCatchTy, caughtExnAlignment); - LValue dest = cgf.makeAddrLValue(paramAddr, catchType); - LValue src = cgf.makeAddrLValue(adjustedExn, catchType); - cgf.emitAggregateCopy(dest, src, catchType, AggValueSlot::DoesNotOverlap); - return; - } - - cgf.cgm.errorNYI(loc, "initCatchParam: cir::TEK_Aggregate non-trivial copy"); -} - -/// Begins a catch statement by initializing the catch variable and -/// calling __cxa_begin_catch. -void CIRGenItaniumCXXABI::emitBeginCatch(CIRGenFunction &cgf, - const CXXCatchStmt *catchStmt, - mlir::Value ehToken) { - // We have to be very careful with the ordering of cleanups here: - // C++ [except.throw]p4: - // The destruction [of the exception temporary] occurs - // immediately after the destruction of the object declared in - // the exception-declaration in the handler. - // - // So the precise ordering is: - // 1. Construct catch variable. - // 2. __cxa_begin_catch - // 3. Enter __cxa_end_catch cleanup - // 4. Enter dtor cleanup - // - // We do this by using a slightly abnormal initialization process. - // Delegation sequence: - // - ExitCXXTryStmt opens a RunCleanupsScope - // - EmitAutoVarAlloca creates the variable and debug info - // - InitCatchParam initializes the variable from the exception - // - CallBeginCatch calls __cxa_begin_catch - // - CallBeginCatch enters the __cxa_end_catch cleanup - // - EmitAutoVarCleanups enters the variable destructor cleanup - // - EmitCXXTryStmt emits the code for the catch body - // - EmitCXXTryStmt close the RunCleanupsScope - - VarDecl *catchParam = catchStmt->getExceptionDecl(); - if (!catchParam) { - callBeginCatch(cgf, ehToken, cgf.getBuilder().getVoidPtrTy(), - /*endMightThrow=*/true); - return; - } - - auto getCatchParamAllocaIP = [&]() { - cir::CIRBaseBuilderTy::InsertPoint currIns = - cgf.getBuilder().saveInsertionPoint(); - mlir::Operation *currParent = currIns.getBlock()->getParentOp(); - - mlir::Block *insertBlock = nullptr; - if (auto scopeOp = currParent->getParentOfType()) { - insertBlock = &scopeOp.getScopeRegion().getBlocks().back(); - } else if (auto fnOp = currParent->getParentOfType()) { - insertBlock = &fnOp.getRegion().getBlocks().back(); - } else { - llvm_unreachable("unknown outermost scope-like parent"); - } - return cgf.getBuilder().getBestAllocaInsertPoint(insertBlock); - }; - - // Emit the local. Make sure the alloca's superseed the current scope, since - // these are going to be consumed by `cir.catch`, which is not within the - // current scope. - - CIRGenFunction::AutoVarEmission var = - cgf.emitAutoVarAlloca(*catchParam, getCatchParamAllocaIP()); - initCatchParam(cgf, ehToken, *catchParam, var.getObjectAddress(cgf), - catchStmt->getBeginLoc()); - cgf.emitAutoVarCleanups(var); -} - bool CIRGenItaniumCXXABI::hasAnyUnusedVirtualInlineFunction( const CXXRecordDecl *rd) const { const auto &vtableLayout = cgm.getItaniumVTableContext().getVTableLayout(rd); diff --git a/clang/lib/CIR/Dialect/Transforms/EHABILowering.cpp b/clang/lib/CIR/Dialect/Transforms/EHABILowering.cpp index abdc32951f857..baec91de9f89c 100644 --- a/clang/lib/CIR/Dialect/Transforms/EHABILowering.cpp +++ b/clang/lib/CIR/Dialect/Transforms/EHABILowering.cpp @@ -130,6 +130,7 @@ class ItaniumEHLowering : public EHABILowering { void lowerDispatch(cir::EhDispatchOp dispatch, mlir::Value exnPtr, mlir::Value typeId, SmallVectorImpl &deadOps); + void lowerInitCatchParam(cir::InitCatchParamOp op); }; /// Lower all EH operations in the module to the Itanium-specific form. @@ -278,6 +279,14 @@ mlir::LogicalResult ItaniumEHLowering::lowerFunc(cir::FuncOp funcOp) { } } + // Lower any cir.init_catch_param ops in this function. These materialize + // the catch parameter local from the (already lowered) begin_catch result, + // and are independent of the eh_token graph traversal above. + SmallVector initCatchOps; + funcOp.walk([&](cir::InitCatchParamOp op) { initCatchOps.push_back(op); }); + for (cir::InitCatchParamOp op : initCatchOps) + lowerInitCatchParam(op); + return mlir::success(); } @@ -529,6 +538,88 @@ void ItaniumEHLowering::lowerDispatch( deadOps.push_back(dispatch); } +/// Lower a cir.init_catch_param into the Itanium-specific sequence that +/// materializes the catch parameter's local variable from the exception +/// pointer returned by __cxa_begin_catch. The shape of the lowering +/// depends on the init catch kind: +/// +/// - Reference: the begin_catch result is +/// the pointer value itself, so just bitcast and store it into the alloca +/// except if it reference of pointer of record. +/// - Pointer: the begin_catch result is +/// the pointer value itself, so just bitcast and store it into the +/// alloca. +/// - Scalar (any other by-value catch): treat the begin_catch result as a +/// pointer to the value, load it, and store it into the alloca. +/// - Objc: Handle pointer representation with ObjCLifetime. +/// - TrivialCopy: copy the exception +/// object's bytes into the alloca via cir.copy. +/// - NonTrivialCopy: copy the exception +/// object's bytes into the alloca via copy constructor. +/// +void ItaniumEHLowering::lowerInitCatchParam(cir::InitCatchParamOp op) { + builder.setInsertionPoint(op); + mlir::Location loc = op.getLoc(); + mlir::Value exnPtr = op.getExnPtr(); + mlir::Value paramAddr = op.getParamAddr(); + auto paramAddrType = mlir::cast(paramAddr.getType()); + mlir::Type elementType = paramAddrType.getPointee(); + cir::InitCatchKind kind = op.getKind(); + + switch (kind) { + case InitCatchKind::Reference: { + // We have no way to tell the personality function that we're + // catching by reference, so if we're catching a pointer, + // __cxa_begin_catch will actually return that pointer by value. + if (const auto ref = mlir::dyn_cast(elementType)) { + // When catching by reference, generally we should just ignore + // this by-value pointer and use the exception object instead. + if (auto ptr = mlir::dyn_cast(ref.getPointee())) + if (!mlir::isa(ptr.getPointee())) + llvm_unreachable( + "InitCatchParam: reference of pointer or non-record is NYI"); + } + + mlir::Value casted = cir::CastOp::create(builder, loc, elementType, + cir::CastKind::bitcast, exnPtr); + cir::StoreOp::create(builder, loc, casted, paramAddr, {}, {}, {}, {}); + break; + } + case InitCatchKind::TrivialCopy: { + mlir::Value srcPtr = cir::CastOp::create(builder, loc, paramAddrType, + cir::CastKind::bitcast, exnPtr); + cir::CopyOp::create(builder, loc, paramAddr, srcPtr, {}, {}); + break; + } + case InitCatchKind::NonTrivialCopy: { + llvm_unreachable("InitCatchParam: non-trivial-copy is NYI"); + break; + } + case InitCatchKind::Scalar: { + // Scalar by-value catch (integer, float, complex, etc.). The begin_catch + // result points into the exception object; load the value through a + // typed pointer and store it into the alloca. + mlir::Value srcPtr = cir::CastOp::create(builder, loc, paramAddrType, + cir::CastKind::bitcast, exnPtr); + auto loadOp = cir::LoadOp::create(builder, loc, elementType, srcPtr); + cir::StoreOp::create(builder, loc, loadOp.getResult(), paramAddr, {}, {}, + {}, {}); + break; + } + case InitCatchKind::Pointer: { + mlir::Value casted = cir::CastOp::create(builder, loc, elementType, + cir::CastKind::bitcast, exnPtr); + cir::StoreOp::create(builder, loc, casted, paramAddr, {}, {}, {}, {}); + break; + } + case InitCatchKind::Objc: + llvm_unreachable("InitCatchParam: ObjCLifetime is NYI"); + break; + } + + op.erase(); +} + //===----------------------------------------------------------------------===// // The Pass //===----------------------------------------------------------------------===// @@ -542,9 +633,9 @@ struct CIREHABILoweringPass void CIREHABILoweringPass::runOnOperation() { auto mod = mlir::cast(getOperation()); - // The target triple is attached to the module as the "cir.triple" attribute. - // If it is absent (e.g. a CIR module parsed from text without a triple) we - // cannot determine the ABI and must skip the pass. + // The target triple is attached to the module as the "cir.triple" + // attribute. If it is absent (e.g. a CIR module parsed from text without a + // triple) we cannot determine the ABI and must skip the pass. auto tripleAttr = mlir::dyn_cast_if_present( mod->getAttr(cir::CIRDialect::getTripleAttrName())); if (!tripleAttr) { diff --git a/clang/test/CIR/CodeGen/try-catch-all-with-cleanup.cpp b/clang/test/CIR/CodeGen/try-catch-all-with-cleanup.cpp index 3827275bfc1be..6594165b823cb 100644 --- a/clang/test/CIR/CodeGen/try-catch-all-with-cleanup.cpp +++ b/clang/test/CIR/CodeGen/try-catch-all-with-cleanup.cpp @@ -161,10 +161,9 @@ void test_catch_all_and_specific_with_cleanup() { // CIR: } // CIR: cir.yield // CIR: } catch [type #cir.global_view<@_ZTIi> : !cir.ptr] (%{{.*}}: !cir.eh_token {{.*}}) { -// CIR: %{{.*}}, %[[EXN:.*]] = cir.begin_catch %{{.*}} : !cir.eh_token -> (!cir.catch_token, !cir.ptr) +// CIR: %{{.*}}, %[[EXN:.*]] = cir.begin_catch %{{.*}} : !cir.eh_token -> (!cir.catch_token, !cir.ptr) // CIR: cir.cleanup.scope { -// CIR: cir.load{{.*}} %[[EXN]] : !cir.ptr, !s32i -// CIR: cir.store{{.*}} %{{.*}}, %[[E]] : !s32i, !cir.ptr +// CIR: cir.init_catch_param scalar %[[EXN]] to %[[E]] : !cir.ptr, !cir.ptr // CIR: cir.yield // CIR: } cleanup all { // CIR: cir.end_catch %{{.*}} : !cir.catch_token @@ -186,7 +185,6 @@ void test_catch_all_and_specific_with_cleanup() { // CIR-FLAT-LABEL: cir.func {{.*}} @_Z40test_catch_all_and_specific_with_cleanupv() // // CIR-FLAT: %[[S:.*]] = cir.alloca !rec_S -// CIR-FLAT: %[[E:.*]] = cir.alloca !s32i // // Ctor may throw; unwinds directly to the dispatch (no cleanup needed yet). // CIR-FLAT: cir.try_call @_ZN1SC1Ev(%[[S]]) ^[[AFTER_CTOR:bb[0-9]+]], ^[[CTOR_UNWIND:bb[0-9]+]] @@ -226,9 +224,8 @@ void test_catch_all_and_specific_with_cleanup() { // // Catch (int): bind e, end_catch, merge to return. // CIR-FLAT: ^[[CATCH_INT]](%{{.*}}: !cir.eh_token): -// CIR-FLAT: %{{.*}}, %[[EXN_PTR:.*]] = cir.begin_catch %{{.*}} : !cir.eh_token -> (!cir.catch_token, !cir.ptr) -// CIR-FLAT: cir.load{{.*}} %[[EXN_PTR]] : !cir.ptr, !s32i -// CIR-FLAT: cir.store{{.*}} %{{.*}}, %[[E]] : !s32i, !cir.ptr +// CIR-FLAT: %{{.*}}, %[[EXN_PTR:.*]] = cir.begin_catch %{{.*}} : !cir.eh_token -> (!cir.catch_token, !cir.ptr) +// CIR-FLAT: cir.init_catch_param scalar %[[EXN_PTR]] to %{{.*}} : !cir.ptr, !cir.ptr // CIR-FLAT: cir.end_catch %{{.*}} : !cir.catch_token // CIR-FLAT: cir.br ^{{.*}} // @@ -248,7 +245,6 @@ void test_catch_all_and_specific_with_cleanup() { // LLVM-LABEL: define {{.*}} void @_Z40test_catch_all_and_specific_with_cleanupv() // LLVM-SAME: personality ptr @__gxx_personality_v0 // LLVM: %[[S:.*]] = alloca %struct.S -// LLVM: %[[E:.*]] = alloca i32 // LLVM: invoke void @_ZN1SC1Ev({{.*}}%[[S]]) // LLVM: to label %[[AFTER_CTOR:.*]] unwind label %[[CTOR_LP:.*]] // LLVM: [[AFTER_CTOR]]: @@ -269,8 +265,6 @@ void test_catch_all_and_specific_with_cleanup() { // LLVM: icmp eq i32 {{.*}}, {{.*}} // LLVM: {{.*}}: // LLVM: call ptr @__cxa_begin_catch -// LLVM: load i32, ptr {{.*}} -// LLVM: store i32 {{.*}}, ptr %[[E]] // LLVM: call void @__cxa_end_catch() // LLVM: {{.*}}: // LLVM: call ptr @__cxa_begin_catch diff --git a/clang/test/CIR/CodeGen/try-catch.cpp b/clang/test/CIR/CodeGen/try-catch.cpp index 7f50c7ca6ec28..dd9ed9d97b795 100644 --- a/clang/test/CIR/CodeGen/try-catch.cpp +++ b/clang/test/CIR/CodeGen/try-catch.cpp @@ -127,6 +127,7 @@ void try_catch_with_alloca() { } } +// CIR: cir.func {{.*}} @_Z21try_catch_with_allocav() personality(@__gxx_personality_v0) // CIR: cir.scope { // CIR: %[[A_ADDR:.*]] = cir.alloca !s32i, !cir.ptr, ["a"] // CIR: %[[B_ADDR:.*]] = cir.alloca !s32i, !cir.ptr, ["b"] @@ -213,7 +214,7 @@ void call_function_inside_try_catch_all() { // CIR: %[[CATCH_TOKEN:.*]], %[[EXN_PTR:.*]] = cir.begin_catch %[[EH_TOKEN]] : !cir.eh_token -> (!cir.catch_token, !cir.ptr) // CIR: cir.cleanup.scope { // CIR: cir.yield -// CIR: } cleanup {{.*}} { +// CIR: } cleanup all { // CIR: cir.end_catch %[[CATCH_TOKEN]] : !cir.catch_token // CIR: cir.yield // CIR: } @@ -291,17 +292,15 @@ void call_function_inside_try_catch_with_exception_type() { // CIR: cir.func {{.*}} @_Z50call_function_inside_try_catch_with_exception_typev() personality(@__gxx_personality_v0) // CIR: cir.scope { -// CIR: %[[EXCEPTION_ADDR:.*]] = cir.alloca !s32i, !cir.ptr, ["e"] // CIR: cir.try { // CIR: %[[CALL:.*]] = cir.call @_Z8divisionv() // CIR: cir.yield // CIR: } catch [type #cir.global_view<@_ZTIi> : !cir.ptr] (%[[EH_TOKEN:.*]]: !cir.eh_token{{.*}}) { -// CIR: %[[CATCH_TOKEN:.*]], %[[EXN_PTR:.*]] = cir.begin_catch %[[EH_TOKEN]] : !cir.eh_token -> (!cir.catch_token, !cir.ptr) +// CIR: %[[CATCH_TOKEN:.*]], %[[EXN_PTR:.*]] = cir.begin_catch %[[EH_TOKEN]] : !cir.eh_token -> (!cir.catch_token, !cir.ptr) // CIR: cir.cleanup.scope { -// CIR: %[[TMP:.*]] = cir.load {{.*}} %[[EXN_PTR]] : !cir.ptr, !s32i -// CIR: cir.store {{.*}} %[[TMP]], %[[EXCEPTION_ADDR]] : !s32i, !cir.ptr +// CIR: cir.init_catch_param scalar %[[EXN_PTR]] to %{{.*}} : !cir.ptr, !cir.ptr // CIR: cir.yield -// CIR: } cleanup {{.*}} { +// CIR: } cleanup all { // CIR: cir.end_catch %[[CATCH_TOKEN]] : !cir.catch_token // CIR: cir.yield // CIR: } @@ -342,8 +341,6 @@ void call_function_inside_try_catch_with_exception_type() { // LLVM: %[[TOKEN:.*]] = call ptr @__cxa_begin_catch(ptr %[[EXN_OBJ_PHI2]]) // LLVM: br label %[[CATCH_BODY:.*]] // LLVM: [[CATCH_BODY]]: -// LLVM: %[[LOAD:.*]] = load i32, ptr %[[TOKEN]], align 4 -// LLVM: store i32 %[[LOAD]], ptr {{.*}}, align 4 // LLVM: br label %[[END_CATCH:.*]] // LLVM: [[END_CATCH]]: // LLVM: call void @__cxa_end_catch() @@ -409,14 +406,13 @@ void call_function_inside_try_catch_with_ref_exception_type() { // CIR: cir.func {{.*}} @_Z54call_function_inside_try_catch_with_ref_exception_typev() personality(@__gxx_personality_v0) // CIR: cir.scope { -// CIR: %[[EXCEPTION_ADDR:.*]] = cir.alloca !cir.ptr, !cir.ptr>, ["ref", const] // CIR: cir.try { // CIR: %[[CALL:.*]] = cir.call @_Z8divisionv() // CIR: cir.yield // CIR: } catch [type #cir.global_view<@_ZTIi> : !cir.ptr] (%{{.*}}: !cir.eh_token {{.*}}) { -// CIR: %[[CATCH_TOKEN:.*]], %[[EXN_PTR:.*]] = cir.begin_catch %{{.*}} : !cir.eh_token -> (!cir.catch_token, !cir.ptr) +// CIR: %[[CATCH_TOKEN:.*]], %[[EXN_PTR:.*]] = cir.begin_catch %{{.*}} : !cir.eh_token -> (!cir.catch_token, !cir.ptr) // CIR: cir.cleanup.scope { -// CIR: cir.store {{.*}} %[[EXN_PTR]], %[[EXCEPTION_ADDR]] : !cir.ptr, !cir.ptr> +// CIR: cir.init_catch_param reference %[[EXN_PTR]] to %{{.*}} : !cir.ptr, !cir.ptr> // CIR: cir.yield // CIR: } cleanup all { // CIR: cir.end_catch %[[CATCH_TOKEN]] : !cir.catch_token @@ -459,7 +455,6 @@ void call_function_inside_try_catch_with_ref_exception_type() { // LLVM: %[[TOKEN:.*]] = call ptr @__cxa_begin_catch(ptr %[[EXN_OBJ_PHI2]]) // LLVM: br label %[[CATCH_BODY:.*]] // LLVM: [[CATCH_BODY]]: -// LLVM: store ptr %[[TOKEN]], ptr %{{.*}}, align 8 // LLVM: br label %[[END_CATCH:.*]] // LLVM: [[END_CATCH]]: // LLVM: call void @__cxa_end_catch() @@ -524,17 +519,15 @@ void call_function_inside_try_catch_with_complex_exception_type() { // CIR: cir.func {{.*}} @_Z58call_function_inside_try_catch_with_complex_exception_typev() personality(@__gxx_personality_v0) // CIR: cir.scope { -// CIR: %[[EXCEPTION_ADDR:.*]] = cir.alloca !cir.complex, !cir.ptr>, ["e"] // CIR: cir.try { // CIR: %[[CALL:.*]] = cir.call @_Z8divisionv() // CIR: cir.yield // CIR: } catch [type #cir.global_view<@_ZTICi> : !cir.ptr] (%[[EH_TOKEN:.*]]: !cir.eh_token{{.*}}) { -// CIR: %[[CATCH_TOKEN:.*]], %[[EXN_PTR:.*]] = cir.begin_catch %[[EH_TOKEN]] : !cir.eh_token -> (!cir.catch_token, !cir.ptr>) +// CIR: %[[CATCH_TOKEN:.*]], %[[EXN_PTR:.*]] = cir.begin_catch %[[EH_TOKEN]] : !cir.eh_token -> (!cir.catch_token, !cir.ptr) // CIR: cir.cleanup.scope { -// CIR: %[[TMP:.*]] = cir.load {{.*}} %[[EXN_PTR]] : !cir.ptr>, !cir.complex -// CIR: cir.store {{.*}} %[[TMP]], %[[EXCEPTION_ADDR]] : !cir.complex, !cir.ptr> +// CIR: cir.init_catch_param scalar %[[EXN_PTR]] to %{{.*}} : !cir.ptr, !cir.ptr> // CIR: cir.yield -// CIR: } cleanup {{.*}} { +// CIR: } cleanup all { // CIR: cir.end_catch %[[CATCH_TOKEN]] : !cir.catch_token // CIR: cir.yield // CIR: } @@ -575,8 +568,6 @@ void call_function_inside_try_catch_with_complex_exception_type() { // LLVM: %[[TOKEN:.*]] = call ptr @__cxa_begin_catch(ptr %[[EXN_OBJ_PHI2]]) // LLVM: br label %[[CATCH_BODY:.*]] // LLVM: [[CATCH_BODY]]: -// LLVM: %[[LOAD:.*]] = load { i32, i32 }, ptr %[[TOKEN]], align 4 -// LLVM: store { i32, i32 } %[[LOAD]], ptr {{.*}}, align 4 // LLVM: br label %[[END_CATCH:.*]] // LLVM: [[END_CATCH]]: // LLVM: call void @__cxa_end_catch() @@ -648,16 +639,15 @@ void call_function_inside_try_catch_with_array_exception_type() { // CIR: cir.func {{.*}} @_Z56call_function_inside_try_catch_with_array_exception_typev() personality(@__gxx_personality_v0) // CIR: cir.scope { -// CIR: %[[E_ADDR:.*]] = cir.alloca !cir.ptr, !cir.ptr>, ["e"] // CIR: cir.try { // CIR: %[[CALL:.*]] = cir.call @_Z8divisionv() // CIR: cir.yield // CIR: } catch [type #cir.global_view<@_ZTIPi> : !cir.ptr] (%[[EH_TOKEN:.*]]: !cir.eh_token{{.*}}) { -// CIR: %[[CATCH_TOKEN:.*]], %[[EXN_PTR:.*]] = cir.begin_catch %[[EH_TOKEN]] : !cir.eh_token -> (!cir.catch_token, !cir.ptr) +// CIR: %[[CATCH_TOKEN:.*]], %[[EXN_PTR:.*]] = cir.begin_catch %[[EH_TOKEN]] : !cir.eh_token -> (!cir.catch_token, !cir.ptr) // CIR: cir.cleanup.scope { -// CIR: cir.store {{.*}} %[[EXN_PTR]], %[[E_ADDR]] : !cir.ptr, !cir.ptr> +// CIR: cir.init_catch_param pointer %[[EXN_PTR]] to %{{.*}} : !cir.ptr, !cir.ptr> // CIR: cir.yield -// CIR: } cleanup {{.*}} { +// CIR: } cleanup all { // CIR: cir.end_catch %[[CATCH_TOKEN]] : !cir.catch_token // CIR: cir.yield // CIR: } @@ -698,7 +688,6 @@ void call_function_inside_try_catch_with_array_exception_type() { // LLVM: %[[TOKEN:.*]] = call ptr @__cxa_begin_catch(ptr %[[EXN_OBJ_PHI2]]) // LLVM: br label %[[CATCH_BODY:.*]] // LLVM: [[CATCH_BODY]]: -// LLVM: store ptr %[[TOKEN]], ptr {{.*}}, align 8 // LLVM: br label %[[END_CATCH:.*]] // LLVM: [[END_CATCH]]: // LLVM: call void @__cxa_end_catch() @@ -764,17 +753,15 @@ void call_function_inside_try_catch_with_exception_type_and_catch_all() { // CIR: cir.func {{.*}} @_Z64call_function_inside_try_catch_with_exception_type_and_catch_allv() personality(@__gxx_personality_v0) // CIR: cir.scope { -// CIR: %[[EXCEPTION_ADDR:.*]] = cir.alloca !s32i, !cir.ptr, ["e"] // CIR: cir.try { // CIR: %[[CALL:.*]] = cir.call @_Z8divisionv() // CIR: cir.yield // CIR: } catch [type #cir.global_view<@_ZTIi> : !cir.ptr] (%[[EH_TOKEN:.*]]: !cir.eh_token{{.*}}) { -// CIR: %[[CATCH_TOKEN:.*]], %[[EXN_PTR:.*]] = cir.begin_catch %[[EH_TOKEN]] : !cir.eh_token -> (!cir.catch_token, !cir.ptr) +// CIR: %[[CATCH_TOKEN:.*]], %[[EXN_PTR:.*]] = cir.begin_catch %[[EH_TOKEN]] : !cir.eh_token -> (!cir.catch_token, !cir.ptr) // CIR: cir.cleanup.scope { -// CIR: %[[TMP:.*]] = cir.load {{.*}} %[[EXN_PTR]] : !cir.ptr, !s32i -// CIR: cir.store {{.*}} %[[TMP]], %[[EXCEPTION_ADDR]] : !s32i, !cir.ptr +// CIR: cir.init_catch_param scalar %[[EXN_PTR]] to %{{.*}} : !cir.ptr, !cir.ptr // CIR: cir.yield -// CIR: } cleanup {{.*}} { +// CIR: } cleanup all { // CIR: cir.end_catch %[[CATCH_TOKEN]] : !cir.catch_token // CIR: cir.yield // CIR: } @@ -783,7 +770,7 @@ void call_function_inside_try_catch_with_exception_type_and_catch_all() { // CIR: %[[CATCH_TOKEN2:.*]], %{{.*}} = cir.begin_catch %[[EH_TOKEN2]] : !cir.eh_token -> (!cir.catch_token, !cir.ptr) // CIR: cir.cleanup.scope { // CIR: cir.yield -// CIR: } cleanup {{.*}} { +// CIR: } cleanup all { // CIR: cir.end_catch %[[CATCH_TOKEN2]] : !cir.catch_token // CIR: cir.yield // CIR: } @@ -822,8 +809,6 @@ void call_function_inside_try_catch_with_exception_type_and_catch_all() { // LLVM: %[[TOKEN:.*]] = call ptr @__cxa_begin_catch(ptr %[[EXN_OBJ_PHI2]]) // LLVM: br label %[[CATCH_BODY:.*]] // LLVM: [[CATCH_BODY]]: -// LLVM: %[[LOAD:.*]] = load i32, ptr %[[TOKEN]], align 4 -// LLVM: store i32 %[[LOAD]], ptr {{.*}}, align 4 // LLVM: br label %[[END_CATCH:.*]] // LLVM: [[END_CATCH]]: // LLVM: call void @__cxa_end_catch() @@ -1011,14 +996,13 @@ void call_function_inside_try_catch_with_aggregate_exception_type() { // CIR: cir.func {{.*}} @_Z60call_function_inside_try_catch_with_aggregate_exception_typev(){{.*}} personality(@__gxx_personality_v0){{.*}} { // CIR: cir.scope { -// CIR: %[[E_ADDR:.*]] = cir.alloca !rec_CustomError, !cir.ptr, ["e"] // CIR: cir.try { // CIR: %[[CALL:.*]] = cir.call @_Z8divisionv() : () -> (!s32i {llvm.noundef}) // CIR: cir.yield // CIR: } catch [type #cir.global_view<@_ZTI11CustomError> : !cir.ptr] (%{{.*}}: !cir.eh_token {{.*}}) { -// CIR: %[[CATCH_TOKEN:.*]], %[[EXN_PTR:.*]] = cir.begin_catch %{{.*}} : !cir.eh_token -> (!cir.catch_token, !cir.ptr) +// CIR: %[[CATCH_TOKEN:.*]], %[[EXN_PTR:.*]] = cir.begin_catch %{{.*}} : !cir.eh_token -> (!cir.catch_token, !cir.ptr) // CIR: cir.cleanup.scope { -// CIR: cir.copy %[[EXN_PTR]] to %[[E_ADDR]] : !cir.ptr +// CIR: cir.init_catch_param trivial_copy %[[EXN_PTR]] to %{{.*}} : !cir.ptr, !cir.ptr // CIR: cir.yield // CIR: } cleanup all { // CIR: cir.end_catch %[[CATCH_TOKEN]] : !cir.catch_token @@ -1061,7 +1045,6 @@ void call_function_inside_try_catch_with_aggregate_exception_type() { // LLVM: %[[TOKEN:.*]] = call ptr @__cxa_begin_catch(ptr %[[EXN_OBJ_PHI2]]) // LLVM: br label %[[CATCH_BODY:.*]] // LLVM: [[CATCH_BODY]]: -// LLVM: call void @llvm.memcpy.p0.p0.i64(ptr %{{.*}}, ptr %[[TOKEN]], i64 4, i1 false) // LLVM: br label %[[END_CATCH:.*]] // LLVM: [[END_CATCH]]: // LLVM: call void @__cxa_end_catch() @@ -1131,16 +1114,13 @@ void call_function_inside_try_catch_with_ref_ptr_of_record_exception_type() { // CIR: cir.func {{.*}} @_Z68call_function_inside_try_catch_with_ref_ptr_of_record_exception_typev(){{.*}} personality(@__gxx_personality_v0){{.*}} { // CIR: %[[E_ADDR:.*]] = cir.alloca !cir.ptr>, !cir.ptr>>, ["ref_ptr", const] -// CIR: %[[EXN_BYREF_TMP:.*]] = cir.alloca !cir.ptr, !cir.ptr>, ["exn.byref.tmp"] // CIR: cir.try { // CIR: %[[CALL:.*]] = cir.call @_Z8divisionv() : () -> (!s32i {llvm.noundef}) // CIR: cir.yield // CIR: } catch [type #cir.global_view<@_ZTIP6Record> : !cir.ptr] (%[[EH_TOKEN:.*]]: !cir.eh_token {{.*}}) { -// CIR: %[[CATCH_TOKEN:.*]], %[[EXN_PTR:.*]] = cir.begin_catch %[[EH_TOKEN]] : !cir.eh_token -> (!cir.catch_token, !cir.ptr>) +// CIR: %[[CATCH_TOKEN:.*]], %[[EXN_PTR:.*]] = cir.begin_catch %[[EH_TOKEN]] : !cir.eh_token -> (!cir.catch_token, !cir.ptr) // CIR: cir.cleanup.scope { -// CIR: %[[EXN_PTR_REC_PTR:.*]] = cir.cast bitcast %[[EXN_PTR]] : !cir.ptr> -> !cir.ptr -// CIR: cir.store {{.*}} %[[EXN_PTR_REC_PTR]], %[[EXN_BYREF_TMP]] : !cir.ptr, !cir.ptr> -// CIR: cir.store {{.*}} %[[EXN_BYREF_TMP]], %[[E_ADDR]] : !cir.ptr>, !cir.ptr>> +// CIR: cir.init_catch_param reference %[[EXN_PTR]] to %{{.*}} : !cir.ptr, !cir.ptr>> // CIR: cir.yield // CIR: } cleanup all { // CIR: cir.end_catch %[[CATCH_TOKEN]] : !cir.catch_token @@ -1153,8 +1133,6 @@ void call_function_inside_try_catch_with_ref_ptr_of_record_exception_type() { // CIR: } // LLVM: define {{.*}} void @_Z68call_function_inside_try_catch_with_ref_ptr_of_record_exception_typev() {{.*}} personality ptr @__gxx_personality_v0 -// LLVM: %[[E_ADDR:.*]] = alloca ptr -// LLVM: %[[EXN_BYREF_TMP:.*]] = alloca ptr // LLVM: br label %[[TRY_SCOPE:.*]] // LLVM: [[TRY_SCOPE]]: // LLVM: br label %[[TRY_BEGIN:.*]] @@ -1185,8 +1163,6 @@ void call_function_inside_try_catch_with_ref_ptr_of_record_exception_type() { // LLVM: %[[TOKEN:.*]] = call ptr @__cxa_begin_catch(ptr %[[EXN_OBJ_PHI2]]) // LLVM: br label %[[CATCH_BODY:.*]] // LLVM: [[CATCH_BODY]]: -// LLVM: store ptr %[[TOKEN]], ptr %[[EXN_BYREF_TMP]], align 8 -// LLVM: store ptr %[[EXN_BYREF_TMP]], ptr %[[E_ADDR]], align 8 // LLVM: br label %[[END_CATCH:.*]] // LLVM: [[END_CATCH]]: // LLVM: call void @__cxa_end_catch() @@ -1253,15 +1229,13 @@ void call_function_inside_try_catch_with_exception_member_ptr_type() { // CIR: cir.func {{.*}} @_Z61call_function_inside_try_catch_with_exception_member_ptr_typev(){{.*}} personality(@__gxx_personality_v0){{.*}} { // CIR: cir.scope { -// CIR: %[[E_ADDR:.*]] = cir.alloca !s64i, !cir.ptr, ["memberPtr"] // CIR: cir.try { // CIR: %[[CALL:.*]] = cir.call @_Z8divisionv() : () -> (!s32i {llvm.noundef}) // CIR: cir.yield // CIR: } catch [type #cir.global_view<@_ZTIM6Recordi> : !cir.ptr] (%{{.*}}: !cir.eh_token {{.*}} { -// CIR: %[[CATCH_TOKEN:.*]], %[[EXN_PTR:.*]] = cir.begin_catch %{{.*}} : !cir.eh_token -> (!cir.catch_token, !cir.ptr) +// CIR: %[[CATCH_TOKEN:.*]], %[[EXN_PTR:.*]] = cir.begin_catch %{{.*}} : !cir.eh_token -> (!cir.catch_token, !cir.ptr) // CIR: cir.cleanup.scope { -// CIR: %[[TMP:.*]] = cir.load {{.*}} %[[EXN_PTR]] : !cir.ptr, !s64i -// CIR: cir.store {{.*}} %[[TMP]], %[[E_ADDR]] : !s64i, !cir.ptr +// CIR: cir.init_catch_param scalar %[[EXN_PTR]] to %{{.*}} : !cir.ptr, !cir.ptr // CIR: cir.yield // CIR: } cleanup all { // CIR: cir.end_catch %[[CATCH_TOKEN]] : !cir.catch_token @@ -1293,8 +1267,8 @@ void call_function_inside_try_catch_with_exception_member_ptr_type() { // 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: %[[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 @_ZTIM6Recordi) // LLVM: %[[TYPE_ID_EQ:.*]] = icmp eq i32 %[[EH_SELECTOR_PHI1]], %[[EH_TYPE_ID]] // LLVM: br i1 %[[TYPE_ID_EQ]], label %[[BEGIN_CATCH:.*]], label %[[RESUME:.*]] @@ -1304,8 +1278,6 @@ void call_function_inside_try_catch_with_exception_member_ptr_type() { // LLVM: %[[TOKEN:.*]] = call ptr @__cxa_begin_catch(ptr %[[EXN_OBJ_PHI2]]) // LLVM: br label %[[CATCH_BODY:.*]] // LLVM: [[CATCH_BODY]]: -// LLVM: %[[LOAD:.*]] = load i64, ptr %[[TOKEN]], align 8 -// LLVM: store i64 %[[LOAD]], ptr {{.*}}, align 8 // LLVM: br label %[[END_CATCH:.*]] // LLVM: [[END_CATCH]]: // LLVM: call void @__cxa_end_catch() @@ -1362,3 +1334,284 @@ void call_function_inside_try_catch_with_exception_member_ptr_type() { // 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_type_int() { + int rv = 0; + try { + division(); + } catch (int x) { + rv = x; + } + return rv; +} + +// CIR: cir.func {{.*}} @_Z30init_catch_param_with_type_intv() {{.*}} personality(@__gxx_personality_v0) +// CIR: %[[RET_ADDR:.*]] = cir.alloca !s32i, !cir.ptr, ["__retval"] +// CIR: %[[RV_ADDR:.*]] = cir.alloca !s32i, !cir.ptr, ["rv", init] +// CIR: cir.scope { +// CIR: %[[X_ADDR:.*]] = cir.alloca !s32i, !cir.ptr, ["x"] +// CIR: cir.try { +// CIR: %[[CALL:.*]] = cir.call @_Z8divisionv() : () -> (!s32i {llvm.noundef}) +// CIR: cir.yield +// CIR: } catch [type #cir.global_view<@_ZTIi> : !cir.ptr] (%{{.*}}: !cir.eh_token {{.*}}) { +// CIR: %[[CATCH_TOKEN:.*]], %[[EXN_PTR:.*]] = cir.begin_catch %{{.*}} : !cir.eh_token -> (!cir.catch_token, !cir.ptr) +// CIR: cir.cleanup.scope { +// CIR: cir.init_catch_param scalar %[[EXN_PTR]] to %[[X_ADDR]] : !cir.ptr, !cir.ptr +// CIR: %[[TMP_EXN:.*]] = cir.load {{.*}} %[[X_ADDR]] : !cir.ptr, !s32i +// CIR: cir.store {{.*}} %[[TMP_EXN]], %[[RV_ADDR]] : !s32i, !cir.ptr +// 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 +// CIR: cir.store %[[TMP_RV]], %[[RET_ADDR]] : !s32i, !cir.ptr +// CIR: %[[TMP_RET:.*]] = cir.load %[[RET_ADDR]] : !cir.ptr, !s32i +// CIR: cir.return %[[TMP_RET]] : !s32i + +// LLVM: define {{.*}} i32 @_Z30init_catch_param_with_type_intv() {{.*}} personality ptr @__gxx_personality_v0 +// LLVM: %[[X_ADDR:.*]] = alloca i32, i64 1, align 4 +// 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 @_ZTIi +// 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 @_ZTIi) +// 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_PTR:.*]] = call ptr @__cxa_begin_catch(ptr %[[EXN_OBJ_PHI2]]) +// LLVM: br label %[[CATCH_BODY:.*]] +// LLVM: [[CATCH_BODY]]: +// LLVM: %[[TMP_EXN:.*]] = load i32, ptr %[[EXN_PTR]], align 4 +// LLVM: store i32 %[[TMP_EXN]], ptr %[[X_ADDR]], align 4 +// LLVM: %[[TMP_X:.*]] = load i32, ptr %[[X_ADDR]], align 4 +// LLVM: store i32 %[[TMP_X]], 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 @_Z30init_catch_param_with_type_intv() {{.*}} 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: %[[X_ADDR:.*]] = alloca i32, align 4 +// 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 @_ZTIi +// 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 @_ZTIi) +// 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: %[[TMP_BEGIN_CATCH:.*]] = load i32, ptr %[[BEGIN_CATCH]], align 4 +// OGCG: store i32 %[[TMP_BEGIN_CATCH]], ptr %[[X_ADDR]], align 4 +// OGCG: %[[TMP_X:.*]] = load i32, ptr %[[X_ADDR]], align 4 +// OGCG: store i32 %[[TMP_X]], 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]] + + +int init_catch_param_with_type_int_ptr() { + int rv = 0; + try { + division(); + } catch (int *x) { + rv = *x; + } + return rv; +} + +// CIR: cir.func {{.*}} @_Z34init_catch_param_with_type_int_ptrv() {{.*}} personality(@__gxx_personality_v0) +// CIR: %[[RET_ADDR:.*]] = cir.alloca !s32i, !cir.ptr, ["__retval"] +// CIR: %[[RV_ADDR:.*]] = cir.alloca !s32i, !cir.ptr, ["rv", init] +// CIR: cir.scope { +// CIR: %[[X_ADDR:.*]] = cir.alloca !cir.ptr, !cir.ptr>, ["x"] +// CIR: cir.try { +// CIR: %[[CALL:.*]] = cir.call @_Z8divisionv() : () -> (!s32i {llvm.noundef}) +// CIR: cir.yield +// CIR: } catch [type #cir.global_view<@_ZTIPi> : !cir.ptr] (%{{.*}}: !cir.eh_token {{.*}}) { +// CIR: %[[CATCH_TOKEN:.*]], %[[EXN_PTR:.*]] = cir.begin_catch %{{.*}} : !cir.eh_token -> (!cir.catch_token, !cir.ptr) +// CIR: cir.cleanup.scope { +// CIR: cir.init_catch_param pointer %[[EXN_PTR]] to %[[X_ADDR]] : !cir.ptr, !cir.ptr> +// CIR: %[[DEREF_X:.*]] = cir.load deref {{.*}} %[[X_ADDR]] : !cir.ptr>, !cir.ptr +// CIR: %[[LOADED_INT:.*]] = cir.load {{.*}} %[[DEREF_X]] : !cir.ptr, !s32i +// CIR: cir.store {{.*}} %[[LOADED_INT]], %[[RV_ADDR]] : !s32i, !cir.ptr +// 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 +// CIR: cir.store %[[TMP_RV]], %[[RET_ADDR]] : !s32i, !cir.ptr +// CIR: %[[TMP_RET:.*]] = cir.load %[[RET_ADDR]] : !cir.ptr, !s32i +// CIR: cir.return %[[TMP_RET]] : !s32i + +// LLVM: define {{.*}} i32 @_Z34init_catch_param_with_type_int_ptrv() {{.*}} personality ptr @__gxx_personality_v0 +// LLVM: %[[X_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_PTR:.*]] = call ptr @__cxa_begin_catch(ptr %[[EXN_OBJ_PHI2]]) +// LLVM: br label %[[CATCH_BODY:.*]] +// LLVM: [[CATCH_BODY]]: +// LLVM: store ptr %[[EXN_PTR]], ptr %[[X_ADDR]], align 8 +// LLVM: %[[DEREF_X:.*]] = load ptr, ptr %[[X_ADDR]], align 8 +// LLVM: %[[TMP_EXN:.*]] = load i32, ptr %[[DEREF_X]], 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 @_Z34init_catch_param_with_type_int_ptrv() {{.*}} 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: %[[C_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: store ptr %[[BEGIN_CATCH]], ptr %[[X_ADDR]], align 8 +// OGCG: %[[DEREF_X:.*]] = load ptr, ptr %[[X_ADDR]], align 8 +// OGCG: %[[TMP_X:.*]] = load i32, ptr %[[DEREF_X]], align 4 +// OGCG: store i32 %[[TMP_X]], 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]]