forked from OSchip/llvm-project
[SEH] Implement GetExceptionCode in __except blocks
This introduces an intrinsic called llvm.eh.exceptioncode. It is lowered by copying the EAX value live into whatever basic block it is called from. Obviously, this only works if you insert it late during codegen, because otherwise mid-level passes might reschedule it. llvm-svn: 235768
This commit is contained in:
parent
75ef0c09d0
commit
cfbfe6f29c
|
@ -221,7 +221,7 @@ public:
|
|||
int getArgumentFrameIndex(const Argument *A);
|
||||
|
||||
private:
|
||||
void addSEHHandlersForLPads();
|
||||
void addSEHHandlersForLPads(ArrayRef<const LandingPadInst *> LPads);
|
||||
|
||||
/// LiveOutRegInfo - Information about live out vregs.
|
||||
IndexedMap<LiveOutInfo, VirtReg2IndexFunctor> LiveOutRegInfo;
|
||||
|
|
|
@ -421,6 +421,8 @@ def int_eh_endcatch : Intrinsic<[], []>;
|
|||
// Represents the list of actions to take when an exception is thrown.
|
||||
def int_eh_actions : Intrinsic<[llvm_ptr_ty], [llvm_vararg_ty], []>;
|
||||
|
||||
def int_eh_exceptioncode : Intrinsic<[llvm_i32_ty], []>;
|
||||
|
||||
// __builtin_unwind_init is an undocumented GCC intrinsic that causes all
|
||||
// callee-saved registers to be saved and restored (regardless of whether they
|
||||
// are used) in the calling function. It is used by libgcc_eh.
|
||||
|
|
|
@ -271,40 +271,49 @@ void FunctionLoweringInfo::set(const Function &fn, MachineFunction &mf,
|
|||
}
|
||||
|
||||
// Mark landing pad blocks.
|
||||
const LandingPadInst *LP = nullptr;
|
||||
SmallVector<const LandingPadInst *, 4> LPads;
|
||||
for (BB = Fn->begin(); BB != EB; ++BB) {
|
||||
if (const auto *Invoke = dyn_cast<InvokeInst>(BB->getTerminator()))
|
||||
MBBMap[Invoke->getSuccessor(1)]->setIsLandingPad();
|
||||
if (BB->isLandingPad())
|
||||
LP = BB->getLandingPadInst();
|
||||
LPads.push_back(BB->getLandingPadInst());
|
||||
}
|
||||
|
||||
// Calculate EH numbers for MSVC C++ EH and save SEH handlers if necessary.
|
||||
// If this is an MSVC EH personality, we need to do a bit more work.
|
||||
EHPersonality Personality = EHPersonality::Unknown;
|
||||
if (LP)
|
||||
Personality = classifyEHPersonality(LP->getPersonalityFn());
|
||||
if (!LPads.empty())
|
||||
Personality = classifyEHPersonality(LPads.back()->getPersonalityFn());
|
||||
if (!isMSVCEHPersonality(Personality))
|
||||
return;
|
||||
|
||||
WinEHFuncInfo *EHInfo = nullptr;
|
||||
if (Personality == EHPersonality::MSVC_Win64SEH) {
|
||||
addSEHHandlersForLPads();
|
||||
addSEHHandlersForLPads(LPads);
|
||||
} else if (Personality == EHPersonality::MSVC_CXX) {
|
||||
const Function *WinEHParentFn = MMI.getWinEHParent(&fn);
|
||||
WinEHFuncInfo &FI = MMI.getWinEHFuncInfo(WinEHParentFn);
|
||||
if (FI.LandingPadStateMap.empty()) {
|
||||
WinEHNumbering Num(FI);
|
||||
EHInfo = &MMI.getWinEHFuncInfo(WinEHParentFn);
|
||||
if (EHInfo->LandingPadStateMap.empty()) {
|
||||
WinEHNumbering Num(*EHInfo);
|
||||
Num.calculateStateNumbers(*WinEHParentFn);
|
||||
// Pop everything on the handler stack.
|
||||
Num.processCallSite(None, ImmutableCallSite());
|
||||
}
|
||||
|
||||
// Copy the state numbers to LandingPadInfo for the current function, which
|
||||
// could be a handler or the parent.
|
||||
for (const LandingPadInst *LP : LPads) {
|
||||
MachineBasicBlock *LPadMBB = MBBMap[LP->getParent()];
|
||||
MMI.addWinEHState(LPadMBB, EHInfo->LandingPadStateMap[LP]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void FunctionLoweringInfo::addSEHHandlersForLPads() {
|
||||
void FunctionLoweringInfo::addSEHHandlersForLPads(
|
||||
ArrayRef<const LandingPadInst *> LPads) {
|
||||
MachineModuleInfo &MMI = MF->getMMI();
|
||||
|
||||
// Iterate over all landing pads with llvm.eh.actions calls.
|
||||
for (const BasicBlock &BB : *Fn) {
|
||||
const LandingPadInst *LP = BB.getLandingPadInst();
|
||||
if (!LP)
|
||||
continue;
|
||||
for (const LandingPadInst *LP : LPads) {
|
||||
const IntrinsicInst *ActionsCall =
|
||||
dyn_cast<IntrinsicInst>(LP->getNextNode());
|
||||
if (!ActionsCall ||
|
||||
|
|
|
@ -4817,6 +4817,18 @@ SelectionDAGBuilder::visitIntrinsicCall(const CallInst &I, unsigned Intrinsic) {
|
|||
case Intrinsic::eh_begincatch:
|
||||
case Intrinsic::eh_endcatch:
|
||||
llvm_unreachable("begin/end catch intrinsics not lowered in codegen");
|
||||
case Intrinsic::eh_exceptioncode: {
|
||||
unsigned Reg = TLI.getExceptionPointerRegister();
|
||||
assert(Reg && "cannot get exception code on this platform");
|
||||
MVT PtrVT = TLI.getPointerTy();
|
||||
const TargetRegisterClass *PtrRC = TLI.getRegClassFor(PtrVT);
|
||||
unsigned VReg = FuncInfo.MBB->addLiveIn(Reg, PtrRC);
|
||||
SDValue N =
|
||||
DAG.getCopyFromReg(DAG.getEntryNode(), getCurSDLoc(), VReg, PtrVT);
|
||||
N = DAG.getZExtOrTrunc(N, getCurSDLoc(), MVT::i32);
|
||||
setValue(&I, N);
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -961,12 +961,6 @@ bool SelectionDAGISel::PrepareEHLandingPad() {
|
|||
for (MachineBasicBlock *InvokeBB : InvokeBBs)
|
||||
InvokeBB->removeSuccessor(MBB);
|
||||
|
||||
// Transfer EH state number assigned to the IR block to the MBB.
|
||||
if (Personality == EHPersonality::MSVC_CXX) {
|
||||
WinEHFuncInfo &FI = MF->getMMI().getWinEHFuncInfo(MF->getFunction());
|
||||
MF->getMMI().addWinEHState(MBB, FI.LandingPadStateMap[LPadInst]);
|
||||
}
|
||||
|
||||
// Don't select instructions for the landingpad.
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -71,7 +71,7 @@ class WinEHPrepare : public FunctionPass {
|
|||
public:
|
||||
static char ID; // Pass identification, replacement for typeid.
|
||||
WinEHPrepare(const TargetMachine *TM = nullptr)
|
||||
: FunctionPass(ID), DT(nullptr) {}
|
||||
: FunctionPass(ID), DT(nullptr), SEHExceptionCodeSlot(nullptr) {}
|
||||
|
||||
bool runOnFunction(Function &Fn) override;
|
||||
|
||||
|
@ -133,6 +133,8 @@ private:
|
|||
// outlined into a handler. This is done after all handlers have been
|
||||
// outlined but before the outlined code is pruned from the parent function.
|
||||
DenseMap<const BasicBlock *, BasicBlock *> LPadTargetBlocks;
|
||||
|
||||
AllocaInst *SEHExceptionCodeSlot;
|
||||
};
|
||||
|
||||
class WinEHFrameVariableMaterializer : public ValueMaterializer {
|
||||
|
@ -628,6 +630,13 @@ bool WinEHPrepare::prepareExceptionHandlers(
|
|||
Type *Int32Type = Type::getInt32Ty(Context);
|
||||
Function *ActionIntrin = Intrinsic::getDeclaration(M, Intrinsic::eh_actions);
|
||||
|
||||
if (isAsynchronousEHPersonality(Personality)) {
|
||||
// FIXME: Switch the ehptr type to i32 and then switch this.
|
||||
SEHExceptionCodeSlot =
|
||||
new AllocaInst(Int8PtrType, nullptr, "seh_exception_code",
|
||||
F.getEntryBlock().getFirstInsertionPt());
|
||||
}
|
||||
|
||||
for (LandingPadInst *LPad : LPads) {
|
||||
// Look for evidence that this landingpad has already been processed.
|
||||
bool LPadHasActionList = false;
|
||||
|
@ -680,23 +689,48 @@ bool WinEHPrepare::prepareExceptionHandlers(
|
|||
|
||||
// Replace all extracted values with undef and ultimately replace the
|
||||
// landingpad with undef.
|
||||
// FIXME: This doesn't handle SEH GetExceptionCode(). For now, we just give
|
||||
// out undef until we figure out the codegen support.
|
||||
SmallVector<Instruction *, 4> Extracts;
|
||||
SmallVector<Instruction *, 4> SEHCodeUses;
|
||||
SmallVector<Instruction *, 4> EHUndefs;
|
||||
for (User *U : LPad->users()) {
|
||||
auto *E = dyn_cast<ExtractValueInst>(U);
|
||||
if (!E)
|
||||
continue;
|
||||
assert(E->getNumIndices() == 1 &&
|
||||
"Unexpected operation: extracting both landing pad values");
|
||||
Extracts.push_back(E);
|
||||
unsigned Idx = *E->idx_begin();
|
||||
assert((Idx == 0 || Idx == 1) && "unexpected index");
|
||||
if (Idx == 0 && isAsynchronousEHPersonality(Personality))
|
||||
SEHCodeUses.push_back(E);
|
||||
else
|
||||
EHUndefs.push_back(E);
|
||||
}
|
||||
for (Instruction *E : Extracts) {
|
||||
for (Instruction *E : EHUndefs) {
|
||||
E->replaceAllUsesWith(UndefValue::get(E->getType()));
|
||||
E->eraseFromParent();
|
||||
}
|
||||
LPad->replaceAllUsesWith(UndefValue::get(LPad->getType()));
|
||||
|
||||
// Rewrite uses of the exception pointer to loads of an alloca.
|
||||
for (Instruction *E : SEHCodeUses) {
|
||||
SmallVector<Use *, 4> Uses;
|
||||
for (Use &U : E->uses())
|
||||
Uses.push_back(&U);
|
||||
for (Use *U : Uses) {
|
||||
auto *I = cast<Instruction>(U->getUser());
|
||||
if (isa<ResumeInst>(I))
|
||||
continue;
|
||||
LoadInst *LI;
|
||||
if (auto *Phi = dyn_cast<PHINode>(I))
|
||||
LI = new LoadInst(SEHExceptionCodeSlot, "sehcode", false,
|
||||
Phi->getIncomingBlock(*U));
|
||||
else
|
||||
LI = new LoadInst(SEHExceptionCodeSlot, "sehcode", false, I);
|
||||
U->set(LI);
|
||||
}
|
||||
E->replaceAllUsesWith(UndefValue::get(E->getType()));
|
||||
E->eraseFromParent();
|
||||
}
|
||||
|
||||
// Add a call to describe the actions for this landing pad.
|
||||
std::vector<Value *> ActionArgs;
|
||||
for (ActionHandler *Action : Actions) {
|
||||
|
@ -820,6 +854,13 @@ bool WinEHPrepare::prepareExceptionHandlers(
|
|||
Builder.SetInsertPoint(&F.getEntryBlock().back());
|
||||
Builder.CreateCall(FrameEscapeFn, AllocasToEscape);
|
||||
|
||||
if (SEHExceptionCodeSlot) {
|
||||
if (SEHExceptionCodeSlot->hasNUses(0))
|
||||
SEHExceptionCodeSlot->eraseFromParent();
|
||||
else
|
||||
PromoteMemToReg(SEHExceptionCodeSlot, *DT);
|
||||
}
|
||||
|
||||
// Clean up the handler action maps we created for this function
|
||||
DeleteContainerSeconds(CatchHandlerMap);
|
||||
CatchHandlerMap.clear();
|
||||
|
@ -1193,6 +1234,7 @@ bool WinEHPrepare::outlineHandler(ActionHandler *Action, Function *SrcFn,
|
|||
/// target.
|
||||
void WinEHPrepare::processSEHCatchHandler(CatchHandler *CatchAction,
|
||||
BasicBlock *StartBB) {
|
||||
LLVMContext &Context = StartBB->getContext();
|
||||
BasicBlock *HandlerBB;
|
||||
BasicBlock *NextBB;
|
||||
Constant *Selector;
|
||||
|
@ -1210,6 +1252,12 @@ void WinEHPrepare::processSEHCatchHandler(CatchHandler *CatchAction,
|
|||
HandlerBB =
|
||||
StartBB->splitBasicBlock(StartBB->getFirstInsertionPt(), "catch.all");
|
||||
}
|
||||
IRBuilder<> Builder(HandlerBB->getFirstInsertionPt());
|
||||
Function *EHCodeFn = Intrinsic::getDeclaration(
|
||||
StartBB->getParent()->getParent(), Intrinsic::eh_exceptioncode);
|
||||
Value *Code = Builder.CreateCall(EHCodeFn, "sehcode");
|
||||
Code = Builder.CreateIntToPtr(Code, SEHExceptionCodeSlot->getAllocatedType());
|
||||
Builder.CreateStore(Code, SEHExceptionCodeSlot);
|
||||
CatchAction->setHandlerBlockOrFunc(BlockAddress::get(HandlerBB));
|
||||
TinyPtrVector<BasicBlock *> Targets(HandlerBB);
|
||||
CatchAction->setReturnTargets(Targets);
|
||||
|
|
|
@ -55,9 +55,8 @@ eh.resume:
|
|||
; CHECK-NEXT: indirectbr {{.*}} [label %__except]
|
||||
;
|
||||
; CHECK: __except:
|
||||
; FIXME: This should not be undef, it should be the new landingpad value, which
|
||||
; should ultimately lower down to eax.
|
||||
; CHECK: invoke void @might_crash(i8* undef)
|
||||
; CHECK: call i32 @llvm.eh.exceptioncode()
|
||||
; CHECK: invoke void @might_crash(i8* %{{.*}})
|
||||
; CHECK: landingpad { i8*, i32 }
|
||||
; CHECK-NEXT: cleanup
|
||||
; CHECK-NEXT: call i8* (...) @llvm.eh.actions(i32 0, void (i8*, i8*)* @resume_phi.cleanup)
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
; RUN: llc -mtriple=x86_64-windows-msvc < %s | FileCheck %s
|
||||
|
||||
@str = internal unnamed_addr constant [10 x i8] c"recovered\00", align 1
|
||||
@str = linkonce_odr unnamed_addr constant [27 x i8] c"GetExceptionCode(): 0x%lx\0A\00", align 1
|
||||
|
||||
declare i32 @__C_specific_handler(...)
|
||||
declare void @crash()
|
||||
declare i32 @puts(i8*)
|
||||
declare i32 @printf(i8* nocapture readonly, ...) nounwind
|
||||
|
||||
define i32 @main() {
|
||||
entry:
|
||||
|
@ -14,7 +14,10 @@ entry:
|
|||
lpad:
|
||||
%0 = landingpad { i8*, i32 } personality i8* bitcast (i32 (...)* @__C_specific_handler to i8*)
|
||||
catch i8* null
|
||||
call i32 @puts(i8* getelementptr inbounds ([10 x i8], [10 x i8]* @str, i64 0, i64 0))
|
||||
%1 = extractvalue { i8*, i32 } %0, 0
|
||||
%2 = ptrtoint i8* %1 to i64
|
||||
%3 = trunc i64 %2 to i32
|
||||
call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([27 x i8], [27 x i8]* @str, i64 0, i64 0), i32 %3)
|
||||
br label %__try.cont
|
||||
|
||||
__try.cont:
|
||||
|
@ -24,7 +27,15 @@ eh.resume:
|
|||
resume { i8*, i32 } %0
|
||||
}
|
||||
|
||||
; Check that we can get the exception code from eax to the printf.
|
||||
|
||||
; CHECK-LABEL: main:
|
||||
; CHECK: retq
|
||||
; CHECK: # Block address taken
|
||||
; CHECK: leaq str(%rip), %rcx
|
||||
; CHECK: movl %eax, %edx
|
||||
; CHECK: callq printf
|
||||
|
||||
; CHECK: .seh_handlerdata
|
||||
; CHECK-NEXT: .long 1
|
||||
; CHECK-NEXT: .Ltmp{{[0-9]+}}@IMGREL
|
||||
|
|
Loading…
Reference in New Issue