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
This commit is contained in:
Reid Kleckner 2015-04-23 18:34:01 +00:00
parent 184f8f7c10
commit 70e56ae6b3
16 changed files with 312 additions and 11 deletions

View File

@ -77,6 +77,7 @@ struct LandingPadInfo {
MachineBasicBlock *LandingPadBlock; // Landing pad block.
SmallVector<MCSymbol *, 1> BeginLabels; // Labels prior to invoke.
SmallVector<MCSymbol *, 1> EndLabels; // Labels after invoke.
SmallVector<MCSymbol *, 1> ClauseLabels; // Labels for each clause.
SmallVector<SEHHandler, 1> 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);

View File

@ -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<const GlobalValue *> &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);
}
}
}

View File

@ -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) {

View File

@ -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.

View File

@ -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<bool>
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<DominatorTreeWrapperPass>().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;

View File

@ -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"

View File

@ -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.

View File

@ -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:
;

View File

@ -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();

View File

@ -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"

View File

@ -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

View File

@ -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

View File

@ -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*);

View File

@ -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

View File

@ -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.

View File

@ -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.