Index: lib/CodeGen/WinEHPrepare.cpp =================================================================== --- lib/CodeGen/WinEHPrepare.cpp +++ lib/CodeGen/WinEHPrepare.cpp @@ -2710,6 +2710,9 @@ DEBUG(dbgs() << "CatchHigh[" << FirstTryPad->getName() << "]: " << CatchHigh << '\n'); } else if (isa(FirstNonPHI)) { + // A cleanup can have multiple exits; don't re-process after the first. + if (FuncInfo.EHPadStateMap.count(FirstNonPHI)) + return; int CleanupState = addUnwindMapEntry(FuncInfo, ParentState, &BB); FuncInfo.EHPadStateMap[FirstNonPHI] = CleanupState; DEBUG(dbgs() << "Assigning state #" << CleanupState << " to BB " @@ -2717,6 +2720,15 @@ for (const BasicBlock *PredBlock : predecessors(&BB)) if ((PredBlock = getEHPadFromPredecessor(PredBlock))) calculateExplicitCXXStateNumbers(FuncInfo, *PredBlock, CleanupState); + } else if (auto *CEPI = dyn_cast(FirstNonPHI)) { + // Propagate ParentState to the cleanuppad in case it doesn't have + // any cleanuprets. + BasicBlock *CleanupBlock = CEPI->getCleanupPad()->getParent(); + calculateExplicitCXXStateNumbers(FuncInfo, *CleanupBlock, ParentState); + // Anything unwinding through CleanupEndPadInst is in ParentState. + for (const BasicBlock *PredBlock : predecessors(&BB)) + if ((PredBlock = getEHPadFromPredecessor(PredBlock))) + calculateExplicitCXXStateNumbers(FuncInfo, *PredBlock, ParentState); } else if (isa(FirstNonPHI)) { report_fatal_error("Not yet implemented!"); } else { @@ -2790,6 +2802,9 @@ if ((PredBlock = getEHPadFromPredecessor(PredBlock))) calculateExplicitSEHStateNumbers(FuncInfo, *PredBlock, ParentState); } else if (isa(FirstNonPHI)) { + // A cleanup can have multiple exits; don't re-process after the first. + if (FuncInfo.EHPadStateMap.count(FirstNonPHI)) + return; int CleanupState = addSEHFinally(FuncInfo, ParentState, &BB); FuncInfo.EHPadStateMap[FirstNonPHI] = CleanupState; DEBUG(dbgs() << "Assigning state #" << CleanupState << " to BB " @@ -2797,7 +2812,11 @@ for (const BasicBlock *PredBlock : predecessors(&BB)) if ((PredBlock = getEHPadFromPredecessor(PredBlock))) calculateExplicitSEHStateNumbers(FuncInfo, *PredBlock, CleanupState); - } else if (isa(FirstNonPHI)) { + } else if (auto *CEPI = dyn_cast(FirstNonPHI)) { + // Propagate ParentState to the cleanuppad in case it doesn't have + // any cleanuprets. + BasicBlock *CleanupBlock = CEPI->getCleanupPad()->getParent(); + calculateExplicitSEHStateNumbers(FuncInfo, *CleanupBlock, ParentState); // Anything unwinding through CleanupEndPadInst is in ParentState. FuncInfo.EHPadStateMap[FirstNonPHI] = ParentState; DEBUG(dbgs() << "Assigning state #" << ParentState << " to BB " @@ -2855,9 +2874,6 @@ if (BB.isLandingPad()) report_fatal_error("MSVC C++ EH cannot use landingpads"); const Instruction *FirstNonPHI = BB.getFirstNonPHI(); - // Skip cleanupendpads; they are exits, not entries. - if (isa(FirstNonPHI)) - continue; if (!doesEHPadUnwindToCaller(FirstNonPHI)) continue; calculateExplicitCXXStateNumbers(FuncInfo, BB, -1); Index: test/CodeGen/WinEH/wineh-statenumbering-cleanups.ll =================================================================== --- /dev/null +++ test/CodeGen/WinEH/wineh-statenumbering-cleanups.ll @@ -0,0 +1,100 @@ +; RUN: sed -e s/.Cxx:// %s | opt -mtriple=x86-pc-windows-msvc -S -x86-winehstate | FileCheck %s +; RUN: sed -e s/.SEH:// %s | opt -mtriple=x86-pc-windows-msvc -S -x86-winehstate | FileCheck %s + +declare i32 @__CxxFrameHandler3(...) +declare i32 @_except_handler3(...) +declare void @dummy_filter() + +declare void @f(i32) + +; CHECK-LABEL: define void @test1( +;Cxx: define void @test1() personality i32 (...)* @__CxxFrameHandler3 { +;SEH: define void @test1() personality i32 (...)* @_except_handler3 { +entry: + ; CHECK: entry: + ; CHECK: store i32 0 + ; CHECK: invoke void @f(i32 0) + invoke void @f(i32 0) + to label %exit unwind label %cleanup.pad +cleanup.pad: + ; CHECK: cleanup.pad: + ; CHECK: store i32 1 + ; CHECK: invoke void @f(i32 1) + %cleanup = cleanuppad [] + invoke void @f(i32 1) + to label %cleanup.ret unwind label %catch.pad +catch.pad: +;Cxx: %catch = catchpad [i8* null, i32 u0x40, i8* null] +;SEH: %catch = catchpad [void ()* @dummy_filter] + to label %catch.body unwind label %catch.end +catch.body: + catchret %catch to label %cleanup.ret +catch.end: + catchendpad unwind label %cleanup.end +cleanup.ret: + cleanupret %cleanup unwind to caller +cleanup.end: + cleanupendpad %cleanup unwind to caller +exit: + ret void +} + +; CHECK-LABEL: define void @test2( +;Cxx: define void @test2(i1 %b) personality i32 (...)* @__CxxFrameHandler3 { +;SEH: define void @test2(i1 %b) personality i32 (...)* @_except_handler3 { +entry: + ; CHECK: entry: + ; CHECK: store i32 1 + ; CHECK: invoke void @f(i32 1) + invoke void @f(i32 1) + to label %exit unwind label %cleanup.pad +cleanup.pad: + %cleanup = cleanuppad [] + br i1 %b, label %left, label %right +left: + cleanupret %cleanup unwind label %catch.pad +right: + cleanupret %cleanup unwind label %catch.pad +catch.pad: +;Cxx: %catch = catchpad [i8* null, i32 u0x40, i8* null] +;SEH: %catch = catchpad [void ()* @dummy_filter] + to label %catch.body unwind label %catch.end +catch.body: + catchret %catch to label %exit +catch.end: + catchendpad unwind to caller +exit: + ret void +} + +; CHECK-LABEL: define void @test3( +;Cxx: define void @test3() personality i32 (...)* @__CxxFrameHandler3 { +;SEH: define void @test3() personality i32 (...)* @_except_handler3 { +entry: + ; CHECK: entry: + ; CHECK: store i32 1 + ; CHECK: invoke void @f(i32 1) + invoke void @f(i32 1) + to label %exit unwind label %cleanup.pad +cleanup.pad: + ; CHECK: cleanup.pad: + ; CHECK: store i32 0 + ; CHECK: invoke void @f(i32 0) + %cleanup = cleanuppad [] + invoke void @f(i32 0) + to label %unreachable unwind label %cleanup.end +unreachable: + unreachable +cleanup.end: + cleanupendpad %cleanup unwind label %catch.pad +catch.pad: +;Cxx: %catch = catchpad [i8* null, i32 u0x40, i8* null] +;SEH: %catch = catchpad [void ()* @dummy_filter] + to label %catch.body unwind label %catch.end +catch.body: + catchret %catch to label %exit +catch.end: + catchendpad unwind to caller +exit: + ret void +}