From ee97a1a33b2cb1173e0b4c601ed5976e56654063 Mon Sep 17 00:00:00 2001 From: Reid Kleckner Date: Wed, 7 Oct 2015 00:27:33 +0000 Subject: [PATCH] [SEH] Add llvm.eh.exceptioncode intrinsic This will support the Clang __exception_code intrinsic. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@249492 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/llvm/CodeGen/FunctionLoweringInfo.h | 8 +++- include/llvm/IR/Intrinsics.td | 6 ++- .../SelectionDAG/FunctionLoweringInfo.cpp | 11 +++++ .../SelectionDAG/SelectionDAGBuilder.cpp | 16 +++++++- lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp | 41 ++++++++++++++++--- lib/CodeGen/WinEHPrepare.cpp | 17 ++++---- lib/IR/Verifier.cpp | 1 + test/CodeGen/WinEH/seh-exception-code.ll | 4 +- test/CodeGen/WinEH/seh-exception-code2.ll | 2 +- test/CodeGen/WinEH/seh-resume-phi.ll | 2 +- 10 files changed, 87 insertions(+), 21 deletions(-) diff --git a/include/llvm/CodeGen/FunctionLoweringInfo.h b/include/llvm/CodeGen/FunctionLoweringInfo.h index 46bfd1e1c94..21205a163f5 100644 --- a/include/llvm/CodeGen/FunctionLoweringInfo.h +++ b/include/llvm/CodeGen/FunctionLoweringInfo.h @@ -72,7 +72,10 @@ public: /// ValueMap - Since we emit code for the function a basic block at a time, /// we must remember which virtual registers hold the values for /// cross-basic-block values. - DenseMap ValueMap; + DenseMap ValueMap; + + /// Track virtual registers created for exception pointers. + DenseMap CatchPadExceptionPointers; // Keep track of frame indices allocated for statepoints as they could be used // across basic block boundaries. @@ -234,6 +237,9 @@ public: /// getArgumentFrameIndex - Get frame index for the byval argument. int getArgumentFrameIndex(const Argument *A); + unsigned getCatchPadExceptionPointerVReg(const Value *CPI, + const TargetRegisterClass *RC); + private: void addSEHHandlersForLPads(ArrayRef LPads); diff --git a/include/llvm/IR/Intrinsics.td b/include/llvm/IR/Intrinsics.td index acee3b2897f..2b77e58ca77 100644 --- a/include/llvm/IR/Intrinsics.td +++ b/include/llvm/IR/Intrinsics.td @@ -441,10 +441,14 @@ def int_eh_endcatch : Intrinsic<[], []>; def int_eh_exceptionpointer : Intrinsic<[llvm_anyptr_ty], [llvm_token_ty], [IntrNoMem]>; +// Gets the exception code from a catchpad token. Only used on some platforms. +def int_eh_exceptioncode : Intrinsic<[llvm_i32_ty], [llvm_token_ty], [IntrNoMem]>; + // 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], [], [IntrReadMem]>; +// FIXME: Remove this when landing pad EH can be removed. +def int_eh_exceptioncode_old : Intrinsic<[llvm_i32_ty], [], [IntrReadMem]>; // __builtin_unwind_init is an undocumented GCC intrinsic that causes all // callee-saved registers to be saved and restored (regardless of whether they diff --git a/lib/CodeGen/SelectionDAG/FunctionLoweringInfo.cpp b/lib/CodeGen/SelectionDAG/FunctionLoweringInfo.cpp index a7f5ba1269e..cf2d84f9a11 100644 --- a/lib/CodeGen/SelectionDAG/FunctionLoweringInfo.cpp +++ b/lib/CodeGen/SelectionDAG/FunctionLoweringInfo.cpp @@ -577,6 +577,17 @@ int FunctionLoweringInfo::getArgumentFrameIndex(const Argument *A) { return 0; } +unsigned FunctionLoweringInfo::getCatchPadExceptionPointerVReg( + const Value *CPI, const TargetRegisterClass *RC) { + MachineRegisterInfo &MRI = MF->getRegInfo(); + auto I = CatchPadExceptionPointers.insert({CPI, 0}); + unsigned &VReg = I.first->second; + if (I.second) + VReg = MRI.createVirtualRegister(RC); + assert(VReg && "null vreg in exception pointer table!"); + return VReg; +} + /// ComputeUsesVAFloatArgument - Determine if any floating-point values are /// being passed to this variadic function, and set the MachineModuleInfo's /// usesVAFloatArgument flag if so. This flag is used to emit an undefined diff --git a/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp b/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp index 22809aa0b3e..ed96742db7c 100644 --- a/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp +++ b/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp @@ -5240,7 +5240,7 @@ 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: { + case Intrinsic::eh_exceptioncode_old: { unsigned Reg = TLI.getExceptionPointerRegister(); assert(Reg && "cannot get exception code on this platform"); MVT PtrVT = TLI.getPointerTy(DAG.getDataLayout()); @@ -5253,6 +5253,20 @@ SelectionDAGBuilder::visitIntrinsicCall(const CallInst &I, unsigned Intrinsic) { setValue(&I, N); return nullptr; } + + case Intrinsic::eh_exceptionpointer: + case Intrinsic::eh_exceptioncode: { + // Get the exception pointer vreg, copy from it, and resize it to fit. + const auto *CPI = cast(I.getArgOperand(0)); + MVT PtrVT = TLI.getPointerTy(DAG.getDataLayout()); + const TargetRegisterClass *PtrRC = TLI.getRegClassFor(PtrVT); + unsigned VReg = FuncInfo.getCatchPadExceptionPointerVReg(CPI, 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 c20270d9a7e..bd60bba318c 100644 --- a/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp +++ b/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp @@ -922,14 +922,46 @@ void SelectionDAGISel::DoInstructionSelection() { PostprocessISelDAG(); } +static bool hasExceptionPointerOrCodeUser(const CatchPadInst *CPI) { + for (const User *U : CPI->users()) { + if (const IntrinsicInst *EHPtrCall = dyn_cast(U)) { + Intrinsic::ID IID = EHPtrCall->getIntrinsicID(); + if (IID == Intrinsic::eh_exceptionpointer || + IID == Intrinsic::eh_exceptioncode) + return true; + } + } + return false; +} + /// PrepareEHLandingPad - Emit an EH_LABEL, set up live-in registers, and /// do other setup for EH landing-pad blocks. bool SelectionDAGISel::PrepareEHLandingPad() { MachineBasicBlock *MBB = FuncInfo->MBB; - + const BasicBlock *LLVMBB = MBB->getBasicBlock(); const TargetRegisterClass *PtrRC = TLI->getRegClassFor(TLI->getPointerTy(CurDAG->getDataLayout())); + // Catchpads have one live-in register, which typically holds the exception + // pointer or code. + if (const auto *CPI = dyn_cast(LLVMBB->getFirstNonPHI())) { + if (hasExceptionPointerOrCodeUser(CPI)) { + // Get or create the virtual register to hold the pointer or code. Mark + // the live in physreg and copy into the vreg. + MCPhysReg EHPhysReg = TLI->getExceptionPointerRegister(); + assert(EHPhysReg && "target lacks exception pointer register"); + FuncInfo->ExceptionPointerVirtReg = MBB->addLiveIn(EHPhysReg, PtrRC); + unsigned VReg = FuncInfo->getCatchPadExceptionPointerVReg(CPI, PtrRC); + BuildMI(*MBB, FuncInfo->InsertPt, SDB->getCurDebugLoc(), + TII->get(TargetOpcode::COPY), VReg) + .addReg(EHPhysReg, RegState::Kill); + } + return true; + } + + if (!LLVMBB->isLandingPad()) + return true; + // Add a label to mark the beginning of the landing pad. Deletion of the // landing pad can thus be detected via the MachineModuleInfo. MCSymbol *Label = MF->getMMI().addLandingPad(MBB); @@ -943,7 +975,6 @@ bool SelectionDAGISel::PrepareEHLandingPad() { // If this personality function uses funclets, we need to split the landing // pad into several BBs. - const BasicBlock *LLVMBB = MBB->getBasicBlock(); const Constant *Personality = MF->getFunction()->getPersonalityFn(); if (const auto *PF = dyn_cast(Personality->stripPointerCasts())) MF->getMMI().addPersonality(PF); @@ -1159,10 +1190,8 @@ void SelectionDAGISel::SelectAllBasicBlocks(const Function &Fn) { // Setup an EH landing-pad block. FuncInfo->ExceptionPointerVirtReg = 0; FuncInfo->ExceptionSelectorVirtReg = 0; - if (LLVMBB->isLandingPad()) - if (!PrepareEHLandingPad()) - continue; - + if (!PrepareEHLandingPad()) + continue; // Before doing SelectionDAG ISel, see if FastISel has been requested. if (FastIS) { diff --git a/lib/CodeGen/WinEHPrepare.cpp b/lib/CodeGen/WinEHPrepare.cpp index a9fec812071..86b511cfb67 100644 --- a/lib/CodeGen/WinEHPrepare.cpp +++ b/lib/CodeGen/WinEHPrepare.cpp @@ -1614,7 +1614,7 @@ void WinEHPrepare::processSEHCatchHandler(CatchHandler *CatchAction, } IRBuilder<> Builder(HandlerBB->getFirstInsertionPt()); Function *EHCodeFn = Intrinsic::getDeclaration( - StartBB->getParent()->getParent(), Intrinsic::eh_exceptioncode); + StartBB->getParent()->getParent(), Intrinsic::eh_exceptioncode_old); Value *Code = Builder.CreateCall(EHCodeFn, {}, "sehcode"); Code = Builder.CreateIntToPtr(Code, SEHExceptionCodeSlot->getAllocatedType()); Builder.CreateStore(Code, SEHExceptionCodeSlot); @@ -3019,12 +3019,11 @@ colorFunclets(Function &F, SmallVectorImpl &EntryBlocks, // Mark this as a funclet head as a member of itself. FuncletBlocks[Visiting].insert(Visiting); // Queue exits with the parent color. - for (User *Exit : VisitingHead->users()) { - for (BasicBlock *Succ : - successors(cast(Exit)->getParent())) { - if (BlockColors[Succ].insert(Color).second) { - Worklist.push_back({Succ, Color}); - } + for (User *U : VisitingHead->users()) { + if (auto *Exit = dyn_cast(U)) { + for (BasicBlock *Succ : successors(Exit->getParent())) + if (BlockColors[Succ].insert(Color).second) + Worklist.push_back({Succ, Color}); } } // Handle CatchPad specially since its successors need different colors. @@ -3124,7 +3123,9 @@ void llvm::calculateCatchReturnSuccessorColors(const Function *Fn, // The users of a catchpad are always catchrets. for (User *Exit : CatchPad->users()) { - auto *CatchReturn = cast(Exit); + auto *CatchReturn = dyn_cast(Exit); + if (!CatchReturn) + continue; BasicBlock *CatchRetSuccessor = CatchReturn->getSuccessor(); std::set &SuccessorColors = BlockColors[CatchRetSuccessor]; assert(SuccessorColors.size() == 1 && "Expected BB to be monochrome!"); diff --git a/lib/IR/Verifier.cpp b/lib/IR/Verifier.cpp index a3808e4ff3a..7b07bcea560 100644 --- a/lib/IR/Verifier.cpp +++ b/lib/IR/Verifier.cpp @@ -3681,6 +3681,7 @@ void Verifier::visitIntrinsicCallSite(Intrinsic::ID ID, CallSite CS) { "gc.relocate: relocating a pointer shouldn't change its address space", CS); break; } + case Intrinsic::eh_exceptioncode: case Intrinsic::eh_exceptionpointer: { Assert(isa(CS.getArgOperand(0)), "eh.exceptionpointer argument must be a catchpad", CS); diff --git a/test/CodeGen/WinEH/seh-exception-code.ll b/test/CodeGen/WinEH/seh-exception-code.ll index 2998e798213..acb3d5c5e47 100644 --- a/test/CodeGen/WinEH/seh-exception-code.ll +++ b/test/CodeGen/WinEH/seh-exception-code.ll @@ -52,13 +52,13 @@ __try.cont: ; preds = %invoke.cont, %__exc ; CHECK: landingpad ; CHECK: indirectbr i8* %{{[^,]*}}, [label %[[except_split1:.*]]] ; CHECK: [[except_split1]]: -; CHECK: call i32 @llvm.eh.exceptioncode() +; CHECK: call i32 @llvm.eh.exceptioncode.old() ; CHECK: br label %__except ; ; CHECK: landingpad ; CHECK: indirectbr i8* %{{[^,]*}}, [label %[[except_split2:.*]]] ; CHECK: [[except_split2]]: -; CHECK: call i32 @llvm.eh.exceptioncode() +; CHECK: call i32 @llvm.eh.exceptioncode.old() ; CHECK: br label %__except ; ; CHECK: __except: diff --git a/test/CodeGen/WinEH/seh-exception-code2.ll b/test/CodeGen/WinEH/seh-exception-code2.ll index 0356956502c..6b64a7923f6 100644 --- a/test/CodeGen/WinEH/seh-exception-code2.ll +++ b/test/CodeGen/WinEH/seh-exception-code2.ll @@ -87,5 +87,5 @@ entry: ; CHECK-NEXT: indirectbr i8* %{{[^,]*}}, [label %__except] ; ; CHECK: __except: -; CHECK: call i32 @llvm.eh.exceptioncode() +; CHECK: call i32 @llvm.eh.exceptioncode.old() ; CHECK: call i32 (i8*, ...) @printf diff --git a/test/CodeGen/WinEH/seh-resume-phi.ll b/test/CodeGen/WinEH/seh-resume-phi.ll index 4ce55193dc4..f629a4dd50c 100644 --- a/test/CodeGen/WinEH/seh-resume-phi.ll +++ b/test/CodeGen/WinEH/seh-resume-phi.ll @@ -55,7 +55,7 @@ eh.resume: ; CHECK-NEXT: indirectbr {{.*}} [label %__except] ; ; CHECK: __except: -; CHECK: call i32 @llvm.eh.exceptioncode() +; CHECK: call i32 @llvm.eh.exceptioncode.old() ; CHECK: invoke void @might_crash(i8* %{{.*}}) ; CHECK: landingpad { i8*, i32 } ; CHECK-NEXT: cleanup -- 2.34.1