[SEH] Emit 32-bit SEH tables for the new EH IR
The 32-bit tables don't actually contain PC range data, so emitting them is incredibly simple. The 64-bit tables, on the other hand, use the same table for state numbering as well as label ranges. This makes things more difficult, so it will be implemented later. llvm-svn: 247192
This commit is contained in:
parent
81f3ccb505
commit
94b704c469
|
@ -14,9 +14,10 @@
|
||||||
#ifndef LLVM_CODEGEN_WINEHFUNCINFO_H
|
#ifndef LLVM_CODEGEN_WINEHFUNCINFO_H
|
||||||
#define LLVM_CODEGEN_WINEHFUNCINFO_H
|
#define LLVM_CODEGEN_WINEHFUNCINFO_H
|
||||||
|
|
||||||
|
#include "llvm/ADT/DenseMap.h"
|
||||||
|
#include "llvm/ADT/PointerUnion.h"
|
||||||
#include "llvm/ADT/SmallVector.h"
|
#include "llvm/ADT/SmallVector.h"
|
||||||
#include "llvm/ADT/TinyPtrVector.h"
|
#include "llvm/ADT/TinyPtrVector.h"
|
||||||
#include "llvm/ADT/DenseMap.h"
|
|
||||||
|
|
||||||
namespace llvm {
|
namespace llvm {
|
||||||
class AllocaInst;
|
class AllocaInst;
|
||||||
|
@ -120,17 +121,32 @@ struct WinEHUnwindMapEntry {
|
||||||
const Value *Cleanup;
|
const Value *Cleanup;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
typedef PointerUnion<const BasicBlock *, MachineBasicBlock *> MBBOrBasicBlock;
|
||||||
|
typedef PointerUnion<const Value *, MachineBasicBlock *> ValueOrMBB;
|
||||||
|
|
||||||
|
/// Similar to WinEHUnwindMapEntry, but supports SEH filters.
|
||||||
|
struct SEHUnwindMapEntry {
|
||||||
|
/// If unwinding continues through this handler, transition to the handler at
|
||||||
|
/// this state. This indexes into SEHUnwindMap.
|
||||||
|
int ToState = -1;
|
||||||
|
|
||||||
|
/// Holds the filter expression function.
|
||||||
|
const Function *Filter = nullptr;
|
||||||
|
|
||||||
|
/// Holds the __except or __finally basic block.
|
||||||
|
MBBOrBasicBlock Handler;
|
||||||
|
};
|
||||||
|
|
||||||
struct WinEHHandlerType {
|
struct WinEHHandlerType {
|
||||||
int Adjectives;
|
int Adjectives;
|
||||||
GlobalVariable *TypeDescriptor;
|
GlobalVariable *TypeDescriptor;
|
||||||
int CatchObjRecoverIdx;
|
int CatchObjRecoverIdx;
|
||||||
const Value *Handler;
|
ValueOrMBB Handler;
|
||||||
MachineBasicBlock *HandlerMBB;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct WinEHTryBlockMapEntry {
|
struct WinEHTryBlockMapEntry {
|
||||||
int TryLow;
|
int TryLow = -1;
|
||||||
int TryHigh;
|
int TryHigh = -1;
|
||||||
int CatchHigh = -1;
|
int CatchHigh = -1;
|
||||||
SmallVector<WinEHHandlerType, 1> HandlerArray;
|
SmallVector<WinEHHandlerType, 1> HandlerArray;
|
||||||
};
|
};
|
||||||
|
@ -147,6 +163,7 @@ struct WinEHFuncInfo {
|
||||||
DenseMap<const Function *, int> HandlerBaseState;
|
DenseMap<const Function *, int> HandlerBaseState;
|
||||||
SmallVector<WinEHUnwindMapEntry, 4> UnwindMap;
|
SmallVector<WinEHUnwindMapEntry, 4> UnwindMap;
|
||||||
SmallVector<WinEHTryBlockMapEntry, 4> TryBlockMap;
|
SmallVector<WinEHTryBlockMapEntry, 4> TryBlockMap;
|
||||||
|
SmallVector<SEHUnwindMapEntry, 4> SEHUnwindMap;
|
||||||
SmallVector<std::pair<MCSymbol *, int>, 4> IPToStateList;
|
SmallVector<std::pair<MCSymbol *, int>, 4> IPToStateList;
|
||||||
int UnwindHelpFrameIdx = INT_MAX;
|
int UnwindHelpFrameIdx = INT_MAX;
|
||||||
int UnwindHelpFrameOffset = -1;
|
int UnwindHelpFrameOffset = -1;
|
||||||
|
@ -169,5 +186,7 @@ struct WinEHFuncInfo {
|
||||||
void calculateWinCXXEHStateNumbers(const Function *ParentFn,
|
void calculateWinCXXEHStateNumbers(const Function *ParentFn,
|
||||||
WinEHFuncInfo &FuncInfo);
|
WinEHFuncInfo &FuncInfo);
|
||||||
|
|
||||||
|
void calculateSEHStateNumbers(const Function *ParentFn,
|
||||||
|
WinEHFuncInfo &FuncInfo);
|
||||||
}
|
}
|
||||||
#endif // LLVM_CODEGEN_WINEHFUNCINFO_H
|
#endif // LLVM_CODEGEN_WINEHFUNCINFO_H
|
||||||
|
|
|
@ -161,7 +161,7 @@ void WinException::endFunction(const MachineFunction *MF) {
|
||||||
// Emit the tables appropriate to the personality function in use. If we
|
// Emit the tables appropriate to the personality function in use. If we
|
||||||
// don't recognize the personality, assume it uses an Itanium-style LSDA.
|
// don't recognize the personality, assume it uses an Itanium-style LSDA.
|
||||||
if (Per == EHPersonality::MSVC_Win64SEH)
|
if (Per == EHPersonality::MSVC_Win64SEH)
|
||||||
emitCSpecificHandlerTable();
|
emitCSpecificHandlerTable(MF);
|
||||||
else if (Per == EHPersonality::MSVC_X86SEH)
|
else if (Per == EHPersonality::MSVC_X86SEH)
|
||||||
emitExceptHandlerTable(MF);
|
emitExceptHandlerTable(MF);
|
||||||
else if (Per == EHPersonality::MSVC_CXX)
|
else if (Per == EHPersonality::MSVC_CXX)
|
||||||
|
@ -222,9 +222,13 @@ const MCExpr *WinException::create32bitRef(const Value *V) {
|
||||||
/// imagerel32 LabelLPad; // Zero means __finally.
|
/// imagerel32 LabelLPad; // Zero means __finally.
|
||||||
/// } Entries[NumEntries];
|
/// } Entries[NumEntries];
|
||||||
/// };
|
/// };
|
||||||
void WinException::emitCSpecificHandlerTable() {
|
void WinException::emitCSpecificHandlerTable(const MachineFunction *MF) {
|
||||||
const std::vector<LandingPadInfo> &PadInfos = MMI->getLandingPads();
|
const std::vector<LandingPadInfo> &PadInfos = MMI->getLandingPads();
|
||||||
|
|
||||||
|
WinEHFuncInfo &FuncInfo = MMI->getWinEHFuncInfo(MF->getFunction());
|
||||||
|
if (!FuncInfo.SEHUnwindMap.empty())
|
||||||
|
report_fatal_error("x64 SEH tables not yet implemented");
|
||||||
|
|
||||||
// Simplifying assumptions for first implementation:
|
// Simplifying assumptions for first implementation:
|
||||||
// - Cleanups are not implemented.
|
// - Cleanups are not implemented.
|
||||||
// - Filters are not implemented.
|
// - Filters are not implemented.
|
||||||
|
@ -309,6 +313,15 @@ void WinException::emitCSpecificHandlerTable() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Retreive the MCSymbol for a GlobalValue or MachineBasicBlock. GlobalValues
|
||||||
|
/// are used in the old WinEH scheme, and they will be removed eventually.
|
||||||
|
static MCSymbol *getMCSymbolForMBBOrGV(AsmPrinter *Asm, ValueOrMBB Handler) {
|
||||||
|
if (Handler.is<MachineBasicBlock *>())
|
||||||
|
return Handler.get<MachineBasicBlock *>()->getSymbol();
|
||||||
|
else
|
||||||
|
return Asm->getSymbol(cast<GlobalValue>(Handler.get<const Value *>()));
|
||||||
|
}
|
||||||
|
|
||||||
void WinException::emitCXXFrameHandler3Table(const MachineFunction *MF) {
|
void WinException::emitCXXFrameHandler3Table(const MachineFunction *MF) {
|
||||||
const Function *F = MF->getFunction();
|
const Function *F = MF->getFunction();
|
||||||
const Function *ParentF = MMI->getWinEHParent(F);
|
const Function *ParentF = MMI->getWinEHParent(F);
|
||||||
|
@ -422,9 +435,9 @@ void WinException::emitCXXFrameHandler3Table(const MachineFunction *MF) {
|
||||||
int CatchHigh = TBME.CatchHigh;
|
int CatchHigh = TBME.CatchHigh;
|
||||||
if (CatchHigh == -1) {
|
if (CatchHigh == -1) {
|
||||||
for (WinEHHandlerType &HT : TBME.HandlerArray)
|
for (WinEHHandlerType &HT : TBME.HandlerArray)
|
||||||
CatchHigh = std::max(
|
CatchHigh =
|
||||||
CatchHigh,
|
std::max(CatchHigh, FuncInfo.CatchHandlerMaxState[cast<Function>(
|
||||||
FuncInfo.CatchHandlerMaxState[cast<Function>(HT.Handler)]);
|
HT.Handler.get<const Value *>())]);
|
||||||
}
|
}
|
||||||
|
|
||||||
assert(TBME.TryLow <= TBME.TryHigh);
|
assert(TBME.TryLow <= TBME.TryHigh);
|
||||||
|
@ -464,13 +477,12 @@ void WinException::emitCXXFrameHandler3Table(const MachineFunction *MF) {
|
||||||
FrameAllocOffsetRef = MCConstantExpr::create(0, Asm->OutContext);
|
FrameAllocOffsetRef = MCConstantExpr::create(0, Asm->OutContext);
|
||||||
}
|
}
|
||||||
|
|
||||||
OS.EmitIntValue(HT.Adjectives, 4); // Adjectives
|
MCSymbol *HandlerSym = getMCSymbolForMBBOrGV(Asm, HT.Handler);
|
||||||
OS.EmitValue(create32bitRef(HT.TypeDescriptor), 4); // Type
|
|
||||||
OS.EmitValue(FrameAllocOffsetRef, 4); // CatchObjOffset
|
OS.EmitIntValue(HT.Adjectives, 4); // Adjectives
|
||||||
if (HT.HandlerMBB) // Handler
|
OS.EmitValue(create32bitRef(HT.TypeDescriptor), 4); // Type
|
||||||
OS.EmitValue(create32bitRef(HT.HandlerMBB->getSymbol()), 4);
|
OS.EmitValue(FrameAllocOffsetRef, 4); // CatchObjOffset
|
||||||
else
|
OS.EmitValue(create32bitRef(HandlerSym), 4); // Handler
|
||||||
OS.EmitValue(create32bitRef(HT.Handler), 4);
|
|
||||||
|
|
||||||
if (shouldEmitPersonality) {
|
if (shouldEmitPersonality) {
|
||||||
if (FuncInfo.CatchHandlerParentFrameObjOffset.empty()) {
|
if (FuncInfo.CatchHandlerParentFrameObjOffset.empty()) {
|
||||||
|
@ -482,7 +494,8 @@ void WinException::emitCXXFrameHandler3Table(const MachineFunction *MF) {
|
||||||
} else {
|
} else {
|
||||||
MCSymbol *ParentFrameOffset =
|
MCSymbol *ParentFrameOffset =
|
||||||
Asm->OutContext.getOrCreateParentFrameOffsetSymbol(
|
Asm->OutContext.getOrCreateParentFrameOffsetSymbol(
|
||||||
GlobalValue::getRealLinkageName(HT.Handler->getName()));
|
GlobalValue::getRealLinkageName(
|
||||||
|
HT.Handler.get<const Value *>()->getName()));
|
||||||
const MCSymbolRefExpr *ParentFrameOffsetRef =
|
const MCSymbolRefExpr *ParentFrameOffsetRef =
|
||||||
MCSymbolRefExpr::create(ParentFrameOffset, Asm->OutContext);
|
MCSymbolRefExpr::create(ParentFrameOffset, Asm->OutContext);
|
||||||
OS.EmitValue(ParentFrameOffsetRef, 4); // ParentFrameOffset
|
OS.EmitValue(ParentFrameOffsetRef, 4); // ParentFrameOffset
|
||||||
|
@ -642,6 +655,19 @@ void WinException::emitExceptHandlerTable(const MachineFunction *MF) {
|
||||||
BaseState = -2;
|
BaseState = -2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!FuncInfo.SEHUnwindMap.empty()) {
|
||||||
|
for (SEHUnwindMapEntry &UME : FuncInfo.SEHUnwindMap) {
|
||||||
|
MCSymbol *ExceptOrFinally =
|
||||||
|
UME.Handler.get<MachineBasicBlock *>()->getSymbol();
|
||||||
|
OS.EmitIntValue(UME.ToState, 4); // ToState
|
||||||
|
OS.EmitValue(create32bitRef(UME.Filter), 4); // Filter
|
||||||
|
OS.EmitValue(create32bitRef(ExceptOrFinally), 4); // Except/Finally
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// FIXME: The following code is for the old landingpad-based SEH
|
||||||
|
// implementation. Remove it when possible.
|
||||||
|
|
||||||
// Build a list of pointers to LandingPadInfos and then sort by WinEHState.
|
// Build a list of pointers to LandingPadInfos and then sort by WinEHState.
|
||||||
const std::vector<LandingPadInfo> &PadInfos = MMI->getLandingPads();
|
const std::vector<LandingPadInfo> &PadInfos = MMI->getLandingPads();
|
||||||
SmallVector<const LandingPadInfo *, 4> LPads;
|
SmallVector<const LandingPadInfo *, 4> LPads;
|
||||||
|
|
|
@ -36,7 +36,7 @@ class LLVM_LIBRARY_VISIBILITY WinException : public EHStreamer {
|
||||||
/// True if this is a 64-bit target and we should use image relative offsets.
|
/// True if this is a 64-bit target and we should use image relative offsets.
|
||||||
bool useImageRel32 = false;
|
bool useImageRel32 = false;
|
||||||
|
|
||||||
void emitCSpecificHandlerTable();
|
void emitCSpecificHandlerTable(const MachineFunction *MF);
|
||||||
|
|
||||||
/// Emit the EH table data for 32-bit and 64-bit functions using
|
/// Emit the EH table data for 32-bit and 64-bit functions using
|
||||||
/// the __CxxFrameHandler3 personality.
|
/// the __CxxFrameHandler3 personality.
|
||||||
|
|
|
@ -287,21 +287,31 @@ void FunctionLoweringInfo::set(const Function &fn, MachineFunction &mf,
|
||||||
addSEHHandlersForLPads(LPads);
|
addSEHHandlersForLPads(LPads);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Calculate state numbers if we haven't already.
|
||||||
WinEHFuncInfo &EHInfo = MMI.getWinEHFuncInfo(&fn);
|
WinEHFuncInfo &EHInfo = MMI.getWinEHFuncInfo(&fn);
|
||||||
if (Personality == EHPersonality::MSVC_CXX) {
|
if (Personality == EHPersonality::MSVC_CXX) {
|
||||||
// Calculate state numbers and then map from funclet BBs to MBBs.
|
|
||||||
const Function *WinEHParentFn = MMI.getWinEHParent(&fn);
|
const Function *WinEHParentFn = MMI.getWinEHParent(&fn);
|
||||||
calculateWinCXXEHStateNumbers(WinEHParentFn, EHInfo);
|
calculateWinCXXEHStateNumbers(WinEHParentFn, EHInfo);
|
||||||
|
} else {
|
||||||
|
const Function *WinEHParentFn = MMI.getWinEHParent(&fn);
|
||||||
|
calculateSEHStateNumbers(WinEHParentFn, EHInfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Map all BB references in the EH data to MBBs.
|
||||||
for (WinEHTryBlockMapEntry &TBME : EHInfo.TryBlockMap)
|
for (WinEHTryBlockMapEntry &TBME : EHInfo.TryBlockMap)
|
||||||
for (WinEHHandlerType &H : TBME.HandlerArray)
|
for (WinEHHandlerType &H : TBME.HandlerArray)
|
||||||
if (const auto *BB = dyn_cast<BasicBlock>(H.Handler))
|
if (const auto *BB =
|
||||||
H.HandlerMBB = MBBMap[BB];
|
dyn_cast<BasicBlock>(H.Handler.get<const Value *>()))
|
||||||
// If there's an explicit EH registration node on the stack, record its
|
H.Handler = MBBMap[BB];
|
||||||
// frame index.
|
for (SEHUnwindMapEntry &UME : EHInfo.SEHUnwindMap) {
|
||||||
if (EHInfo.EHRegNode && EHInfo.EHRegNode->getParent()->getParent() == Fn) {
|
const BasicBlock *BB = UME.Handler.get<const BasicBlock *>();
|
||||||
assert(StaticAllocaMap.count(EHInfo.EHRegNode));
|
UME.Handler = MBBMap[BB];
|
||||||
EHInfo.EHRegNodeFrameIndex = StaticAllocaMap[EHInfo.EHRegNode];
|
|
||||||
}
|
}
|
||||||
|
// If there's an explicit EH registration node on the stack, record its
|
||||||
|
// frame index.
|
||||||
|
if (EHInfo.EHRegNode && EHInfo.EHRegNode->getParent()->getParent() == Fn) {
|
||||||
|
assert(StaticAllocaMap.count(EHInfo.EHRegNode));
|
||||||
|
EHInfo.EHRegNodeFrameIndex = StaticAllocaMap[EHInfo.EHRegNode];
|
||||||
}
|
}
|
||||||
|
|
||||||
// Copy the state numbers to LandingPadInfo for the current function, which
|
// Copy the state numbers to LandingPadInfo for the current function, which
|
||||||
|
|
|
@ -1989,7 +1989,6 @@ void SelectionDAGBuilder::visitInvoke(const InvokeInst &I) {
|
||||||
// and catchendpads for successors.
|
// and catchendpads for successors.
|
||||||
MachineBasicBlock *Return = FuncInfo.MBBMap[I.getSuccessor(0)];
|
MachineBasicBlock *Return = FuncInfo.MBBMap[I.getSuccessor(0)];
|
||||||
const BasicBlock *EHPadBB = I.getSuccessor(1);
|
const BasicBlock *EHPadBB = I.getSuccessor(1);
|
||||||
bool IsLandingPad = EHPadBB->isLandingPad();
|
|
||||||
|
|
||||||
const Value *Callee(I.getCalledValue());
|
const Value *Callee(I.getCalledValue());
|
||||||
const Function *Fn = dyn_cast<Function>(Callee);
|
const Function *Fn = dyn_cast<Function>(Callee);
|
||||||
|
@ -2025,16 +2024,26 @@ void SelectionDAGBuilder::visitInvoke(const InvokeInst &I) {
|
||||||
// Catchpads are conditional branches that add real MBB destinations and
|
// Catchpads are conditional branches that add real MBB destinations and
|
||||||
// continue the loop. EH "end" pads are not real BBs and simply continue.
|
// continue the loop. EH "end" pads are not real BBs and simply continue.
|
||||||
SmallVector<MachineBasicBlock *, 1> UnwindDests;
|
SmallVector<MachineBasicBlock *, 1> UnwindDests;
|
||||||
|
bool IsMSVCCXX = classifyEHPersonality(FuncInfo.Fn->getPersonalityFn()) ==
|
||||||
|
EHPersonality::MSVC_CXX;
|
||||||
while (EHPadBB) {
|
while (EHPadBB) {
|
||||||
const Instruction *Pad = EHPadBB->getFirstNonPHI();
|
const Instruction *Pad = EHPadBB->getFirstNonPHI();
|
||||||
if (isa<CleanupPadInst>(Pad) || isa<LandingPadInst>(Pad)) {
|
if (isa<LandingPadInst>(Pad)) {
|
||||||
assert(FuncInfo.MBBMap[EHPadBB]);
|
// Stop on landingpads. They are not funclets.
|
||||||
// Stop on cleanup pads and landingpads.
|
|
||||||
UnwindDests.push_back(FuncInfo.MBBMap[EHPadBB]);
|
UnwindDests.push_back(FuncInfo.MBBMap[EHPadBB]);
|
||||||
break;
|
break;
|
||||||
|
} else if (isa<CleanupPadInst>(Pad) || isa<LandingPadInst>(Pad)) {
|
||||||
|
// Stop on cleanup pads. Cleanups are always funclet entries for all known
|
||||||
|
// personalities.
|
||||||
|
UnwindDests.push_back(FuncInfo.MBBMap[EHPadBB]);
|
||||||
|
UnwindDests.back()->setIsEHFuncletEntry();
|
||||||
|
break;
|
||||||
} else if (const auto *CPI = dyn_cast<CatchPadInst>(Pad)) {
|
} else if (const auto *CPI = dyn_cast<CatchPadInst>(Pad)) {
|
||||||
// Add the catchpad handler to the possible destinations.
|
// Add the catchpad handler to the possible destinations.
|
||||||
UnwindDests.push_back(FuncInfo.MBBMap[CPI->getNormalDest()]);
|
UnwindDests.push_back(FuncInfo.MBBMap[CPI->getNormalDest()]);
|
||||||
|
// In MSVC C++, catchblocks are funclets and need prologues.
|
||||||
|
if (IsMSVCCXX)
|
||||||
|
UnwindDests.back()->setIsEHFuncletEntry();
|
||||||
EHPadBB = CPI->getUnwindDest();
|
EHPadBB = CPI->getUnwindDest();
|
||||||
} else if (const auto *CEPI = dyn_cast<CatchEndPadInst>(Pad)) {
|
} else if (const auto *CEPI = dyn_cast<CatchEndPadInst>(Pad)) {
|
||||||
EHPadBB = CEPI->getUnwindDest();
|
EHPadBB = CEPI->getUnwindDest();
|
||||||
|
@ -2043,13 +2052,11 @@ void SelectionDAGBuilder::visitInvoke(const InvokeInst &I) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update successor info
|
// Update successor info.
|
||||||
// FIXME: The weights for catchpads will be wrong.
|
// FIXME: The weights for catchpads will be wrong.
|
||||||
addSuccessorWithWeight(InvokeMBB, Return);
|
addSuccessorWithWeight(InvokeMBB, Return);
|
||||||
for (auto *UnwindDest : UnwindDests) {
|
for (MachineBasicBlock *UnwindDest : UnwindDests) {
|
||||||
UnwindDest->setIsEHPad();
|
UnwindDest->setIsEHPad();
|
||||||
if (!IsLandingPad)
|
|
||||||
UnwindDest->setIsEHFuncletEntry();
|
|
||||||
addSuccessorWithWeight(InvokeMBB, UnwindDest);
|
addSuccessorWithWeight(InvokeMBB, UnwindDest);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2616,7 +2616,6 @@ static void addTryBlockMapEntry(WinEHFuncInfo &FuncInfo, int TryLow,
|
||||||
cast<GlobalVariable>(CS->getAggregateElement(1)->stripPointerCasts());
|
cast<GlobalVariable>(CS->getAggregateElement(1)->stripPointerCasts());
|
||||||
}
|
}
|
||||||
HT.Handler = CPI->getNormalDest();
|
HT.Handler = CPI->getNormalDest();
|
||||||
HT.HandlerMBB = nullptr;
|
|
||||||
// FIXME: Pass CPI->getArgOperand(1).
|
// FIXME: Pass CPI->getArgOperand(1).
|
||||||
HT.CatchObjRecoverIdx = -1;
|
HT.CatchObjRecoverIdx = -1;
|
||||||
TBME.HandlerArray.push_back(HT);
|
TBME.HandlerArray.push_back(HT);
|
||||||
|
@ -2645,7 +2644,8 @@ void WinEHNumbering::createTryBlockMapEntry(int TryLow, int TryHigh,
|
||||||
continue;
|
continue;
|
||||||
int N;
|
int N;
|
||||||
for (N = 0; N < NumHandlers; ++N) {
|
for (N = 0; N < NumHandlers; ++N) {
|
||||||
if (Entry.HandlerArray[N].Handler != Handlers[N]->getHandlerBlockOrFunc())
|
if (Entry.HandlerArray[N].Handler.get<const Value *>() !=
|
||||||
|
Handlers[N]->getHandlerBlockOrFunc())
|
||||||
break; // breaks out of inner loop
|
break; // breaks out of inner loop
|
||||||
}
|
}
|
||||||
// If all the handlers match, this is what we were looking for.
|
// If all the handlers match, this is what we were looking for.
|
||||||
|
@ -2692,7 +2692,6 @@ void WinEHNumbering::createTryBlockMapEntry(int TryLow, int TryHigh,
|
||||||
cast<GlobalVariable>(CS->getAggregateElement(1)->stripPointerCasts());
|
cast<GlobalVariable>(CS->getAggregateElement(1)->stripPointerCasts());
|
||||||
}
|
}
|
||||||
HT.Handler = cast<Function>(CH->getHandlerBlockOrFunc());
|
HT.Handler = cast<Function>(CH->getHandlerBlockOrFunc());
|
||||||
HT.HandlerMBB = nullptr;
|
|
||||||
HT.CatchObjRecoverIdx = CH->getExceptionVarIndex();
|
HT.CatchObjRecoverIdx = CH->getExceptionVarIndex();
|
||||||
TBME.HandlerArray.push_back(HT);
|
TBME.HandlerArray.push_back(HT);
|
||||||
}
|
}
|
||||||
|
@ -2949,13 +2948,45 @@ void WinEHNumbering::findActionRootLPads(const Function &F) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static const BasicBlock *getSingleCatchPadPredecessor(const BasicBlock &BB) {
|
static const CatchPadInst *getSingleCatchPadPredecessor(const BasicBlock *BB) {
|
||||||
for (const BasicBlock *PredBlock : predecessors(&BB))
|
for (const BasicBlock *PredBlock : predecessors(BB))
|
||||||
if (isa<CatchPadInst>(PredBlock->getFirstNonPHI()))
|
if (auto *CPI = dyn_cast<CatchPadInst>(PredBlock->getFirstNonPHI()))
|
||||||
return PredBlock;
|
return CPI;
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Find all the catchpads that feed directly into the catchendpad. Frontends
|
||||||
|
/// using this personality should ensure that each catchendpad and catchpad has
|
||||||
|
/// one or zero catchpad predecessors.
|
||||||
|
///
|
||||||
|
/// The following C++ generates the IR after it:
|
||||||
|
/// try {
|
||||||
|
/// } catch (A) {
|
||||||
|
/// } catch (B) {
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// IR:
|
||||||
|
/// %catchpad.A
|
||||||
|
/// catchpad [i8* A typeinfo]
|
||||||
|
/// to label %catch.A unwind label %catchpad.B
|
||||||
|
/// %catchpad.B
|
||||||
|
/// catchpad [i8* B typeinfo]
|
||||||
|
/// to label %catch.B unwind label %endcatches
|
||||||
|
/// %endcatches
|
||||||
|
/// catchendblock unwind to caller
|
||||||
|
void findCatchPadsForCatchEndPad(
|
||||||
|
const BasicBlock *CatchEndBB,
|
||||||
|
SmallVectorImpl<const CatchPadInst *> &Handlers) {
|
||||||
|
const CatchPadInst *CPI = getSingleCatchPadPredecessor(CatchEndBB);
|
||||||
|
while (CPI) {
|
||||||
|
Handlers.push_back(CPI);
|
||||||
|
CPI = getSingleCatchPadPredecessor(CPI->getParent());
|
||||||
|
}
|
||||||
|
// 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());
|
||||||
|
}
|
||||||
|
|
||||||
// Given BB which ends in an unwind edge, return the EHPad that this BB belongs
|
// 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.
|
// to. If the unwind edge came from an invoke, return null.
|
||||||
static const BasicBlock *getEHPadFromPredecessor(const BasicBlock *BB) {
|
static const BasicBlock *getEHPadFromPredecessor(const BasicBlock *BB) {
|
||||||
|
@ -2970,9 +3001,9 @@ static const BasicBlock *getEHPadFromPredecessor(const BasicBlock *BB) {
|
||||||
return cast<CleanupReturnInst>(TI)->getCleanupPad()->getParent();
|
return cast<CleanupReturnInst>(TI)->getCleanupPad()->getParent();
|
||||||
}
|
}
|
||||||
|
|
||||||
static void calculateExplicitStateNumbers(WinEHFuncInfo &FuncInfo,
|
static void calculateExplicitCXXStateNumbers(WinEHFuncInfo &FuncInfo,
|
||||||
const BasicBlock &BB,
|
const BasicBlock &BB,
|
||||||
int ParentState) {
|
int ParentState) {
|
||||||
assert(BB.isEHPad());
|
assert(BB.isEHPad());
|
||||||
const Instruction *FirstNonPHI = BB.getFirstNonPHI();
|
const Instruction *FirstNonPHI = BB.getFirstNonPHI();
|
||||||
// All catchpad instructions will be handled when we process their
|
// All catchpad instructions will be handled when we process their
|
||||||
|
@ -2981,36 +3012,30 @@ static void calculateExplicitStateNumbers(WinEHFuncInfo &FuncInfo,
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (isa<CatchEndPadInst>(FirstNonPHI)) {
|
if (isa<CatchEndPadInst>(FirstNonPHI)) {
|
||||||
const BasicBlock *TryPad = &BB;
|
|
||||||
const BasicBlock *LastTryPad = nullptr;
|
|
||||||
SmallVector<const CatchPadInst *, 2> Handlers;
|
SmallVector<const CatchPadInst *, 2> Handlers;
|
||||||
do {
|
findCatchPadsForCatchEndPad(&BB, Handlers);
|
||||||
LastTryPad = TryPad;
|
const BasicBlock *FirstTryPad = Handlers.front()->getParent();
|
||||||
TryPad = getSingleCatchPadPredecessor(*TryPad);
|
|
||||||
if (TryPad)
|
|
||||||
Handlers.push_back(cast<CatchPadInst>(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);
|
int TryLow = addUnwindMapEntry(FuncInfo, ParentState, nullptr);
|
||||||
FuncInfo.EHPadStateMap[Handlers.front()] = TryLow;
|
FuncInfo.EHPadStateMap[Handlers.front()] = TryLow;
|
||||||
for (const BasicBlock *PredBlock : predecessors(LastTryPad))
|
for (const BasicBlock *PredBlock : predecessors(FirstTryPad))
|
||||||
if ((PredBlock = getEHPadFromPredecessor(PredBlock)))
|
if ((PredBlock = getEHPadFromPredecessor(PredBlock)))
|
||||||
calculateExplicitStateNumbers(FuncInfo, *PredBlock, TryLow);
|
calculateExplicitCXXStateNumbers(FuncInfo, *PredBlock, TryLow);
|
||||||
int CatchLow = addUnwindMapEntry(FuncInfo, ParentState, nullptr);
|
int CatchLow = addUnwindMapEntry(FuncInfo, ParentState, nullptr);
|
||||||
|
|
||||||
|
// catchpads are separate funclets in C++ EH due to the way rethrow works.
|
||||||
|
// In SEH, they aren't, so no invokes will unwind to the catchendpad.
|
||||||
FuncInfo.EHPadStateMap[FirstNonPHI] = CatchLow;
|
FuncInfo.EHPadStateMap[FirstNonPHI] = CatchLow;
|
||||||
int TryHigh = CatchLow - 1;
|
int TryHigh = CatchLow - 1;
|
||||||
for (const BasicBlock *PredBlock : predecessors(&BB))
|
for (const BasicBlock *PredBlock : predecessors(&BB))
|
||||||
if ((PredBlock = getEHPadFromPredecessor(PredBlock)))
|
if ((PredBlock = getEHPadFromPredecessor(PredBlock)))
|
||||||
calculateExplicitStateNumbers(FuncInfo, *PredBlock, CatchLow);
|
calculateExplicitCXXStateNumbers(FuncInfo, *PredBlock, CatchLow);
|
||||||
int CatchHigh = FuncInfo.getLastStateNumber();
|
int CatchHigh = FuncInfo.getLastStateNumber();
|
||||||
addTryBlockMapEntry(FuncInfo, TryLow, TryHigh, CatchHigh, Handlers);
|
addTryBlockMapEntry(FuncInfo, TryLow, TryHigh, CatchHigh, Handlers);
|
||||||
DEBUG(dbgs() << "TryLow[" << LastTryPad->getName() << "]: " << TryLow
|
DEBUG(dbgs() << "TryLow[" << FirstTryPad->getName() << "]: " << TryLow
|
||||||
<< '\n');
|
<< '\n');
|
||||||
DEBUG(dbgs() << "TryHigh[" << LastTryPad->getName() << "]: " << TryHigh
|
DEBUG(dbgs() << "TryHigh[" << FirstTryPad->getName() << "]: " << TryHigh
|
||||||
<< '\n');
|
<< '\n');
|
||||||
DEBUG(dbgs() << "CatchHigh[" << LastTryPad->getName() << "]: " << CatchHigh
|
DEBUG(dbgs() << "CatchHigh[" << FirstTryPad->getName() << "]: " << CatchHigh
|
||||||
<< '\n');
|
<< '\n');
|
||||||
} else if (isa<CleanupPadInst>(FirstNonPHI)) {
|
} else if (isa<CleanupPadInst>(FirstNonPHI)) {
|
||||||
int CleanupState = addUnwindMapEntry(FuncInfo, ParentState, &BB);
|
int CleanupState = addUnwindMapEntry(FuncInfo, ParentState, &BB);
|
||||||
|
@ -3019,7 +3044,7 @@ static void calculateExplicitStateNumbers(WinEHFuncInfo &FuncInfo,
|
||||||
<< BB.getName() << '\n');
|
<< BB.getName() << '\n');
|
||||||
for (const BasicBlock *PredBlock : predecessors(&BB))
|
for (const BasicBlock *PredBlock : predecessors(&BB))
|
||||||
if ((PredBlock = getEHPadFromPredecessor(PredBlock)))
|
if ((PredBlock = getEHPadFromPredecessor(PredBlock)))
|
||||||
calculateExplicitStateNumbers(FuncInfo, *PredBlock, CleanupState);
|
calculateExplicitCXXStateNumbers(FuncInfo, *PredBlock, CleanupState);
|
||||||
} else if (isa<TerminatePadInst>(FirstNonPHI)) {
|
} else if (isa<TerminatePadInst>(FirstNonPHI)) {
|
||||||
report_fatal_error("Not yet implemented!");
|
report_fatal_error("Not yet implemented!");
|
||||||
} else {
|
} else {
|
||||||
|
@ -3027,6 +3052,103 @@ static void calculateExplicitStateNumbers(WinEHFuncInfo &FuncInfo,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int addSEHHandler(WinEHFuncInfo &FuncInfo, int ParentState,
|
||||||
|
const Function *Filter, const BasicBlock *Handler) {
|
||||||
|
SEHUnwindMapEntry Entry;
|
||||||
|
Entry.ToState = ParentState;
|
||||||
|
Entry.Filter = Filter;
|
||||||
|
Entry.Handler = Handler;
|
||||||
|
FuncInfo.SEHUnwindMap.push_back(Entry);
|
||||||
|
return FuncInfo.SEHUnwindMap.size() - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void calculateExplicitSEHStateNumbers(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<CatchPadInst>(FirstNonPHI))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (isa<CatchEndPadInst>(FirstNonPHI)) {
|
||||||
|
// Extract the filter function and the __except basic block and create a
|
||||||
|
// state for them.
|
||||||
|
SmallVector<const CatchPadInst *, 1> Handlers;
|
||||||
|
findCatchPadsForCatchEndPad(&BB, Handlers);
|
||||||
|
assert(Handlers.size() == 1 &&
|
||||||
|
"SEH doesn't have multiple handlers per __try");
|
||||||
|
const CatchPadInst *CPI = Handlers.front();
|
||||||
|
const BasicBlock *CatchPadBB = CPI->getParent();
|
||||||
|
const Function *Filter =
|
||||||
|
cast<Function>(CPI->getArgOperand(0)->stripPointerCasts());
|
||||||
|
int TryState =
|
||||||
|
addSEHHandler(FuncInfo, ParentState, Filter, CPI->getNormalDest());
|
||||||
|
|
||||||
|
// Everything in the __try block uses TryState as its parent state.
|
||||||
|
FuncInfo.EHPadStateMap[CPI] = TryState;
|
||||||
|
DEBUG(dbgs() << "Assigning state #" << TryState << " to BB "
|
||||||
|
<< CatchPadBB->getName() << '\n');
|
||||||
|
for (const BasicBlock *PredBlock : predecessors(CatchPadBB))
|
||||||
|
if ((PredBlock = getEHPadFromPredecessor(PredBlock)))
|
||||||
|
calculateExplicitSEHStateNumbers(FuncInfo, *PredBlock, TryState);
|
||||||
|
|
||||||
|
// Everything in the __except block unwinds to ParentState, just like code
|
||||||
|
// outside the __try.
|
||||||
|
FuncInfo.EHPadStateMap[FirstNonPHI] = ParentState;
|
||||||
|
DEBUG(dbgs() << "Assigning state #" << ParentState << " to BB "
|
||||||
|
<< BB.getName() << '\n');
|
||||||
|
for (const BasicBlock *PredBlock : predecessors(&BB))
|
||||||
|
if ((PredBlock = getEHPadFromPredecessor(PredBlock)))
|
||||||
|
calculateExplicitSEHStateNumbers(FuncInfo, *PredBlock, ParentState);
|
||||||
|
} else if (isa<CleanupPadInst>(FirstNonPHI)) {
|
||||||
|
int CleanupState =
|
||||||
|
addSEHHandler(FuncInfo, ParentState, /*Filter=*/nullptr, &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)))
|
||||||
|
calculateExplicitSEHStateNumbers(FuncInfo, *PredBlock, CleanupState);
|
||||||
|
} else if (isa<TerminatePadInst>(FirstNonPHI)) {
|
||||||
|
report_fatal_error("Not yet implemented!");
|
||||||
|
} else {
|
||||||
|
llvm_unreachable("unexpected EH Pad!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Check if the EH Pad unwinds to caller. Cleanups are a little bit of a
|
||||||
|
/// special case because we have to look at the cleanupret instruction that uses
|
||||||
|
/// the cleanuppad.
|
||||||
|
static bool doesEHPadUnwindToCaller(const Instruction *EHPad) {
|
||||||
|
auto *CPI = dyn_cast<CleanupPadInst>(EHPad);
|
||||||
|
if (!CPI)
|
||||||
|
return EHPad->mayThrow();
|
||||||
|
|
||||||
|
// This cleanup does not return or unwind, so we say it unwinds to caller.
|
||||||
|
if (CPI->use_empty())
|
||||||
|
return true;
|
||||||
|
|
||||||
|
const Instruction *User = CPI->user_back();
|
||||||
|
if (auto *CRI = dyn_cast<CleanupReturnInst>(User))
|
||||||
|
return CRI->unwindsToCaller();
|
||||||
|
return cast<CleanupEndPadInst>(User)->unwindsToCaller();
|
||||||
|
}
|
||||||
|
|
||||||
|
void llvm::calculateSEHStateNumbers(const Function *ParentFn,
|
||||||
|
WinEHFuncInfo &FuncInfo) {
|
||||||
|
// Don't compute state numbers twice.
|
||||||
|
if (!FuncInfo.SEHUnwindMap.empty())
|
||||||
|
return;
|
||||||
|
|
||||||
|
for (const BasicBlock &BB : *ParentFn) {
|
||||||
|
if (!BB.isEHPad() || !doesEHPadUnwindToCaller(BB.getFirstNonPHI()))
|
||||||
|
continue;
|
||||||
|
calculateExplicitSEHStateNumbers(FuncInfo, BB, -1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void llvm::calculateWinCXXEHStateNumbers(const Function *ParentFn,
|
void llvm::calculateWinCXXEHStateNumbers(const Function *ParentFn,
|
||||||
WinEHFuncInfo &FuncInfo) {
|
WinEHFuncInfo &FuncInfo) {
|
||||||
// Return if it's already been done.
|
// Return if it's already been done.
|
||||||
|
@ -3041,28 +3163,9 @@ void llvm::calculateWinCXXEHStateNumbers(const Function *ParentFn,
|
||||||
// Skip cleanupendpads; they are exits, not entries.
|
// Skip cleanupendpads; they are exits, not entries.
|
||||||
if (isa<CleanupEndPadInst>(FirstNonPHI))
|
if (isa<CleanupEndPadInst>(FirstNonPHI))
|
||||||
continue;
|
continue;
|
||||||
// Check if the EH Pad has no exceptional successors (i.e. it unwinds to
|
if (!doesEHPadUnwindToCaller(FirstNonPHI))
|
||||||
// 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;
|
|
||||||
if (FirstNonPHI->mayThrow()) {
|
|
||||||
HasNoSuccessors = true;
|
|
||||||
} else if (auto *CPI = dyn_cast<CleanupPadInst>(FirstNonPHI)) {
|
|
||||||
if (CPI->use_empty()) {
|
|
||||||
HasNoSuccessors = true;
|
|
||||||
} else {
|
|
||||||
const Instruction *User = CPI->user_back();
|
|
||||||
if (auto *CRI = dyn_cast<CleanupReturnInst>(User))
|
|
||||||
HasNoSuccessors = CRI->unwindsToCaller();
|
|
||||||
else
|
|
||||||
HasNoSuccessors = cast<CleanupEndPadInst>(User)->unwindsToCaller();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!HasNoSuccessors)
|
|
||||||
continue;
|
continue;
|
||||||
calculateExplicitStateNumbers(FuncInfo, BB, -1);
|
calculateExplicitCXXStateNumbers(FuncInfo, BB, -1);
|
||||||
IsExplicit = true;
|
IsExplicit = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -16880,6 +16880,16 @@ SDValue X86TargetLowering::LowerCATCHRET(SDValue Op, SelectionDAG &DAG) const {
|
||||||
SDLoc DL(Op);
|
SDLoc DL(Op);
|
||||||
|
|
||||||
MVT PtrVT = getPointerTy(DAG.getDataLayout());
|
MVT PtrVT = getPointerTy(DAG.getDataLayout());
|
||||||
|
|
||||||
|
MachineFunction &MF = DAG.getMachineFunction();
|
||||||
|
if (isAsynchronousEHPersonality(
|
||||||
|
classifyEHPersonality(MF.getFunction()->getPersonalityFn()))) {
|
||||||
|
// For SEH, codegen catchret as a branch for now.
|
||||||
|
// FIXME: Insert something to restore the frame.
|
||||||
|
return DAG.getNode(ISD::BR, DL, MVT::Other, Chain, Dest);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
unsigned ReturnReg = (PtrVT == MVT::i64 ? X86::RAX : X86::EAX);
|
unsigned ReturnReg = (PtrVT == MVT::i64 ? X86::RAX : X86::EAX);
|
||||||
|
|
||||||
// Load the address of the destination block.
|
// Load the address of the destination block.
|
||||||
|
|
|
@ -68,9 +68,10 @@ private:
|
||||||
void unlinkExceptionRegistration(IRBuilder<> &Builder);
|
void unlinkExceptionRegistration(IRBuilder<> &Builder);
|
||||||
void addCXXStateStores(Function &F, WinEHFuncInfo &FuncInfo);
|
void addCXXStateStores(Function &F, WinEHFuncInfo &FuncInfo);
|
||||||
void addSEHStateStores(Function &F, WinEHFuncInfo &FuncInfo);
|
void addSEHStateStores(Function &F, WinEHFuncInfo &FuncInfo);
|
||||||
void addCXXStateStoresToFunclet(Value *ParentRegNode, WinEHFuncInfo &FuncInfo,
|
void addStateStoresToFunclet(Value *ParentRegNode, WinEHFuncInfo &FuncInfo,
|
||||||
Function &F, int BaseState);
|
Function &F, int BaseState);
|
||||||
void insertStateNumberStore(Value *ParentRegNode, Instruction *IP, int State);
|
void insertStateNumberStore(Value *ParentRegNode, Instruction *IP, int State);
|
||||||
|
void insertRestoreFrame(BasicBlock *BB);
|
||||||
|
|
||||||
Value *emitEHLSDA(IRBuilder<> &Builder, Function *F);
|
Value *emitEHLSDA(IRBuilder<> &Builder, Function *F);
|
||||||
|
|
||||||
|
@ -91,6 +92,7 @@ private:
|
||||||
Function *FrameRecover = nullptr;
|
Function *FrameRecover = nullptr;
|
||||||
Function *FrameAddress = nullptr;
|
Function *FrameAddress = nullptr;
|
||||||
Function *FrameEscape = nullptr;
|
Function *FrameEscape = nullptr;
|
||||||
|
Function *RestoreFrame = nullptr;
|
||||||
|
|
||||||
// Per-function state
|
// Per-function state
|
||||||
EHPersonality Personality = EHPersonality::Unknown;
|
EHPersonality Personality = EHPersonality::Unknown;
|
||||||
|
@ -123,6 +125,8 @@ bool WinEHStatePass::doInitialization(Module &M) {
|
||||||
FrameEscape = Intrinsic::getDeclaration(TheModule, Intrinsic::localescape);
|
FrameEscape = Intrinsic::getDeclaration(TheModule, Intrinsic::localescape);
|
||||||
FrameRecover = Intrinsic::getDeclaration(TheModule, Intrinsic::localrecover);
|
FrameRecover = Intrinsic::getDeclaration(TheModule, Intrinsic::localrecover);
|
||||||
FrameAddress = Intrinsic::getDeclaration(TheModule, Intrinsic::frameaddress);
|
FrameAddress = Intrinsic::getDeclaration(TheModule, Intrinsic::frameaddress);
|
||||||
|
RestoreFrame =
|
||||||
|
Intrinsic::getDeclaration(TheModule, Intrinsic::x86_seh_restoreframe);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -414,7 +418,7 @@ void WinEHStatePass::addCXXStateStores(Function &F, WinEHFuncInfo &FuncInfo) {
|
||||||
calculateWinCXXEHStateNumbers(&F, FuncInfo);
|
calculateWinCXXEHStateNumbers(&F, FuncInfo);
|
||||||
|
|
||||||
// The base state for the parent is -1.
|
// The base state for the parent is -1.
|
||||||
addCXXStateStoresToFunclet(RegNode, FuncInfo, F, -1);
|
addStateStoresToFunclet(RegNode, FuncInfo, F, -1);
|
||||||
|
|
||||||
// Set up RegNodeEscapeIndex
|
// Set up RegNodeEscapeIndex
|
||||||
int RegNodeEscapeIndex = escapeRegNode(F);
|
int RegNodeEscapeIndex = escapeRegNode(F);
|
||||||
|
@ -434,7 +438,7 @@ void WinEHStatePass::addCXXStateStores(Function &F, WinEHFuncInfo &FuncInfo) {
|
||||||
FrameRecover, {FI8, ParentFP, Builder.getInt32(RegNodeEscapeIndex)});
|
FrameRecover, {FI8, ParentFP, Builder.getInt32(RegNodeEscapeIndex)});
|
||||||
RecoveredRegNode =
|
RecoveredRegNode =
|
||||||
Builder.CreateBitCast(RecoveredRegNode, RegNodeTy->getPointerTo(0));
|
Builder.CreateBitCast(RecoveredRegNode, RegNodeTy->getPointerTo(0));
|
||||||
addCXXStateStoresToFunclet(RecoveredRegNode, FuncInfo, *Handler, BaseState);
|
addStateStoresToFunclet(RecoveredRegNode, FuncInfo, *Handler, BaseState);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -470,11 +474,17 @@ int WinEHStatePass::escapeRegNode(Function &F) {
|
||||||
return Args.size() - 1;
|
return Args.size() - 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
void WinEHStatePass::addCXXStateStoresToFunclet(Value *ParentRegNode,
|
void WinEHStatePass::insertRestoreFrame(BasicBlock *BB) {
|
||||||
WinEHFuncInfo &FuncInfo,
|
Instruction *Start = BB->getFirstInsertionPt();
|
||||||
Function &F, int BaseState) {
|
if (match(Start, m_Intrinsic<Intrinsic::x86_seh_restoreframe>()))
|
||||||
Function *RestoreFrame =
|
return;
|
||||||
Intrinsic::getDeclaration(TheModule, Intrinsic::x86_seh_restoreframe);
|
IRBuilder<> Builder(Start);
|
||||||
|
Builder.CreateCall(RestoreFrame, {});
|
||||||
|
}
|
||||||
|
|
||||||
|
void WinEHStatePass::addStateStoresToFunclet(Value *ParentRegNode,
|
||||||
|
WinEHFuncInfo &FuncInfo,
|
||||||
|
Function &F, int BaseState) {
|
||||||
// Iterate all the instructions and emit state number stores.
|
// Iterate all the instructions and emit state number stores.
|
||||||
for (BasicBlock &BB : F) {
|
for (BasicBlock &BB : F) {
|
||||||
for (Instruction &I : BB) {
|
for (Instruction &I : BB) {
|
||||||
|
@ -494,16 +504,14 @@ void WinEHStatePass::addCXXStateStoresToFunclet(Value *ParentRegNode,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Insert calls to llvm.x86.seh.restoreframe at catchret destinations.
|
// Insert calls to llvm.x86.seh.restoreframe at catchret destinations. In
|
||||||
if (auto *CR = dyn_cast<CatchReturnInst>(BB.getTerminator())) {
|
// SEH, insert them before the catchret.
|
||||||
Instruction *Start = CR->getSuccessor()->begin();
|
// FIXME: We should probably do this as part of catchret lowering in the
|
||||||
assert(!isa<PHINode>(Start) &&
|
// DAG.
|
||||||
"winehprepare failed to demote phi after catchret");
|
if (auto *CR = dyn_cast<CatchReturnInst>(BB.getTerminator()))
|
||||||
if (match(Start, m_Intrinsic<Intrinsic::x86_seh_restoreframe>()))
|
insertRestoreFrame(Personality == EHPersonality::MSVC_X86SEH
|
||||||
continue;
|
? CR->getParent()
|
||||||
IRBuilder<> Builder(Start);
|
: CR->getSuccessor());
|
||||||
Builder.CreateCall(RestoreFrame, {});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -519,6 +527,23 @@ void WinEHStatePass::addSEHStateStores(Function &F, WinEHFuncInfo &FuncInfo) {
|
||||||
int RegNodeEscapeIndex = escapeRegNode(F);
|
int RegNodeEscapeIndex = escapeRegNode(F);
|
||||||
FuncInfo.EHRegNodeEscapeIndex = RegNodeEscapeIndex;
|
FuncInfo.EHRegNodeEscapeIndex = RegNodeEscapeIndex;
|
||||||
|
|
||||||
|
// If this funciton uses the new EH IR, use the explicit state numbering
|
||||||
|
// algorithm and return early.
|
||||||
|
bool UsesLPads = false;
|
||||||
|
for (BasicBlock &BB : F) {
|
||||||
|
if (BB.isLandingPad()) {
|
||||||
|
UsesLPads = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!UsesLPads) {
|
||||||
|
calculateSEHStateNumbers(&F, FuncInfo);
|
||||||
|
addStateStoresToFunclet(RegNode, FuncInfo, F, -1);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// FIXME: Delete the rest of this code and clean things up when new EH is
|
||||||
|
// done.
|
||||||
|
|
||||||
// Iterate all the instructions and emit state number stores.
|
// Iterate all the instructions and emit state number stores.
|
||||||
int CurState = 0;
|
int CurState = 0;
|
||||||
SmallPtrSet<BasicBlock *, 4> ExceptBlocks;
|
SmallPtrSet<BasicBlock *, 4> ExceptBlocks;
|
||||||
|
|
|
@ -0,0 +1,219 @@
|
||||||
|
; RUN: llc < %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"
|
||||||
|
|
||||||
|
define void @try_except() #0 personality i8* bitcast (i32 (...)* @_except_handler3 to i8*) {
|
||||||
|
entry:
|
||||||
|
%__exception_code = alloca i32, align 4
|
||||||
|
call void (...) @llvm.localescape(i32* %__exception_code)
|
||||||
|
invoke void @f(i32 1) #3
|
||||||
|
to label %invoke.cont unwind label %catch.dispatch
|
||||||
|
|
||||||
|
catch.dispatch: ; preds = %entry
|
||||||
|
%0 = catchpad [i8* bitcast (i32 ()* @try_except_filter_catchall to i8*)] to label %__except.ret unwind label %catchendblock
|
||||||
|
|
||||||
|
__except.ret: ; preds = %catch.dispatch
|
||||||
|
catchret %0 to label %__except
|
||||||
|
|
||||||
|
__except: ; preds = %__except.ret
|
||||||
|
call void @f(i32 2)
|
||||||
|
br label %__try.cont
|
||||||
|
|
||||||
|
__try.cont: ; preds = %__except, %invoke.cont
|
||||||
|
call void @f(i32 3)
|
||||||
|
ret void
|
||||||
|
|
||||||
|
catchendblock: ; preds = %catch.dispatch
|
||||||
|
catchendpad unwind to caller
|
||||||
|
|
||||||
|
invoke.cont: ; preds = %entry
|
||||||
|
br label %__try.cont
|
||||||
|
}
|
||||||
|
|
||||||
|
; CHECK-LABEL: _try_except:
|
||||||
|
; Store state #0
|
||||||
|
; CHECK: movl $0, -[[state:[0-9]+]](%ebp)
|
||||||
|
; CHECK: movl $1, (%esp)
|
||||||
|
; CHECK: calll _f
|
||||||
|
; CHECK: movl $-1, -[[state]](%ebp)
|
||||||
|
; CHECK: movl $3, (%esp)
|
||||||
|
; CHECK: calll _f
|
||||||
|
; CHECK: retl
|
||||||
|
|
||||||
|
; __except
|
||||||
|
; CHECK: movl $-1, -[[state]](%ebp)
|
||||||
|
; CHECK: movl $2, (%esp)
|
||||||
|
; CHECK: calll _f
|
||||||
|
|
||||||
|
; CHECK: .section .xdata,"dr"
|
||||||
|
; CHECK: L__ehtable$try_except:
|
||||||
|
; CHECK: .long -1
|
||||||
|
; CHECK: .long _try_except_filter_catchall
|
||||||
|
; CHECK: .long LBB0_1
|
||||||
|
|
||||||
|
define internal i32 @try_except_filter_catchall() #0 {
|
||||||
|
entry:
|
||||||
|
%0 = call i8* @llvm.frameaddress(i32 1)
|
||||||
|
%1 = call i8* @llvm.x86.seh.recoverfp(i8* bitcast (void ()* @try_except to i8*), i8* %0)
|
||||||
|
%2 = call i8* @llvm.localrecover(i8* bitcast (void ()* @try_except to i8*), i8* %1, i32 0)
|
||||||
|
%__exception_code = bitcast i8* %2 to i32*
|
||||||
|
%3 = getelementptr inbounds i8, i8* %0, i32 -20
|
||||||
|
%4 = bitcast i8* %3 to i8**
|
||||||
|
%5 = load i8*, i8** %4, align 4
|
||||||
|
%6 = bitcast i8* %5 to { i32*, i8* }*
|
||||||
|
%7 = getelementptr inbounds { i32*, i8* }, { i32*, i8* }* %6, i32 0, i32 0
|
||||||
|
%8 = load i32*, i32** %7, align 4
|
||||||
|
%9 = load i32, i32* %8, align 4
|
||||||
|
store i32 %9, i32* %__exception_code, align 4
|
||||||
|
ret i32 1
|
||||||
|
}
|
||||||
|
|
||||||
|
define void @nested_exceptions() #0 personality i8* bitcast (i32 (...)* @_except_handler3 to i8*) {
|
||||||
|
entry:
|
||||||
|
%__exception_code = alloca i32, align 4
|
||||||
|
call void (...) @llvm.localescape(i32* %__exception_code)
|
||||||
|
invoke void @crash() #3
|
||||||
|
to label %__try.cont unwind label %catch.dispatch
|
||||||
|
|
||||||
|
catch.dispatch: ; preds = %entry
|
||||||
|
%0 = catchpad [i8* bitcast (i32 ()* @nested_exceptions_filter_catchall to i8*)] to label %__except.ret unwind label %catchendblock
|
||||||
|
|
||||||
|
__except.ret: ; preds = %catch.dispatch
|
||||||
|
catchret %0 to label %__try.cont
|
||||||
|
|
||||||
|
__try.cont: ; preds = %entry, %__except.ret
|
||||||
|
invoke void @crash() #3
|
||||||
|
to label %__try.cont.9 unwind label %catch.dispatch.5
|
||||||
|
|
||||||
|
catch.dispatch.5: ; preds = %__try.cont
|
||||||
|
%1 = catchpad [i8* bitcast (i32 ()* @nested_exceptions_filter_catchall to i8*)] to label %__except.ret.7 unwind label %catchendblock.6
|
||||||
|
|
||||||
|
__except.ret.7: ; preds = %catch.dispatch.5
|
||||||
|
catchret %1 to label %__try.cont.9
|
||||||
|
|
||||||
|
__try.cont.9: ; preds = %__try.cont, %__except.ret.7
|
||||||
|
invoke void @crash() #3
|
||||||
|
to label %__try.cont.15 unwind label %catch.dispatch.11
|
||||||
|
|
||||||
|
catch.dispatch.11: ; preds = %catchendblock, %catchendblock.6, %__try.cont.9
|
||||||
|
%2 = catchpad [i8* bitcast (i32 ()* @nested_exceptions_filter_catchall to i8*)] to label %__except.ret.13 unwind label %catchendblock.12
|
||||||
|
|
||||||
|
__except.ret.13: ; preds = %catch.dispatch.11
|
||||||
|
catchret %2 to label %__try.cont.15
|
||||||
|
|
||||||
|
__try.cont.15: ; preds = %__try.cont.9, %__except.ret.13
|
||||||
|
invoke void @crash() #3
|
||||||
|
to label %__try.cont.35 unwind label %catch.dispatch.17
|
||||||
|
|
||||||
|
catch.dispatch.17: ; preds = %catchendblock.12, %__try.cont.15
|
||||||
|
%3 = catchpad [i8* bitcast (i32 ()* @nested_exceptions_filter_catchall to i8*)] to label %__except.ret.19 unwind label %catchendblock.18
|
||||||
|
|
||||||
|
__except.ret.19: ; preds = %catch.dispatch.17
|
||||||
|
catchret %3 to label %__except.20
|
||||||
|
|
||||||
|
__except.20: ; preds = %__except.ret.19
|
||||||
|
invoke void @crash() #3
|
||||||
|
to label %__try.cont.27 unwind label %catch.dispatch.23
|
||||||
|
|
||||||
|
catch.dispatch.23: ; preds = %__except.20
|
||||||
|
%4 = catchpad [i8* bitcast (i32 ()* @nested_exceptions_filter_catchall to i8*)] to label %__except.ret.25 unwind label %catchendblock.24
|
||||||
|
|
||||||
|
__except.ret.25: ; preds = %catch.dispatch.23
|
||||||
|
catchret %4 to label %__try.cont.27
|
||||||
|
|
||||||
|
__try.cont.27: ; preds = %__except.20, %__except.ret.25
|
||||||
|
invoke void @crash() #3
|
||||||
|
to label %__try.cont.35 unwind label %catch.dispatch.30
|
||||||
|
|
||||||
|
catch.dispatch.30: ; preds = %__try.cont.27
|
||||||
|
%5 = catchpad [i8* bitcast (i32 ()* @nested_exceptions_filter_catchall to i8*)] to label %__except.ret.32 unwind label %catchendblock.31
|
||||||
|
|
||||||
|
__except.ret.32: ; preds = %catch.dispatch.30
|
||||||
|
catchret %5 to label %__try.cont.35
|
||||||
|
|
||||||
|
__try.cont.35: ; preds = %__try.cont.15, %__try.cont.27, %__except.ret.32
|
||||||
|
ret void
|
||||||
|
|
||||||
|
catchendblock.31: ; preds = %catch.dispatch.30
|
||||||
|
catchendpad unwind to caller
|
||||||
|
|
||||||
|
catchendblock.24: ; preds = %catch.dispatch.23
|
||||||
|
catchendpad unwind to caller
|
||||||
|
|
||||||
|
catchendblock.18: ; preds = %catch.dispatch.17
|
||||||
|
catchendpad unwind to caller
|
||||||
|
|
||||||
|
catchendblock.12: ; preds = %catch.dispatch.11
|
||||||
|
catchendpad unwind label %catch.dispatch.17
|
||||||
|
|
||||||
|
catchendblock.6: ; preds = %catch.dispatch.5
|
||||||
|
catchendpad unwind label %catch.dispatch.11
|
||||||
|
|
||||||
|
catchendblock: ; preds = %catch.dispatch
|
||||||
|
catchendpad unwind label %catch.dispatch.11
|
||||||
|
}
|
||||||
|
|
||||||
|
; This table is equivalent to the one produced by MSVC, even if it isn't in
|
||||||
|
; quite the same order.
|
||||||
|
|
||||||
|
; CHECK-LABEL: _nested_exceptions:
|
||||||
|
; CHECK: L__ehtable$nested_exceptions:
|
||||||
|
; CHECK: .long -1
|
||||||
|
; CHECK: .long _nested_exceptions_filter_catchall
|
||||||
|
; CHECK: .long LBB
|
||||||
|
; CHECK: .long -1
|
||||||
|
; CHECK: .long _nested_exceptions_filter_catchall
|
||||||
|
; CHECK: .long LBB
|
||||||
|
; CHECK: .long -1
|
||||||
|
; CHECK: .long _nested_exceptions_filter_catchall
|
||||||
|
; CHECK: .long LBB
|
||||||
|
; CHECK: .long 2
|
||||||
|
; CHECK: .long _nested_exceptions_filter_catchall
|
||||||
|
; CHECK: .long LBB
|
||||||
|
; CHECK: .long 3
|
||||||
|
; CHECK: .long _nested_exceptions_filter_catchall
|
||||||
|
; CHECK: .long LBB
|
||||||
|
; CHECK: .long 3
|
||||||
|
; CHECK: .long _nested_exceptions_filter_catchall
|
||||||
|
; CHECK: .long LBB
|
||||||
|
|
||||||
|
declare void @crash() #0
|
||||||
|
|
||||||
|
define internal i32 @nested_exceptions_filter_catchall() #0 {
|
||||||
|
entry:
|
||||||
|
%0 = call i8* @llvm.frameaddress(i32 1)
|
||||||
|
%1 = call i8* @llvm.x86.seh.recoverfp(i8* bitcast (void ()* @nested_exceptions to i8*), i8* %0)
|
||||||
|
%2 = call i8* @llvm.localrecover(i8* bitcast (void ()* @nested_exceptions to i8*), i8* %1, i32 0)
|
||||||
|
%__exception_code3 = bitcast i8* %2 to i32*
|
||||||
|
%3 = getelementptr inbounds i8, i8* %0, i32 -20
|
||||||
|
%4 = bitcast i8* %3 to i8**
|
||||||
|
%5 = load i8*, i8** %4, align 4
|
||||||
|
%6 = bitcast i8* %5 to { i32*, i8* }*
|
||||||
|
%7 = getelementptr inbounds { i32*, i8* }, { i32*, i8* }* %6, i32 0, i32 0
|
||||||
|
%8 = load i32*, i32** %7, align 4
|
||||||
|
%9 = load i32, i32* %8, align 4
|
||||||
|
store i32 %9, i32* %__exception_code3, align 4
|
||||||
|
ret i32 1
|
||||||
|
}
|
||||||
|
|
||||||
|
; Function Attrs: nounwind readnone
|
||||||
|
declare i8* @llvm.frameaddress(i32) #1
|
||||||
|
|
||||||
|
; Function Attrs: nounwind readnone
|
||||||
|
declare i8* @llvm.x86.seh.recoverfp(i8*, i8*) #1
|
||||||
|
|
||||||
|
; Function Attrs: nounwind readnone
|
||||||
|
declare i8* @llvm.localrecover(i8*, i8*, i32) #1
|
||||||
|
|
||||||
|
declare void @f(i32) #0
|
||||||
|
|
||||||
|
declare i32 @_except_handler3(...)
|
||||||
|
|
||||||
|
; Function Attrs: nounwind
|
||||||
|
declare void @llvm.localescape(...) #2
|
||||||
|
|
||||||
|
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 readnone }
|
||||||
|
attributes #2 = { nounwind }
|
||||||
|
attributes #3 = { noinline }
|
Loading…
Reference in New Issue