From bfc4ce4b74af1a6cab6f2fc3dcdee70f6a0ed8a1 Mon Sep 17 00:00:00 2001 From: Andrew Kaylor Date: Mon, 12 Dec 2016 23:05:38 +0000 Subject: [PATCH] Avoid infinite loops in branch folding Differential Revision: https://reviews.llvm.org/D27582 llvm-svn: 289486 --- lib/CodeGen/BranchFolding.cpp | 14 ++++- test/CodeGen/WinEH/wineh-noret-cleanup.ll | 12 ++-- test/CodeGen/X86/branchfolding-catchpads.ll | 64 +++++++++++++++++++++ 3 files changed, 83 insertions(+), 7 deletions(-) diff --git a/lib/CodeGen/BranchFolding.cpp b/lib/CodeGen/BranchFolding.cpp index 20dc8805150..913d5d91890 100644 --- a/lib/CodeGen/BranchFolding.cpp +++ b/lib/CodeGen/BranchFolding.cpp @@ -1624,10 +1624,22 @@ ReoptimizeBlock: // Okay, there is no really great place to put this block. If, however, // the block before this one would be a fall-through if this block were - // removed, move this block to the end of the function. + // removed, move this block to the end of the function. There is no real + // advantage in "falling through" to an EH block, so we don't want to + // perform this transformation for that case. + // + // Also, Windows EH introduced the possibility of an arbitrary number of + // successors to a given block. The analyzeBranch call does not consider + // exception handling and so we can get in a state where a block + // containing a call is followed by multiple EH blocks that would be + // rotated infinitely at the end of the function if the transformation + // below were performed for EH "FallThrough" blocks. Therefore, even if + // that appears not to be happening anymore, we should assume that it is + // possible and not remove the "!FallThrough()->isEHPad" condition below. MachineBasicBlock *PrevTBB = nullptr, *PrevFBB = nullptr; SmallVector PrevCond; if (FallThrough != MF.end() && + !FallThrough->isEHPad() && !TII->analyzeBranch(PrevBB, PrevTBB, PrevFBB, PrevCond, true) && PrevBB.isSuccessor(&*FallThrough)) { MBB->moveAfter(&MF.back()); diff --git a/test/CodeGen/WinEH/wineh-noret-cleanup.ll b/test/CodeGen/WinEH/wineh-noret-cleanup.ll index 85241c6d42d..7d4d833aa9b 100644 --- a/test/CodeGen/WinEH/wineh-noret-cleanup.ll +++ b/test/CodeGen/WinEH/wineh-noret-cleanup.ll @@ -50,13 +50,13 @@ catch.body.2: ; CXX-NEXT: .long 1 ; CXX-NEXT: .long .Ltmp1@IMGREL+1 ; CXX-NEXT: .long -1 -; CXX-NEXT: .long "?catch$2@?0?test@4HA"@IMGREL +; CXX-NEXT: .long "?catch$3@?0?test@4HA"@IMGREL ; CXX-NEXT: .long 2 ; CXX-NEXT: .long .Ltmp2@IMGREL+1 ; CXX-NEXT: .long 3 ; CXX-NEXT: .long .Ltmp3@IMGREL+1 ; CXX-NEXT: .long 2 -; CXX-NEXT: .long "?catch$4@?0?test@4HA"@IMGREL +; CXX-NEXT: .long "?catch$5@?0?test@4HA"@IMGREL ; CXX-NEXT: .long 4 ; SEH-LABEL: test: @@ -64,17 +64,17 @@ catch.body.2: ; SEH-NEXT: .long .Ltmp0@IMGREL+1 ; SEH-NEXT: .long .Ltmp1@IMGREL+1 ; SEH-NEXT: .long dummy_filter@IMGREL -; SEH-NEXT: .long .LBB0_2@IMGREL +; SEH-NEXT: .long .LBB0_3@IMGREL ; SEH-NEXT: .long .Ltmp0@IMGREL+1 ; SEH-NEXT: .long .Ltmp1@IMGREL+1 ; SEH-NEXT: .long dummy_filter@IMGREL -; SEH-NEXT: .long .LBB0_4@IMGREL +; SEH-NEXT: .long .LBB0_5@IMGREL ; SEH-NEXT: .long .Ltmp2@IMGREL+1 ; SEH-NEXT: .long .Ltmp3@IMGREL+1 -; SEH-NEXT: .long "?dtor$5@?0?test@4HA"@IMGREL +; SEH-NEXT: .long "?dtor$2@?0?test@4HA"@IMGREL ; SEH-NEXT: .long 0 ; SEH-NEXT: .long .Ltmp2@IMGREL+1 ; SEH-NEXT: .long .Ltmp3@IMGREL+1 ; SEH-NEXT: .long dummy_filter@IMGREL -; SEH-NEXT: .long .LBB0_4@IMGREL +; SEH-NEXT: .long .LBB0_5@IMGREL ; SEH-NEXT: .Llsda_end0: diff --git a/test/CodeGen/X86/branchfolding-catchpads.ll b/test/CodeGen/X86/branchfolding-catchpads.ll index 0468b3c314f..013219e2d36 100644 --- a/test/CodeGen/X86/branchfolding-catchpads.ll +++ b/test/CodeGen/X86/branchfolding-catchpads.ll @@ -93,3 +93,67 @@ unreachable: ; ; CHECK-LABEL: .def test2; +declare void @g() + +define void @test3() optsize personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*) { +entry: + switch i32 undef, label %if.end57 [ + i32 64, label %sw.bb + i32 128, label %sw.epilog + i32 256, label %if.then56 + i32 1024, label %sw.bb + i32 4096, label %sw.bb33 + i32 16, label %sw.epilog + i32 8, label %sw.epilog + i32 32, label %sw.bb44 + ] + +sw.bb: + unreachable + +sw.bb33: + br i1 undef, label %if.end57, label %while.cond.i163.preheader + +while.cond.i163.preheader: + unreachable + +sw.bb44: + %temp0 = load void ()*, void ()** undef + invoke void %temp0() + to label %if.end57 unwind label %catch.dispatch + +sw.epilog: + %temp1 = load i8*, i8** undef + br label %if.end57 + +catch.dispatch: + %cs = catchswitch within none [label %catch1, label %catch2, label %catch3] unwind to caller + +catch1: + %c1 = catchpad within %cs [i8* null, i32 8, i8* null] + unreachable + +catch2: + %c2 = catchpad within %cs [i8* null, i32 32, i8* null] + unreachable + +catch3: + %c3 = catchpad within %cs [i8* null, i32 64, i8* null] + unreachable + +if.then56: + call void @g() + br label %if.end57 + +if.end57: + ret void +} + +; This test exercises a complex case that produced an infinite loop during +; compilation when the two cases above did not. The multiple targets from the +; entry switch are not actually fundamental to the failure, but they are +; necessary to suppress various control flow optimizations that would prevent +; the conditions that lead to the failure. +; +; CHECK-LABEL: .def test3; +