From d0430e85808b2ef6f71d0383b201d608b0d1955a Mon Sep 17 00:00:00 2001 From: Andrew Kaylor Date: Mon, 23 Nov 2015 19:16:15 +0000 Subject: [PATCH] [WinEH] Fix problem where CodeGenPrepare incorrectly sinks a bitcast into an EH pad. Differential Revision: http://reviews.llvm.org/D14842 llvm-svn: 253902 --- llvm/lib/CodeGen/CodeGenPrepare.cpp | 6 ++ .../CodeGenPrepare/catchpad-phi-cast.ll | 59 +++++++++++++++++++ 2 files changed, 65 insertions(+) create mode 100644 llvm/test/Transforms/CodeGenPrepare/catchpad-phi-cast.ll diff --git a/llvm/lib/CodeGen/CodeGenPrepare.cpp b/llvm/lib/CodeGen/CodeGenPrepare.cpp index ce6308dd7093..d619044e86ca 100644 --- a/llvm/lib/CodeGen/CodeGenPrepare.cpp +++ b/llvm/lib/CodeGen/CodeGenPrepare.cpp @@ -730,6 +730,12 @@ static bool SinkCast(CastInst *CI) { // 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->getTerminator()->isEHPad()) + continue; + // If this user is in the same block as the cast, don't change the cast. if (UserBB == DefBB) continue; diff --git a/llvm/test/Transforms/CodeGenPrepare/catchpad-phi-cast.ll b/llvm/test/Transforms/CodeGenPrepare/catchpad-phi-cast.ll new file mode 100644 index 000000000000..998ca7069c8b --- /dev/null +++ b/llvm/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 +}