Would've been good to land the move separately from the behavior change⦠On Tue, Mar 3, 2015 at 11:21 AM, Reid Kleckner <[email protected]> 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@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@XZ" > -// WIN32-NOT: @"\01??1A@@QAE@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@XZ" > -// WIN32: invoke void @"\01?TakeRef@@YAXABUA@@@Z" > -// > -// WIN32: invoke x86_thiscallcc %struct.A* @"\01??0A@@QAE@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@XZ" > -// WIN32: invoke void @"\01?TakeRef@@YAXABUA@@@Z" > -// WIN32: invoke x86_thiscallcc %struct.A* @"\01??0A@@QAE@XZ" > -// WIN32: store i1 false, i1* %[[isactive]] > -// > -// WIN32: invoke i32 @"\01?TakesTwo@@YAHUA@@0@Z"([[argmem_ty]]* > inalloca %[[argmem]]) > -// WIN32: call void @llvm.stackrestore > -// Destroy the two const ref temporaries. > -// WIN32: invoke x86_thiscallcc void @"\01??1A@@QAE@XZ" > -// WIN32: invoke x86_thiscallcc void @"\01??1A@@QAE@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@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@Z"(i1 > zeroext %{{.*}}) {{.*}} { > -// WIN32: store i1 false > -// WIN32: br i1 > -// WIN32: call i8* @llvm.stacksave() > -// WIN32: invoke x86_thiscallcc %struct.A* @"\01??0A@@QAE@XZ"(%struct.A* > %{{.*}}) > -// WIN32: store i1 true > -// WIN32: invoke x86_thiscallcc %struct.A* @"\01??0A@@QAE@XZ"(%struct.A* > %{{.*}}) > -// WIN32: invoke i32 @"\01?TakesTwo@@YAHUA@@0@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@XZ"({{.*}}) > -// WIN32-NOT: invoke x86_thiscallcc void @"\01??1A@@QAE@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@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@XZ" > -// WIN32: store i1 true > -// WIN32: invoke void @"\01?TakeRef@@YAXABUA@@@Z" > -// WIN32: invoke x86_thiscallcc %struct.A* @"\01??0A@@QAE@XZ" > -// WIN32: store i1 true, i1* %[[arg1_cond]] > -// WIN32: invoke x86_thiscallcc %struct.A* @"\01??0A@@QAE@XZ" > -// WIN32: store i1 true > -// WIN32: invoke void @"\01?TakeRef@@YAXABUA@@@Z" > -// WIN32: invoke x86_thiscallcc %struct.A* @"\01??0A@@QAE@XZ" > -// WIN32: store i1 true > -// WIN32: store i1 false, i1* %[[arg1_cond]] > -// WIN32: invoke i32 @"\01?TakesTwo@@YAHUA@@0@Z" > -// False condition. > -// WIN32: invoke i32 @"\01?CouldThrow@@YAHXZ"() > -// Two normal cleanups for TakeRef args. > -// WIN32: invoke x86_thiscallcc void @"\01??1A@@QAE@XZ" > -// WIN32: invoke x86_thiscallcc void @"\01??1A@@QAE@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@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@crash_on_partial_destroy@@QAE@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@crash_on_partial_destroy@@UAE@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@crash_on_partial_destroy@@UAE@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 > [email protected] > http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits >
_______________________________________________ cfe-commits mailing list [email protected] http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits
