Index: llvm/trunk/include/llvm/CodeGen/WinEHFuncInfo.h =================================================================== --- llvm/trunk/include/llvm/CodeGen/WinEHFuncInfo.h +++ llvm/trunk/include/llvm/CodeGen/WinEHFuncInfo.h @@ -115,19 +115,20 @@ struct WinEHUnwindMapEntry { int ToState; - Function *Cleanup; + const Value *Cleanup; }; struct WinEHHandlerType { int Adjectives; GlobalVariable *TypeDescriptor; int CatchObjRecoverIdx; - Function *Handler; + const Value *Handler; }; struct WinEHTryBlockMapEntry { int TryLow; int TryHigh; + int CatchHigh = -1; SmallVector HandlerArray; }; @@ -136,7 +137,7 @@ DenseMap LastInvoke; DenseMap HandlerEnclosedState; DenseMap LastInvokeVisited; - DenseMap LandingPadStateMap; + DenseMap EHPadStateMap; DenseMap CatchHandlerParentFrameObjIdx; DenseMap CatchHandlerParentFrameObjOffset; DenseMap CatchHandlerMaxState; @@ -148,6 +149,8 @@ int UnwindHelpFrameOffset = -1; unsigned NumIPToStateFuncsVisited = 0; + int getLastStateNumber() const { return UnwindMap.size() - 1; } + /// localescape index of the 32-bit EH registration node. Set by /// WinEHStatePass and used indirectly by SEH filter functions of the parent. int EHRegNodeEscapeIndex = INT_MAX; Index: llvm/trunk/lib/CodeGen/AsmPrinter/WinException.h =================================================================== --- llvm/trunk/lib/CodeGen/AsmPrinter/WinException.h +++ llvm/trunk/lib/CodeGen/AsmPrinter/WinException.h @@ -18,9 +18,9 @@ namespace llvm { class Function; -class GlobalValue; class MachineFunction; class MCExpr; +class Value; struct WinEHFuncInfo; class LLVM_LIBRARY_VISIBILITY WinException : public EHStreamer { @@ -56,7 +56,7 @@ StringRef FLinkageName); const MCExpr *create32bitRef(const MCSymbol *Value); - const MCExpr *create32bitRef(const GlobalValue *GV); + const MCExpr *create32bitRef(const Value *V); public: //===--------------------------------------------------------------------===// Index: llvm/trunk/lib/CodeGen/AsmPrinter/WinException.cpp =================================================================== --- llvm/trunk/lib/CodeGen/AsmPrinter/WinException.cpp +++ llvm/trunk/lib/CodeGen/AsmPrinter/WinException.cpp @@ -182,10 +182,10 @@ Asm->OutContext); } -const MCExpr *WinException::create32bitRef(const GlobalValue *GV) { - if (!GV) +const MCExpr *WinException::create32bitRef(const Value *V) { + if (!V) return MCConstantExpr::create(0, Asm->OutContext); - return create32bitRef(Asm->getSymbol(GV)); + return create32bitRef(Asm->getSymbol(cast(V))); } /// Emit the language-specific data that __C_specific_handler expects. This @@ -413,7 +413,8 @@ int CatchHigh = -1; for (WinEHHandlerType &HT : TBME.HandlerArray) CatchHigh = - std::max(CatchHigh, FuncInfo.CatchHandlerMaxState[HT.Handler]); + std::max(CatchHigh, + FuncInfo.CatchHandlerMaxState[cast(HT.Handler)]); assert(TBME.TryLow <= TBME.TryHigh); OS.EmitIntValue(TBME.TryLow, 4); // TryLow Index: llvm/trunk/lib/CodeGen/SelectionDAG/FunctionLoweringInfo.cpp =================================================================== --- llvm/trunk/lib/CodeGen/SelectionDAG/FunctionLoweringInfo.cpp +++ llvm/trunk/lib/CodeGen/SelectionDAG/FunctionLoweringInfo.cpp @@ -283,7 +283,7 @@ Personality == EHPersonality::MSVC_X86SEH) { for (const LandingPadInst *LP : LPads) { MachineBasicBlock *LPadMBB = MBBMap[LP->getParent()]; - MMI.addWinEHState(LPadMBB, EHInfo.LandingPadStateMap[LP]); + MMI.addWinEHState(LPadMBB, EHInfo.EHPadStateMap[LP]); } } } Index: llvm/trunk/lib/CodeGen/WinEHPrepare.cpp =================================================================== --- llvm/trunk/lib/CodeGen/WinEHPrepare.cpp +++ llvm/trunk/lib/CodeGen/WinEHPrepare.cpp @@ -2575,14 +2575,52 @@ }; } -void WinEHNumbering::createUnwindMapEntry(int ToState, ActionHandler *AH) { +static int addUnwindMapEntry(WinEHFuncInfo &FuncInfo, int ToState, + const Value *V) { WinEHUnwindMapEntry UME; UME.ToState = ToState; - if (auto *CH = dyn_cast_or_null(AH)) - UME.Cleanup = cast(CH->getHandlerBlockOrFunc()); - else - UME.Cleanup = nullptr; + UME.Cleanup = V; FuncInfo.UnwindMap.push_back(UME); + return FuncInfo.getLastStateNumber(); +} + +static void addTryBlockMapEntry(WinEHFuncInfo &FuncInfo, int TryLow, + int TryHigh, int CatchHigh, + ArrayRef Handlers) { + WinEHTryBlockMapEntry TBME; + TBME.TryLow = TryLow; + TBME.TryHigh = TryHigh; + TBME.CatchHigh = CatchHigh; + assert(TBME.TryLow <= TBME.TryHigh); + for (const CatchPadInst *CPI : Handlers) { + WinEHHandlerType HT; + Constant *TypeInfo = cast(CPI->getArgOperand(0)); + if (TypeInfo->isNullValue()) { + HT.Adjectives = 0x40; + HT.TypeDescriptor = nullptr; + } else { + auto *GV = cast(TypeInfo->stripPointerCasts()); + // Selectors are always pointers to GlobalVariables with 'struct' type. + // The struct has two fields, adjectives and a type descriptor. + auto *CS = cast(GV->getInitializer()); + HT.Adjectives = + cast(CS->getAggregateElement(0U))->getZExtValue(); + HT.TypeDescriptor = + cast(CS->getAggregateElement(1)->stripPointerCasts()); + } + HT.Handler = CPI->getParent(); + // FIXME: Pass CPI->getArgOperand(1). + HT.CatchObjRecoverIdx = -1; + TBME.HandlerArray.push_back(HT); + } + FuncInfo.TryBlockMap.push_back(TBME); +} + +void WinEHNumbering::createUnwindMapEntry(int ToState, ActionHandler *AH) { + Value *V = nullptr; + if (auto *CH = dyn_cast_or_null(AH)) + V = cast(CH->getHandlerBlockOrFunc()); + addUnwindMapEntry(FuncInfo, ToState, V); } void WinEHNumbering::createTryBlockMapEntry(int TryLow, int TryHigh, @@ -2838,7 +2876,7 @@ continue; processCallSite(ActionList, II); ActionList.clear(); - FuncInfo.LandingPadStateMap[LPI] = currentEHNumber(); + FuncInfo.EHPadStateMap[LPI] = currentEHNumber(); DEBUG(dbgs() << "Assigning state " << currentEHNumber() << " to landing pad at " << LPI->getParent()->getName() << '\n'); @@ -2902,10 +2940,114 @@ } } +static const BasicBlock *getSingleCatchPadPredecessor(const BasicBlock &BB) { + for (const BasicBlock *PredBlock : predecessors(&BB)) + if (isa(PredBlock->getFirstNonPHI())) + return PredBlock; + return nullptr; +} + +// Given BB which ends in an unwind edge, return the EHPad that this BB belongs +// to. If the unwind edge came from an invoke, return null. +static const BasicBlock *getEHPadFromPredecessor(const BasicBlock *BB) { + const TerminatorInst *TI = BB->getTerminator(); + if (isa(TI)) + return nullptr; + if (isa(TI) || isa(TI) || + isa(TI)) + return BB; + return cast(cast(TI)->getReturnValue()) + ->getParent(); +} + +static void calculateExplicitStateNumbers(WinEHFuncInfo &FuncInfo, + const BasicBlock &BB, + int ParentState) { + assert(BB.isEHPad()); + const Instruction *FirstNonPHI = BB.getFirstNonPHI(); + // All catchpad instructions will be handled when we process their + // respective catchendpad instruction. + if (isa(FirstNonPHI)) + return; + + if (isa(FirstNonPHI)) { + const BasicBlock *TryPad = &BB; + const BasicBlock *LastTryPad = nullptr; + SmallVector Handlers; + do { + LastTryPad = TryPad; + TryPad = getSingleCatchPadPredecessor(*TryPad); + if (TryPad) + Handlers.push_back(cast(TryPad->getFirstNonPHI())); + } while (TryPad); + // We've pushed these back into reverse source order. Reverse them to get + // the list back into source order. + std::reverse(Handlers.begin(), Handlers.end()); + int TryLow = addUnwindMapEntry(FuncInfo, ParentState, nullptr); + FuncInfo.EHPadStateMap[Handlers.front()] = TryLow; + for (const BasicBlock *PredBlock : predecessors(LastTryPad)) + if ((PredBlock = getEHPadFromPredecessor(PredBlock))) + calculateExplicitStateNumbers(FuncInfo, *PredBlock, TryLow); + int CatchLow = addUnwindMapEntry(FuncInfo, ParentState, nullptr); + FuncInfo.EHPadStateMap[FirstNonPHI] = CatchLow; + int TryHigh = CatchLow - 1; + for (const BasicBlock *PredBlock : predecessors(&BB)) + if ((PredBlock = getEHPadFromPredecessor(PredBlock))) + calculateExplicitStateNumbers(FuncInfo, *PredBlock, CatchLow); + int CatchHigh = FuncInfo.getLastStateNumber(); + addTryBlockMapEntry(FuncInfo, TryLow, TryHigh, CatchHigh, Handlers); + DEBUG(dbgs() << "TryLow[" << LastTryPad->getName() << "]: " << TryLow + << '\n'); + DEBUG(dbgs() << "TryHigh[" << LastTryPad->getName() << "]: " << TryHigh + << '\n'); + DEBUG(dbgs() << "CatchHigh[" << LastTryPad->getName() << "]: " << CatchHigh + << '\n'); + } else if (isa(FirstNonPHI)) { + int CleanupState = addUnwindMapEntry(FuncInfo, ParentState, &BB); + FuncInfo.EHPadStateMap[FirstNonPHI] = CleanupState; + DEBUG(dbgs() << "Assigning state #" << CleanupState << " to BB " + << BB.getName() << '\n'); + for (const BasicBlock *PredBlock : predecessors(&BB)) + if ((PredBlock = getEHPadFromPredecessor(PredBlock))) + calculateExplicitStateNumbers(FuncInfo, *PredBlock, CleanupState); + } else if (isa(FirstNonPHI)) { + report_fatal_error("Not yet implemented!"); + } else { + llvm_unreachable("unexpected EH Pad!"); + } +} + void llvm::calculateWinCXXEHStateNumbers(const Function *ParentFn, WinEHFuncInfo &FuncInfo) { // Return if it's already been done. - if (!FuncInfo.LandingPadStateMap.empty()) + if (!FuncInfo.EHPadStateMap.empty()) + return; + + bool IsExplicit = false; + for (const BasicBlock &BB : *ParentFn) { + if (!BB.isEHPad()) + continue; + // Check if the EH Pad has no exceptional successors (i.e. it unwinds to + // caller). Cleanups are a little bit of a special case because their + // control flow cannot be determined by looking at the pad but instead by + // the pad's users. + bool HasNoSuccessors = false; + const Instruction *FirstNonPHI = BB.getFirstNonPHI(); + if (FirstNonPHI->mayThrow()) { + HasNoSuccessors = true; + } else if (auto *CPI = dyn_cast(FirstNonPHI)) { + HasNoSuccessors = + CPI->use_empty() || + cast(CPI->user_back())->unwindsToCaller(); + } + + if (!HasNoSuccessors) + continue; + calculateExplicitStateNumbers(FuncInfo, BB, -1); + IsExplicit = true; + } + + if (IsExplicit) return; WinEHNumbering Num(FuncInfo); @@ -3141,6 +3283,7 @@ BlockColors.clear(); FuncletBlocks.clear(); + return true; } Index: llvm/trunk/lib/Target/X86/X86TargetMachine.cpp =================================================================== --- llvm/trunk/lib/Target/X86/X86TargetMachine.cpp +++ llvm/trunk/lib/Target/X86/X86TargetMachine.cpp @@ -28,10 +28,17 @@ cl::desc("Enable the machine combiner pass"), cl::init(true), cl::Hidden); +namespace llvm { +void initializeWinEHStatePassPass(PassRegistry &); +} + extern "C" void LLVMInitializeX86Target() { // Register the target. RegisterTargetMachine X(TheX86_32Target); RegisterTargetMachine Y(TheX86_64Target); + + PassRegistry &PR = *PassRegistry::getPassRegistry(); + initializeWinEHStatePassPass(PR); } static std::unique_ptr createTLOF(const Triple &TT) { Index: llvm/trunk/lib/Target/X86/X86WinEHState.cpp =================================================================== --- llvm/trunk/lib/Target/X86/X86WinEHState.cpp +++ llvm/trunk/lib/Target/X86/X86WinEHState.cpp @@ -38,12 +38,16 @@ #define DEBUG_TYPE "winehstate" +namespace llvm { void initializeWinEHStatePassPass(PassRegistry &); } + namespace { class WinEHStatePass : public FunctionPass { public: static char ID; // Pass identification, replacement for typeid. - WinEHStatePass() : FunctionPass(ID) {} + WinEHStatePass() : FunctionPass(ID) { + initializeWinEHStatePassPass(*PassRegistry::getPassRegistry()); + } bool runOnFunction(Function &Fn) override; @@ -62,8 +66,8 @@ void linkExceptionRegistration(IRBuilder<> &Builder, Function *Handler); void unlinkExceptionRegistration(IRBuilder<> &Builder); - void addCXXStateStores(Function &F, MachineModuleInfo &MMI); - void addSEHStateStores(Function &F, MachineModuleInfo &MMI); + void addCXXStateStores(Function &F, WinEHFuncInfo &FuncInfo); + void addSEHStateStores(Function &F, WinEHFuncInfo &FuncInfo); void addCXXStateStoresToFunclet(Value *ParentRegNode, WinEHFuncInfo &FuncInfo, Function &F, int BaseState); void insertStateNumberStore(Value *ParentRegNode, Instruction *IP, int State); @@ -111,6 +115,9 @@ char WinEHStatePass::ID = 0; +INITIALIZE_PASS(WinEHStatePass, "x86-winehstate", + "Insert stores for EH state numbers", false, false) + bool WinEHStatePass::doInitialization(Module &M) { TheModule = &M; FrameEscape = Intrinsic::getDeclaration(TheModule, Intrinsic::localescape); @@ -163,13 +170,23 @@ emitExceptionRegistrationRecord(&F); - auto *MMIPtr = getAnalysisIfAvailable(); - assert(MMIPtr && "MachineModuleInfo should always be available"); - MachineModuleInfo &MMI = *MMIPtr; + auto *MMI = getAnalysisIfAvailable(); + // If MMI is null, create our own WinEHFuncInfo. This only happens in opt + // tests. + std::unique_ptr FuncInfoPtr; + if (!MMI) + FuncInfoPtr.reset(new WinEHFuncInfo()); + WinEHFuncInfo &FuncInfo = + *(MMI ? &MMI->getWinEHFuncInfo(&F) : FuncInfoPtr.get()); + switch (Personality) { default: llvm_unreachable("unexpected personality function"); - case EHPersonality::MSVC_CXX: addCXXStateStores(F, MMI); break; - case EHPersonality::MSVC_X86SEH: addSEHStateStores(F, MMI); break; + case EHPersonality::MSVC_CXX: + addCXXStateStores(F, FuncInfo); + break; + case EHPersonality::MSVC_X86SEH: + addSEHStateStores(F, FuncInfo); + break; } // Reset per-function state. @@ -391,8 +408,7 @@ Builder.CreateStore(Next, FSZero); } -void WinEHStatePass::addCXXStateStores(Function &F, MachineModuleInfo &MMI) { - WinEHFuncInfo &FuncInfo = MMI.getWinEHFuncInfo(&F); +void WinEHStatePass::addCXXStateStores(Function &F, WinEHFuncInfo &FuncInfo) { calculateWinCXXEHStateNumbers(&F, FuncInfo); // The base state for the parent is -1. @@ -466,10 +482,10 @@ insertStateNumberStore(ParentRegNode, CI, BaseState); } else if (auto *II = dyn_cast(&I)) { // Look up the state number of the landingpad this unwinds to. - LandingPadInst *LPI = II->getUnwindDest()->getLandingPadInst(); + Instruction *PadInst = II->getUnwindDest()->getFirstNonPHI(); // FIXME: Why does this assertion fail? - //assert(FuncInfo.LandingPadStateMap.count(LPI) && "LP has no state!"); - int State = FuncInfo.LandingPadStateMap[LPI]; + //assert(FuncInfo.EHPadStateMap.count(PadInst) && "EH Pad has no state!"); + int State = FuncInfo.EHPadStateMap[PadInst]; insertStateNumberStore(ParentRegNode, II, State); } } @@ -481,9 +497,7 @@ /// handlers aren't outlined and the runtime doesn't have to figure out which /// catch handler frame to unwind to. /// FIXME: __finally blocks are outlined, so this approach may break down there. -void WinEHStatePass::addSEHStateStores(Function &F, MachineModuleInfo &MMI) { - WinEHFuncInfo &FuncInfo = MMI.getWinEHFuncInfo(&F); - +void WinEHStatePass::addSEHStateStores(Function &F, WinEHFuncInfo &FuncInfo) { // Remember and return the index that we used. We save it in WinEHFuncInfo so // that we can lower llvm.x86.seh.recoverfp later in filter functions without // too much trouble. @@ -507,7 +521,7 @@ // Look up the state number of the landingpad this unwinds to. LandingPadInst *LPI = II->getUnwindDest()->getLandingPadInst(); auto InsertionPair = - FuncInfo.LandingPadStateMap.insert(std::make_pair(LPI, CurState)); + FuncInfo.EHPadStateMap.insert(std::make_pair(LPI, CurState)); auto Iter = InsertionPair.first; int &State = Iter->second; bool Inserted = InsertionPair.second; Index: llvm/trunk/test/CodeGen/WinEH/wineh-statenumbering.ll =================================================================== --- llvm/trunk/test/CodeGen/WinEH/wineh-statenumbering.ll +++ llvm/trunk/test/CodeGen/WinEH/wineh-statenumbering.ll @@ -0,0 +1,96 @@ +; RUN: opt -mtriple=i686-pc-windows-msvc -S -x86-winehstate < %s | FileCheck %s + +target datalayout = "e-m:x-p:32:32-i64:64-f80:32-n8:16:32-a:0:32-S32" +target triple = "i686-pc-windows-msvc" + +%rtti.TypeDescriptor2 = type { i8**, i8*, [3 x i8] } +%eh.CatchableType = type { i32, i8*, i32, i32, i32, i32, i8* } +%eh.CatchableTypeArray.1 = type { i32, [1 x %eh.CatchableType*] } +%eh.ThrowInfo = type { i32, i8*, i8*, i8* } + +$"\01??_R0H@8" = comdat any + +$"_CT??_R0H@84" = comdat any + +$_CTA1H = comdat any + +$_TI1H = comdat any + +@"\01??_7type_info@@6B@" = external constant i8* +@"\01??_R0H@8" = linkonce_odr global %rtti.TypeDescriptor2 { i8** @"\01??_7type_info@@6B@", i8* null, [3 x i8] c".H\00" }, comdat +@"_CT??_R0H@84" = linkonce_odr unnamed_addr constant %eh.CatchableType { i32 1, i8* bitcast (%rtti.TypeDescriptor2* @"\01??_R0H@8" to i8*), i32 0, i32 -1, i32 0, i32 4, i8* null }, section ".xdata", comdat +@_CTA1H = linkonce_odr unnamed_addr constant %eh.CatchableTypeArray.1 { i32 1, [1 x %eh.CatchableType*] [%eh.CatchableType* @"_CT??_R0H@84"] }, section ".xdata", comdat +@_TI1H = linkonce_odr unnamed_addr constant %eh.ThrowInfo { i32 0, i8* null, i8* null, i8* bitcast (%eh.CatchableTypeArray.1* @_CTA1H to i8*) }, section ".xdata", comdat + +define i32 @main() #0 personality i32 (...)* @__CxxFrameHandler3 { +entry: + %tmp = alloca i32, align 4 + ; CHECK: entry: + ; CHECK: store i32 -1 + ; CHECK: call void @g(i32 3) + call void @g(i32 3) + store i32 0, i32* %tmp, align 4 + %0 = bitcast i32* %tmp to i8* + ; CHECK: store i32 0 + ; CHECK: invoke void @_CxxThrowException( + invoke void @_CxxThrowException(i8* %0, %eh.ThrowInfo* nonnull @_TI1H) #1 + to label %unreachable.for.entry unwind label %catch.dispatch + +catch.dispatch: ; preds = %entry + %1 = catchpad token [i8* null, i8* null] to label %catch unwind label %catchendblock + +catch: ; preds = %catch.dispatch + ; CHECK: catch: + ; CHECK: store i32 2 + ; CHECK: invoke void @_CxxThrowException( + invoke void @_CxxThrowException(i8* null, %eh.ThrowInfo* null) #1 + to label %unreachable unwind label %catch.dispatch.1 + +catch.dispatch.1: ; preds = %catch + %2 = catchpad token [i8* null, i8* null] to label %catch.3 unwind label %catchendblock.2 + +catch.3: ; preds = %catch.dispatch.1 + ; CHECK: catch.3: + ; CHECK: store i32 3 + ; CHECK: invoke void @g(i32 1) + invoke void @g(i32 1) + to label %invoke.cont unwind label %catchendblock.2 + +invoke.cont: ; preds = %catch.3 + catchret token %2 to label %try.cont + +try.cont: ; preds = %invoke.cont + ; CHECK: try.cont: + ; CHECK: store i32 1 + ; CHECK: invoke void @g(i32 2) + invoke void @g(i32 2) + to label %invoke.cont.4 unwind label %catchendblock + +invoke.cont.4: ; preds = %try.cont + unreachable + +catchendblock.2: ; preds = %catch.3, %catch.dispatch.1 + catchendpad unwind label %catchendblock + +catchendblock: ; preds = %catchendblock.2, %try.cont, %catch.dispatch + catchendpad unwind to caller + +unreachable: ; preds = %catch + unreachable + +unreachable.for.entry: ; preds = %entry + unreachable +} + +declare void @g(i32) #0 + +declare x86_stdcallcc void @_CxxThrowException(i8*, %eh.ThrowInfo*) + +declare i32 @__CxxFrameHandler3(...) + +attributes #0 = { "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-realign-stack" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" } +attributes #1 = { noreturn } + +!llvm.ident = !{!0} + +!0 = !{!"clang version 3.8.0 (trunk 245153) (llvm/trunk 245238)"}