From 76b827089dee46f4952294e56389cbe0a7ac2550 Mon Sep 17 00:00:00 2001 From: Reid Kleckner Date: Thu, 10 Sep 2015 21:46:36 +0000 Subject: [PATCH] Fix SEH state numbering algorithm to handle cleanupendpads WinEHPrepare's new coloring algorithm really expects to see cleanupendpads now, so Clang will start emitting them soon. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@247341 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/CodeGen/WinEHPrepare.cpp | 13 +- test/CodeGen/X86/win-cleanuppad.ll | 138 ++++++++++++++++++++ test/CodeGen/X86/win32-seh-cleanupendpad.ll | 81 ++++++++++++ 3 files changed, 228 insertions(+), 4 deletions(-) create mode 100644 test/CodeGen/X86/win-cleanuppad.ll create mode 100644 test/CodeGen/X86/win32-seh-cleanupendpad.ll diff --git a/lib/CodeGen/WinEHPrepare.cpp b/lib/CodeGen/WinEHPrepare.cpp index 3f666c944e2..bbf61a14bf1 100644 --- a/lib/CodeGen/WinEHPrepare.cpp +++ b/lib/CodeGen/WinEHPrepare.cpp @@ -2993,11 +2993,8 @@ static const BasicBlock *getEHPadFromPredecessor(const BasicBlock *BB) { const TerminatorInst *TI = BB->getTerminator(); if (isa(TI)) return nullptr; - if (isa(TI) || isa(TI) || - isa(TI)) + if (TI->isEHPad()) return BB; - if (auto *CEPI = dyn_cast(TI)) - return CEPI->getCleanupPad()->getParent(); return cast(TI)->getCleanupPad()->getParent(); } @@ -3111,6 +3108,14 @@ static void calculateExplicitSEHStateNumbers(WinEHFuncInfo &FuncInfo, for (const BasicBlock *PredBlock : predecessors(&BB)) if ((PredBlock = getEHPadFromPredecessor(PredBlock))) calculateExplicitSEHStateNumbers(FuncInfo, *PredBlock, CleanupState); + } else if (isa(FirstNonPHI)) { + // Anything unwinding through CleanupEndPadInst is in ParentState. + FuncInfo.EHPadStateMap[FirstNonPHI] = ParentState; + DEBUG(dbgs() << "Assigning state #" << ParentState << " to BB " + << BB.getName() << '\n'); + for (const BasicBlock *PredBlock : predecessors(&BB)) + if ((PredBlock = getEHPadFromPredecessor(PredBlock))) + calculateExplicitSEHStateNumbers(FuncInfo, *PredBlock, ParentState); } else if (isa(FirstNonPHI)) { report_fatal_error("Not yet implemented!"); } else { diff --git a/test/CodeGen/X86/win-cleanuppad.ll b/test/CodeGen/X86/win-cleanuppad.ll new file mode 100644 index 00000000000..b369e8ce6b1 --- /dev/null +++ b/test/CodeGen/X86/win-cleanuppad.ll @@ -0,0 +1,138 @@ +; RUN: llc -mtriple=i686-pc-windows-msvc < %s | FileCheck --check-prefix=X86 %s +; RUN: llc -mtriple=x86_64-pc-windows-msvc < %s | FileCheck --check-prefix=X64 %s + +%struct.Dtor = type { i8 } + +define void @simple_cleanup() #0 personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*) { +entry: + %o = alloca %struct.Dtor, align 1 + invoke void @f(i32 1) + to label %invoke.cont unwind label %ehcleanup + +invoke.cont: ; preds = %entry + call x86_thiscallcc void @"\01??1Dtor@@QAE@XZ"(%struct.Dtor* %o) #2 + ret void + +ehcleanup: ; preds = %entry + %0 = cleanuppad [] + call x86_thiscallcc void @"\01??1Dtor@@QAE@XZ"(%struct.Dtor* %o) #2 + cleanupret %0 unwind to caller +} + +declare void @f(i32) #0 + +declare i32 @__CxxFrameHandler3(...) + +; Function Attrs: nounwind +declare x86_thiscallcc void @"\01??1Dtor@@QAE@XZ"(%struct.Dtor*) #1 + +define void @nested_cleanup() #0 personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*) { +entry: + %o1 = alloca %struct.Dtor, align 1 + %o2 = alloca %struct.Dtor, align 1 + invoke void @f(i32 1) + to label %invoke.cont unwind label %cleanup.outer + +invoke.cont: ; preds = %entry + invoke void @f(i32 2) + to label %invoke.cont.1 unwind label %cleanup.inner + +invoke.cont.1: ; preds = %invoke.cont + call x86_thiscallcc void @"\01??1Dtor@@QAE@XZ"(%struct.Dtor* %o2) #2 + invoke void @f(i32 3) + to label %invoke.cont.2 unwind label %cleanup.outer + +invoke.cont.2: ; preds = %invoke.cont.1 + call x86_thiscallcc void @"\01??1Dtor@@QAE@XZ"(%struct.Dtor* %o1) #2 + ret void + +cleanup.inner: ; preds = %invoke.cont + %0 = cleanuppad [] + call x86_thiscallcc void @"\01??1Dtor@@QAE@XZ"(%struct.Dtor* %o2) #2 + cleanupret %0 unwind label %cleanup.outer + +cleanup.outer: ; preds = %invoke.cont.1, %cleanup.inner, %entry + %1 = cleanuppad [] + call x86_thiscallcc void @"\01??1Dtor@@QAE@XZ"(%struct.Dtor* %o1) #2 + cleanupret %1 unwind to caller +} + +; X86-LABEL: _nested_cleanup: +; X86: movl $1, (%esp) +; X86: calll _f +; X86: movl $2, (%esp) +; X86: calll _f +; X86: movl $3, (%esp) +; X86: calll _f + +; X86: LBB1_[[cleanup_inner:[0-9]+]]: # %cleanup.inner +; X86: leal {{.*}}(%ebp), %ecx +; X86: calll "??1Dtor@@QAE@XZ" +; X86: retl # CLEANUPRET + +; X86: LBB1_[[cleanup_outer:[0-9]+]]: # %cleanup.outer +; X86: leal {{.*}}(%ebp), %ecx +; X86: calll "??1Dtor@@QAE@XZ" +; X86: retl # CLEANUPRET + +; X86: L__ehtable$nested_cleanup: +; X86: .long 429065506 +; X86: .long 2 +; X86: .long ($stateUnwindMap$nested_cleanup) +; X86: .long 0 +; X86: .long 0 +; X86: .long 0 +; X86: .long 0 +; X86: .long 0 +; X86: .long 1 +; X86: $stateUnwindMap$nested_cleanup: +; X86: .long -1 +; X86: .long LBB1_[[cleanup_outer]] +; X86: .long 0 +; X86: .long LBB1_[[cleanup_inner]] + +; X64-LABEL: nested_cleanup: +; X64: movl $1, %ecx +; X64: callq f +; X64: movl $2, %ecx +; X64: callq f +; X64: movl $3, %ecx +; X64: callq f + +; X64: .LBB1_[[cleanup_inner:[0-9]+]]: # %cleanup.inner +; X64: leaq {{.*}}(%rbp), %rcx +; X64: callq "??1Dtor@@QAE@XZ" +; X64: retq # CLEANUPRET + +; X64: .LBB1_[[cleanup_outer:[0-9]+]]: # %cleanup.outer +; X64: leaq {{.*}}(%rbp), %rcx +; X64: callq "??1Dtor@@QAE@XZ" +; X64: retq # CLEANUPRET + +; X64: .seh_handlerdata +; X64: .long ($cppxdata$nested_cleanup)@IMGREL +; X64: .align 4 +; X64:$cppxdata$nested_cleanup: +; X64: .long 429065506 +; X64: .long 2 +; X64: .long ($stateUnwindMap$nested_cleanup)@IMGREL +; X64: .long 0 +; X64: .long 0 +; X64: .long 1 +; X64: .long ($ip2state$nested_cleanup)@IMGREL +; X64: .long 40 +; X64: .long 0 +; X64: .long 1 +; X64:$stateUnwindMap$nested_cleanup: +; X64: .long -1 +; X64: .long .LBB1_[[cleanup_outer]]@IMGREL +; X64: .long 0 +; X64: .long .LBB1_[[cleanup_inner]]@IMGREL +; FIXME: The ip2state table is totally wrong. +; X64:$ip2state$nested_cleanup: +; X64: .long .Lfunc_begin1@IMGREL +; X64: .long -1 + +attributes #0 = { "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-realign-stack" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" } +attributes #1 = { nounwind "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-realign-stack" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" } +attributes #2 = { nounwind } diff --git a/test/CodeGen/X86/win32-seh-cleanupendpad.ll b/test/CodeGen/X86/win32-seh-cleanupendpad.ll new file mode 100644 index 00000000000..7f1fc322d18 --- /dev/null +++ b/test/CodeGen/X86/win32-seh-cleanupendpad.ll @@ -0,0 +1,81 @@ +; RUN: llc < %s | FileCheck %s + +target datalayout = "e-m:x-p:32:32-i64:64-f80:32-n8:16:32-a:0:32-S32" +target triple = "i686-pc-windows-msvc" + +define void @nested_finally() #0 personality i8* bitcast (i32 (...)* @_except_handler3 to i8*) { +entry: + invoke void @f(i32 1) #3 + to label %invoke.cont unwind label %ehcleanup + +invoke.cont: ; preds = %entry + invoke void @f(i32 2) #3 + to label %invoke.cont.1 unwind label %ehcleanup.3 + +invoke.cont.1: ; preds = %invoke.cont + call void @f(i32 3) #3 + ret void + +ehcleanup: ; preds = %entry + %0 = cleanuppad [] + invoke void @f(i32 2) #3 + to label %invoke.cont.2 unwind label %ehcleanup.end + +invoke.cont.2: ; preds = %ehcleanup + cleanupret %0 unwind label %ehcleanup.3 + +ehcleanup.end: ; preds = %ehcleanup + cleanupendpad %0 unwind label %ehcleanup.3 + +ehcleanup.3: ; preds = %invoke.cont.2, %ehcleanup.end, %invoke.cont + %1 = cleanuppad [] + invoke void @f(i32 3) #3 + to label %invoke.cont.4 unwind label %ehcleanup.end.5 + +invoke.cont.4: ; preds = %ehcleanup.3 + cleanupret %1 unwind to caller + +ehcleanup.end.5: ; preds = %ehcleanup.3 + cleanupendpad %1 unwind to caller +} + +declare void @f(i32) #0 + +declare i32 @_except_handler3(...) + +attributes #0 = { "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-realign-stack" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" } +attributes #1 = { noinline nounwind "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-realign-stack" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" } +attributes #2 = { nounwind readnone } +attributes #3 = { noinline } + +; CHECK: _nested_finally: +; CHECK: movl $-1, -[[state:[0-9]+]](%ebp) +; CHECK: movl {{.*}}, %fs:0 +; CHECK: movl $1, -[[state]](%ebp) +; CHECK: movl $1, (%esp) +; CHECK: calll _f +; CHECK: movl $0, -[[state]](%ebp) +; CHECK: movl $2, (%esp) +; CHECK: calll _f +; CHECK: movl $-1, -[[state]](%ebp) +; CHECK: movl $3, (%esp) +; CHECK: calll _f +; CHECK: retl + +; CHECK: LBB0_[[inner:[0-9]+]]: # %ehcleanup +; CHECK: movl $0, -[[state]](%ebp) +; CHECK: movl $2, (%esp) +; CHECK: calll _f + +; CHECK: LBB0_[[outer:[0-9]+]]: # %ehcleanup.3 +; CHECK: movl $-1, -[[state]](%ebp) +; CHECK: movl $3, (%esp) +; CHECK: calll _f + +; CHECK: L__ehtable$nested_finally: +; CHECK: .long -1 +; CHECK: .long 0 +; CHECK: .long LBB0_[[outer]] +; CHECK: .long 0 +; CHECK: .long 0 +; CHECK: .long LBB0_[[inner]] -- 2.34.1