From 70e56ae6b3772061bf7a6590b51a9a916e954626 Mon Sep 17 00:00:00 2001 From: Reid Kleckner Date: Thu, 23 Apr 2015 18:34:01 +0000 Subject: [PATCH] Revert "[SEH] Remove the old __C_specific_handler code now that WinEHPrepare works" We still have some "uses remain after removal" issues in -O0 builds. This reverts commit r235557. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@235617 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/llvm/CodeGen/MachineModuleInfo.h | 6 + lib/CodeGen/AsmPrinter/Win64Exception.cpp | 40 ++++ lib/CodeGen/MachineModuleInfo.cpp | 8 + lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp | 60 +++++- lib/CodeGen/WinEHPrepare.cpp | 15 ++ test/CodeGen/WinEH/seh-catch-all.ll | 2 +- test/CodeGen/WinEH/seh-inlined-finally.ll | 2 +- test/CodeGen/WinEH/seh-outlined-finally.ll | 2 +- test/CodeGen/WinEH/seh-prepared-basic.ll | 2 +- test/CodeGen/WinEH/seh-simple.ll | 2 +- test/CodeGen/X86/seh-basic.ll | 175 ++++++++++++++++++ test/CodeGen/X86/seh-catch-all.ll | 1 + test/CodeGen/X86/seh-except-finally.ll | 2 +- test/CodeGen/X86/seh-finally.ll | 2 +- test/CodeGen/X86/seh-safe-div.ll | 2 +- test/CodeGen/X86/win_eh_prepare.ll | 2 +- 16 files changed, 312 insertions(+), 11 deletions(-) create mode 100644 test/CodeGen/X86/seh-basic.ll diff --git a/include/llvm/CodeGen/MachineModuleInfo.h b/include/llvm/CodeGen/MachineModuleInfo.h index d53fdd4ce5a..d631f7c4c7b 100644 --- a/include/llvm/CodeGen/MachineModuleInfo.h +++ b/include/llvm/CodeGen/MachineModuleInfo.h @@ -77,6 +77,7 @@ struct LandingPadInfo { MachineBasicBlock *LandingPadBlock; // Landing pad block. SmallVector BeginLabels; // Labels prior to invoke. SmallVector EndLabels; // Labels after invoke. + SmallVector ClauseLabels; // Labels for each clause. SmallVector SEHHandlers; // SEH handlers active at this lpad. MCSymbol *LandingPadLabel; // Label at beginning of landing pad. const Function *Personality; // Personality function. @@ -360,6 +361,11 @@ public: /// void addCleanup(MachineBasicBlock *LandingPad); + /// Add a clause for a landing pad. Returns a new label for the clause. This + /// is used by EH schemes that have more than one landing pad. In this case, + /// each clause gets its own basic block. + MCSymbol *addClauseForLandingPad(MachineBasicBlock *LandingPad); + void addSEHCatchHandler(MachineBasicBlock *LandingPad, const Function *Filter, const BlockAddress *RecoverLabel); diff --git a/lib/CodeGen/AsmPrinter/Win64Exception.cpp b/lib/CodeGen/AsmPrinter/Win64Exception.cpp index be15989e5f6..2737a5323d6 100644 --- a/lib/CodeGen/AsmPrinter/Win64Exception.cpp +++ b/lib/CodeGen/AsmPrinter/Win64Exception.cpp @@ -206,6 +206,12 @@ void Win64Exception::emitCSpecificHandlerTable() { for (const CallSiteEntry &CSE : CallSites) { if (!CSE.LPad) continue; // Ignore gaps. + for (int Selector : CSE.LPad->TypeIds) { + // Ignore C++ filter clauses in SEH. + // FIXME: Implement cleanup clauses. + if (isCatchEHSelector(Selector)) + ++NumEntries; + } NumEntries += CSE.LPad->SEHHandlers.size(); } Asm->OutStreamer.EmitIntValue(NumEntries, 4); @@ -261,6 +267,40 @@ void Win64Exception::emitCSpecificHandlerTable() { else Asm->OutStreamer.EmitIntValue(0, 4); } + if (!LPad->SEHHandlers.empty()) + continue; + + // These aren't really type info globals, they are actually pointers to + // filter functions ordered by selector. The zero selector is used for + // cleanups, so slot zero corresponds to selector 1. + const std::vector &SelectorToFilter = MMI->getTypeInfos(); + + // Do a parallel iteration across typeids and clause labels, skipping filter + // clauses. + size_t NextClauseLabel = 0; + for (size_t I = 0, E = LPad->TypeIds.size(); I < E; ++I) { + // AddLandingPadInfo stores the clauses in reverse, but there is a FIXME + // to change that. + int Selector = LPad->TypeIds[E - I - 1]; + + // Ignore C++ filter clauses in SEH. + // FIXME: Implement cleanup clauses. + if (!isCatchEHSelector(Selector)) + continue; + + Asm->OutStreamer.EmitValue(Begin, 4); + Asm->OutStreamer.EmitValue(End, 4); + if (isCatchEHSelector(Selector)) { + assert(unsigned(Selector - 1) < SelectorToFilter.size()); + const GlobalValue *TI = SelectorToFilter[Selector - 1]; + if (TI) // Emit the filter function pointer. + Asm->OutStreamer.EmitValue(createImageRel32(Asm->getSymbol(TI)), 4); + else // Otherwise, this is a "catch i8* null", or catch all. + Asm->OutStreamer.EmitIntValue(1, 4); + } + MCSymbol *ClauseLabel = LPad->ClauseLabels[NextClauseLabel++]; + Asm->OutStreamer.EmitValue(createImageRel32(ClauseLabel), 4); + } } } diff --git a/lib/CodeGen/MachineModuleInfo.cpp b/lib/CodeGen/MachineModuleInfo.cpp index 2352692aca5..e4f2aea287f 100644 --- a/lib/CodeGen/MachineModuleInfo.cpp +++ b/lib/CodeGen/MachineModuleInfo.cpp @@ -461,6 +461,14 @@ void MachineModuleInfo::addCleanup(MachineBasicBlock *LandingPad) { LP.TypeIds.push_back(0); } +MCSymbol * +MachineModuleInfo::addClauseForLandingPad(MachineBasicBlock *LandingPad) { + MCSymbol *ClauseLabel = Context.CreateTempSymbol(); + LandingPadInfo &LP = getOrCreateLandingPadInfo(LandingPad); + LP.ClauseLabels.push_back(ClauseLabel); + return ClauseLabel; +} + void MachineModuleInfo::addSEHCatchHandler(MachineBasicBlock *LandingPad, const Function *Filter, const BlockAddress *RecoverBA) { diff --git a/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp b/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp index f3735cb5315..982d719ca1d 100644 --- a/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp +++ b/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp @@ -955,20 +955,76 @@ bool SelectionDAGISel::PrepareEHLandingPad() { // Mark the clause as a landing pad or MI passes will delete it. ClauseBB->setIsLandingPad(); } + } else { + // Otherwise, we haven't done the preparation, and we need to invent some + // clause basic blocks that branch into the landingpad. + // FIXME: Remove this code once SEH preparation works. + ActionsCall = nullptr; + + // Make virtual registers and a series of labels that fill in values for + // the clauses. + auto &RI = MF->getRegInfo(); + FuncInfo->ExceptionSelectorVirtReg = RI.createVirtualRegister(PtrRC); + + // Emit separate machine basic blocks with separate labels for each clause + // before the main landing pad block. + MachineInstrBuilder SelectorPHI = BuildMI( + *MBB, MBB->begin(), SDB->getCurDebugLoc(), + TII->get(TargetOpcode::PHI), FuncInfo->ExceptionSelectorVirtReg); + for (unsigned I = 0, E = LPadInst->getNumClauses(); I != E; ++I) { + // Skip filter clauses, we can't implement them. + if (LPadInst->isFilter(I)) + continue; + + MachineBasicBlock *ClauseBB = MF->CreateMachineBasicBlock(LLVMBB); + MF->insert(MBB, ClauseBB); + + // Add the edge from the invoke to the clause. + for (MachineBasicBlock *InvokeBB : InvokeBBs) + InvokeBB->addSuccessor(ClauseBB); + + // Mark the clause as a landing pad or MI passes will delete it. + ClauseBB->setIsLandingPad(); + + GlobalValue *ClauseGV = ExtractTypeInfo(LPadInst->getClause(I)); + + // Start the BB with a label. + MCSymbol *ClauseLabel = MF->getMMI().addClauseForLandingPad(MBB); + BuildMI(*ClauseBB, ClauseBB->begin(), SDB->getCurDebugLoc(), II) + .addSym(ClauseLabel); + + // Construct a simple BB that defines a register with the typeid + // constant. + FuncInfo->MBB = ClauseBB; + FuncInfo->InsertPt = ClauseBB->end(); + unsigned VReg = SDB->visitLandingPadClauseBB(ClauseGV, MBB); + CurDAG->setRoot(SDB->getRoot()); + SDB->clear(); + CodeGenAndEmitDAG(); + + // Add the typeid virtual register to the phi in the main landing pad. + SelectorPHI.addReg(VReg).addMBB(ClauseBB); + } } // Remove the edge from the invoke to the lpad. for (MachineBasicBlock *InvokeBB : InvokeBBs) InvokeBB->removeSuccessor(MBB); + // Restore FuncInfo back to its previous state and select the main landing + // pad block. + FuncInfo->MBB = MBB; + FuncInfo->InsertPt = MBB->end(); + // 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; + // Select instructions for the landingpad if there was no llvm.eh.actions + // call. + return ActionsCall == nullptr; } // Mark exception register as live in. diff --git a/lib/CodeGen/WinEHPrepare.cpp b/lib/CodeGen/WinEHPrepare.cpp index e11da29fedc..57671f09378 100644 --- a/lib/CodeGen/WinEHPrepare.cpp +++ b/lib/CodeGen/WinEHPrepare.cpp @@ -323,6 +323,11 @@ FunctionPass *llvm::createWinEHPass(const TargetMachine *TM) { return new WinEHPrepare(TM); } +// FIXME: Remove this once the backend can handle the prepared IR. +static cl::opt + SEHPrepare("sehprepare", cl::Hidden, + cl::desc("Prepare functions with SEH personalities")); + bool WinEHPrepare::runOnFunction(Function &Fn) { // No need to prepare outlined handlers. if (Fn.hasFnAttribute("wineh-parent")) @@ -350,6 +355,16 @@ bool WinEHPrepare::runOnFunction(Function &Fn) { DT = &getAnalysis().getDomTree(); + if (isAsynchronousEHPersonality(Personality) && !SEHPrepare) { + // Replace all resume instructions with unreachable. + // FIXME: Remove this once the backend can handle the prepared IR. + for (ResumeInst *Resume : Resumes) { + IRBuilder<>(Resume).CreateUnreachable(); + Resume->eraseFromParent(); + } + return true; + } + // If there were any landing pads, prepareExceptionHandlers will make changes. prepareExceptionHandlers(Fn, LPads); return true; diff --git a/test/CodeGen/WinEH/seh-catch-all.ll b/test/CodeGen/WinEH/seh-catch-all.ll index ab6c9effbf4..fb2b9ba7cfd 100644 --- a/test/CodeGen/WinEH/seh-catch-all.ll +++ b/test/CodeGen/WinEH/seh-catch-all.ll @@ -1,4 +1,4 @@ -; RUN: opt -S -winehprepare < %s | FileCheck %s +; RUN: opt -S -winehprepare -sehprepare < %s | FileCheck %s target datalayout = "e-m:w-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-pc-windows-msvc" diff --git a/test/CodeGen/WinEH/seh-inlined-finally.ll b/test/CodeGen/WinEH/seh-inlined-finally.ll index d2080cff79d..54045f8d9f1 100644 --- a/test/CodeGen/WinEH/seh-inlined-finally.ll +++ b/test/CodeGen/WinEH/seh-inlined-finally.ll @@ -1,4 +1,4 @@ -; RUN: opt -S -winehprepare < %s | FileCheck %s +; RUN: opt -S -winehprepare -sehprepare < %s | FileCheck %s ; Check that things work when the mid-level optimizer inlines the finally ; block. diff --git a/test/CodeGen/WinEH/seh-outlined-finally.ll b/test/CodeGen/WinEH/seh-outlined-finally.ll index 19558b70530..bc9d3221ad4 100644 --- a/test/CodeGen/WinEH/seh-outlined-finally.ll +++ b/test/CodeGen/WinEH/seh-outlined-finally.ll @@ -1,4 +1,4 @@ -; RUN: opt -S -winehprepare -mtriple=x86_64-windows-msvc < %s | FileCheck %s +; RUN: opt -S -winehprepare -sehprepare -mtriple=x86_64-windows-msvc < %s | FileCheck %s ; Test case based on this code: ; diff --git a/test/CodeGen/WinEH/seh-prepared-basic.ll b/test/CodeGen/WinEH/seh-prepared-basic.ll index 880bb3c33a8..0c6850a972b 100644 --- a/test/CodeGen/WinEH/seh-prepared-basic.ll +++ b/test/CodeGen/WinEH/seh-prepared-basic.ll @@ -1,4 +1,4 @@ -; RUN: llc < %s | FileCheck %s +; RUN: llc -sehprepare < %s | FileCheck %s ; Test case based on this code: ; extern "C" unsigned long _exception_code(); diff --git a/test/CodeGen/WinEH/seh-simple.ll b/test/CodeGen/WinEH/seh-simple.ll index a2a2139c270..6d9ee1c4f07 100644 --- a/test/CodeGen/WinEH/seh-simple.ll +++ b/test/CodeGen/WinEH/seh-simple.ll @@ -1,4 +1,4 @@ -; RUN: opt -S -winehprepare -mtriple=x86_64-windows-msvc < %s | FileCheck %s +; RUN: opt -S -winehprepare -sehprepare -mtriple=x86_64-windows-msvc < %s | FileCheck %s target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-pc-windows-msvc" diff --git a/test/CodeGen/X86/seh-basic.ll b/test/CodeGen/X86/seh-basic.ll new file mode 100644 index 00000000000..69d70d70948 --- /dev/null +++ b/test/CodeGen/X86/seh-basic.ll @@ -0,0 +1,175 @@ +; RUN: llc -mtriple x86_64-pc-windows-msvc < %s | FileCheck %s + +define void @two_invoke_merged() { +entry: + invoke void @try_body() + to label %again unwind label %lpad + +again: + invoke void @try_body() + to label %done unwind label %lpad + +done: + ret void + +lpad: + %vals = landingpad { i8*, i32 } personality i8* bitcast (i32 (...)* @__C_specific_handler to i8*) + catch i8* bitcast (i32 (i8*, i8*)* @filt0 to i8*) + catch i8* bitcast (i32 (i8*, i8*)* @filt1 to i8*) + %sel = extractvalue { i8*, i32 } %vals, 1 + call void @use_selector(i32 %sel) + ret void +} + +; Normal path code + +; CHECK-LABEL: {{^}}two_invoke_merged: +; CHECK: .seh_proc two_invoke_merged +; CHECK: .seh_handler __C_specific_handler, @unwind, @except +; CHECK: .Ltmp0: +; CHECK: callq try_body +; CHECK-NEXT: .Ltmp1: +; CHECK: .Ltmp2: +; CHECK: callq try_body +; CHECK-NEXT: .Ltmp3: +; CHECK: retq + +; Landing pad code + +; CHECK: .Ltmp5: +; CHECK: movl $1, %ecx +; CHECK: jmp +; CHECK: .Ltmp6: +; CHECK: movl $2, %ecx +; CHECK: callq use_selector + +; CHECK: .seh_handlerdata +; CHECK-NEXT: .long 2 +; CHECK-NEXT: .long .Ltmp0@IMGREL +; CHECK-NEXT: .long .Ltmp3@IMGREL+1 +; CHECK-NEXT: .long filt0@IMGREL +; CHECK-NEXT: .long .Ltmp5@IMGREL +; CHECK-NEXT: .long .Ltmp0@IMGREL +; CHECK-NEXT: .long .Ltmp3@IMGREL+1 +; CHECK-NEXT: .long filt1@IMGREL +; CHECK-NEXT: .long .Ltmp6@IMGREL +; CHECK: .text +; CHECK: .seh_endproc + +define void @two_invoke_gap() { +entry: + invoke void @try_body() + to label %again unwind label %lpad + +again: + call void @do_nothing_on_unwind() + invoke void @try_body() + to label %done unwind label %lpad + +done: + ret void + +lpad: + %vals = landingpad { i8*, i32 } personality i8* bitcast (i32 (...)* @__C_specific_handler to i8*) + catch i8* bitcast (i32 (i8*, i8*)* @filt0 to i8*) + %sel = extractvalue { i8*, i32 } %vals, 1 + call void @use_selector(i32 %sel) + ret void +} + +; Normal path code + +; CHECK-LABEL: {{^}}two_invoke_gap: +; CHECK: .seh_proc two_invoke_gap +; CHECK: .seh_handler __C_specific_handler, @unwind, @except +; CHECK: .Ltmp11: +; CHECK: callq try_body +; CHECK-NEXT: .Ltmp12: +; CHECK: callq do_nothing_on_unwind +; CHECK: .Ltmp13: +; CHECK: callq try_body +; CHECK-NEXT: .Ltmp14: +; CHECK: retq + +; Landing pad code + +; CHECK: .Ltmp16: +; CHECK: movl $1, %ecx +; CHECK: callq use_selector + +; CHECK: .seh_handlerdata +; CHECK-NEXT: .long 2 +; CHECK-NEXT: .long .Ltmp11@IMGREL +; CHECK-NEXT: .long .Ltmp12@IMGREL+1 +; CHECK-NEXT: .long filt0@IMGREL +; CHECK-NEXT: .long .Ltmp16@IMGREL +; CHECK-NEXT: .long .Ltmp13@IMGREL +; CHECK-NEXT: .long .Ltmp14@IMGREL+1 +; CHECK-NEXT: .long filt0@IMGREL +; CHECK-NEXT: .long .Ltmp16@IMGREL +; CHECK: .text +; CHECK: .seh_endproc + +define void @two_invoke_nounwind_gap() { +entry: + invoke void @try_body() + to label %again unwind label %lpad + +again: + call void @cannot_unwind() + invoke void @try_body() + to label %done unwind label %lpad + +done: + ret void + +lpad: + %vals = landingpad { i8*, i32 } personality i8* bitcast (i32 (...)* @__C_specific_handler to i8*) + catch i8* bitcast (i32 (i8*, i8*)* @filt0 to i8*) + %sel = extractvalue { i8*, i32 } %vals, 1 + call void @use_selector(i32 %sel) + ret void +} + +; Normal path code + +; CHECK-LABEL: {{^}}two_invoke_nounwind_gap: +; CHECK: .seh_proc two_invoke_nounwind_gap +; CHECK: .seh_handler __C_specific_handler, @unwind, @except +; CHECK: .Ltmp21: +; CHECK: callq try_body +; CHECK-NEXT: .Ltmp22: +; CHECK: callq cannot_unwind +; CHECK: .Ltmp23: +; CHECK: callq try_body +; CHECK-NEXT: .Ltmp24: +; CHECK: retq + +; Landing pad code + +; CHECK: .Ltmp26: +; CHECK: movl $1, %ecx +; CHECK: callq use_selector + +; CHECK: .seh_handlerdata +; CHECK-NEXT: .long 1 +; CHECK-NEXT: .long .Ltmp21@IMGREL +; CHECK-NEXT: .long .Ltmp24@IMGREL+1 +; CHECK-NEXT: .long filt0@IMGREL +; CHECK-NEXT: .long .Ltmp26@IMGREL +; CHECK: .text +; CHECK: .seh_endproc + +declare void @try_body() +declare void @do_nothing_on_unwind() +declare void @cannot_unwind() nounwind +declare void @use_selector(i32) + +declare i32 @filt0(i8* %eh_info, i8* %rsp) +declare i32 @filt1(i8* %eh_info, i8* %rsp) + +declare void @handler0() +declare void @handler1() + +declare i32 @__C_specific_handler(...) +declare i32 @llvm.eh.typeid.for(i8*) readnone nounwind diff --git a/test/CodeGen/X86/seh-catch-all.ll b/test/CodeGen/X86/seh-catch-all.ll index 931046e5115..a224da5638b 100644 --- a/test/CodeGen/X86/seh-catch-all.ll +++ b/test/CodeGen/X86/seh-catch-all.ll @@ -1,3 +1,4 @@ +; RUN: llc -sehprepare -mtriple=x86_64-windows-msvc < %s | FileCheck %s ; RUN: llc -mtriple=x86_64-windows-msvc < %s | FileCheck %s @str = internal unnamed_addr constant [10 x i8] c"recovered\00", align 1 diff --git a/test/CodeGen/X86/seh-except-finally.ll b/test/CodeGen/X86/seh-except-finally.ll index c796f1ef288..42f7d729c1b 100644 --- a/test/CodeGen/X86/seh-except-finally.ll +++ b/test/CodeGen/X86/seh-except-finally.ll @@ -1,4 +1,4 @@ -; RUN: llc < %s | FileCheck %s +; RUN: llc -sehprepare < %s | FileCheck %s ; Test case based on this source: ; int puts(const char*); diff --git a/test/CodeGen/X86/seh-finally.ll b/test/CodeGen/X86/seh-finally.ll index 91baed570f2..e6d1f1b1a76 100644 --- a/test/CodeGen/X86/seh-finally.ll +++ b/test/CodeGen/X86/seh-finally.ll @@ -1,4 +1,4 @@ -; RUN: llc -mtriple=x86_64-windows-msvc < %s | FileCheck %s +; RUN: llc -sehprepare -mtriple=x86_64-windows-msvc < %s | FileCheck %s @str_recovered = internal unnamed_addr constant [10 x i8] c"recovered\00", align 1 diff --git a/test/CodeGen/X86/seh-safe-div.ll b/test/CodeGen/X86/seh-safe-div.ll index 80b15b60102..1f9e22c5462 100644 --- a/test/CodeGen/X86/seh-safe-div.ll +++ b/test/CodeGen/X86/seh-safe-div.ll @@ -1,4 +1,4 @@ -; RUN: llc -mtriple x86_64-pc-windows-msvc < %s | FileCheck %s +; RUN: llc -sehprepare -mtriple x86_64-pc-windows-msvc < %s | FileCheck %s ; This test case is also intended to be run manually as a complete functional ; test. It should link, print something, and exit zero rather than crashing. diff --git a/test/CodeGen/X86/win_eh_prepare.ll b/test/CodeGen/X86/win_eh_prepare.ll index a33dd92ad72..3e513e072ea 100644 --- a/test/CodeGen/X86/win_eh_prepare.ll +++ b/test/CodeGen/X86/win_eh_prepare.ll @@ -1,4 +1,4 @@ -; RUN: opt -S -winehprepare -dwarfehprepare -mtriple x86_64-pc-windows-msvc < %s | FileCheck %s +; RUN: opt -S -winehprepare -sehprepare -dwarfehprepare -mtriple x86_64-pc-windows-msvc < %s | FileCheck %s ; FIXME: Add and test outlining here.