From: Reid Kleckner Date: Mon, 28 Sep 2015 23:56:30 +0000 (+0000) Subject: [WinEH] Fix ip2state table emission with funclets X-Git-Url: http://plrg.eecs.uci.edu/git/?p=oota-llvm.git;a=commitdiff_plain;h=c18144386497cf02082206ddb6cc78e45d5e3667;hp=7df74560640c58b524620fc11eb740cac685ba13 [WinEH] Fix ip2state table emission with funclets Previously we were hijacking the old LandingPadInfo data structures to communicate our state numbers. Now we don't need that anymore. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@248763 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/llvm/CodeGen/WinEHFuncInfo.h b/include/llvm/CodeGen/WinEHFuncInfo.h index 0f947812a01..ac19ddf86bd 100644 --- a/include/llvm/CodeGen/WinEHFuncInfo.h +++ b/include/llvm/CodeGen/WinEHFuncInfo.h @@ -28,6 +28,7 @@ class GlobalVariable; class InvokeInst; class IntrinsicInst; class LandingPadInst; +class MCExpr; class MCSymbol; class MachineBasicBlock; class Value; @@ -160,15 +161,18 @@ struct WinEHTryBlockMapEntry { struct WinEHFuncInfo { DenseMap EHPadStateMap; + DenseMap> InvokeToStateMap; SmallVector UnwindMap; SmallVector TryBlockMap; SmallVector SEHUnwindMap; - SmallVector, 4> IPToStateList; int UnwindHelpFrameIdx = INT_MAX; int UnwindHelpFrameOffset = -1; int getLastStateNumber() const { return UnwindMap.size() - 1; } + void addIPToStateRange(const BasicBlock *PadBB, MCSymbol *InvokeBegin, + MCSymbol *InvokeEnd); + /// 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; diff --git a/lib/CodeGen/AsmPrinter/AsmPrinter.cpp b/lib/CodeGen/AsmPrinter/AsmPrinter.cpp index fdba2a92818..141cc0fc6e8 100644 --- a/lib/CodeGen/AsmPrinter/AsmPrinter.cpp +++ b/lib/CodeGen/AsmPrinter/AsmPrinter.cpp @@ -965,7 +965,7 @@ void AsmPrinter::EmitFunctionBody() { EmitFunctionBodyEnd(); if (!MMI->getLandingPads().empty() || MMI->hasDebugInfo() || - MAI->hasDotTypeDotSizeDirective()) { + MMI->hasEHFunclets() || MAI->hasDotTypeDotSizeDirective()) { // Create a symbol for the end of function. CurrentFnEnd = createTempSymbol("func_end"); OutStreamer->EmitLabel(CurrentFnEnd); @@ -1260,7 +1260,7 @@ void AsmPrinter::SetupMachineFunction(MachineFunction &MF) { CurExceptionSym = nullptr; bool NeedsLocalForSize = MAI->needsLocalForSize(); if (!MMI->getLandingPads().empty() || MMI->hasDebugInfo() || - NeedsLocalForSize) { + MMI->hasEHFunclets() || NeedsLocalForSize) { CurrentFnBegin = createTempSymbol("func_begin"); if (NeedsLocalForSize) CurrentFnSymForSize = CurrentFnBegin; diff --git a/lib/CodeGen/AsmPrinter/WinException.cpp b/lib/CodeGen/AsmPrinter/WinException.cpp index 95947cb88c4..f662a1b5e70 100644 --- a/lib/CodeGen/AsmPrinter/WinException.cpp +++ b/lib/CodeGen/AsmPrinter/WinException.cpp @@ -176,6 +176,12 @@ const MCExpr *WinException::create32bitRef(const Value *V) { return create32bitRef(MMI->getAddrLabelSymbol(cast(V))); } +const MCExpr *WinException::getLabelPlusOne(MCSymbol *Label) { + return MCBinaryExpr::createAdd(create32bitRef(Label), + MCConstantExpr::create(1, Asm->OutContext), + Asm->OutContext); +} + /// Emit the language-specific data that __C_specific_handler expects. This /// handler lives in the x64 Microsoft C runtime and allows catching or cleaning /// up after faults with __try, __except, and __finally. The typeinfo values @@ -263,9 +269,7 @@ void WinException::emitCSpecificHandlerTable(const MachineFunction *MF) { if (CSE.EndLabel) { // The interval is half-open, so we have to add one to include the return // address of the last invoke in the range. - End = MCBinaryExpr::createAdd(create32bitRef(CSE.EndLabel), - MCConstantExpr::create(1, Asm->OutContext), - Asm->OutContext); + End = getLabelPlusOne(CSE.EndLabel); } else { End = create32bitRef(EHFuncEndSym); } @@ -312,13 +316,15 @@ void WinException::emitCXXFrameHandler3Table(const MachineFunction *MF) { StringRef FuncLinkageName = GlobalValue::getRealLinkageName(F->getName()); + SmallVector, 4> IPToStateTable; MCSymbol *FuncInfoXData = nullptr; if (shouldEmitPersonality) { + // If we're 64-bit, emit a pointer to the C++ EH data, and build a map from + // IPs to state numbers. FuncInfoXData = Asm->OutContext.getOrCreateSymbol(Twine("$cppxdata$", FuncLinkageName)); OS.EmitValue(create32bitRef(FuncInfoXData), 4); - - extendIP2StateTable(MF, FuncInfo); + computeIP2StateTable(MF, FuncInfo, IPToStateTable); } else { FuncInfoXData = Asm->OutContext.getOrCreateLSDASymbol(FuncLinkageName); emitEHRegistrationOffsetLabel(FuncInfo, FuncLinkageName); @@ -333,7 +339,7 @@ void WinException::emitCXXFrameHandler3Table(const MachineFunction *MF) { if (!FuncInfo.TryBlockMap.empty()) TryBlockMapXData = Asm->OutContext.getOrCreateSymbol(Twine("$tryMap$", FuncLinkageName)); - if (!FuncInfo.IPToStateList.empty()) + if (!IPToStateTable.empty()) IPToStateXData = Asm->OutContext.getOrCreateSymbol(Twine("$ip2state$", FuncLinkageName)); @@ -359,7 +365,7 @@ void WinException::emitCXXFrameHandler3Table(const MachineFunction *MF) { OS.EmitValue(create32bitRef(UnwindMapXData), 4); // UnwindMap OS.EmitIntValue(FuncInfo.TryBlockMap.size(), 4); // NumTryBlocks OS.EmitValue(create32bitRef(TryBlockMapXData), 4); // TryBlockMap - OS.EmitIntValue(FuncInfo.IPToStateList.size(), 4); // IPMapEntries + OS.EmitIntValue(IPToStateTable.size(), 4); // IPMapEntries OS.EmitValue(create32bitRef(IPToStateXData), 4); // IPToStateMap if (Asm->MAI->usesWindowsCFI()) OS.EmitIntValue(FuncInfo.UnwindHelpFrameOffset, 4); // UnwindHelp @@ -477,80 +483,87 @@ void WinException::emitCXXFrameHandler3Table(const MachineFunction *MF) { // }; if (IPToStateXData) { OS.EmitLabel(IPToStateXData); - for (auto &IPStatePair : FuncInfo.IPToStateList) { - OS.EmitValue(create32bitRef(IPStatePair.first), 4); // IP - OS.EmitIntValue(IPStatePair.second, 4); // State + for (auto &IPStatePair : IPToStateTable) { + OS.EmitValue(IPStatePair.first, 4); // IP + OS.EmitIntValue(IPStatePair.second, 4); // State } } } -void WinException::extendIP2StateTable(const MachineFunction *MF, - WinEHFuncInfo &FuncInfo) { - // The Itanium LSDA table sorts similar landing pads together to simplify the - // actions table, but we don't need that. - SmallVector LandingPads; - const std::vector &PadInfos = MMI->getLandingPads(); - LandingPads.reserve(PadInfos.size()); - for (const auto &LP : PadInfos) - LandingPads.push_back(&LP); - - RangeMapType PadMap; - computePadMap(LandingPads, PadMap); - - // The end label of the previous invoke or nounwind try-range. - MCSymbol *LastLabel = Asm->getFunctionBegin(); - +void WinException::computeIP2StateTable( + const MachineFunction *MF, WinEHFuncInfo &FuncInfo, + SmallVectorImpl> &IPToStateTable) { // Whether there is a potentially throwing instruction (currently this means // an ordinary call) between the end of the previous try-range and now. - bool SawPotentiallyThrowing = false; + bool SawPotentiallyThrowing = true; - int LastEHState = -2; + // Remember what state we were in the last time we found a begin try label. + // This allows us to coalesce many nearby invokes with the same state into one + // entry. + int LastEHState = -1; + MCSymbol *LastEndLabel = Asm->getFunctionBegin(); + assert(LastEndLabel && "need local function start label"); - // The parent function and the catch handlers contribute to the 'ip2state' - // table. + // Indicate that all calls from the prologue to the first invoke unwind to + // caller. We handle this as a special case since other ranges starting at end + // labels need to use LtmpN+1. + IPToStateTable.push_back(std::make_pair(create32bitRef(LastEndLabel), -1)); - // Include ip2state entries for the beginning of the main function and - // for catch handler functions. - FuncInfo.IPToStateList.push_back(std::make_pair(LastLabel, -1)); - LastEHState = -1; for (const auto &MBB : *MF) { + // FIXME: Do we need to emit entries for funclet base states? + for (const auto &MI : MBB) { + // Find all the EH_LABEL instructions, tracking if we've crossed a + // potentially throwing call since the last label. if (!MI.isEHLabel()) { if (MI.isCall()) SawPotentiallyThrowing |= !callToNoUnwindFunction(&MI); continue; } - // End of the previous try-range? - MCSymbol *BeginLabel = MI.getOperand(0).getMCSymbol(); - if (BeginLabel == LastLabel) + // If this was an end label, return SawPotentiallyThrowing to the start + // state and keep going. Otherwise, we will consider the call between the + // begin/end labels to be a potentially throwing call and generate extra + // table entries. + MCSymbol *Label = MI.getOperand(0).getMCSymbol(); + if (Label == LastEndLabel) SawPotentiallyThrowing = false; - // Beginning of a new try-range? - RangeMapType::const_iterator L = PadMap.find(BeginLabel); - if (L == PadMap.end()) - // Nope, it was just some random label. + // Check if this was a begin label. Otherwise, it must be an end label or + // some random label, and we should continue. + auto StateAndEnd = FuncInfo.InvokeToStateMap.find(Label); + if (StateAndEnd == FuncInfo.InvokeToStateMap.end()) continue; - const PadRange &P = L->second; - const LandingPadInfo *LandingPad = LandingPads[P.PadIndex]; - assert(BeginLabel == LandingPad->BeginLabels[P.RangeIndex] && - "Inconsistent landing pad map!"); + // Extract the state and end label. + int State; + MCSymbol *EndLabel; + std::tie(State, EndLabel) = StateAndEnd->second; - // FIXME: Should this be using FuncInfo.HandlerBaseState? + // If there was a potentially throwing call between this begin label and + // the last end label, we need an extra base state entry to indicate that + // those calls unwind directly to the caller. if (SawPotentiallyThrowing && LastEHState != -1) { - FuncInfo.IPToStateList.push_back(std::make_pair(LastLabel, -1)); + IPToStateTable.push_back( + std::make_pair(getLabelPlusOne(LastEndLabel), -1)); SawPotentiallyThrowing = false; LastEHState = -1; } - if (LandingPad->WinEHState != LastEHState) - FuncInfo.IPToStateList.push_back( - std::make_pair(BeginLabel, LandingPad->WinEHState)); - LastEHState = LandingPad->WinEHState; - LastLabel = LandingPad->EndLabels[P.RangeIndex]; + // Emit an entry indicating that PCs after 'Label' have this EH state. + if (State != LastEHState) + IPToStateTable.push_back(std::make_pair(create32bitRef(Label), State)); + LastEHState = State; + LastEndLabel = EndLabel; } } + + if (LastEndLabel != Asm->getFunctionBegin()) { + // Indicate that all calls from the last invoke until the epilogue unwind to + // caller. This also ensures that we have at least one ip2state entry, if + // somehow all invokes were deleted during CodeGen. + IPToStateTable.push_back(std::make_pair(getLabelPlusOne(LastEndLabel), -1)); + } } void WinException::emitEHRegistrationOffsetLabel(const WinEHFuncInfo &FuncInfo, diff --git a/lib/CodeGen/AsmPrinter/WinException.h b/lib/CodeGen/AsmPrinter/WinException.h index ac06db2a2fd..37d2ab6ae4e 100644 --- a/lib/CodeGen/AsmPrinter/WinException.h +++ b/lib/CodeGen/AsmPrinter/WinException.h @@ -47,7 +47,9 @@ class LLVM_LIBRARY_VISIBILITY WinException : public EHStreamer { /// tables. void emitExceptHandlerTable(const MachineFunction *MF); - void extendIP2StateTable(const MachineFunction *MF, WinEHFuncInfo &FuncInfo); + void computeIP2StateTable( + const MachineFunction *MF, WinEHFuncInfo &FuncInfo, + SmallVectorImpl> &IPToStateTable); /// Emits the label used with llvm.x86.seh.recoverfp, which is used by /// outlined funclets. @@ -56,6 +58,7 @@ class LLVM_LIBRARY_VISIBILITY WinException : public EHStreamer { const MCExpr *create32bitRef(const MCSymbol *Value); const MCExpr *create32bitRef(const Value *V); + const MCExpr *getLabelPlusOne(MCSymbol *Label); public: //===--------------------------------------------------------------------===// diff --git a/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp b/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp index 97caa9d014a..3e80cd8e5db 100644 --- a/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp +++ b/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp @@ -5262,7 +5262,13 @@ SelectionDAGBuilder::lowerInvokable(TargetLowering::CallLoweringInfo &CLI, DAG.setRoot(DAG.getEHLabel(getCurSDLoc(), getRoot(), EndLabel)); // Inform MachineModuleInfo of range. - MMI.addInvoke(FuncInfo.MBBMap[EHPadBB], BeginLabel, EndLabel); + if (MMI.hasEHFunclets()) { + WinEHFuncInfo &EHInfo = + MMI.getWinEHFuncInfo(DAG.getMachineFunction().getFunction()); + EHInfo.addIPToStateRange(EHPadBB, BeginLabel, EndLabel); + } else { + MMI.addInvoke(FuncInfo.MBBMap[EHPadBB], BeginLabel, EndLabel); + } } return Result; diff --git a/lib/CodeGen/WinEHPrepare.cpp b/lib/CodeGen/WinEHPrepare.cpp index b062b1a29d3..7240159b083 100644 --- a/lib/CodeGen/WinEHPrepare.cpp +++ b/lib/CodeGen/WinEHPrepare.cpp @@ -34,6 +34,7 @@ #include "llvm/IR/IntrinsicInst.h" #include "llvm/IR/Module.h" #include "llvm/IR/PatternMatch.h" +#include "llvm/MC/MCSymbol.h" #include "llvm/Pass.h" #include "llvm/Support/Debug.h" #include "llvm/Support/raw_ostream.h" @@ -3499,3 +3500,12 @@ void WinEHPrepare::replaceUseWithLoad(Value *V, Use &U, AllocaInst *&SpillSlot, U.set(Load); } } + +void WinEHFuncInfo::addIPToStateRange(const BasicBlock *PadBB, + MCSymbol *InvokeBegin, + MCSymbol *InvokeEnd) { + assert(PadBB->isEHPad() && EHPadStateMap.count(PadBB->getFirstNonPHI()) && + "should get EH pad BB with precomputed state"); + InvokeToStateMap[InvokeBegin] = + std::make_pair(EHPadStateMap[PadBB->getFirstNonPHI()], InvokeEnd); +} diff --git a/test/CodeGen/X86/win-catchpad.ll b/test/CodeGen/X86/win-catchpad.ll index f9a5c7ca2f2..597f0e8ae80 100644 --- a/test/CodeGen/X86/win-catchpad.ll +++ b/test/CodeGen/X86/win-catchpad.ll @@ -119,12 +119,14 @@ catchendblock: ; preds = %catch, %catch.2, %c ; X86-NEXT: .long [[catch2bb]] ; X64-LABEL: try_catch_catch: +; X64: Lfunc_begin0: ; X64: pushq %rbp ; X64: .seh_pushreg 5 ; X64: subq $48, %rsp ; X64: .seh_stackalloc 48 ; X64: leaq 48(%rsp), %rbp ; X64: .seh_setframe 5, 48 +; X64: .Ltmp0 ; X64-DAG: leaq -[[local_offs:[0-9]+]](%rbp), %rdx ; X64-DAG: movl $1, %ecx ; X64: callq f @@ -138,6 +140,7 @@ catchendblock: ; preds = %catch, %catch.2, %c ; X64: pushq %rbp ; X64: movq %rdx, %rbp ; X64: subq $32, %rsp +; X64-DAG: .Ltmp4 ; X64-DAG: leaq -[[local_offs]](%rbp), %rdx ; X64-DAG: movl [[e_addr:[-0-9]+]](%rbp), %ecx ; X64: callq f @@ -154,20 +157,50 @@ catchendblock: ; preds = %catch, %catch.2, %c ; X64-DAG: leaq -[[local_offs]](%rbp), %rdx ; X64-DAG: movl $3, %ecx ; X64: callq f +; X64: .Ltmp3 ; X64: addq $32, %rsp ; X64-NEXT: popq %rbp ; X64-NEXT: leaq [[contbb]](%rip), %rax ; X64-NEXT: retq +; X64: $cppxdata$try_catch_catch: +; X64-NEXT: .long 429065506 +; X64-NEXT: .long 2 +; X64-NEXT: .long ($stateUnwindMap$try_catch_catch)@IMGREL +; X64-NEXT: .long 1 +; X64-NEXT: .long ($tryMap$try_catch_catch)@IMGREL +; X64-NEXT: .long 4 +; X64-NEXT: .long ($ip2state$try_catch_catch)@IMGREL +; X64-NEXT: .long 32 +; X64-NEXT: .long 0 +; X64-NEXT: .long 1 + +; X64: $tryMap$try_catch_catch: +; X64-NEXT: .long 0 +; X64-NEXT: .long 0 +; X64-NEXT: .long 1 +; X64-NEXT: .long 2 +; X64-NEXT: .long ($handlerMap$0$try_catch_catch)@IMGREL + ; X64: $handlerMap$0$try_catch_catch: -; X64: .long 0 -; X64: .long "??_R0H@8"@IMGREL +; X64-NEXT: .long 0 +; X64-NEXT: .long "??_R0H@8"@IMGREL ; FIXME: This should probably be offset from rsp, not rbp. -; X64: .long [[e_addr]] -; X64: .long [[catch1bb]]@IMGREL -; X64: .long 56 -; X64: .long 64 -; X64: .long 0 -; X64: .long 0 -; X64: .long [[catch2bb]]@IMGREL -; X64: .long 56 +; X64-NEXT: .long [[e_addr]] +; X64-NEXT: .long [[catch1bb]]@IMGREL +; X64-NEXT: .long 56 +; X64-NEXT: .long 64 +; X64-NEXT: .long 0 +; X64-NEXT: .long 0 +; X64-NEXT: .long [[catch2bb]]@IMGREL +; X64-NEXT: .long 56 + +; X64: $ip2state$try_catch_catch: +; X64-NEXT: .long .Lfunc_begin0@IMGREL +; X64-NEXT: .long -1 +; X64-NEXT: .long .Ltmp0@IMGREL +; X64-NEXT: .long 0 +; X64-NEXT: .long .Ltmp4@IMGREL +; X64-NEXT: .long 1 +; X64-NEXT: .long .Ltmp3@IMGREL+1 +; X64-NEXT: .long -1 diff --git a/test/CodeGen/X86/win-cleanuppad.ll b/test/CodeGen/X86/win-cleanuppad.ll index 808e322751d..a08fd976fa9 100644 --- a/test/CodeGen/X86/win-cleanuppad.ll +++ b/test/CodeGen/X86/win-cleanuppad.ll @@ -96,12 +96,19 @@ cleanup.outer: ; preds = %invoke.cont.1, %c ; X86: .long LBB1_[[cleanup_inner]] ; X64-LABEL: nested_cleanup: +; X64: .Lfunc_begin1: +; X64: .Ltmp8: ; X64: movl $1, %ecx ; X64: callq f +; X64: .Ltmp10: ; X64: movl $2, %ecx ; X64: callq f +; X64: .Ltmp11: +; X64: callq "??1Dtor@@QAE@XZ" +; X64: .Ltmp12: ; X64: movl $3, %ecx ; X64: callq f +; X64: .Ltmp13: ; X64: .LBB1_[[cleanup_inner:[0-9]+]]: # %cleanup.inner ; X64: pushq %rbp @@ -117,29 +124,38 @@ cleanup.outer: ; preds = %invoke.cont.1, %c ; X64: popq %rbp ; X64: retq -; X64: .seh_handlerdata -; X64: .long ($cppxdata$nested_cleanup)@IMGREL -; X64: .align 4 -; X64:$cppxdata$nested_cleanup: -; X64: .long 429065506 -; X64: .long 2 -; X64: .long ($stateUnwindMap$nested_cleanup)@IMGREL -; X64: .long 0 -; X64: .long 0 -; X64: .long 1 -; X64: .long ($ip2state$nested_cleanup)@IMGREL -; X64: .long 40 -; X64: .long 0 -; X64: .long 1 -; X64:$stateUnwindMap$nested_cleanup: -; X64: .long -1 -; X64: .long .LBB1_[[cleanup_outer]]@IMGREL -; X64: .long 0 -; X64: .long .LBB1_[[cleanup_inner]]@IMGREL -; FIXME: The ip2state table is totally wrong. -; X64:$ip2state$nested_cleanup: -; X64: .long .Lfunc_begin1@IMGREL -; X64: .long -1 +; X64: .seh_handlerdata +; X64-NEXT: .long ($cppxdata$nested_cleanup)@IMGREL +; X64-NEXT: .align 4 +; X64: $cppxdata$nested_cleanup: +; X64-NEXT: .long 429065506 +; X64-NEXT: .long 2 +; X64-NEXT: .long ($stateUnwindMap$nested_cleanup)@IMGREL +; X64-NEXT: .long 0 +; X64-NEXT: .long 0 +; X64-NEXT: .long 5 +; X64-NEXT: .long ($ip2state$nested_cleanup)@IMGREL +; X64-NEXT: .long 40 +; X64-NEXT: .long 0 +; X64-NEXT: .long 1 + +; X64: $stateUnwindMap$nested_cleanup: +; X64-NEXT: .long -1 +; X64-NEXT: .long .LBB1_[[cleanup_outer]]@IMGREL +; X64-NEXT: .long 0 +; X64-NEXT: .long .LBB1_[[cleanup_inner]]@IMGREL + +; X64: $ip2state$nested_cleanup: +; X64-NEXT: .long .Lfunc_begin1@IMGREL +; X64-NEXT: .long -1 +; X64-NEXT: .long .Ltmp8@IMGREL +; X64-NEXT: .long 0 +; X64-NEXT: .long .Ltmp10@IMGREL +; X64-NEXT: .long 1 +; X64-NEXT: .long .Ltmp12@IMGREL +; X64-NEXT: .long 0 +; X64-NEXT: .long .Ltmp13@IMGREL+1 +; X64-NEXT: .long -1 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 = { nounwind "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" }