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