r231105 - Split catch IRgen into ItaniumCXXABI and MicrosoftCXXABI
Nico Weber
thakis at chromium.org
Tue Mar 3 11:55:26 PST 2015
Would've been good to land the move separately from the behavior changeā¦
On Tue, Mar 3, 2015 at 11:21 AM, Reid Kleckner <reid at kleckner.net> wrote:
> Author: rnk
> Date: Tue Mar 3 13:21:04 2015
> New Revision: 231105
>
> URL: http://llvm.org/viewvc/llvm-project?rev=231105&view=rev
> Log:
> Split catch IRgen into ItaniumCXXABI and MicrosoftCXXABI
>
> Use llvm.eh.begincatch for Microsoft-style catches.
>
> This moves lots of CGException code into ItaniumCXXABI. Sorry for the
> blame pain.
>
> Added:
> cfe/trunk/test/CodeGenCXX/microsoft-abi-eh-catch.cpp
> cfe/trunk/test/CodeGenCXX/microsoft-abi-eh-cleanups.cpp
> - copied, changed from r231098,
> cfe/trunk/test/CodeGenCXX/microsoft-abi-exceptions.cpp
> Removed:
> cfe/trunk/test/CodeGenCXX/microsoft-abi-exceptions.cpp
> Modified:
> cfe/trunk/lib/CodeGen/CGCXXABI.cpp
> cfe/trunk/lib/CodeGen/CGCXXABI.h
> cfe/trunk/lib/CodeGen/CGException.cpp
> cfe/trunk/lib/CodeGen/CodeGenModule.h
> cfe/trunk/lib/CodeGen/ItaniumCXXABI.cpp
> cfe/trunk/lib/CodeGen/MicrosoftCXXABI.cpp
> cfe/trunk/test/CodeGenCXX/microsoft-abi-try-throw.cpp
>
> Modified: cfe/trunk/lib/CodeGen/CGCXXABI.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGCXXABI.cpp?rev=231105&r1=231104&r2=231105&view=diff
>
> ==============================================================================
> --- cfe/trunk/lib/CodeGen/CGCXXABI.cpp (original)
> +++ cfe/trunk/lib/CodeGen/CGCXXABI.cpp Tue Mar 3 13:21:04 2015
> @@ -302,3 +302,10 @@ CGCXXABI::EmitCtorCompleteObjectHandler(
> bool CGCXXABI::NeedsVTTParameter(GlobalDecl GD) {
> return false;
> }
> +
> +llvm::CallInst *
> +CGCXXABI::emitTerminateForUnexpectedException(CodeGenFunction &CGF,
> + llvm::Value *Exn) {
> + // Just call std::terminate and ignore the violating exception.
> + return CGF.EmitNounwindRuntimeCall(CGF.CGM.getTerminateFn());
> +}
>
> Modified: cfe/trunk/lib/CodeGen/CGCXXABI.h
> URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGCXXABI.h?rev=231105&r1=231104&r2=231105&view=diff
>
> ==============================================================================
> --- cfe/trunk/lib/CodeGen/CGCXXABI.h (original)
> +++ cfe/trunk/lib/CodeGen/CGCXXABI.h Tue Mar 3 13:21:04 2015
> @@ -22,6 +22,7 @@ namespace llvm {
> class Constant;
> class Type;
> class Value;
> +class CallInst;
> }
>
> namespace clang {
> @@ -215,6 +216,12 @@ public:
> const CXXDestructorDecl *Dtor) = 0;
> virtual void emitRethrow(CodeGenFunction &CGF, bool isNoReturn) = 0;
>
> + virtual void emitBeginCatch(CodeGenFunction &CGF, const CXXCatchStmt
> *C) = 0;
> +
> + virtual llvm::CallInst *
> + emitTerminateForUnexpectedException(CodeGenFunction &CGF,
> + llvm::Value *Exn);
> +
> virtual llvm::Constant *getAddrOfRTTIDescriptor(QualType Ty) = 0;
>
> virtual bool shouldTypeidBeNullChecked(bool IsDeref,
>
> Modified: cfe/trunk/lib/CodeGen/CGException.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGException.cpp?rev=231105&r1=231104&r2=231105&view=diff
>
> ==============================================================================
> --- cfe/trunk/lib/CodeGen/CGException.cpp (original)
> +++ cfe/trunk/lib/CodeGen/CGException.cpp Tue Mar 3 13:21:04 2015
> @@ -54,39 +54,6 @@ static llvm::Constant *getThrowFn(CodeGe
> return CGM.CreateRuntimeFunction(FTy, "__cxa_throw");
> }
>
> -static llvm::Constant *getGetExceptionPtrFn(CodeGenModule &CGM) {
> - // void *__cxa_get_exception_ptr(void*);
> -
> - llvm::FunctionType *FTy =
> - llvm::FunctionType::get(CGM.Int8PtrTy, CGM.Int8PtrTy,
> /*IsVarArgs=*/false);
> -
> - return CGM.CreateRuntimeFunction(FTy, "__cxa_get_exception_ptr");
> -}
> -
> -static llvm::Constant *getBeginCatchFn(CodeGenModule &CGM) {
> - if (CGM.getTarget().getCXXABI().isMicrosoft())
> - return CGM.getIntrinsic(llvm::Intrinsic::eh_begincatch);
> -
> - // void *__cxa_begin_catch(void*);
> -
> - llvm::FunctionType *FTy =
> - llvm::FunctionType::get(CGM.Int8PtrTy, CGM.Int8PtrTy,
> /*IsVarArgs=*/false);
> -
> - return CGM.CreateRuntimeFunction(FTy, "__cxa_begin_catch");
> -}
> -
> -static llvm::Constant *getEndCatchFn(CodeGenModule &CGM) {
> - if (CGM.getTarget().getCXXABI().isMicrosoft())
> - return CGM.getIntrinsic(llvm::Intrinsic::eh_endcatch);
> -
> - // void __cxa_end_catch();
> -
> - llvm::FunctionType *FTy =
> - llvm::FunctionType::get(CGM.VoidTy, /*IsVarArgs=*/false);
> -
> - return CGM.CreateRuntimeFunction(FTy, "__cxa_end_catch");
> -}
> -
> static llvm::Constant *getUnexpectedFn(CodeGenModule &CGM) {
> // void __cxa_call_unexpected(void *thrown_exception);
>
> @@ -96,27 +63,27 @@ static llvm::Constant *getUnexpectedFn(C
> return CGM.CreateRuntimeFunction(FTy, "__cxa_call_unexpected");
> }
>
> -static llvm::Constant *getTerminateFn(CodeGenModule &CGM) {
> +llvm::Constant *CodeGenModule::getTerminateFn() {
> // void __terminate();
>
> llvm::FunctionType *FTy =
> - llvm::FunctionType::get(CGM.VoidTy, /*IsVarArgs=*/false);
> + llvm::FunctionType::get(VoidTy, /*IsVarArgs=*/false);
>
> StringRef name;
>
> // In C++, use std::terminate().
> - if (CGM.getLangOpts().CPlusPlus &&
> - CGM.getTarget().getCXXABI().isItaniumFamily()) {
> + if (getLangOpts().CPlusPlus &&
> + getTarget().getCXXABI().isItaniumFamily()) {
> name = "_ZSt9terminatev";
> - } else if (CGM.getLangOpts().CPlusPlus &&
> - CGM.getTarget().getCXXABI().isMicrosoft()) {
> + } else if (getLangOpts().CPlusPlus &&
> + getTarget().getCXXABI().isMicrosoft()) {
> name = "\01?terminate@@YAXXZ";
> - } else if (CGM.getLangOpts().ObjC1 &&
> - CGM.getLangOpts().ObjCRuntime.hasTerminate())
> + } else if (getLangOpts().ObjC1 &&
> + getLangOpts().ObjCRuntime.hasTerminate())
> name = "objc_terminate";
> else
> name = "abort";
> - return CGM.CreateRuntimeFunction(FTy, name);
> + return CreateRuntimeFunction(FTy, name);
> }
>
> static llvm::Constant *getCatchallRethrowFn(CodeGenModule &CGM,
> @@ -482,7 +449,7 @@ void CodeGenFunction::EmitCXXThrowExpr(c
>
> if (CGM.getTarget().getTriple().isKnownWindowsMSVCEnvironment()) {
> // Call std::terminate().
> - llvm::CallInst *TermCall =
> EmitNounwindRuntimeCall(getTerminateFn(CGM));
> + llvm::CallInst *TermCall =
> EmitNounwindRuntimeCall(CGM.getTerminateFn());
> TermCall->setDoesNotReturn();
>
> // throw is an expression, and the expression emitters expect us
> @@ -920,263 +887,6 @@ llvm::BasicBlock *CodeGenFunction::EmitL
> return lpad;
> }
>
> -namespace {
> - /// 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 : EHScopeStack::Cleanup {
> - CallEndCatch(bool MightThrow) : MightThrow(MightThrow) {}
> - bool MightThrow;
> -
> - void Emit(CodeGenFunction &CGF, Flags flags) override {
> - if (!MightThrow) {
> - CGF.EmitNounwindRuntimeCall(getEndCatchFn(CGF.CGM));
> - return;
> - }
> -
> - CGF.EmitRuntimeCallOrInvoke(getEndCatchFn(CGF.CGM));
> - }
> - };
> -}
> -
> -/// Emits a call to __cxa_begin_catch and enters a cleanup to call
> -/// __cxa_end_catch.
> -///
> -/// \param EndMightThrow - true if __cxa_end_catch might throw
> -static llvm::Value *CallBeginCatch(CodeGenFunction &CGF,
> - llvm::Value *Exn,
> - bool EndMightThrow) {
> - llvm::CallInst *call =
> - CGF.EmitNounwindRuntimeCall(getBeginCatchFn(CGF.CGM), Exn);
> -
> - CGF.EHStack.pushCleanup<CallEndCatch>(NormalAndEHCleanup,
> EndMightThrow);
> -
> - return call;
> -}
> -
> -/// A "special initializer" callback for initializing a catch
> -/// parameter during catch initialization.
> -static void InitCatchParam(CodeGenFunction &CGF,
> - const VarDecl &CatchParam,
> - llvm::Value *ParamAddr,
> - SourceLocation Loc) {
> - // Load the exception from where the landing pad saved it.
> - llvm::Value *Exn = CGF.getExceptionFromSlot();
> -
> - CanQualType CatchType =
> - CGF.CGM.getContext().getCanonicalType(CatchParam.getType());
> - llvm::Type *LLVMCatchTy = CGF.ConvertTypeForMem(CatchType);
> -
> - // 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();
> - bool EndCatchMightThrow = CaughtType->isRecordType();
> -
> - // __cxa_begin_catch returns the adjusted object pointer.
> - llvm::Value *AdjustedExn = CallBeginCatch(CGF, Exn,
> 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<PointerType>(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()) {
> -
> - // Exn points to the struct _Unwind_Exception header, which
> - // we have to skip past in order to reach the exception data.
> - unsigned HeaderSize =
> - CGF.CGM.getTargetCodeGenInfo().getSizeOfUnwindException();
> - AdjustedExn = CGF.Builder.CreateConstGEP1_32(Exn, HeaderSize);
> -
> - // However, if we're catching a pointer-to-record type that won't
> - // work, because the personality function might have adjusted
> - // the pointer. There's actually no way for us to fully satisfy
> - // the language/ABI contract here: we can't use Exn because it
> - // might have the wrong adjustment, but we can't use the by-value
> - // pointer because it's off by a level of abstraction.
> - //
> - // The current solution is to dump the adjusted pointer into an
> - // alloca, which breaks language semantics (because changing the
> - // pointer doesn't change the exception) but at least works.
> - // The better solution would be to filter out non-exact matches
> - // and rethrow them, but this is tricky because the rethrow
> - // really needs to be catchable by other sites at this landing
> - // pad. The best solution is to fix the personality function.
> - } else {
> - // Pull the pointer for the reference type off.
> - llvm::Type *PtrTy =
> - cast<llvm::PointerType>(LLVMCatchTy)->getElementType();
> -
> - // Create the temporary and write the adjusted pointer into it.
> - llvm::Value *ExnPtrTmp = CGF.CreateTempAlloca(PtrTy,
> "exn.byref.tmp");
> - llvm::Value *Casted = CGF.Builder.CreateBitCast(AdjustedExn,
> PtrTy);
> - CGF.Builder.CreateStore(Casted, ExnPtrTmp);
> -
> - // Bind the reference to the temporary.
> - AdjustedExn = ExnPtrTmp;
> - }
> - }
> -
> - llvm::Value *ExnCast =
> - CGF.Builder.CreateBitCast(AdjustedExn, LLVMCatchTy, "exn.byref");
> - CGF.Builder.CreateStore(ExnCast, ParamAddr);
> - return;
> - }
> -
> - // Scalars and complexes.
> - TypeEvaluationKind TEK = CGF.getEvaluationKind(CatchType);
> - if (TEK != TEK_Aggregate) {
> - llvm::Value *AdjustedExn = CallBeginCatch(CGF, Exn, false);
> -
> - // If the catch type is a pointer type, __cxa_begin_catch returns
> - // the pointer by value.
> - if (CatchType->hasPointerRepresentation()) {
> - llvm::Value *CastExn =
> - CGF.Builder.CreateBitCast(AdjustedExn, LLVMCatchTy, "exn.casted");
> -
> - switch (CatchType.getQualifiers().getObjCLifetime()) {
> - case Qualifiers::OCL_Strong:
> - CastExn = CGF.EmitARCRetainNonBlock(CastExn);
> - // fallthrough
> -
> - case Qualifiers::OCL_None:
> - case Qualifiers::OCL_ExplicitNone:
> - case Qualifiers::OCL_Autoreleasing:
> - CGF.Builder.CreateStore(CastExn, ParamAddr);
> - return;
> -
> - case Qualifiers::OCL_Weak:
> - CGF.EmitARCInitWeak(ParamAddr, CastExn);
> - return;
> - }
> - llvm_unreachable("bad ownership qualifier!");
> - }
> -
> - // Otherwise, it returns a pointer into the exception object.
> -
> - llvm::Type *PtrTy = LLVMCatchTy->getPointerTo(0); // addrspace 0 ok
> - llvm::Value *Cast = CGF.Builder.CreateBitCast(AdjustedExn, PtrTy);
> -
> - LValue srcLV = CGF.MakeNaturalAlignAddrLValue(Cast, CatchType);
> - LValue destLV = CGF.MakeAddrLValue(ParamAddr, CatchType,
> -
> CGF.getContext().getDeclAlign(&CatchParam));
> - switch (TEK) {
> - case TEK_Complex:
> - CGF.EmitStoreOfComplex(CGF.EmitLoadOfComplex(srcLV, Loc), destLV,
> - /*init*/ true);
> - return;
> - case TEK_Scalar: {
> - llvm::Value *ExnLoad = CGF.EmitLoadOfScalar(srcLV, Loc);
> - CGF.EmitStoreOfScalar(ExnLoad, destLV, /*init*/ true);
> - return;
> - }
> - case TEK_Aggregate:
> - llvm_unreachable("evaluation kind filtered out!");
> - }
> - llvm_unreachable("bad evaluation kind");
> - }
> -
> - assert(isa<RecordType>(CatchType) && "unexpected catch type!");
> -
> - llvm::Type *PtrTy = LLVMCatchTy->getPointerTo(0); // addrspace 0 ok
> -
> - // 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) {
> - llvm::Value *rawAdjustedExn = CallBeginCatch(CGF, Exn, true);
> - llvm::Value *adjustedExn = CGF.Builder.CreateBitCast(rawAdjustedExn,
> PtrTy);
> - CGF.EmitAggregateCopy(ParamAddr, adjustedExn, CatchType);
> - return;
> - }
> -
> - // We have to call __cxa_get_exception_ptr to get the adjusted
> - // pointer before copying.
> - llvm::CallInst *rawAdjustedExn =
> - CGF.EmitNounwindRuntimeCall(getGetExceptionPtrFn(CGF.CGM), Exn);
> -
> - // Cast that to the appropriate type.
> - llvm::Value *adjustedExn = CGF.Builder.CreateBitCast(rawAdjustedExn,
> PtrTy);
> -
> - // The copy expression is defined in terms of an OpaqueValueExpr.
> - // Find it and map it to the adjusted expression.
> - CodeGenFunction::OpaqueValueMapping
> - opaque(CGF, OpaqueValueExpr::findInCopyConstruct(copyExpr),
> - CGF.MakeAddrLValue(adjustedExn, CatchParam.getType()));
> -
> - // Call the copy ctor in a terminate scope.
> - CGF.EHStack.pushTerminate();
> -
> - // Perform the copy construction.
> - CharUnits Alignment = CGF.getContext().getDeclAlign(&CatchParam);
> - CGF.EmitAggExpr(copyExpr,
> - AggValueSlot::forAddr(ParamAddr, Alignment,
> Qualifiers(),
> - AggValueSlot::IsNotDestructed,
> -
> AggValueSlot::DoesNotNeedGCBarriers,
> - AggValueSlot::IsNotAliased));
> -
> - // Leave the terminate scope.
> - CGF.EHStack.popTerminate();
> -
> - // Undo the opaque value mapping.
> - opaque.pop();
> -
> - // Finally we can call __cxa_begin_catch.
> - CallBeginCatch(CGF, Exn, true);
> -}
> -
> -/// Begins a catch statement by initializing the catch variable and
> -/// calling __cxa_begin_catch.
> -static void BeginCatch(CodeGenFunction &CGF, const CXXCatchStmt *S) {
> - // 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 = S->getExceptionDecl();
> - if (!CatchParam) {
> - llvm::Value *Exn = CGF.getExceptionFromSlot();
> - CallBeginCatch(CGF, Exn, true);
> - return;
> - }
> -
> - // Emit the local.
> - CodeGenFunction::AutoVarEmission var =
> CGF.EmitAutoVarAlloca(*CatchParam);
> - InitCatchParam(CGF, *CatchParam, var.getObjectAddress(CGF),
> S->getLocStart());
> - CGF.EmitAutoVarCleanups(var);
> -}
> -
> /// Emit the structure of the dispatch block for the given catch scope.
> /// It is an invariant that the dispatch block already exists.
> static void emitCatchDispatchBlock(CodeGenFunction &CGF,
> @@ -1315,7 +1025,7 @@ void CodeGenFunction::ExitCXXTryStmt(con
> RunCleanupsScope CatchScope(*this);
>
> // Initialize the catch variable and set up the cleanups.
> - BeginCatch(*this, C);
> + CGM.getCXXABI().emitBeginCatch(*this, C);
>
> // Emit the PGO counter increment.
> RegionCounter CatchCnt = getPGORegionCounter(C);
> @@ -1543,70 +1253,6 @@ void CodeGenFunction::FinallyInfo::exit(
> CGF.PopCleanupBlock();
> }
>
> -/// In a terminate landing pad, should we use __clang__call_terminate
> -/// or just a naked call to std::terminate?
> -///
> -/// __clang_call_terminate calls __cxa_begin_catch, which then allows
> -/// std::terminate to usefully report something about the
> -/// violating exception.
> -static bool useClangCallTerminate(CodeGenModule &CGM) {
> - // Only do this for Itanium-family ABIs in C++ mode.
> - return (CGM.getLangOpts().CPlusPlus &&
> - CGM.getTarget().getCXXABI().isItaniumFamily());
> -}
> -
> -/// Get or define the following function:
> -/// void @__clang_call_terminate(i8* %exn) nounwind noreturn
> -/// This code is used only in C++.
> -static llvm::Constant *getClangCallTerminateFn(CodeGenModule &CGM) {
> - llvm::FunctionType *fnTy =
> - llvm::FunctionType::get(CGM.VoidTy, CGM.Int8PtrTy,
> /*IsVarArgs=*/false);
> - llvm::Constant *fnRef =
> - CGM.CreateRuntimeFunction(fnTy, "__clang_call_terminate");
> -
> - llvm::Function *fn = dyn_cast<llvm::Function>(fnRef);
> - if (fn && fn->empty()) {
> - fn->setDoesNotThrow();
> - fn->setDoesNotReturn();
> -
> - // What we really want is to massively penalize inlining without
> - // forbidding it completely. The difference between that and
> - // 'noinline' is negligible.
> - fn->addFnAttr(llvm::Attribute::NoInline);
> -
> - // Allow this function to be shared across translation units, but
> - // we don't want it to turn into an exported symbol.
> - fn->setLinkage(llvm::Function::LinkOnceODRLinkage);
> - fn->setVisibility(llvm::Function::HiddenVisibility);
> - if (CGM.supportsCOMDAT())
> - fn->setComdat(CGM.getModule().getOrInsertComdat(fn->getName()));
> -
> - // Set up the function.
> - llvm::BasicBlock *entry =
> - llvm::BasicBlock::Create(CGM.getLLVMContext(), "", fn);
> - CGBuilderTy builder(entry);
> -
> - // Pull the exception pointer out of the parameter list.
> - llvm::Value *exn = &*fn->arg_begin();
> -
> - // Call __cxa_begin_catch(exn).
> - llvm::CallInst *catchCall = builder.CreateCall(getBeginCatchFn(CGM),
> exn);
> - catchCall->setDoesNotThrow();
> - catchCall->setCallingConv(CGM.getRuntimeCC());
> -
> - // Call std::terminate().
> - llvm::CallInst *termCall = builder.CreateCall(getTerminateFn(CGM));
> - termCall->setDoesNotThrow();
> - termCall->setDoesNotReturn();
> - termCall->setCallingConv(CGM.getRuntimeCC());
> -
> - // std::terminate cannot return.
> - builder.CreateUnreachable();
> - }
> -
> - return fnRef;
> -}
> -
> llvm::BasicBlock *CodeGenFunction::getTerminateLandingPad() {
> if (TerminateLandingPad)
> return TerminateLandingPad;
> @@ -1624,14 +1270,11 @@ llvm::BasicBlock *CodeGenFunction::getTe
> getOpaquePersonalityFn(CGM, Personality), 0);
> LPadInst->addClause(getCatchAllValue(*this));
>
> - llvm::CallInst *terminateCall;
> - if (useClangCallTerminate(CGM)) {
> - // Extract out the exception pointer.
> - llvm::Value *exn = Builder.CreateExtractValue(LPadInst, 0);
> - terminateCall = EmitNounwindRuntimeCall(getClangCallTerminateFn(CGM),
> exn);
> - } else {
> - terminateCall = EmitNounwindRuntimeCall(getTerminateFn(CGM));
> - }
> + llvm::Value *Exn = 0;
> + if (getLangOpts().CPlusPlus)
> + Exn = Builder.CreateExtractValue(LPadInst, 0);
> + llvm::CallInst *terminateCall =
> + CGM.getCXXABI().emitTerminateForUnexpectedException(*this, Exn);
> terminateCall->setDoesNotReturn();
> Builder.CreateUnreachable();
>
> @@ -1651,14 +1294,11 @@ llvm::BasicBlock *CodeGenFunction::getTe
> // end of the function by FinishFunction.
> TerminateHandler = createBasicBlock("terminate.handler");
> Builder.SetInsertPoint(TerminateHandler);
> - llvm::CallInst *terminateCall;
> - if (useClangCallTerminate(CGM)) {
> - // Load the exception pointer.
> - llvm::Value *exn = getExceptionFromSlot();
> - terminateCall = EmitNounwindRuntimeCall(getClangCallTerminateFn(CGM),
> exn);
> - } else {
> - terminateCall = EmitNounwindRuntimeCall(getTerminateFn(CGM));
> - }
> + llvm::Value *Exn = 0;
> + if (getLangOpts().CPlusPlus)
> + Exn = getExceptionFromSlot();
> + llvm::CallInst *terminateCall =
> + CGM.getCXXABI().emitTerminateForUnexpectedException(*this, Exn);
> terminateCall->setDoesNotReturn();
> Builder.CreateUnreachable();
>
>
> Modified: cfe/trunk/lib/CodeGen/CodeGenModule.h
> URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CodeGenModule.h?rev=231105&r1=231104&r2=231105&view=diff
>
> ==============================================================================
> --- cfe/trunk/lib/CodeGen/CodeGenModule.h (original)
> +++ cfe/trunk/lib/CodeGen/CodeGenModule.h Tue Mar 3 13:21:04 2015
> @@ -1108,6 +1108,9 @@ public:
> void EmitVTableBitSetEntries(llvm::GlobalVariable *VTable,
> const VTableLayout &VTLayout);
>
> + /// \breif Get the declaration of std::terminate for the platform.
> + llvm::Constant *getTerminateFn();
> +
> private:
> llvm::Constant *
> GetOrCreateLLVMFunction(StringRef MangledName, llvm::Type *Ty,
> GlobalDecl D,
>
> Modified: cfe/trunk/lib/CodeGen/ItaniumCXXABI.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/ItaniumCXXABI.cpp?rev=231105&r1=231104&r2=231105&view=diff
>
> ==============================================================================
> --- cfe/trunk/lib/CodeGen/ItaniumCXXABI.cpp (original)
> +++ cfe/trunk/lib/CodeGen/ItaniumCXXABI.cpp Tue Mar 3 13:21:04 2015
> @@ -19,14 +19,18 @@
>
> //===----------------------------------------------------------------------===//
>
> #include "CGCXXABI.h"
> +#include "CGCleanup.h"
> #include "CGRecordLayout.h"
> #include "CGVTables.h"
> #include "CodeGenFunction.h"
> #include "CodeGenModule.h"
> +#include "TargetInfo.h"
> #include "clang/AST/Mangle.h"
> #include "clang/AST/Type.h"
> +#include "clang/AST/StmtCXX.h"
> #include "llvm/IR/CallSite.h"
> #include "llvm/IR/DataLayout.h"
> +#include "llvm/IR/Instructions.h"
> #include "llvm/IR/Intrinsics.h"
> #include "llvm/IR/Value.h"
>
> @@ -112,6 +116,12 @@ public:
>
> void emitRethrow(CodeGenFunction &CGF, bool isNoReturn) override;
>
> + void emitBeginCatch(CodeGenFunction &CGF, const CXXCatchStmt *C)
> override;
> +
> + llvm::CallInst *
> + emitTerminateForUnexpectedException(CodeGenFunction &CGF,
> + llvm::Value *Exn) override;
> +
> void EmitFundamentalRTTIDescriptor(QualType Type);
> void EmitFundamentalRTTIDescriptors();
> llvm::Constant *getAddrOfRTTIDescriptor(QualType Ty) override;
> @@ -3220,3 +3230,348 @@ void ItaniumCXXABI::emitCXXStructor(cons
> CGM.maybeSetTrivialComdat(*MD, *Fn);
> }
> }
> +
> +static llvm::Constant *getBeginCatchFn(CodeGenModule &CGM) {
> + // void *__cxa_begin_catch(void*);
> + llvm::FunctionType *FTy = llvm::FunctionType::get(
> + CGM.Int8PtrTy, CGM.Int8PtrTy, /*IsVarArgs=*/false);
> +
> + return CGM.CreateRuntimeFunction(FTy, "__cxa_begin_catch");
> +}
> +
> +static llvm::Constant *getEndCatchFn(CodeGenModule &CGM) {
> + // void __cxa_end_catch();
> + llvm::FunctionType *FTy =
> + llvm::FunctionType::get(CGM.VoidTy, /*IsVarArgs=*/false);
> +
> + return CGM.CreateRuntimeFunction(FTy, "__cxa_end_catch");
> +}
> +
> +static llvm::Constant *getGetExceptionPtrFn(CodeGenModule &CGM) {
> + // void *__cxa_get_exception_ptr(void*);
> + llvm::FunctionType *FTy = llvm::FunctionType::get(
> + CGM.Int8PtrTy, CGM.Int8PtrTy, /*IsVarArgs=*/false);
> +
> + return CGM.CreateRuntimeFunction(FTy, "__cxa_get_exception_ptr");
> +}
> +
> +namespace {
> + /// 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 : EHScopeStack::Cleanup {
> + CallEndCatch(bool MightThrow) : MightThrow(MightThrow) {}
> + bool MightThrow;
> +
> + void Emit(CodeGenFunction &CGF, Flags flags) override {
> + if (!MightThrow) {
> + CGF.EmitNounwindRuntimeCall(getEndCatchFn(CGF.CGM));
> + return;
> + }
> +
> + CGF.EmitRuntimeCallOrInvoke(getEndCatchFn(CGF.CGM));
> + }
> + };
> +}
> +
> +/// Emits a call to __cxa_begin_catch and enters a cleanup to call
> +/// __cxa_end_catch.
> +///
> +/// \param EndMightThrow - true if __cxa_end_catch might throw
> +static llvm::Value *CallBeginCatch(CodeGenFunction &CGF,
> + llvm::Value *Exn,
> + bool EndMightThrow) {
> + llvm::CallInst *call =
> + CGF.EmitNounwindRuntimeCall(getBeginCatchFn(CGF.CGM), Exn);
> +
> + CGF.EHStack.pushCleanup<CallEndCatch>(NormalAndEHCleanup,
> EndMightThrow);
> +
> + return call;
> +}
> +
> +/// A "special initializer" callback for initializing a catch
> +/// parameter during catch initialization.
> +static void InitCatchParam(CodeGenFunction &CGF,
> + const VarDecl &CatchParam,
> + llvm::Value *ParamAddr,
> + SourceLocation Loc) {
> + // Load the exception from where the landing pad saved it.
> + llvm::Value *Exn = CGF.getExceptionFromSlot();
> +
> + CanQualType CatchType =
> + CGF.CGM.getContext().getCanonicalType(CatchParam.getType());
> + llvm::Type *LLVMCatchTy = CGF.ConvertTypeForMem(CatchType);
> +
> + // 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();
> + bool EndCatchMightThrow = CaughtType->isRecordType();
> +
> + // __cxa_begin_catch returns the adjusted object pointer.
> + llvm::Value *AdjustedExn = CallBeginCatch(CGF, Exn,
> 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<PointerType>(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()) {
> +
> + // Exn points to the struct _Unwind_Exception header, which
> + // we have to skip past in order to reach the exception data.
> + unsigned HeaderSize =
> + CGF.CGM.getTargetCodeGenInfo().getSizeOfUnwindException();
> + AdjustedExn = CGF.Builder.CreateConstGEP1_32(Exn, HeaderSize);
> +
> + // However, if we're catching a pointer-to-record type that won't
> + // work, because the personality function might have adjusted
> + // the pointer. There's actually no way for us to fully satisfy
> + // the language/ABI contract here: we can't use Exn because it
> + // might have the wrong adjustment, but we can't use the by-value
> + // pointer because it's off by a level of abstraction.
> + //
> + // The current solution is to dump the adjusted pointer into an
> + // alloca, which breaks language semantics (because changing the
> + // pointer doesn't change the exception) but at least works.
> + // The better solution would be to filter out non-exact matches
> + // and rethrow them, but this is tricky because the rethrow
> + // really needs to be catchable by other sites at this landing
> + // pad. The best solution is to fix the personality function.
> + } else {
> + // Pull the pointer for the reference type off.
> + llvm::Type *PtrTy =
> + cast<llvm::PointerType>(LLVMCatchTy)->getElementType();
> +
> + // Create the temporary and write the adjusted pointer into it.
> + llvm::Value *ExnPtrTmp = CGF.CreateTempAlloca(PtrTy,
> "exn.byref.tmp");
> + llvm::Value *Casted = CGF.Builder.CreateBitCast(AdjustedExn,
> PtrTy);
> + CGF.Builder.CreateStore(Casted, ExnPtrTmp);
> +
> + // Bind the reference to the temporary.
> + AdjustedExn = ExnPtrTmp;
> + }
> + }
> +
> + llvm::Value *ExnCast =
> + CGF.Builder.CreateBitCast(AdjustedExn, LLVMCatchTy, "exn.byref");
> + CGF.Builder.CreateStore(ExnCast, ParamAddr);
> + return;
> + }
> +
> + // Scalars and complexes.
> + TypeEvaluationKind TEK = CGF.getEvaluationKind(CatchType);
> + if (TEK != TEK_Aggregate) {
> + llvm::Value *AdjustedExn = CallBeginCatch(CGF, Exn, false);
> +
> + // If the catch type is a pointer type, __cxa_begin_catch returns
> + // the pointer by value.
> + if (CatchType->hasPointerRepresentation()) {
> + llvm::Value *CastExn =
> + CGF.Builder.CreateBitCast(AdjustedExn, LLVMCatchTy, "exn.casted");
> +
> + switch (CatchType.getQualifiers().getObjCLifetime()) {
> + case Qualifiers::OCL_Strong:
> + CastExn = CGF.EmitARCRetainNonBlock(CastExn);
> + // fallthrough
> +
> + case Qualifiers::OCL_None:
> + case Qualifiers::OCL_ExplicitNone:
> + case Qualifiers::OCL_Autoreleasing:
> + CGF.Builder.CreateStore(CastExn, ParamAddr);
> + return;
> +
> + case Qualifiers::OCL_Weak:
> + CGF.EmitARCInitWeak(ParamAddr, CastExn);
> + return;
> + }
> + llvm_unreachable("bad ownership qualifier!");
> + }
> +
> + // Otherwise, it returns a pointer into the exception object.
> +
> + llvm::Type *PtrTy = LLVMCatchTy->getPointerTo(0); // addrspace 0 ok
> + llvm::Value *Cast = CGF.Builder.CreateBitCast(AdjustedExn, PtrTy);
> +
> + LValue srcLV = CGF.MakeNaturalAlignAddrLValue(Cast, CatchType);
> + LValue destLV = CGF.MakeAddrLValue(ParamAddr, CatchType,
> +
> CGF.getContext().getDeclAlign(&CatchParam));
> + switch (TEK) {
> + case TEK_Complex:
> + CGF.EmitStoreOfComplex(CGF.EmitLoadOfComplex(srcLV, Loc), destLV,
> + /*init*/ true);
> + return;
> + case TEK_Scalar: {
> + llvm::Value *ExnLoad = CGF.EmitLoadOfScalar(srcLV, Loc);
> + CGF.EmitStoreOfScalar(ExnLoad, destLV, /*init*/ true);
> + return;
> + }
> + case TEK_Aggregate:
> + llvm_unreachable("evaluation kind filtered out!");
> + }
> + llvm_unreachable("bad evaluation kind");
> + }
> +
> + assert(isa<RecordType>(CatchType) && "unexpected catch type!");
> +
> + llvm::Type *PtrTy = LLVMCatchTy->getPointerTo(0); // addrspace 0 ok
> +
> + // 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) {
> + llvm::Value *rawAdjustedExn = CallBeginCatch(CGF, Exn, true);
> + llvm::Value *adjustedExn = CGF.Builder.CreateBitCast(rawAdjustedExn,
> PtrTy);
> + CGF.EmitAggregateCopy(ParamAddr, adjustedExn, CatchType);
> + return;
> + }
> +
> + // We have to call __cxa_get_exception_ptr to get the adjusted
> + // pointer before copying.
> + llvm::CallInst *rawAdjustedExn =
> + CGF.EmitNounwindRuntimeCall(getGetExceptionPtrFn(CGF.CGM), Exn);
> +
> + // Cast that to the appropriate type.
> + llvm::Value *adjustedExn = CGF.Builder.CreateBitCast(rawAdjustedExn,
> PtrTy);
> +
> + // The copy expression is defined in terms of an OpaqueValueExpr.
> + // Find it and map it to the adjusted expression.
> + CodeGenFunction::OpaqueValueMapping
> + opaque(CGF, OpaqueValueExpr::findInCopyConstruct(copyExpr),
> + CGF.MakeAddrLValue(adjustedExn, CatchParam.getType()));
> +
> + // Call the copy ctor in a terminate scope.
> + CGF.EHStack.pushTerminate();
> +
> + // Perform the copy construction.
> + CharUnits Alignment = CGF.getContext().getDeclAlign(&CatchParam);
> + CGF.EmitAggExpr(copyExpr,
> + AggValueSlot::forAddr(ParamAddr, Alignment,
> Qualifiers(),
> + AggValueSlot::IsNotDestructed,
> +
> AggValueSlot::DoesNotNeedGCBarriers,
> + AggValueSlot::IsNotAliased));
> +
> + // Leave the terminate scope.
> + CGF.EHStack.popTerminate();
> +
> + // Undo the opaque value mapping.
> + opaque.pop();
> +
> + // Finally we can call __cxa_begin_catch.
> + CallBeginCatch(CGF, Exn, true);
> +}
> +
> +/// Begins a catch statement by initializing the catch variable and
> +/// calling __cxa_begin_catch.
> +void ItaniumCXXABI::emitBeginCatch(CodeGenFunction &CGF,
> + const CXXCatchStmt *S) {
> + // 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 = S->getExceptionDecl();
> + if (!CatchParam) {
> + llvm::Value *Exn = CGF.getExceptionFromSlot();
> + CallBeginCatch(CGF, Exn, true);
> + return;
> + }
> +
> + // Emit the local.
> + CodeGenFunction::AutoVarEmission var =
> CGF.EmitAutoVarAlloca(*CatchParam);
> + InitCatchParam(CGF, *CatchParam, var.getObjectAddress(CGF),
> S->getLocStart());
> + CGF.EmitAutoVarCleanups(var);
> +}
> +
> +/// Get or define the following function:
> +/// void @__clang_call_terminate(i8* %exn) nounwind noreturn
> +/// This code is used only in C++.
> +static llvm::Constant *getClangCallTerminateFn(CodeGenModule &CGM) {
> + llvm::FunctionType *fnTy =
> + llvm::FunctionType::get(CGM.VoidTy, CGM.Int8PtrTy,
> /*IsVarArgs=*/false);
> + llvm::Constant *fnRef =
> + CGM.CreateRuntimeFunction(fnTy, "__clang_call_terminate");
> +
> + llvm::Function *fn = dyn_cast<llvm::Function>(fnRef);
> + if (fn && fn->empty()) {
> + fn->setDoesNotThrow();
> + fn->setDoesNotReturn();
> +
> + // What we really want is to massively penalize inlining without
> + // forbidding it completely. The difference between that and
> + // 'noinline' is negligible.
> + fn->addFnAttr(llvm::Attribute::NoInline);
> +
> + // Allow this function to be shared across translation units, but
> + // we don't want it to turn into an exported symbol.
> + fn->setLinkage(llvm::Function::LinkOnceODRLinkage);
> + fn->setVisibility(llvm::Function::HiddenVisibility);
> + if (CGM.supportsCOMDAT())
> + fn->setComdat(CGM.getModule().getOrInsertComdat(fn->getName()));
> +
> + // Set up the function.
> + llvm::BasicBlock *entry =
> + llvm::BasicBlock::Create(CGM.getLLVMContext(), "", fn);
> + CGBuilderTy builder(entry);
> +
> + // Pull the exception pointer out of the parameter list.
> + llvm::Value *exn = &*fn->arg_begin();
> +
> + // Call __cxa_begin_catch(exn).
> + llvm::CallInst *catchCall = builder.CreateCall(getBeginCatchFn(CGM),
> exn);
> + catchCall->setDoesNotThrow();
> + catchCall->setCallingConv(CGM.getRuntimeCC());
> +
> + // Call std::terminate().
> + llvm::CallInst *termCall = builder.CreateCall(CGM.getTerminateFn());
> + termCall->setDoesNotThrow();
> + termCall->setDoesNotReturn();
> + termCall->setCallingConv(CGM.getRuntimeCC());
> +
> + // std::terminate cannot return.
> + builder.CreateUnreachable();
> + }
> +
> + return fnRef;
> +}
> +
> +llvm::CallInst *
> +ItaniumCXXABI::emitTerminateForUnexpectedException(CodeGenFunction &CGF,
> + llvm::Value *Exn) {
> + // In C++, we want to call __cxa_begin_catch() before terminating.
> + if (Exn) {
> + assert(CGF.CGM.getLangOpts().CPlusPlus);
> + return CGF.EmitNounwindRuntimeCall(getClangCallTerminateFn(CGF.CGM),
> Exn);
> + }
> + return CGF.EmitNounwindRuntimeCall(CGF.CGM.getTerminateFn());
> +}
>
> Modified: cfe/trunk/lib/CodeGen/MicrosoftCXXABI.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/MicrosoftCXXABI.cpp?rev=231105&r1=231104&r2=231105&view=diff
>
> ==============================================================================
> --- cfe/trunk/lib/CodeGen/MicrosoftCXXABI.cpp (original)
> +++ cfe/trunk/lib/CodeGen/MicrosoftCXXABI.cpp Tue Mar 3 13:21:04 2015
> @@ -17,12 +17,15 @@
> #include "CGCXXABI.h"
> #include "CGVTables.h"
> #include "CodeGenModule.h"
> +#include "TargetInfo.h"
> #include "clang/AST/Decl.h"
> #include "clang/AST/DeclCXX.h"
> +#include "clang/AST/StmtCXX.h"
> #include "clang/AST/VTableBuilder.h"
> #include "llvm/ADT/StringExtras.h"
> #include "llvm/ADT/StringSet.h"
> #include "llvm/IR/CallSite.h"
> +#include "llvm/IR/Intrinsics.h"
>
> using namespace clang;
> using namespace CodeGen;
> @@ -72,6 +75,8 @@ public:
>
> void emitRethrow(CodeGenFunction &CGF, bool isNoReturn) override;
>
> + void emitBeginCatch(CodeGenFunction &CGF, const CXXCatchStmt *C)
> override;
> +
> llvm::GlobalVariable *getMSCompleteObjectLocator(const CXXRecordDecl
> *RD,
> const VPtrInfo *Info);
>
> @@ -695,6 +700,42 @@ void MicrosoftCXXABI::emitRethrow(CodeGe
> CGF.EmitRuntimeCallOrInvoke(Fn, Args);
> }
>
> +namespace {
> +struct CallEndCatchMSVC : EHScopeStack::Cleanup {
> + CallEndCatchMSVC() {}
> + void Emit(CodeGenFunction &CGF, Flags flags) override {
> + CGF.EmitNounwindRuntimeCall(
> + CGF.CGM.getIntrinsic(llvm::Intrinsic::eh_endcatch));
> + }
> +};
> +}
> +
> +void MicrosoftCXXABI::emitBeginCatch(CodeGenFunction &CGF,
> + const CXXCatchStmt *S) {
> + // In the MS ABI, the runtime handles the copy, and the catch handler is
> + // responsible for destruction.
> + VarDecl *CatchParam = S->getExceptionDecl();
> + llvm::Value *Exn = CGF.getExceptionFromSlot();
> + llvm::Function *BeginCatch =
> + CGF.CGM.getIntrinsic(llvm::Intrinsic::eh_begincatch);
> +
> + if (!CatchParam) {
> + llvm::Value *Args[2] = {Exn,
> llvm::Constant::getNullValue(CGF.Int8PtrTy)};
> + CGF.EmitNounwindRuntimeCall(BeginCatch, Args);
> + CGF.EHStack.pushCleanup<CallEndCatchMSVC>(NormalAndEHCleanup);
> + return;
> + }
> +
> + CodeGenFunction::AutoVarEmission var =
> CGF.EmitAutoVarAlloca(*CatchParam);
> + llvm::Value *ParamAddr =
> + CGF.Builder.CreateBitCast(var.getObjectAddress(CGF), CGF.Int8PtrTy);
> + llvm::Value *Args[2] = {Exn, ParamAddr};
> + CGF.EmitNounwindRuntimeCall(BeginCatch, Args);
> + // FIXME: Do we really need exceptional endcatch cleanups?
> + CGF.EHStack.pushCleanup<CallEndCatchMSVC>(NormalAndEHCleanup);
> + CGF.EmitAutoVarCleanups(var);
> +}
> +
> std::pair<llvm::Value *, llvm::Value *>
> MicrosoftCXXABI::performBaseAdjustment(CodeGenFunction &CGF, llvm::Value
> *Value,
> QualType SrcRecordTy) {
>
> Added: cfe/trunk/test/CodeGenCXX/microsoft-abi-eh-catch.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/microsoft-abi-eh-catch.cpp?rev=231105&view=auto
>
> ==============================================================================
> --- cfe/trunk/test/CodeGenCXX/microsoft-abi-eh-catch.cpp (added)
> +++ cfe/trunk/test/CodeGenCXX/microsoft-abi-eh-catch.cpp Tue Mar 3
> 13:21:04 2015
> @@ -0,0 +1,98 @@
> +// RUN: %clang_cc1 -std=c++11 -emit-llvm %s -o -
> -triple=x86_64-pc-windows-msvc -mconstructor-aliases -fexceptions
> -fcxx-exceptions | FileCheck -check-prefix WIN64 %s
> +
> +extern "C" void might_throw();
> +
> +// Simplify the generated IR with noexcept.
> +extern "C" void recover() noexcept(true);
> +extern "C" void handle_exception(void *e) noexcept(true);
> +
> +extern "C" void catch_all() {
> + try {
> + might_throw();
> + } catch (...) {
> + recover();
> + }
> +}
> +
> +// WIN64-LABEL: define void @catch_all()
> +// WIN64: invoke void @might_throw()
> +// WIN64-NEXT: to label %[[cont:[^ ]*]] unwind label %[[lpad:[^ ]*]]
> +//
> +// WIN64: [[cont]]
> +// WIN64: br label %[[ret:[^ ]*]]
> +//
> +// WIN64: [[lpad]]
> +// WIN64: landingpad { i8*, i32 }
> +// WIN64-NEXT: catch i8* null
> +// WIN64: call void @llvm.eh.begincatch(i8* %{{[^,]*}}, i8* null)
> +// WIN64: call void @recover()
> +// WIN64: call void @llvm.eh.endcatch()
> +// WIN64: br label %[[ret]]
> +//
> +// WIN64: [[ret]]
> +// WIN64: ret void
> +
> +extern "C" void catch_int() {
> + try {
> + might_throw();
> + } catch (int e) {
> + handle_exception(&e);
> + }
> +}
> +
> +// WIN64-LABEL: define void @catch_int()
> +// WIN64: landingpad { i8*, i32 }
> +// WIN64: %[[e_i8:[^ ]*]] = bitcast i32* %[[e_addr:[^ ]*]] to i8*
> +// WIN64: call void @llvm.eh.begincatch(i8* %{{.*}}, i8* %[[e_i8]])
> +// WIN64: %[[e_i8:[^ ]*]] = bitcast i32* %[[e_addr]] to i8*
> +// WIN64: call void @handle_exception(i8* %[[e_i8]])
> +// WIN64: call void @llvm.eh.endcatch()
> +
> +struct A {
> + A();
> + A(const A &o);
> + ~A();
> + int a;
> +};
> +
> +struct B : A {
> + B();
> + B(const B &o);
> + ~B();
> + int b;
> +};
> +
> +extern "C" void catch_a_byval() {
> + try {
> + might_throw();
> + } catch (A e) {
> + handle_exception(&e);
> + }
> +}
> +
> +// WIN64-LABEL: define void @catch_a_byval()
> +// WIN64: %[[e_addr:[^ ]*]] = alloca %struct.A
> +// WIN64: landingpad { i8*, i32 }
> +// WIN64: %[[e_i8:[^ ]*]] = bitcast %struct.A* %[[e_addr]] to i8*
> +// WIN64: call void @llvm.eh.begincatch(i8* %{{.*}}, i8* %[[e_i8]])
> +// WIN64: %[[e_i8:[^ ]*]] = bitcast %struct.A* %[[e_addr]] to i8*
> +// WIN64: call void @handle_exception(i8* %[[e_i8]])
> +// WIN64: call void @llvm.eh.endcatch()
> +
> +extern "C" void catch_a_ref() {
> + try {
> + might_throw();
> + } catch (A &e) {
> + handle_exception(&e);
> + }
> +}
> +
> +// WIN64-LABEL: define void @catch_a_ref()
> +// WIN64: %[[e_addr:[^ ]*]] = alloca %struct.A*
> +// WIN64: landingpad { i8*, i32 }
> +// WIN64: %[[e_i8:[^ ]*]] = bitcast %struct.A** %[[e_addr]] to i8*
> +// WIN64: call void @llvm.eh.begincatch(i8* %{{.*}}, i8* %[[e_i8]])
> +// WIN64: %[[eptr:[^ ]*]] = load %struct.A*, %struct.A** %[[e_addr]]
> +// WIN64: %[[eptr_i8:[^ ]*]] = bitcast %struct.A* %[[eptr]] to i8*
> +// WIN64: call void @handle_exception(i8* %[[eptr_i8]])
> +// WIN64: call void @llvm.eh.endcatch()
>
> Copied: cfe/trunk/test/CodeGenCXX/microsoft-abi-eh-cleanups.cpp (from
> r231098, cfe/trunk/test/CodeGenCXX/microsoft-abi-exceptions.cpp)
> URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/microsoft-abi-eh-cleanups.cpp?p2=cfe/trunk/test/CodeGenCXX/microsoft-abi-eh-cleanups.cpp&p1=cfe/trunk/test/CodeGenCXX/microsoft-abi-exceptions.cpp&r1=231098&r2=231105&rev=231105&view=diff
>
> ==============================================================================
> --- cfe/trunk/test/CodeGenCXX/microsoft-abi-exceptions.cpp (original)
> +++ cfe/trunk/test/CodeGenCXX/microsoft-abi-eh-cleanups.cpp Tue Mar 3
> 13:21:04 2015
> @@ -1,4 +1,4 @@
> -// RUN: %clang_cc1 -emit-llvm %s -o - -triple=i386-pc-win32
> -mconstructor-aliases -fexceptions -fno-rtti | FileCheck -check-prefix
> WIN32 %s
> +// RUN: %clang_cc1 -emit-llvm %s -o - -triple=i386-pc-win32
> -mconstructor-aliases -fexceptions -fcxx-exceptions -fno-rtti | FileCheck
> -check-prefix WIN32 %s
>
> struct A {
> A();
>
> Removed: cfe/trunk/test/CodeGenCXX/microsoft-abi-exceptions.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/microsoft-abi-exceptions.cpp?rev=231104&view=auto
>
> ==============================================================================
> --- cfe/trunk/test/CodeGenCXX/microsoft-abi-exceptions.cpp (original)
> +++ cfe/trunk/test/CodeGenCXX/microsoft-abi-exceptions.cpp (removed)
> @@ -1,170 +0,0 @@
> -// RUN: %clang_cc1 -emit-llvm %s -o - -triple=i386-pc-win32
> -mconstructor-aliases -fexceptions -fno-rtti | FileCheck -check-prefix
> WIN32 %s
> -
> -struct A {
> - A();
> - ~A();
> - int a;
> -};
> -
> -A getA();
> -
> -int TakesTwo(A a, A b);
> -void HasEHCleanup() {
> - TakesTwo(getA(), getA());
> -}
> -
> -// With exceptions, we need to clean up at least one of these temporaries.
> -// WIN32-LABEL: define void @"\01?HasEHCleanup@@YAXXZ"() {{.*}} {
> -// WIN32: %[[base:.*]] = call i8* @llvm.stacksave()
> -// If this call throws, we have to restore the stack.
> -// WIN32: invoke void @"\01?getA@@YA?AUA@@XZ"(%struct.A* sret %{{.*}})
> -// If this call throws, we have to cleanup the first temporary.
> -// WIN32: invoke void @"\01?getA@@YA?AUA@@XZ"(%struct.A* sret %{{.*}})
> -// If this call throws, we have to cleanup the stacksave.
> -// WIN32: invoke i32 @"\01?TakesTwo@@YAHUA@@0 at Z"
> -// WIN32: call void @llvm.stackrestore(i8* %[[base]])
> -// WIN32: ret void
> -//
> -// There should be one dtor call for unwinding from the second getA.
> -// WIN32: invoke x86_thiscallcc void @"\01??1A@@QAE at XZ"
> -// WIN32-NOT: @"\01??1A@@QAE at XZ"
> -// WIN32: call void @llvm.stackrestore
> -// WIN32: }
> -
> -void TakeRef(const A &a);
> -int HasDeactivatedCleanups() {
> - return TakesTwo((TakeRef(A()), A()), (TakeRef(A()), A()));
> -}
> -
> -// WIN32-LABEL: define i32 @"\01?HasDeactivatedCleanups@@YAHXZ"() {{.*}}
> {
> -// WIN32: %[[isactive:.*]] = alloca i1
> -// WIN32: call i8* @llvm.stacksave()
> -// WIN32: %[[argmem:.*]] = alloca inalloca [[argmem_ty:<{ %struct.A,
> %struct.A }>]]
> -// WIN32: %[[arg1:.*]] = getelementptr inbounds [[argmem_ty]],
> [[argmem_ty]]* %[[argmem]], i32 0, i32 1
> -// WIN32: invoke x86_thiscallcc %struct.A* @"\01??0A@@QAE at XZ"
> -// WIN32: invoke void @"\01?TakeRef@@YAXABUA@@@Z"
> -//
> -// WIN32: invoke x86_thiscallcc %struct.A* @"\01??0A@@QAE at XZ"(%struct.A*
> %[[arg1]])
> -// WIN32: store i1 true, i1* %[[isactive]]
> -//
> -// WIN32: %[[arg0:.*]] = getelementptr inbounds [[argmem_ty]],
> [[argmem_ty]]* %[[argmem]], i32 0, i32 0
> -// WIN32: invoke x86_thiscallcc %struct.A* @"\01??0A@@QAE at XZ"
> -// WIN32: invoke void @"\01?TakeRef@@YAXABUA@@@Z"
> -// WIN32: invoke x86_thiscallcc %struct.A* @"\01??0A@@QAE at XZ"
> -// WIN32: store i1 false, i1* %[[isactive]]
> -//
> -// WIN32: invoke i32 @"\01?TakesTwo@@YAHUA@@0 at Z"([[argmem_ty]]*
> inalloca %[[argmem]])
> -// WIN32: call void @llvm.stackrestore
> -// Destroy the two const ref temporaries.
> -// WIN32: invoke x86_thiscallcc void @"\01??1A@@QAE at XZ"
> -// WIN32: invoke x86_thiscallcc void @"\01??1A@@QAE at XZ"
> -// WIN32: ret i32
> -//
> -// Conditionally destroy arg1.
> -// WIN32: %[[cond:.*]] = load i1, i1* %[[isactive]]
> -// WIN32: br i1 %[[cond]]
> -// WIN32: invoke x86_thiscallcc void @"\01??1A@@QAE at XZ"(%struct.A*
> %[[arg1]])
> -// WIN32: }
> -
> -// Test putting the cleanups inside a conditional.
> -int CouldThrow();
> -int HasConditionalCleanup(bool cond) {
> - return (cond ? TakesTwo(A(), A()) : CouldThrow());
> -}
> -
> -// WIN32-LABEL: define i32 @"\01?HasConditionalCleanup@@YAH_N at Z"(i1
> zeroext %{{.*}}) {{.*}} {
> -// WIN32: store i1 false
> -// WIN32: br i1
> -// WIN32: call i8* @llvm.stacksave()
> -// WIN32: invoke x86_thiscallcc %struct.A* @"\01??0A@@QAE at XZ"(%struct.A*
> %{{.*}})
> -// WIN32: store i1 true
> -// WIN32: invoke x86_thiscallcc %struct.A* @"\01??0A@@QAE at XZ"(%struct.A*
> %{{.*}})
> -// WIN32: invoke i32 @"\01?TakesTwo@@YAHUA@@0 at Z"
> -// WIN32: call void @llvm.stackrestore
> -//
> -// WIN32: call i32 @"\01?CouldThrow@@YAHXZ"()
> -//
> -// Only one dtor in the invoke for arg1
> -// WIN32: invoke x86_thiscallcc void @"\01??1A@@QAE at XZ"({{.*}})
> -// WIN32-NOT: invoke x86_thiscallcc void @"\01??1A@@QAE at XZ"
> -// WIN32: call void @llvm.stackrestore
> -// WIN32: }
> -
> -// Now test both.
> -int HasConditionalDeactivatedCleanups(bool cond) {
> - return (cond ? TakesTwo((TakeRef(A()), A()), (TakeRef(A()), A())) :
> CouldThrow());
> -}
> -
> -// WIN32-LABEL: define i32 @"\01?HasConditionalDeactivatedCleanups@
> @YAH_N at Z"{{.*}} {
> -// WIN32: alloca i1
> -// WIN32: %[[arg1_cond:.*]] = alloca i1
> -// Start all four cleanups as deactivated.
> -// WIN32: store i1 false
> -// WIN32: store i1 false
> -// WIN32: store i1 false
> -// WIN32: store i1 false
> -// WIN32: br i1
> -// True condition.
> -// WIN32: invoke x86_thiscallcc %struct.A* @"\01??0A@@QAE at XZ"
> -// WIN32: store i1 true
> -// WIN32: invoke void @"\01?TakeRef@@YAXABUA@@@Z"
> -// WIN32: invoke x86_thiscallcc %struct.A* @"\01??0A@@QAE at XZ"
> -// WIN32: store i1 true, i1* %[[arg1_cond]]
> -// WIN32: invoke x86_thiscallcc %struct.A* @"\01??0A@@QAE at XZ"
> -// WIN32: store i1 true
> -// WIN32: invoke void @"\01?TakeRef@@YAXABUA@@@Z"
> -// WIN32: invoke x86_thiscallcc %struct.A* @"\01??0A@@QAE at XZ"
> -// WIN32: store i1 true
> -// WIN32: store i1 false, i1* %[[arg1_cond]]
> -// WIN32: invoke i32 @"\01?TakesTwo@@YAHUA@@0 at Z"
> -// False condition.
> -// WIN32: invoke i32 @"\01?CouldThrow@@YAHXZ"()
> -// Two normal cleanups for TakeRef args.
> -// WIN32: invoke x86_thiscallcc void @"\01??1A@@QAE at XZ"
> -// WIN32: invoke x86_thiscallcc void @"\01??1A@@QAE at XZ"
> -// WIN32: ret i32
> -//
> -// Somewhere in the landing pad soup, we conditionally destroy
> arg1.
> -// WIN32: %[[isactive:.*]] = load i1, i1* %[[arg1_cond]]
> -// WIN32: br i1 %[[isactive]]
> -// WIN32: invoke x86_thiscallcc void @"\01??1A@@QAE at XZ"
> -// WIN32: }
> -
> -namespace crash_on_partial_destroy {
> -struct A {
> - virtual ~A();
> -};
> -
> -struct B : virtual A {
> - // Has an implicit destructor.
> -};
> -
> -struct C : B {
> - C();
> -};
> -
> -void foo();
> -// We used to crash when emitting this.
> -C::C() { foo(); }
> -
> -// Verify that we don't bother with a vbtable lookup when adjusting the
> this
> -// pointer to call a base destructor from a constructor while unwinding.
> -// WIN32-LABEL: define {{.*}} @"\01??0C at crash_on_partial_destroy@@QAE at XZ"{{.*}}
> {
> -// WIN32: landingpad
> -//
> -// We shouldn't do any vbptr loads, just constant GEPs.
> -// WIN32-NOT: load
> -// WIN32: getelementptr i8, i8* %{{.*}}, i32 4
> -// WIN32-NOT: load
> -// WIN32: bitcast i8* %{{.*}} to
> %"struct.crash_on_partial_destroy::B"*
> -// WIN32: invoke x86_thiscallcc void
> @"\01??1B at crash_on_partial_destroy@@UAE at XZ"
> -//
> -// WIN32-NOT: load
> -// WIN32: bitcast %"struct.crash_on_partial_destroy::C"* %{{.*}} to
> i8*
> -// WIN32-NOT: load
> -// WIN32: getelementptr inbounds i8, i8* %{{.*}}, i64 4
> -// WIN32-NOT: load
> -// WIN32: bitcast i8* %{{.*}} to
> %"struct.crash_on_partial_destroy::A"*
> -// WIN32: invoke x86_thiscallcc void
> @"\01??1A at crash_on_partial_destroy@@UAE at XZ"
> -// WIN32: }
> -}
>
> Modified: cfe/trunk/test/CodeGenCXX/microsoft-abi-try-throw.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/microsoft-abi-try-throw.cpp?rev=231105&r1=231104&r2=231105&view=diff
>
> ==============================================================================
> --- cfe/trunk/test/CodeGenCXX/microsoft-abi-try-throw.cpp (original)
> +++ cfe/trunk/test/CodeGenCXX/microsoft-abi-try-throw.cpp Tue Mar 3
> 13:21:04 2015
> @@ -1,5 +1,4 @@
> -// FIXME: Disabled until catch IRgen change lands.
> -// RUNX: %clang_cc1 -emit-llvm %s -o - -triple=i386-pc-win32
> -mconstructor-aliases -fcxx-exceptions -fexceptions -fno-rtti -DTRY |
> FileCheck %s -check-prefix=TRY
> +// RUN: %clang_cc1 -emit-llvm %s -o - -triple=i386-pc-win32
> -mconstructor-aliases -fcxx-exceptions -fexceptions -fno-rtti -DTRY |
> FileCheck %s -check-prefix=TRY
> // RUN: %clang_cc1 -emit-llvm %s -o - -triple=i386-pc-win32
> -mconstructor-aliases -fcxx-exceptions -fexceptions -fno-rtti -DTHROW |
> FileCheck %s -check-prefix=THROW
>
> void external();
> @@ -15,8 +14,8 @@ int main() {
> external(); // TRY: invoke void @"\01?external@@YAXXZ"
> } catch (int) {
> rv = 1;
> - // TRY: call i8* @llvm.eh.begincatch
> - // TRY: call void @llvm.eh.endcatch
> + // TRY: call void @llvm.eh.begincatch(i8* %{{.*}}, i8* %{{.*}})
> + // TRY: call void @llvm.eh.endcatch()
> }
> #endif
> #ifdef THROW
>
>
> _______________________________________________
> cfe-commits mailing list
> cfe-commits at cs.uiuc.edu
> http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/cfe-commits/attachments/20150303/95494c89/attachment.html>
More information about the cfe-commits
mailing list