Index: lib/CodeGen/CodeGenPrepare.cpp =================================================================== --- lib/CodeGen/CodeGenPrepare.cpp +++ lib/CodeGen/CodeGenPrepare.cpp @@ -726,6 +726,16 @@ // Preincrement use iterator so we don't invalidate it. ++UI; + // If the block selected to receive the cast is an EH pad that does not + // allow non-PHI instructions before the terminator, we can't sink the + // cast. + if (UserBB->isEHPad()) { + auto *T = UserBB->getTerminator(); + if (isa(T) || isa(T) || + isa(T) || isa(T)) + continue; + } + // If this user is in the same block as the cast, don't change the cast. if (UserBB == DefBB) continue; Index: lib/Transforms/Scalar/GVN.cpp =================================================================== --- lib/Transforms/Scalar/GVN.cpp +++ lib/Transforms/Scalar/GVN.cpp @@ -1551,6 +1551,20 @@ for (pred_iterator PI = pred_begin(LoadBB), E = pred_end(LoadBB); PI != E; ++PI) { BasicBlock *Pred = *PI; + + // If any predecessor block is an EH pad that does not allow non-PHI + // instructions before the terminator, we can't PRE the load. + if (Pred->isEHPad()) { + auto *T = Pred->getTerminator(); + if (isa(T) || isa(T) || + isa(T) || isa(T)) { + DEBUG(dbgs() + << "COULD NOT PRE LOAD BECAUSE OF AN EH PAD PREDECESSOR '" + << Pred->getName() << "': " << *LI << '\n'); + return false; + } + } + if (IsValueFullyAvailableInBlock(Pred, FullyAvailableBlocks, 0)) { continue; } Index: test/Transforms/CodeGenPrepare/catchpad-phi-cast.ll =================================================================== --- test/Transforms/CodeGenPrepare/catchpad-phi-cast.ll +++ test/Transforms/CodeGenPrepare/catchpad-phi-cast.ll @@ -0,0 +1,59 @@ +; RUN: opt -codegenprepare -S < %s | FileCheck %s + +; The following target lines are needed for the test to exercise what it should. +; Without these lines, CodeGenPrepare does not try to sink the bitcasts. +target datalayout = "e-m:w-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-pc-windows-msvc" + +declare i32 @__CxxFrameHandler3(...) + +declare void @f() + +declare void @g(i8*) + +; CodeGenPrepare will want to sink these bitcasts, but it selects the catchpad +; blocks as the place to which the bitcast should be sunk. Since catchpads +; do not allow non-phi instructions before the terminator, this isn't possible. + +; CHECK-LABEL: @test( +define void @test(i32* %addr) personality i32 (...)* @__CxxFrameHandler3 { +; CHECK: entry: +; CHECK-NEXT: %x = getelementptr i32, i32* %addr, i32 1 +; CHECK-NEXT: %p1 = bitcast i32* %x to i8* +entry: + %x = getelementptr i32, i32* %addr, i32 1 + %p1 = bitcast i32* %x to i8* + invoke void @f() + to label %invoke.cont unwind label %catch1 + +; CHECK: invoke.cont: +; CHECK-NEXT: %y = getelementptr i32, i32* %addr, i32 2 +; CHECK-NEXT: %p2 = bitcast i32* %y to i8* +invoke.cont: + %y = getelementptr i32, i32* %addr, i32 2 + %p2 = bitcast i32* %y to i8* + invoke void @f() + to label %done unwind label %catch2 + +done: + ret void + +catch1: + %cp1 = catchpad [] to label %catch.dispatch unwind label %catchend1 + +catch2: + %cp2 = catchpad [] to label %catch.dispatch unwind label %catchend2 + +; CHECK: catch.dispatch: +; CHECK-NEXT: %p = phi i8* [ %p1, %catch1 ], [ %p2, %catch2 ] +catch.dispatch: + %p = phi i8* [ %p1, %catch1 ], [ %p2, %catch2 ] + call void @g(i8* %p) + unreachable + +catchend1: + catchendpad unwind to caller + +catchend2: + catchendpad unwind to caller +} Index: test/Transforms/GVN/pre-load.ll =================================================================== --- test/Transforms/GVN/pre-load.ll +++ test/Transforms/GVN/pre-load.ll @@ -389,3 +389,50 @@ ; CHECK: block4: ; CHECK-NEXT: phi i32 } + +declare void @f() +declare void @g(i32) +declare i32 @__CxxFrameHandler3(...) + +; Test that loads aren't PRE'd into EH pads. +define void @test12(i32* %p) personality i32 (...)* @__CxxFrameHandler3 { +; CHECK-LABEL: @test12( +block1: + invoke void @f() + to label %block2 unwind label %catch + +block2: + invoke void @f() + to label %block3 unwind label %cleanup + +block3: + ret void + +catch: + %c = catchpad [] + to label %catch.dispatch unwind label %catchend + +catch.dispatch: + catchret %c to label %block2 + +; CHECK: catchend: +; CHECK-NOT: load +; CHECK-NEXT: catchendpad +catchend: + catchendpad unwind label %cleanup2 + +cleanup: + %c1 = cleanuppad [] + store i32 0, i32* %p + cleanupret %c1 unwind label %cleanup2 + +; CHECK: cleanup2: +; CHECK-NOT: phi +; CHECK-NEXT: %c2 = cleanuppad [] +; CHECK-NEXT: %NOTPRE = load i32, i32* %p +cleanup2: + %c2 = cleanuppad [] + %NOTPRE = load i32, i32* %p + call void @g(i32 %NOTPRE) + cleanupret %c2 unwind to caller +}