[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.

llvm-svn: 248763
This commit is contained in:
Reid Kleckner 2015-09-28 23:56:30 +00:00
parent 525c013921
commit c71d6275ca
8 changed files with 175 additions and 90 deletions

View File

@ -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<const Instruction *, int> EHPadStateMap;
DenseMap<MCSymbol *, std::pair<int, MCSymbol *>> InvokeToStateMap;
SmallVector<WinEHUnwindMapEntry, 4> UnwindMap;
SmallVector<WinEHTryBlockMapEntry, 4> TryBlockMap;
SmallVector<SEHUnwindMapEntry, 4> SEHUnwindMap;
SmallVector<std::pair<MCSymbol *, int>, 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;

View File

@ -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;

View File

@ -176,6 +176,12 @@ const MCExpr *WinException::create32bitRef(const Value *V) {
return create32bitRef(MMI->getAddrLabelSymbol(cast<BasicBlock>(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<std::pair<const MCExpr *, int>, 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<const LandingPadInfo *, 64> LandingPads;
const std::vector<LandingPadInfo> &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<std::pair<const MCExpr *, int>> &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,

View File

@ -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<std::pair<const MCExpr *, int>> &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:
//===--------------------------------------------------------------------===//

View File

@ -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;

View File

@ -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);
}

View File

@ -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

View File

@ -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" }