summaryrefslogtreecommitdiffstats
path: root/llvm/lib
diff options
context:
space:
mode:
Diffstat (limited to 'llvm/lib')
-rw-r--r--llvm/lib/CodeGen/AsmPrinter/WinException.cpp89
-rw-r--r--llvm/lib/CodeGen/AsmPrinter/WinException.h7
-rw-r--r--llvm/lib/CodeGen/SelectionDAG/FunctionLoweringInfo.cpp17
-rw-r--r--llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp1
-rw-r--r--llvm/lib/CodeGen/WinEHPrepare.cpp22
-rw-r--r--llvm/lib/Target/X86/X86ISelLowering.cpp17
-rw-r--r--llvm/lib/Target/X86/X86WinEHState.cpp79
7 files changed, 219 insertions, 13 deletions
diff --git a/llvm/lib/CodeGen/AsmPrinter/WinException.cpp b/llvm/lib/CodeGen/AsmPrinter/WinException.cpp
index f1663503c08..1143b044cad 100644
--- a/llvm/lib/CodeGen/AsmPrinter/WinException.cpp
+++ b/llvm/lib/CodeGen/AsmPrinter/WinException.cpp
@@ -144,7 +144,7 @@ void WinException::endFunction(const MachineFunction *MF) {
if (Per == EHPersonality::MSVC_Win64SEH)
emitCSpecificHandlerTable();
else if (Per == EHPersonality::MSVC_X86SEH)
- emitCSpecificHandlerTable(); // FIXME
+ emitExceptHandlerTable(MF);
else if (Per == EHPersonality::MSVC_CXX)
emitCXXFrameHandler3Table(MF);
else
@@ -541,3 +541,90 @@ void WinException::extendIP2StateTable(const MachineFunction *MF,
}
}
}
+
+/// Emit the language-specific data that _except_handler3 and 4 expect. This is
+/// functionally equivalent to the __C_specific_handler table, except it is
+/// indexed by state number instead of IP.
+void WinException::emitExceptHandlerTable(const MachineFunction *MF) {
+ auto &OS = *Asm->OutStreamer;
+
+ // Emit the __ehtable label that we use for llvm.x86.seh.lsda.
+ const Function *F = MF->getFunction();
+ StringRef FLinkageName = GlobalValue::getRealLinkageName(F->getName());
+ MCSymbol *LSDALabel = Asm->OutContext.getOrCreateLSDASymbol(FLinkageName);
+ OS.EmitLabel(LSDALabel);
+
+ const Function *Per = MMI->getPersonality();
+ StringRef PerName = Per->getName();
+ int BaseState = -1;
+ if (PerName == "_except_handler4") {
+ // The LSDA for _except_handler4 starts with this struct, followed by the
+ // scope table:
+ //
+ // struct EH4ScopeTable {
+ // int32_t GSCookieOffset;
+ // int32_t GSCookieXOROffset;
+ // int32_t EHCookieOffset;
+ // int32_t EHCookieXOROffset;
+ // ScopeTableEntry ScopeRecord[];
+ // };
+ //
+ // Only the EHCookieOffset field appears to vary, and it appears to be the
+ // offset from the final saved SP value to the retaddr.
+ OS.EmitIntValue(-2, 4);
+ OS.EmitIntValue(0, 4);
+ // FIXME: Calculate.
+ OS.EmitIntValue(9999, 4);
+ OS.EmitIntValue(0, 4);
+ BaseState = -2;
+ }
+
+ // Build a list of pointers to LandingPadInfos and then sort by WinEHState.
+ const std::vector<LandingPadInfo> &PadInfos = MMI->getLandingPads();
+ SmallVector<const LandingPadInfo *, 4> LPads;
+ LPads.reserve((PadInfos.size()));
+ for (const LandingPadInfo &LPInfo : PadInfos)
+ LPads.push_back(&LPInfo);
+ std::sort(LPads.begin(), LPads.end(),
+ [](const LandingPadInfo *L, const LandingPadInfo *R) {
+ return L->WinEHState < R->WinEHState;
+ });
+
+ // For each action in each lpad, emit one of these:
+ // struct ScopeTableEntry {
+ // int32_t EnclosingLevel;
+ // int32_t (__cdecl *FilterOrFinally)();
+ // void *HandlerLabel;
+ // };
+ //
+ // The "outermost" action will use BaseState as its enclosing level. Each
+ // other action will refer to the previous state as its enclosing level.
+ int CurState = 0;
+ for (const LandingPadInfo *LPInfo : LPads) {
+ int EnclosingLevel = BaseState;
+ assert(CurState + LPInfo->SEHHandlers.size() - 1 == LPInfo->WinEHState &&
+ "gaps in the SEH scope table");
+ for (const SEHHandler &Handler : LPInfo->SEHHandlers) {
+ // Emit the filter or finally function pointer, if present. Otherwise,
+ // emit '1' to indicate a catch-all.
+ const MCExpr *FilterOrFinally;
+ if (const Function *F = Handler.FilterOrFinally)
+ FilterOrFinally = create32bitRef(Asm->getSymbol(F));
+ else
+ FilterOrFinally = MCConstantExpr::create(1, Asm->OutContext);
+
+ // Compute the recovery address, which is a block address or null.
+ const BlockAddress *BA = Handler.RecoverBA;
+ const MCExpr *RecoverBBOrNull =
+ create32bitRef(BA ? Asm->GetBlockAddressSymbol(BA) : nullptr);
+
+ OS.EmitIntValue(EnclosingLevel, 4);
+ OS.EmitValue(FilterOrFinally, 4);
+ OS.EmitValue(RecoverBBOrNull, 4);
+
+ // The next state unwinds to this state.
+ EnclosingLevel = CurState;
+ CurState++;
+ }
+ }
+}
diff --git a/llvm/lib/CodeGen/AsmPrinter/WinException.h b/llvm/lib/CodeGen/AsmPrinter/WinException.h
index 478899b79da..4e276bc95f2 100644
--- a/llvm/lib/CodeGen/AsmPrinter/WinException.h
+++ b/llvm/lib/CodeGen/AsmPrinter/WinException.h
@@ -38,8 +38,15 @@ class WinException : public EHStreamer {
void emitCSpecificHandlerTable();
+ /// Emit the EH table data for 32-bit and 64-bit functions using
+ /// the __CxxFrameHandler3 personality.
void emitCXXFrameHandler3Table(const MachineFunction *MF);
+ /// Emit the EH table data for _except_handler3 and _except_handler4
+ /// personality functions. These are only used on 32-bit and do not use CFI
+ /// tables.
+ void emitExceptHandlerTable(const MachineFunction *MF);
+
void extendIP2StateTable(const MachineFunction *MF, const Function *ParentF,
WinEHFuncInfo &FuncInfo);
diff --git a/llvm/lib/CodeGen/SelectionDAG/FunctionLoweringInfo.cpp b/llvm/lib/CodeGen/SelectionDAG/FunctionLoweringInfo.cpp
index f3d75cb32a7..e6116245bb4 100644
--- a/llvm/lib/CodeGen/SelectionDAG/FunctionLoweringInfo.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/FunctionLoweringInfo.cpp
@@ -264,15 +264,22 @@ void FunctionLoweringInfo::set(const Function &fn, MachineFunction &mf,
if (!isMSVCEHPersonality(Personality))
return;
- if (Personality == EHPersonality::MSVC_Win64SEH) {
+ if (Personality == EHPersonality::MSVC_Win64SEH ||
+ Personality == EHPersonality::MSVC_X86SEH) {
addSEHHandlersForLPads(LPads);
- } else if (Personality == EHPersonality::MSVC_CXX) {
+ }
+
+ WinEHFuncInfo &EHInfo = MMI.getWinEHFuncInfo(&fn);
+ if (Personality == EHPersonality::MSVC_CXX) {
const Function *WinEHParentFn = MMI.getWinEHParent(&fn);
- WinEHFuncInfo &EHInfo = MMI.getWinEHFuncInfo(WinEHParentFn);
calculateWinCXXEHStateNumbers(WinEHParentFn, EHInfo);
+ }
- // Copy the state numbers to LandingPadInfo for the current function, which
- // could be a handler or the parent.
+ // Copy the state numbers to LandingPadInfo for the current function, which
+ // could be a handler or the parent. This should happen for 32-bit SEH and
+ // C++ EH.
+ if (Personality == EHPersonality::MSVC_CXX ||
+ Personality == EHPersonality::MSVC_X86SEH) {
for (const LandingPadInst *LP : LPads) {
MachineBasicBlock *LPadMBB = MBBMap[LP->getParent()];
MMI.addWinEHState(LPadMBB, EHInfo.LandingPadStateMap[LP]);
diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
index 8ba957d6287..4035820244a 100644
--- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
@@ -4983,6 +4983,7 @@ SelectionDAGBuilder::visitIntrinsicCall(const CallInst &I, unsigned Intrinsic) {
assert(Reg && "cannot get exception code on this platform");
MVT PtrVT = TLI.getPointerTy();
const TargetRegisterClass *PtrRC = TLI.getRegClassFor(PtrVT);
+ assert(FuncInfo.MBB->isLandingPad() && "eh.exceptioncode in non-lpad");
unsigned VReg = FuncInfo.MBB->addLiveIn(Reg, PtrRC);
SDValue N =
DAG.getCopyFromReg(DAG.getEntryNode(), getCurSDLoc(), VReg, PtrVT);
diff --git a/llvm/lib/CodeGen/WinEHPrepare.cpp b/llvm/lib/CodeGen/WinEHPrepare.cpp
index c2b3d84ca36..6bdc9c95d61 100644
--- a/llvm/lib/CodeGen/WinEHPrepare.cpp
+++ b/llvm/lib/CodeGen/WinEHPrepare.cpp
@@ -24,6 +24,7 @@
#include "llvm/ADT/Triple.h"
#include "llvm/ADT/TinyPtrVector.h"
#include "llvm/Analysis/LibCallSemantics.h"
+#include "llvm/Analysis/TargetLibraryInfo.h"
#include "llvm/CodeGen/WinEHFuncInfo.h"
#include "llvm/IR/Dominators.h"
#include "llvm/IR/Function.h"
@@ -124,6 +125,7 @@ private:
// All fields are reset by runOnFunction.
DominatorTree *DT = nullptr;
+ const TargetLibraryInfo *LibInfo = nullptr;
EHPersonality Personality = EHPersonality::Unknown;
CatchHandlerMapTy CatchHandlerMap;
CleanupHandlerMapTy CleanupHandlerMap;
@@ -384,6 +386,7 @@ bool WinEHPrepare::runOnFunction(Function &Fn) {
return false;
DT = &getAnalysis<DominatorTreeWrapperPass>().getDomTree();
+ LibInfo = &getAnalysis<TargetLibraryInfoWrapperPass>().getTLI();
// If there were any landing pads, prepareExceptionHandlers will make changes.
prepareExceptionHandlers(Fn, LPads);
@@ -394,6 +397,7 @@ bool WinEHPrepare::doFinalization(Module &M) { return false; }
void WinEHPrepare::getAnalysisUsage(AnalysisUsage &AU) const {
AU.addRequired<DominatorTreeWrapperPass>();
+ AU.addRequired<TargetLibraryInfoWrapperPass>();
}
static bool isSelectorDispatch(BasicBlock *BB, BasicBlock *&CatchHandler,
@@ -1016,10 +1020,17 @@ bool WinEHPrepare::prepareExceptionHandlers(
Builder.CreateCall(FrameEscapeFn, AllocasToEscape);
if (SEHExceptionCodeSlot) {
- if (SEHExceptionCodeSlot->hasNUses(0))
- SEHExceptionCodeSlot->eraseFromParent();
- else if (isAllocaPromotable(SEHExceptionCodeSlot))
+ if (isAllocaPromotable(SEHExceptionCodeSlot)) {
+ SmallPtrSet<BasicBlock *, 4> UserBlocks;
+ for (User *U : SEHExceptionCodeSlot->users()) {
+ if (auto *Inst = dyn_cast<Instruction>(U))
+ UserBlocks.insert(Inst->getParent());
+ }
PromoteMemToReg(SEHExceptionCodeSlot, *DT);
+ // After the promotion, kill off dead instructions.
+ for (BasicBlock *BB : UserBlocks)
+ SimplifyInstructionsInBlock(BB, LibInfo);
+ }
}
// Clean up the handler action maps we created for this function
@@ -1029,6 +1040,7 @@ bool WinEHPrepare::prepareExceptionHandlers(
CleanupHandlerMap.clear();
HandlerToParentFP.clear();
DT = nullptr;
+ LibInfo = nullptr;
SEHExceptionCodeSlot = nullptr;
EHBlocks.clear();
NormalBlocks.clear();
@@ -1143,7 +1155,6 @@ void WinEHPrepare::completeNestedLandingPad(Function *ParentFn,
++II;
// The instruction after the landing pad should now be a call to eh.actions.
const Instruction *Recover = II;
- assert(match(Recover, m_Intrinsic<Intrinsic::eh_actions>()));
const IntrinsicInst *EHActions = cast<IntrinsicInst>(Recover);
// Remap the return target in the nested handler.
@@ -2454,6 +2465,8 @@ void WinEHPrepare::findCleanupHandlers(LandingPadActions &Actions,
void llvm::parseEHActions(
const IntrinsicInst *II,
SmallVectorImpl<std::unique_ptr<ActionHandler>> &Actions) {
+ assert(II->getIntrinsicID() == Intrinsic::eh_actions &&
+ "attempted to parse non eh.actions intrinsic");
for (unsigned I = 0, E = II->getNumArgOperands(); I != E;) {
uint64_t ActionKind =
cast<ConstantInt>(II->getArgOperand(I))->getZExtValue();
@@ -2766,7 +2779,6 @@ void WinEHNumbering::calculateStateNumbers(const Function &F) {
auto *ActionsCall = dyn_cast<IntrinsicInst>(LPI->getNextNode());
if (!ActionsCall)
continue;
- assert(ActionsCall->getIntrinsicID() == Intrinsic::eh_actions);
parseEHActions(ActionsCall, ActionList);
if (ActionList.empty())
continue;
diff --git a/llvm/lib/Target/X86/X86ISelLowering.cpp b/llvm/lib/Target/X86/X86ISelLowering.cpp
index 88598a1ddd0..72f18cc1143 100644
--- a/llvm/lib/Target/X86/X86ISelLowering.cpp
+++ b/llvm/lib/Target/X86/X86ISelLowering.cpp
@@ -15506,6 +15506,23 @@ static SDValue LowerINTRINSIC_WO_CHAIN(SDValue Op, const X86Subtarget *Subtarget
DAG.getTargetExternalSymbol(Name.data(), VT, X86II::MO_NOPREFIX);
return DAG.getNode(X86ISD::Wrapper, dl, VT, Result);
}
+
+ case Intrinsic::eh_exceptioninfo: {
+ // Compute the symbol for the LSDA. We know it'll get emitted later.
+ MachineFunction &MF = DAG.getMachineFunction();
+ SDValue Op1 = Op.getOperand(1);
+ auto *Fn = cast<Function>(cast<GlobalAddressSDNode>(Op1)->getGlobal());
+ MCSymbol *LSDASym = MF.getMMI().getContext().getOrCreateLSDASymbol(
+ GlobalValue::getRealLinkageName(Fn->getName()));
+ StringRef Name = LSDASym->getName();
+ assert(Name.data()[Name.size()] == '\0' && "not null terminated");
+
+ // Generate a simple absolute symbol reference. This intrinsic is only
+ // supported on 32-bit Windows, which isn't PIC.
+ SDValue Result =
+ DAG.getTargetExternalSymbol(Name.data(), VT, X86II::MO_NOPREFIX);
+ return DAG.getNode(X86ISD::Wrapper, dl, VT, Result);
+ }
}
}
diff --git a/llvm/lib/Target/X86/X86WinEHState.cpp b/llvm/lib/Target/X86/X86WinEHState.cpp
index ce69ea72199..0c4aabab880 100644
--- a/llvm/lib/Target/X86/X86WinEHState.cpp
+++ b/llvm/lib/Target/X86/X86WinEHState.cpp
@@ -63,9 +63,12 @@ private:
void linkExceptionRegistration(IRBuilder<> &Builder, Value *Handler);
void unlinkExceptionRegistration(IRBuilder<> &Builder);
void addCXXStateStores(Function &F, MachineModuleInfo &MMI);
+ void addSEHStateStores(Function &F, MachineModuleInfo &MMI);
void addCXXStateStoresToFunclet(Value *ParentRegNode, WinEHFuncInfo &FuncInfo,
Function &F, int BaseState);
void insertStateNumberStore(Value *ParentRegNode, Instruction *IP, int State);
+ iplist<Instruction>::iterator
+ rewriteExceptionInfoIntrinsics(IntrinsicInst *Intrin);
Value *emitEHLSDA(IRBuilder<> &Builder, Function *F);
@@ -171,8 +174,10 @@ bool WinEHStatePass::runOnFunction(Function &F) {
auto *MMIPtr = getAnalysisIfAvailable<MachineModuleInfo>();
assert(MMIPtr && "MachineModuleInfo should always be available");
MachineModuleInfo &MMI = *MMIPtr;
- if (Personality == EHPersonality::MSVC_CXX) {
- addCXXStateStores(F, MMI);
+ switch (Personality) {
+ default: llvm_unreachable("unexpected personality function");
+ case EHPersonality::MSVC_CXX: addCXXStateStores(F, MMI); break;
+ case EHPersonality::MSVC_X86SEH: addSEHStateStores(F, MMI); break;
}
// Reset per-function state.
@@ -472,6 +477,76 @@ void WinEHStatePass::addCXXStateStoresToFunclet(Value *ParentRegNode,
}
}
+/// Assign every distinct landingpad a unique state number for SEH. Unlike C++
+/// EH, we can use this very simple algorithm while C++ EH cannot because catch
+/// 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);
+
+ // Iterate all the instructions and emit state number stores.
+ int CurState = 0;
+ for (BasicBlock &BB : F) {
+ for (auto I = BB.begin(), E = BB.end(); I != E; ++I) {
+ if (auto *CI = dyn_cast<CallInst>(I)) {
+ auto *Intrin = dyn_cast<IntrinsicInst>(CI);
+ if (Intrin) {
+ I = rewriteExceptionInfoIntrinsics(Intrin);
+ // Calls that "don't throw" are considered to be able to throw asynch
+ // exceptions, but intrinsics cannot.
+ continue;
+ }
+ insertStateNumberStore(RegNode, CI, -1);
+ } else if (auto *II = dyn_cast<InvokeInst>(I)) {
+ // 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, 0));
+ auto Iter = InsertionPair.first;
+ int &State = Iter->second;
+ bool Inserted = InsertionPair.second;
+ if (Inserted) {
+ // Each action consumes a state number.
+ auto *EHActions = cast<IntrinsicInst>(LPI->getNextNode());
+ SmallVector<std::unique_ptr<ActionHandler>, 4> ActionList;
+ parseEHActions(EHActions, ActionList);
+ assert(!ActionList.empty());
+ CurState += ActionList.size();
+ State += ActionList.size() - 1;
+ }
+ insertStateNumberStore(RegNode, II, State);
+ }
+ }
+ }
+}
+
+/// Rewrite llvm.eh.exceptioncode and llvm.eh.exceptioninfo to memory loads in
+/// IR.
+iplist<Instruction>::iterator
+WinEHStatePass::rewriteExceptionInfoIntrinsics(IntrinsicInst *Intrin) {
+ Intrinsic::ID ID = Intrin->getIntrinsicID();
+ if (ID != Intrinsic::eh_exceptioncode && ID != Intrinsic::eh_exceptioninfo)
+ return Intrin;
+
+ // RegNode->ExceptionPointers
+ IRBuilder<> Builder(Intrin);
+ Value *Ptrs =
+ Builder.CreateLoad(Builder.CreateStructGEP(RegNodeTy, RegNode, 1));
+ Value *Res;
+ if (ID == Intrinsic::eh_exceptioncode) {
+ // Ptrs->ExceptionRecord->Code
+ Ptrs = Builder.CreateBitCast(
+ Ptrs, Builder.getInt32Ty()->getPointerTo()->getPointerTo());
+ Value *Rec = Builder.CreateLoad(Ptrs);
+ Res = Builder.CreateLoad(Rec);
+ } else {
+ Res = Ptrs;
+ }
+ Intrin->replaceAllUsesWith(Res);
+ return Intrin->eraseFromParent();
+}
+
void WinEHStatePass::insertStateNumberStore(Value *ParentRegNode,
Instruction *IP, int State) {
IRBuilder<> Builder(IP);
OpenPOWER on IntegriCloud