forked from xt-sys/xtchain
		
	Add Hardware Exception for Structured Exception Handling (SEH)
This commit is contained in:
		
							
								
								
									
										601
									
								
								patches/llvm/11.0.0/001-hardware-exception-handling.patch
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										601
									
								
								patches/llvm/11.0.0/001-hardware-exception-handling.patch
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,601 @@ | ||||
| diff --git a/clang/include/clang/AST/Stmt.h b/clang/include/clang/AST/Stmt.h | ||||
| index d3fad58fcf5..dccbbe2fade 100644 | ||||
| --- a/clang/include/clang/AST/Stmt.h | ||||
| +++ b/clang/include/clang/AST/Stmt.h | ||||
| @@ -1764,6 +1764,7 @@ public: | ||||
|  class LabelStmt : public ValueStmt { | ||||
|    LabelDecl *TheDecl; | ||||
|    Stmt *SubStmt; | ||||
| +  bool SideEntry = false; | ||||
|   | ||||
|  public: | ||||
|    /// Build a label statement. | ||||
| @@ -1799,6 +1800,9 @@ public: | ||||
|    static bool classof(const Stmt *T) { | ||||
|      return T->getStmtClass() == LabelStmtClass; | ||||
|    } | ||||
| + | ||||
| +  bool isSideEntry() const { return SideEntry; } | ||||
| +  void setSideEntry() { SideEntry = true; } | ||||
|  }; | ||||
|   | ||||
|  /// Represents an attribute applied to a statement. | ||||
| diff --git a/clang/include/clang/Basic/LangOptions.def b/clang/include/clang/Basic/LangOptions.def | ||||
| index 70f68d664bb..1e87b455db8 100644 | ||||
| --- a/clang/include/clang/Basic/LangOptions.def | ||||
| +++ b/clang/include/clang/Basic/LangOptions.def | ||||
| @@ -128,6 +128,7 @@ LANGOPT(ZVector           , 1, 0, "System z vector extensions") | ||||
|  LANGOPT(Exceptions        , 1, 0, "exception handling") | ||||
|  LANGOPT(ObjCExceptions    , 1, 0, "Objective-C exceptions") | ||||
|  LANGOPT(CXXExceptions     , 1, 0, "C++ exceptions") | ||||
| +LANGOPT(EHAsynch          , 1, 0, "C/C++ EH Asynch exceptions") | ||||
|  LANGOPT(DWARFExceptions   , 1, 0, "dwarf exception handling") | ||||
|  LANGOPT(SjLjExceptions    , 1, 0, "setjmp-longjump exception handling") | ||||
|  LANGOPT(SEHExceptions     , 1, 0, "SEH .xdata exception handling") | ||||
| diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td | ||||
| index 966cb907b7e..dc7b38c254f 100644 | ||||
| --- a/clang/include/clang/Driver/Options.td | ||||
| +++ b/clang/include/clang/Driver/Options.td | ||||
| @@ -889,6 +889,8 @@ def fno_crash_diagnostics : Flag<["-"], "fno-crash-diagnostics">, Group<f_clang_ | ||||
|  def fcrash_diagnostics_dir : Joined<["-"], "fcrash-diagnostics-dir=">, Group<f_clang_Group>, Flags<[NoArgumentUnused, CoreOption]>; | ||||
|  def fcreate_profile : Flag<["-"], "fcreate-profile">, Group<f_Group>; | ||||
|  defm cxx_exceptions: OptInFFlag<"cxx-exceptions", "Enable C++ exceptions">; | ||||
| +def feh_asynch: Flag<["-"], "feh-asynch">, Group<f_Group>, | ||||
| +  HelpText<"Enable EH Asynchronous exceptions">, Flags<[CC1Option]>; | ||||
|  def fcxx_modules : Flag <["-"], "fcxx-modules">, Group<f_Group>, | ||||
|    Flags<[DriverOption]>; | ||||
|  def fdebug_pass_arguments : Flag<["-"], "fdebug-pass-arguments">, Group<f_Group>; | ||||
| @@ -1505,6 +1507,7 @@ def fno_common : Flag<["-"], "fno-common">, Group<f_Group>, Flags<[CC1Option]>, | ||||
|  def fno_constant_cfstrings : Flag<["-"], "fno-constant-cfstrings">, Group<f_Group>, | ||||
|    Flags<[CC1Option]>, | ||||
|    HelpText<"Disable creation of CodeFoundation-type constant strings">; | ||||
| +def fno_eh_asynch: Flag<["-"], "fno-eh-asynch">, Group<f_Group>; | ||||
|  def fno_cxx_modules : Flag <["-"], "fno-cxx-modules">, Group<f_Group>, | ||||
|    Flags<[DriverOption]>; | ||||
|  def fno_diagnostics_fixit_info : Flag<["-"], "fno-diagnostics-fixit-info">, Group<f_Group>, | ||||
| diff --git a/clang/lib/CodeGen/CGCleanup.cpp b/clang/lib/CodeGen/CGCleanup.cpp | ||||
| index ad543ef86c1..7c1902f080f 100644 | ||||
| --- a/clang/lib/CodeGen/CGCleanup.cpp | ||||
| +++ b/clang/lib/CodeGen/CGCleanup.cpp | ||||
| @@ -763,10 +763,22 @@ void CodeGenFunction::PopCleanupBlock(bool FallthroughIsBranchThrough) { | ||||
|      destroyOptimisticNormalEntry(*this, Scope); | ||||
|      EHStack.popCleanup(); | ||||
|    } else { | ||||
| +    // Under -EHa, invoke eha_scope_end() to mark scope end before dtor | ||||
| +    bool IsEHa = getLangOpts().EHAsynch && !Scope.isLifetimeMarker(); | ||||
| +    const EHPersonality &Personality = EHPersonality::get(*this); | ||||
| + | ||||
|      // If we have a fallthrough and no other need for the cleanup, | ||||
|      // emit it directly. | ||||
| -    if (HasFallthrough && !HasPrebranchedFallthrough && | ||||
| -        !HasFixups && !HasExistingBranches) { | ||||
| +    if (HasFallthrough && !HasPrebranchedFallthrough && !HasFixups && | ||||
| +        !HasExistingBranches) { | ||||
| + | ||||
| +      // mark EHa scope end for fall-through flow | ||||
| +      if (IsEHa && getInvokeDest()) | ||||
| +        if (Personality.isMSVCXXPersonality()) | ||||
| +          EmitSehCppScopeEnd(); | ||||
| +        else { | ||||
| +          EmitSehTryScopeEnd(); | ||||
| +        } | ||||
|   | ||||
|        destroyOptimisticNormalEntry(*this, Scope); | ||||
|        EHStack.popCleanup(); | ||||
| @@ -801,6 +813,14 @@ void CodeGenFunction::PopCleanupBlock(bool FallthroughIsBranchThrough) { | ||||
|        // should already be branched to it. | ||||
|        EmitBlock(NormalEntry); | ||||
|   | ||||
| +      // intercept normal cleanup to mark EHa scope end | ||||
| +      if (IsEHa) | ||||
| +        if (Personality.isMSVCXXPersonality()) | ||||
| +          EmitSehCppScopeEnd(); | ||||
| +        else { | ||||
| +          EmitSehTryScopeEnd(); | ||||
| +        } | ||||
| + | ||||
|        // III.  Figure out where we're going and build the cleanup | ||||
|        // epilogue. | ||||
|   | ||||
| @@ -1276,3 +1296,61 @@ void CodeGenFunction::EmitCXXTemporary(const CXXTemporary *Temporary, | ||||
|    pushDestroy(NormalAndEHCleanup, Ptr, TempType, destroyCXXObject, | ||||
|                /*useEHCleanup*/ true); | ||||
|  } | ||||
| + | ||||
| +// Need to set "funclet" in OperandBundle properly for noThrow | ||||
| +//       intrinsic (see CGCall.cpp) | ||||
| +static void EmitSehEHaScope(CodeGenFunction &CGF, | ||||
| +                            llvm::FunctionCallee &SehCppScope) { | ||||
| +  llvm::BasicBlock *InvokeDest = CGF.getInvokeDest(); | ||||
| +  llvm::BasicBlock *BB = CGF.Builder.GetInsertBlock(); | ||||
| +  assert(BB && InvokeDest); | ||||
| +  llvm::BasicBlock *Cont = CGF.createBasicBlock("invoke.cont"); | ||||
| +  SmallVector<llvm::OperandBundleDef, 1> BundleList = | ||||
| +      CGF.getBundlesForFunclet(SehCppScope.getCallee()); | ||||
| +  if (CGF.CurrentFuncletPad) | ||||
| +    BundleList.emplace_back("funclet", CGF.CurrentFuncletPad); | ||||
| +  CGF.Builder.CreateInvoke(SehCppScope, Cont, InvokeDest, None, BundleList); | ||||
| +  CGF.EmitBlock(Cont); | ||||
| +} | ||||
| + | ||||
| +// Invoke a llvm.eha.scope.begin at the beginning of a CPP scope for -EHa | ||||
| +void CodeGenFunction::EmitSehCppScopeBegin() { | ||||
| +  assert(getLangOpts().EHAsynch); | ||||
| +  llvm::FunctionType *FTy = | ||||
| +      llvm::FunctionType::get(CGM.VoidTy, /*isVarArg=*/false); | ||||
| +  llvm::FunctionCallee SehCppScope = | ||||
| +      CGM.CreateRuntimeFunction(FTy, "llvm.eha.scope.begin"); | ||||
| +  EmitSehEHaScope(*this, SehCppScope); | ||||
| +} | ||||
| + | ||||
| +// Invoke a llvm.eha.scope.end at the end of a CPP scope for -EHa | ||||
| +//   llvm.eha.scope.end is emitted before popCleanup, so it's "invoked" | ||||
| +void CodeGenFunction::EmitSehCppScopeEnd() { | ||||
| +  assert(getLangOpts().EHAsynch); | ||||
| +  llvm::FunctionType *FTy = | ||||
| +      llvm::FunctionType::get(CGM.VoidTy, /*isVarArg=*/false); | ||||
| +  llvm::FunctionCallee SehCppScope = | ||||
| +      CGM.CreateRuntimeFunction(FTy, "llvm.eha.scope.end"); | ||||
| +  EmitSehEHaScope(*this, SehCppScope); | ||||
| +} | ||||
| + | ||||
| +// Invoke a llvm.eha.scope.begin at the beginning of a CPP scope for -EHa | ||||
| +void CodeGenFunction::EmitSehTryScopeBegin() { | ||||
| +  assert(getLangOpts().EHAsynch); | ||||
| +  llvm::FunctionType *FTy = | ||||
| +      llvm::FunctionType::get(CGM.VoidTy, /*isVarArg=*/false); | ||||
| +  llvm::FunctionCallee SehCppScope = | ||||
| +      CGM.CreateRuntimeFunction(FTy, "llvm.seh.try.begin"); | ||||
| +  EmitSehEHaScope(*this, SehCppScope); | ||||
| +} | ||||
| + | ||||
| +// Invoke a llvm.eha.scope.end at the end of a CPP scope for -EHa | ||||
| +//   llvm.eha.scope.end is emitted before popCleanup, so it's "invoked" | ||||
| +void CodeGenFunction::EmitSehTryScopeEnd() { | ||||
| +  assert(getLangOpts().EHAsynch); | ||||
| +  llvm::FunctionType *FTy = | ||||
| +      llvm::FunctionType::get(CGM.VoidTy, /*isVarArg=*/false); | ||||
| +  llvm::FunctionCallee SehCppScope = | ||||
| +      CGM.CreateRuntimeFunction(FTy, "llvm.seh.try.end"); | ||||
| +  EmitSehEHaScope(*this, SehCppScope); | ||||
| +} | ||||
| diff --git a/clang/lib/CodeGen/CGDecl.cpp b/clang/lib/CodeGen/CGDecl.cpp | ||||
| index 1729c7ed3c3..c9107b1296f 100644 | ||||
| --- a/clang/lib/CodeGen/CGDecl.cpp | ||||
| +++ b/clang/lib/CodeGen/CGDecl.cpp | ||||
| @@ -2006,9 +2006,16 @@ void CodeGenFunction::EmitAutoVarCleanups(const AutoVarEmission &emission) { | ||||
|    const VarDecl &D = *emission.Variable; | ||||
|   | ||||
|    // Check the type for a cleanup. | ||||
| -  if (QualType::DestructionKind dtorKind = D.needsDestruction(getContext())) | ||||
| +  if (QualType::DestructionKind dtorKind = D.needsDestruction(getContext())) { | ||||
|      emitAutoVarTypeCleanup(emission, dtorKind); | ||||
|   | ||||
| +    // Under -EHa, Invoke llvm.eha.scope.begin() right after | ||||
| +    //   Ctor is emitted and EHStack.pushCleanup | ||||
| +    bool IsEHa = getLangOpts().EHAsynch; | ||||
| +    if (IsEHa && dtorKind == QualType::DK_cxx_destructor) | ||||
| +      EmitSehCppScopeBegin(); | ||||
| +  } | ||||
| + | ||||
|    // In GC mode, honor objc_precise_lifetime. | ||||
|    if (getLangOpts().getGC() != LangOptions::NonGC && | ||||
|        D.hasAttr<ObjCPreciseLifetimeAttr>()) { | ||||
| diff --git a/clang/lib/CodeGen/CGException.cpp b/clang/lib/CodeGen/CGException.cpp | ||||
| index bdf70252b5a..a4e4d7d8120 100644 | ||||
| --- a/clang/lib/CodeGen/CGException.cpp | ||||
| +++ b/clang/lib/CodeGen/CGException.cpp | ||||
| @@ -39,6 +39,18 @@ static llvm::FunctionCallee getFreeExceptionFn(CodeGenModule &CGM) { | ||||
|    return CGM.CreateRuntimeFunction(FTy, "__cxa_free_exception"); | ||||
|  } | ||||
|   | ||||
| +static llvm::FunctionCallee getSehTryBeginFn(CodeGenModule &CGM) { | ||||
| +  llvm::FunctionType *FTy = | ||||
| +      llvm::FunctionType::get(CGM.VoidTy, /*isVarArg=*/false); | ||||
| +  return CGM.CreateRuntimeFunction(FTy, "llvm.seh.try.begin"); | ||||
| +} | ||||
| + | ||||
| +static llvm::FunctionCallee getSehTryEndFn(CodeGenModule &CGM) { | ||||
| +  llvm::FunctionType *FTy = | ||||
| +      llvm::FunctionType::get(CGM.VoidTy, /*isVarArg=*/false); | ||||
| +  return CGM.CreateRuntimeFunction(FTy, "llvm.seh.try.end"); | ||||
| +} | ||||
| + | ||||
|  static llvm::FunctionCallee getUnexpectedFn(CodeGenModule &CGM) { | ||||
|    // void __cxa_call_unexpected(void *thrown_exception); | ||||
|   | ||||
| @@ -451,7 +463,7 @@ void CodeGenFunction::EmitStartEHSpec(const Decl *D) { | ||||
|    if (!FD) { | ||||
|      // Check if CapturedDecl is nothrow and create terminate scope for it. | ||||
|      if (const CapturedDecl* CD = dyn_cast_or_null<CapturedDecl>(D)) { | ||||
| -      if (CD->isNothrow()) | ||||
| +      if (CD->isNothrow() && !getLangOpts().EHAsynch /* !IsEHa */) | ||||
|          EHStack.pushTerminate(); | ||||
|      } | ||||
|      return; | ||||
| @@ -463,7 +475,8 @@ void CodeGenFunction::EmitStartEHSpec(const Decl *D) { | ||||
|    ExceptionSpecificationType EST = Proto->getExceptionSpecType(); | ||||
|    if (isNoexceptExceptionSpec(EST) && Proto->canThrow() == CT_Cannot) { | ||||
|      // noexcept functions are simple terminate scopes. | ||||
| -    EHStack.pushTerminate(); | ||||
| +    if (!getLangOpts().EHAsynch) // -EHa: HW exception still can occur | ||||
| +      EHStack.pushTerminate(); | ||||
|    } else if (EST == EST_Dynamic || EST == EST_DynamicNone) { | ||||
|      // TODO: Revisit exception specifications for the MS ABI.  There is a way to | ||||
|      // encode these in an object file but MSVC doesn't do anything with it. | ||||
| @@ -540,7 +553,7 @@ void CodeGenFunction::EmitEndEHSpec(const Decl *D) { | ||||
|    if (!FD) { | ||||
|      // Check if CapturedDecl is nothrow and pop terminate scope for it. | ||||
|      if (const CapturedDecl* CD = dyn_cast_or_null<CapturedDecl>(D)) { | ||||
| -      if (CD->isNothrow()) | ||||
| +      if (CD->isNothrow() && !EHStack.empty()) | ||||
|          EHStack.popTerminate(); | ||||
|      } | ||||
|      return; | ||||
| @@ -550,7 +563,8 @@ void CodeGenFunction::EmitEndEHSpec(const Decl *D) { | ||||
|      return; | ||||
|   | ||||
|    ExceptionSpecificationType EST = Proto->getExceptionSpecType(); | ||||
| -  if (isNoexceptExceptionSpec(EST) && Proto->canThrow() == CT_Cannot) { | ||||
| +  if (isNoexceptExceptionSpec(EST) && Proto->canThrow() == CT_Cannot && | ||||
| +      !EHStack.empty() /* possible empty when -EHa */) { | ||||
|      EHStack.popTerminate(); | ||||
|    } else if (EST == EST_Dynamic || EST == EST_DynamicNone) { | ||||
|      // TODO: Revisit exception specifications for the MS ABI.  There is a way to | ||||
| @@ -606,6 +620,9 @@ void CodeGenFunction::EnterCXXTryStmt(const CXXTryStmt &S, bool IsFnTryBlock) { | ||||
|      } else { | ||||
|        // No exception decl indicates '...', a catch-all. | ||||
|        CatchScope->setHandler(I, CGM.getCXXABI().getCatchAllTypeInfo(), Handler); | ||||
| +      // Mark scope with SehTryBegin | ||||
| +      if (getLangOpts().EHAsynch) | ||||
| +        EmitRuntimeCallOrInvoke(getSehTryBeginFn(CGM)); | ||||
|      } | ||||
|    } | ||||
|  } | ||||
| @@ -720,7 +737,7 @@ llvm::BasicBlock *CodeGenFunction::getInvokeDestImpl() { | ||||
|    // If exceptions are disabled/ignored and SEH is not in use, then there is no | ||||
|    // invoke destination. SEH "works" even if exceptions are off. In practice, | ||||
|    // this means that C++ destructors and other EH cleanups don't run, which is | ||||
| -  // consistent with MSVC's behavior. | ||||
| +  // consistent with MSVC's behavior, except in the presence of -EHa | ||||
|    const LangOptions &LO = CGM.getLangOpts(); | ||||
|    if (!LO.Exceptions || LO.IgnoreExceptions) { | ||||
|      if (!LO.Borland && !LO.MicrosoftExt) | ||||
| @@ -1610,7 +1627,23 @@ void CodeGenFunction::EmitSEHTryStmt(const SEHTryStmt &S) { | ||||
|      JumpDest TryExit = getJumpDestInCurrentScope("__try.__leave"); | ||||
|   | ||||
|      SEHTryEpilogueStack.push_back(&TryExit); | ||||
| + | ||||
| +    llvm::BasicBlock *TryBB = nullptr; | ||||
| +    // IsEHa: emit an invoke to _seh_try_begin() runtime for -EHa | ||||
| +    if (getLangOpts().EHAsynch) { | ||||
| +      EmitRuntimeCallOrInvoke(getSehTryBeginFn(CGM)); | ||||
| +      if (SEHTryEpilogueStack.size() == 1) // outermost only | ||||
| +        TryBB = Builder.GetInsertBlock(); | ||||
| +    } | ||||
| + | ||||
|      EmitStmt(S.getTryBlock()); | ||||
| + | ||||
| +    // Volatilize all blocks in Try, till current insert point | ||||
| +    if (TryBB) { | ||||
| +      llvm::SmallPtrSet<llvm::BasicBlock *, 10> Visited; | ||||
| +      VolatilizeTryBlocks(TryBB, Visited); | ||||
| +    } | ||||
| + | ||||
|      SEHTryEpilogueStack.pop_back(); | ||||
|   | ||||
|      if (!TryExit.getBlock()->use_empty()) | ||||
| @@ -1621,6 +1654,38 @@ void CodeGenFunction::EmitSEHTryStmt(const SEHTryStmt &S) { | ||||
|    ExitSEHTryStmt(S); | ||||
|  } | ||||
|   | ||||
| +//  Recursively walk through blocks in a _try | ||||
| +//      and make all memory instructions volatile | ||||
| +void CodeGenFunction::VolatilizeTryBlocks( | ||||
| +    llvm::BasicBlock *BB, llvm::SmallPtrSet<llvm::BasicBlock *, 10> &V) { | ||||
| +  if (BB == SEHTryEpilogueStack.back()->getBlock() /* end of Try */ || | ||||
| +      !V.insert(BB).second /* already visited */ || | ||||
| +      !BB->getParent() /* not emitted */ || BB->empty()) | ||||
| +    return; | ||||
| + | ||||
| +  if (!BB->isEHPad()) { | ||||
| +    for (llvm::BasicBlock::iterator J = BB->begin(), JE = BB->end(); J != JE; | ||||
| +         ++J) { | ||||
| +      if (isa<llvm::LoadInst>(J)) { | ||||
| +        auto LI = cast<llvm::LoadInst>(J); | ||||
| +        LI->setVolatile(true); | ||||
| +      } else if (isa<llvm::StoreInst>(J)) { | ||||
| +        auto SI = cast<llvm::StoreInst>(J); | ||||
| +        SI->setVolatile(true); | ||||
| +      } else if (isa<llvm::MemIntrinsic>(J)) { | ||||
| +        auto *MCI = cast<llvm::MemIntrinsic>(J); | ||||
| +        MCI->setVolatile(llvm::ConstantInt::get(Builder.getInt1Ty(), 1)); | ||||
| +      } | ||||
| +    } | ||||
| +  } | ||||
| +  const llvm::Instruction *TI = BB->getTerminator(); | ||||
| +  if (TI) { | ||||
| +    unsigned N = TI->getNumSuccessors(); | ||||
| +    for (unsigned I = 0; I < N; I++) | ||||
| +      VolatilizeTryBlocks(TI->getSuccessor(I), V); | ||||
| +  } | ||||
| +} | ||||
| + | ||||
|  namespace { | ||||
|  struct PerformSEHFinally final : EHScopeStack::Cleanup { | ||||
|    llvm::Function *OutlinedFinally; | ||||
| @@ -2101,6 +2166,12 @@ void CodeGenFunction::ExitSEHTryStmt(const SEHTryStmt &S) { | ||||
|      return; | ||||
|    } | ||||
|   | ||||
| +  // IsEHa: emit an invoke _seh_try_end() to mark end of FT flow | ||||
| +  if (getLangOpts().EHAsynch && Builder.GetInsertBlock()) { | ||||
| +    llvm::FunctionCallee SehTryEnd = getSehTryEndFn(CGM); | ||||
| +    EmitRuntimeCallOrInvoke(SehTryEnd); | ||||
| +  } | ||||
| + | ||||
|    // Otherwise, we must have an __except block. | ||||
|    const SEHExceptStmt *Except = S.getExceptHandler(); | ||||
|    assert(Except && "__try must have __finally xor __except"); | ||||
| diff --git a/clang/lib/CodeGen/CGStmt.cpp b/clang/lib/CodeGen/CGStmt.cpp | ||||
| index 672909849bb..32dca08b8cf 100644 | ||||
| --- a/clang/lib/CodeGen/CGStmt.cpp | ||||
| +++ b/clang/lib/CodeGen/CGStmt.cpp | ||||
| @@ -606,6 +606,11 @@ void CodeGenFunction::LexicalScope::rescopeLabels() { | ||||
|   | ||||
|  void CodeGenFunction::EmitLabelStmt(const LabelStmt &S) { | ||||
|    EmitLabel(S.getDecl()); | ||||
| + | ||||
| +  // IsEHa - emit eha.scope.begin if it's a side entry of a scope | ||||
| +  if (getLangOpts().EHAsynch && S.isSideEntry()) | ||||
| +    EmitSehCppScopeBegin(); | ||||
| + | ||||
|    EmitStmt(S.getSubStmt()); | ||||
|  } | ||||
|   | ||||
| diff --git a/clang/lib/CodeGen/CodeGenFunction.h b/clang/lib/CodeGen/CodeGenFunction.h | ||||
| index d794f4f0fa8..1b5892c7459 100644 | ||||
| --- a/clang/lib/CodeGen/CodeGenFunction.h | ||||
| +++ b/clang/lib/CodeGen/CodeGenFunction.h | ||||
| @@ -2784,6 +2784,11 @@ public: | ||||
|    void EmitCXXTemporary(const CXXTemporary *Temporary, QualType TempType, | ||||
|                          Address Ptr); | ||||
|   | ||||
| +  void EmitSehCppScopeBegin(); | ||||
| +  void EmitSehCppScopeEnd(); | ||||
| +  void EmitSehTryScopeBegin(); | ||||
| +  void EmitSehTryScopeEnd(); | ||||
| + | ||||
|    llvm::Value *EmitLifetimeStart(uint64_t Size, llvm::Value *Addr); | ||||
|    void EmitLifetimeEnd(llvm::Value *Size, llvm::Value *Addr); | ||||
|   | ||||
| @@ -3134,6 +3139,8 @@ public: | ||||
|    void EmitSEHLeaveStmt(const SEHLeaveStmt &S); | ||||
|    void EnterSEHTryStmt(const SEHTryStmt &S); | ||||
|    void ExitSEHTryStmt(const SEHTryStmt &S); | ||||
| +  void VolatilizeTryBlocks(llvm::BasicBlock *BB, | ||||
| +                           llvm::SmallPtrSet<llvm::BasicBlock *, 10> &V); | ||||
|   | ||||
|    void pushSEHCleanup(CleanupKind kind, | ||||
|                        llvm::Function *FinallyFunc); | ||||
| diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp | ||||
| index 4ae8ce7e5cc..5512c8fe88a 100644 | ||||
| --- a/clang/lib/CodeGen/CodeGenModule.cpp | ||||
| +++ b/clang/lib/CodeGen/CodeGenModule.cpp | ||||
| @@ -593,6 +593,9 @@ void CodeGenModule::Release() { | ||||
|                                    llvm::DenormalMode::IEEE); | ||||
|    } | ||||
|   | ||||
| +  if (LangOpts.EHAsynch) | ||||
| +    getModule().addModuleFlag(llvm::Module::Warning, "eh-asynch", 1); | ||||
| + | ||||
|    // Emit OpenCL specific module metadata: OpenCL/SPIR version. | ||||
|    if (LangOpts.OpenCL) { | ||||
|      EmitOpenCLMetadata(); | ||||
| diff --git a/clang/lib/CodeGen/MicrosoftCXXABI.cpp b/clang/lib/CodeGen/MicrosoftCXXABI.cpp | ||||
| index 45c6cb6b2e0..a080c93356a 100644 | ||||
| --- a/clang/lib/CodeGen/MicrosoftCXXABI.cpp | ||||
| +++ b/clang/lib/CodeGen/MicrosoftCXXABI.cpp | ||||
| @@ -131,7 +131,12 @@ public: | ||||
|   | ||||
|    /// MSVC needs an extra flag to indicate a catchall. | ||||
|    CatchTypeInfo getCatchAllTypeInfo() override { | ||||
| -    return CatchTypeInfo{nullptr, 0x40}; | ||||
| +    // For -EHa catch(...) must handle HW exception | ||||
| +    // Adjective = HT_IsStdDotDot (0x40), only catch C++ exceptions | ||||
| +    if (getContext().getLangOpts().EHAsynch) | ||||
| +      return CatchTypeInfo{nullptr, 0}; | ||||
| +    else | ||||
| +      return CatchTypeInfo{nullptr, 0x40}; | ||||
|    } | ||||
|   | ||||
|    bool shouldTypeidBeNullChecked(bool IsDeref, QualType SrcRecordTy) override; | ||||
| diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp | ||||
| index af4bcf951e6..71112783ac0 100644 | ||||
| --- a/clang/lib/Driver/ToolChains/Clang.cpp | ||||
| +++ b/clang/lib/Driver/ToolChains/Clang.cpp | ||||
| @@ -415,6 +415,7 @@ static void addExceptionArgs(const ArgList &Args, types::ID InputType, | ||||
|      Args.ClaimAllArgs(options::OPT_fobjc_exceptions); | ||||
|      Args.ClaimAllArgs(options::OPT_fno_objc_exceptions); | ||||
|      Args.ClaimAllArgs(options::OPT_fcxx_exceptions); | ||||
| +    Args.ClaimAllArgs(options::OPT_feh_asynch); | ||||
|      Args.ClaimAllArgs(options::OPT_fno_cxx_exceptions); | ||||
|      return; | ||||
|    } | ||||
| @@ -423,6 +424,13 @@ static void addExceptionArgs(const ArgList &Args, types::ID InputType, | ||||
|    bool EH = Args.hasFlag(options::OPT_fexceptions, options::OPT_fno_exceptions, | ||||
|                           false); | ||||
|   | ||||
| +  bool EHa = | ||||
| +      Args.hasFlag(options::OPT_feh_asynch, options::OPT_fno_eh_asynch, false); | ||||
| +  if (EHa) { | ||||
| +    CmdArgs.push_back("-feh-asynch"); | ||||
| +    EH = true; | ||||
| +  } | ||||
| + | ||||
|    // Obj-C exceptions are enabled by default, regardless of -fexceptions. This | ||||
|    // is not necessarily sensible, but follows GCC. | ||||
|    if (types::isObjC(InputType) && | ||||
| @@ -6581,7 +6589,10 @@ void Clang::AddClangCLArgs(const ArgList &Args, types::ID InputType, | ||||
|      if (types::isCXX(InputType)) | ||||
|        CmdArgs.push_back("-fcxx-exceptions"); | ||||
|      CmdArgs.push_back("-fexceptions"); | ||||
| +    if (EH.Asynch) | ||||
| +      CmdArgs.push_back("-feh-asynch"); | ||||
|    } | ||||
| + | ||||
|    if (types::isCXX(InputType) && EH.Synch && EH.NoUnwindC) | ||||
|      CmdArgs.push_back("-fexternc-nounwind"); | ||||
|   | ||||
| diff --git a/clang/lib/Frontend/CompilerInvocation.cpp b/clang/lib/Frontend/CompilerInvocation.cpp | ||||
| index 73114c6d76c..b58af0b68e7 100644 | ||||
| --- a/clang/lib/Frontend/CompilerInvocation.cpp | ||||
| +++ b/clang/lib/Frontend/CompilerInvocation.cpp | ||||
| @@ -2819,6 +2819,7 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK, | ||||
|    Opts.IgnoreExceptions = Args.hasArg(OPT_fignore_exceptions); | ||||
|    Opts.ObjCExceptions = Args.hasArg(OPT_fobjc_exceptions); | ||||
|    Opts.CXXExceptions = Args.hasArg(OPT_fcxx_exceptions); | ||||
| +  Opts.EHAsynch = Args.hasArg(OPT_feh_asynch); | ||||
|   | ||||
|    // -ffixed-point | ||||
|    Opts.FixedPoint = | ||||
| diff --git a/clang/lib/Sema/JumpDiagnostics.cpp b/clang/lib/Sema/JumpDiagnostics.cpp | ||||
| index b34243edea3..cbc309a3d42 100644 | ||||
| --- a/clang/lib/Sema/JumpDiagnostics.cpp | ||||
| +++ b/clang/lib/Sema/JumpDiagnostics.cpp | ||||
| @@ -930,6 +930,9 @@ void JumpScopeChecker::CheckJump(Stmt *From, Stmt *To, SourceLocation DiagLoc, | ||||
|    if (!ToScopesWarning.empty()) { | ||||
|      S.Diag(DiagLoc, JumpDiagWarning); | ||||
|      NoteJumpIntoScopes(ToScopesWarning); | ||||
| +    assert(isa<LabelStmt>(To)); | ||||
| +    LabelStmt *Label = cast<LabelStmt>(To); | ||||
| +    Label->setSideEntry(); | ||||
|    } | ||||
|   | ||||
|    // Handle errors. | ||||
| diff --git a/llvm/docs/LangRef.rst b/llvm/docs/LangRef.rst | ||||
| index 9b58b9dfb17..1738ccd94ee 100644 | ||||
| --- a/llvm/docs/LangRef.rst | ||||
| +++ b/llvm/docs/LangRef.rst | ||||
| @@ -11642,6 +11642,59 @@ The '``llvm.localescape``' intrinsic blocks inlining, as inlining changes where | ||||
|  the escaped allocas are allocated, which would break attempts to use | ||||
|  '``llvm.localrecover``'. | ||||
|   | ||||
| +'``llvm.seh.try.begin``' and '``llvm.seh.try.end``' Intrinsics | ||||
| +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ||||
| + | ||||
| +Syntax: | ||||
| +""""""" | ||||
| + | ||||
| +:: | ||||
| + | ||||
| +      declare void @llvm.seh.try.begin() | ||||
| +      declare void @llvm.seh.try.end() | ||||
| + | ||||
| +Overview: | ||||
| +""""""""" | ||||
| + | ||||
| +The '``llvm.seh.try.begin``' and '``llvm.seh.try.end``' intrinsics mark | ||||
| +the boundary of a _try region for Windows SEH Asynchrous Exception Handling. | ||||
| + | ||||
| +Semantics: | ||||
| +"""""""""" | ||||
| + | ||||
| +When a C-function is compiled with Windows SEH Asynchrous Exception option, | ||||
| +-feh_asynch (aka MSVC -EHa), these two intrinsics are injected to mark _try | ||||
| +boundary and to prevent from potential exceptions being moved across boundary. | ||||
| + | ||||
| +'``llvm.eha.scope.begin``' and '``llvm.eha.scope.end``' Intrinsics | ||||
| +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ||||
| + | ||||
| +Syntax: | ||||
| +""""""" | ||||
| + | ||||
| +:: | ||||
| + | ||||
| +      declare void @llvm.eha.scope.begin() | ||||
| +      declare void @llvm.eha.scope.end() | ||||
| + | ||||
| +Overview: | ||||
| +""""""""" | ||||
| + | ||||
| +The '``llvm.eha.scope.begin``' and '``llvm.eha.scope.end``' intrinsics mark | ||||
| +the boundary of a CPP object lifetime for Windows SEH Asynchrous Exception | ||||
| +Handling (MSVC option -EHa). | ||||
| + | ||||
| +Semantics: | ||||
| +"""""""""" | ||||
| + | ||||
| +'``llvm.eha.scope.begin``' is added immediately after an object constructor is | ||||
| +called, i.e., EHStack is not empty. So it will be an invoke, not a call. | ||||
| +With that it's also guaranteed that an associated EH-cleanup-pad is | ||||
| +created in IR regardless whether there exists a call in this object lifetime. | ||||
| +'``llvm.eha.scope.end``' is added before the object destructor. | ||||
| +These intrinsics make Block-level State computation possible in downstream | ||||
| +LLVM code gen pass, even in the presence of ctor/dtor inlining. | ||||
| + | ||||
|  .. _int_read_register: | ||||
|  .. _int_read_volatile_register: | ||||
|  .. _int_write_register: | ||||
| diff --git a/llvm/include/llvm/IR/Intrinsics.td b/llvm/include/llvm/IR/Intrinsics.td | ||||
| index 4918ea876df..7de760291d9 100644 | ||||
| --- a/llvm/include/llvm/IR/Intrinsics.td | ||||
| +++ b/llvm/include/llvm/IR/Intrinsics.td | ||||
| @@ -481,6 +481,16 @@ def int_eh_recoverfp : Intrinsic<[llvm_ptr_ty], | ||||
|                                   [llvm_ptr_ty, llvm_ptr_ty], | ||||
|                                   [IntrNoMem]>; | ||||
|   | ||||
| +// To mark the beginning/end of a try-scope for Windows SEH -EHa | ||||
| +//  calls/invokes to these intrinsics are placed to model control flows | ||||
| +//    caused by HW exceptions under option -EHa. | ||||
| +//  calls/invokes to these intrinsics will be discarded during a codegen pass | ||||
| +//   after EH tables are generated | ||||
| +def int_seh_try_begin : Intrinsic<[], [], [IntrReadMem, IntrWriteMem, IntrWillReturn]>; | ||||
| +def int_seh_try_end : Intrinsic<[], [], [IntrReadMem, IntrWriteMem, IntrWillReturn]>; | ||||
| +def int_eha_scope_begin : Intrinsic<[], [], [IntrNoMem]>; | ||||
| +def int_eha_scope_end : Intrinsic<[], [], [IntrNoMem]>; | ||||
| + | ||||
|  // Note: we treat stacksave/stackrestore as writemem because we don't otherwise | ||||
|  // model their dependencies on allocas. | ||||
|  def int_stacksave     : Intrinsic<[llvm_ptr_ty]>, | ||||
| diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp | ||||
| index d2930391f87..7e58de39962 100644 | ||||
| --- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp | ||||
| +++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp | ||||
| @@ -2801,6 +2801,10 @@ void SelectionDAGBuilder::visitInvoke(const InvokeInst &I) { | ||||
|        llvm_unreachable("Cannot invoke this intrinsic"); | ||||
|      case Intrinsic::donothing: | ||||
|        // Ignore invokes to @llvm.donothing: jump directly to the next BB. | ||||
| +    case Intrinsic::seh_try_begin: | ||||
| +    case Intrinsic::eha_scope_begin: | ||||
| +    case Intrinsic::seh_try_end: | ||||
| +    case Intrinsic::eha_scope_end: | ||||
|        break; | ||||
|      case Intrinsic::experimental_patchpoint_void: | ||||
|      case Intrinsic::experimental_patchpoint_i64: | ||||
| @@ -6635,6 +6639,10 @@ void SelectionDAGBuilder::visitIntrinsicCall(const CallInst &I, | ||||
|        lowerCallToExternalSymbol(I, FunctionName); | ||||
|      return; | ||||
|    case Intrinsic::donothing: | ||||
| +  case Intrinsic::seh_try_begin: | ||||
| +  case Intrinsic::eha_scope_begin: | ||||
| +  case Intrinsic::seh_try_end: | ||||
| +  case Intrinsic::eha_scope_end: | ||||
|      // ignore | ||||
|      return; | ||||
|    case Intrinsic::experimental_stackmap: | ||||
| diff --git a/llvm/lib/IR/Verifier.cpp b/llvm/lib/IR/Verifier.cpp | ||||
| index c518ae87ea9..87dd063ee2e 100644 | ||||
| --- a/llvm/lib/IR/Verifier.cpp | ||||
| +++ b/llvm/lib/IR/Verifier.cpp | ||||
| @@ -4269,6 +4269,10 @@ void Verifier::visitInstruction(Instruction &I) { | ||||
|        Assert( | ||||
|            !F->isIntrinsic() || isa<CallInst>(I) || | ||||
|                F->getIntrinsicID() == Intrinsic::donothing || | ||||
| +              F->getIntrinsicID() == Intrinsic::seh_try_begin || | ||||
| +              F->getIntrinsicID() == Intrinsic::seh_try_end || | ||||
| +              F->getIntrinsicID() == Intrinsic::eha_scope_begin || | ||||
| +              F->getIntrinsicID() == Intrinsic::eha_scope_end || | ||||
|                F->getIntrinsicID() == Intrinsic::coro_resume || | ||||
|                F->getIntrinsicID() == Intrinsic::coro_destroy || | ||||
|                F->getIntrinsicID() == Intrinsic::experimental_patchpoint_void || | ||||
		Reference in New Issue
	
	Block a user