From 39789f81ab330a5582919b2edb592d2a63f6c663 Mon Sep 17 00:00:00 2001 From: Reid Kleckner Date: Fri, 24 Apr 2015 20:25:05 +0000 Subject: [PATCH] [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. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@235768 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/llvm/CodeGen/FunctionLoweringInfo.h | 2 +- include/llvm/IR/Intrinsics.td | 2 + .../SelectionDAG/FunctionLoweringInfo.cpp | 37 +++++++----- .../SelectionDAG/SelectionDAGBuilder.cpp | 12 ++++ lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp | 6 -- lib/CodeGen/WinEHPrepare.cpp | 60 +++++++++++++++++-- test/CodeGen/WinEH/seh-resume-phi.ll | 5 +- test/CodeGen/X86/seh-catch-all.ll | 17 +++++- 8 files changed, 108 insertions(+), 33 deletions(-) diff --git a/include/llvm/CodeGen/FunctionLoweringInfo.h b/include/llvm/CodeGen/FunctionLoweringInfo.h index 66a9ae7407b..dadaf15a48a 100644 --- a/include/llvm/CodeGen/FunctionLoweringInfo.h +++ b/include/llvm/CodeGen/FunctionLoweringInfo.h @@ -221,7 +221,7 @@ public: int getArgumentFrameIndex(const Argument *A); private: - void addSEHHandlersForLPads(); + void addSEHHandlersForLPads(ArrayRef LPads); /// LiveOutRegInfo - Information about live out vregs. IndexedMap LiveOutRegInfo; diff --git a/include/llvm/IR/Intrinsics.td b/include/llvm/IR/Intrinsics.td index 4052a312fd0..b4b98768226 100644 --- a/include/llvm/IR/Intrinsics.td +++ b/include/llvm/IR/Intrinsics.td @@ -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. diff --git a/lib/CodeGen/SelectionDAG/FunctionLoweringInfo.cpp b/lib/CodeGen/SelectionDAG/FunctionLoweringInfo.cpp index b7882329955..fc5ca3ec586 100644 --- a/lib/CodeGen/SelectionDAG/FunctionLoweringInfo.cpp +++ b/lib/CodeGen/SelectionDAG/FunctionLoweringInfo.cpp @@ -271,40 +271,49 @@ void FunctionLoweringInfo::set(const Function &fn, MachineFunction &mf, } // Mark landing pad blocks. - const LandingPadInst *LP = nullptr; + SmallVector LPads; for (BB = Fn->begin(); BB != EB; ++BB) { if (const auto *Invoke = dyn_cast(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 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(LP->getNextNode()); if (!ActionsCall || diff --git a/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp b/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp index 01419cf8fa1..fd59d57580b 100644 --- a/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp +++ b/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp @@ -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; + } } } diff --git a/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp b/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp index f3735cb5315..056ba4a4198 100644 --- a/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp +++ b/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp @@ -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; } diff --git a/lib/CodeGen/WinEHPrepare.cpp b/lib/CodeGen/WinEHPrepare.cpp index 8a0fb7fd1bc..963692a245f 100644 --- a/lib/CodeGen/WinEHPrepare.cpp +++ b/lib/CodeGen/WinEHPrepare.cpp @@ -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 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 Extracts; + SmallVector SEHCodeUses; + SmallVector EHUndefs; for (User *U : LPad->users()) { auto *E = dyn_cast(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 Uses; + for (Use &U : E->uses()) + Uses.push_back(&U); + for (Use *U : Uses) { + auto *I = cast(U->getUser()); + if (isa(I)) + continue; + LoadInst *LI; + if (auto *Phi = dyn_cast(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 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 Targets(HandlerBB); CatchAction->setReturnTargets(Targets); diff --git a/test/CodeGen/WinEH/seh-resume-phi.ll b/test/CodeGen/WinEH/seh-resume-phi.ll index cd30bfcc589..256dd852d28 100644 --- a/test/CodeGen/WinEH/seh-resume-phi.ll +++ b/test/CodeGen/WinEH/seh-resume-phi.ll @@ -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) diff --git a/test/CodeGen/X86/seh-catch-all.ll b/test/CodeGen/X86/seh-catch-all.ll index 931046e5115..51840134eda 100644 --- a/test/CodeGen/X86/seh-catch-all.ll +++ b/test/CodeGen/X86/seh-catch-all.ll @@ -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 -- 2.34.1