; RUN: opt -mtriple=x86_64-pc-windows-msvc -S -winehprepare < %s | FileCheck %s declare i32 @__CxxFrameHandler3(...) declare void @f() declare i32 @g() declare void @h(i32) declare i1 @i() declare void @llvm.bar() nounwind ; CHECK-LABEL: @test1( define void @test1(i1 %B) personality i32 (...)* @__CxxFrameHandler3 { entry: ; Spill slot should be inserted here ; CHECK: [[Slot:%[^ ]+]] = alloca ; Can't store for %phi at these defs because the lifetimes overlap ; CHECK-NOT: store %x = call i32 @g() %y = call i32 @g() br i1 %B, label %left, label %right left: ; CHECK: left: ; CHECK-NEXT: store i32 %x, i32* [[Slot]] ; CHECK-NEXT: invoke void @f invoke void @f() to label %exit unwind label %merge right: ; CHECK: right: ; CHECK-NEXT: store i32 %y, i32* [[Slot]] ; CHECK-NEXT: invoke void @f invoke void @f() to label %exit unwind label %merge merge: ; CHECK: merge: ; CHECK-NOT: = phi %phi = phi i32 [ %x, %left ], [ %y, %right ] %cs1 = catchswitch within none [label %catch] unwind to caller catch: %cp = catchpad within %cs1 [] ; CHECK: catch: ; CHECK: [[Reload:%[^ ]+]] = load i32, i32* [[Slot]] ; CHECK-NEXT: call void @h(i32 [[Reload]]) call void @h(i32 %phi) [ "funclet"(token %cp) ] catchret from %cp to label %exit exit: ret void } ; CHECK-LABEL: @test2( define void @test2(i1 %B) personality i32 (...)* @__CxxFrameHandler3 { entry: br i1 %B, label %left, label %right left: ; Need two stores here because %x and %y interfere so they need 2 slots ; CHECK: left: ; CHECK: store i32 1, i32* [[Slot1:%[^ ]+]] ; CHECK: store i32 1, i32* [[Slot2:%[^ ]+]] ; CHECK-NEXT: invoke void @f invoke void @f() to label %exit unwind label %merge.inner right: ; Need two stores here because %x and %y interfere so they need 2 slots ; CHECK: right: ; CHECK-DAG: store i32 2, i32* [[Slot1]] ; CHECK-DAG: store i32 2, i32* [[Slot2]] ; CHECK: invoke void @f invoke void @f() to label %exit unwind label %merge.inner merge.inner: ; CHECK: merge.inner: ; CHECK-NOT: = phi ; CHECK: catchswitch within none %x = phi i32 [ 1, %left ], [ 2, %right ] %cs1 = catchswitch within none [label %catch.inner] unwind label %merge.outer catch.inner: %cpinner = catchpad within %cs1 [] ; Need just one store here because only %y is affected ; CHECK: catch.inner: %z = call i32 @g() [ "funclet"(token %cpinner) ] ; CHECK: store i32 %z ; CHECK-NEXT: invoke void @f invoke void @f() [ "funclet"(token %cpinner) ] to label %catchret.inner unwind label %merge.outer catchret.inner: catchret from %cpinner to label %exit merge.outer: %y = phi i32 [ %x, %merge.inner ], [ %z, %catch.inner ] ; CHECK: merge.outer: ; CHECK-NOT: = phi ; CHECK: catchswitch within none %cs2 = catchswitch within none [label %catch.outer] unwind to caller catch.outer: %cpouter = catchpad within %cs2 [] ; CHECK: catch.outer: ; CHECK: [[CatchPad:%[^ ]+]] = catchpad within %cs2 [] ; Need to load x and y from two different slots since they're both live ; and can have different values (if we came from catch.inner) ; CHECK-DAG: load i32, i32* [[Slot1]] ; CHECK-DAG: load i32, i32* [[Slot2]] ; CHECK: catchret from [[CatchPad]] to label call void @h(i32 %x) [ "funclet"(token %cpouter) ] call void @h(i32 %y) [ "funclet"(token %cpouter) ] catchret from %cpouter to label %exit exit: ret void } ; test4: don't need stores for %phi.inner, as its only use is to feed %phi.outer ; %phi.outer needs stores in %left, %right, and %join ; CHECK-LABEL: @test4( define void @test4(i1 %B) personality i32 (...)* @__CxxFrameHandler3 { entry: ; CHECK: entry: ; CHECK: [[Slot:%[^ ]+]] = alloca ; CHECK-NEXT: br br i1 %B, label %left, label %right left: ; CHECK: left: ; CHECK-NOT: store ; CHECK: store i32 %l, i32* [[Slot]] ; CHECK-NEXT: invoke void @f %l = call i32 @g() invoke void @f() to label %join unwind label %catchpad.inner right: ; CHECK: right: ; CHECK-NOT: store ; CHECK: store i32 %r, i32* [[Slot]] ; CHECK-NEXT: invoke void @f %r = call i32 @g() invoke void @f() to label %join unwind label %catchpad.inner catchpad.inner: ; CHECK: catchpad.inner: ; CHECK-NEXT: catchswitch within none %phi.inner = phi i32 [ %l, %left ], [ %r, %right ] %cs1 = catchswitch within none [label %catch.inner] unwind label %catchpad.outer catch.inner: %cp1 = catchpad within %cs1 [] catchret from %cp1 to label %join join: ; CHECK: join: ; CHECK-NOT: store ; CHECK: store i32 %j, i32* [[Slot]] ; CHECK-NEXT: invoke void @f %j = call i32 @g() invoke void @f() to label %exit unwind label %catchpad.outer catchpad.outer: ; CHECK: catchpad.outer: ; CHECK-NEXT: catchswitch within none %phi.outer = phi i32 [ %phi.inner, %catchpad.inner ], [ %j, %join ] %cs2 = catchswitch within none [label %catch.outer] unwind to caller catch.outer: ; CHECK: catch.outer: ; CHECK: [[Reload:%[^ ]+]] = load i32, i32* [[Slot]] ; CHECK: call void @h(i32 [[Reload]]) %cp2 = catchpad within %cs2 [] call void @h(i32 %phi.outer) [ "funclet"(token %cp2) ] catchret from %cp2 to label %exit exit: ret void } ; CHECK-LABEL: @test5( define void @test5() personality i32 (...)* @__CxxFrameHandler3 { entry: ; need store for %phi.cleanup ; CHECK: entry: ; CHECK: store i32 1, i32* [[CleanupSlot:%[^ ]+]] ; CHECK-NEXT: invoke void @f invoke void @f() to label %invoke.cont unwind label %cleanup invoke.cont: ; need store for %phi.cleanup ; CHECK: invoke.cont: ; CHECK-NEXT: store i32 2, i32* [[CleanupSlot]] ; CHECK-NEXT: invoke void @f invoke void @f() to label %invoke.cont2 unwind label %cleanup cleanup: ; cleanup phi can be loaded at cleanup entry ; CHECK: cleanup: ; CHECK-NEXT: cleanuppad within none [] ; CHECK: [[CleanupReload:%[^ ]+]] = load i32, i32* [[CleanupSlot]] %phi.cleanup = phi i32 [ 1, %entry ], [ 2, %invoke.cont ] %cp = cleanuppad within none [] %b = call i1 @i() [ "funclet"(token %cp) ] br i1 %b, label %left, label %right left: ; CHECK: left: ; CHECK: call void @h(i32 [[CleanupReload]] call void @h(i32 %phi.cleanup) [ "funclet"(token %cp) ] br label %merge right: ; CHECK: right: ; CHECK: call void @h(i32 [[CleanupReload]] call void @h(i32 %phi.cleanup) [ "funclet"(token %cp) ] br label %merge merge: ; need store for %phi.catch ; CHECK: merge: ; CHECK-NEXT: store i32 [[CleanupReload]], i32* [[CatchSlot:%[^ ]+]] ; CHECK-NEXT: cleanupret cleanupret from %cp unwind label %catchswitch invoke.cont2: ; need store for %phi.catch ; CHECK: invoke.cont2: ; CHECK-NEXT: store i32 3, i32* [[CatchSlot]] ; CHECK-NEXT: invoke void @f invoke void @f() to label %exit unwind label %catchswitch catchswitch: ; CHECK: catchswitch: ; CHECK-NEXT: catchswitch within none %phi.catch = phi i32 [ %phi.cleanup, %merge ], [ 3, %invoke.cont2 ] %cs1 = catchswitch within none [label %catch] unwind to caller catch: ; CHECK: catch: ; CHECK: catchpad within %cs1 ; CHECK: [[CatchReload:%[^ ]+]] = load i32, i32* [[CatchSlot]] ; CHECK: call void @h(i32 [[CatchReload]] %cp2 = catchpad within %cs1 [] call void @h(i32 %phi.catch) [ "funclet"(token %cp2) ] catchret from %cp2 to label %exit exit: ret void } ; We used to demote %x, but we don't need to anymore. ; CHECK-LABEL: @test6( define void @test6() personality i32 (...)* @__CxxFrameHandler3 { entry: ; CHECK: entry: ; CHECK: %x = invoke i32 @g() ; CHECK-NEXT: to label %loop unwind label %to_caller %x = invoke i32 @g() to label %loop unwind label %to_caller to_caller: %cp1 = cleanuppad within none [] cleanupret from %cp1 unwind to caller loop: invoke void @f() to label %loop unwind label %cleanup cleanup: ; CHECK: cleanup: ; CHECK: call void @h(i32 %x) %cp2 = cleanuppad within none [] call void @h(i32 %x) [ "funclet"(token %cp2) ] cleanupret from %cp2 unwind to caller } ; CHECK-LABEL: @test7( define void @test7() personality i32 (...)* @__CxxFrameHandler3 { entry: ; %x is an EH pad phi, so gets stored in pred here ; CHECK: entry: ; CHECK: store i32 1, i32* [[SlotX:%[^ ]+]] ; CHECK: invoke void @f() invoke void @f() to label %invoke.cont unwind label %catchpad invoke.cont: ; %x is an EH pad phi, so gets stored in pred here ; CHECK: invoke.cont: ; CHECK: store i32 2, i32* [[SlotX]] ; CHECK: invoke void @f() invoke void @f() to label %exit unwind label %catchpad catchpad: ; %x phi should be eliminated ; CHECK: catchpad: ; CHECK-NEXT: catchswitch within none %x = phi i32 [ 1, %entry ], [ 2, %invoke.cont ] %cs1 = catchswitch within none [label %catch] unwind to caller catch: ; CHECK: catch: ; CHECK-NEXT: %[[CatchPad:[^ ]+]] = catchpad within %cs1 [] %cp = catchpad within %cs1 [] %b = call i1 @i() [ "funclet"(token %cp) ] br i1 %b, label %left, label %right left: ; Edge from %left to %join needs to be split so that ; the load of %x can be inserted *after* the catchret ; CHECK: left: ; CHECK-NEXT: catchret from %[[CatchPad]] to label %[[SplitLeft:[^ ]+]] catchret from %cp to label %join ; CHECK: [[SplitLeft]]: ; CHECK: [[LoadX:%[^ ]+]] = load i32, i32* [[SlotX]] ; CHECK: br label %join right: ; Edge from %right to %join needs to be split so that ; the load of %y can be inserted *after* the catchret ; CHECK: right: ; CHECK: %y = call i32 @g() ; CHECK: catchret from %[[CatchPad]] to label %join %y = call i32 @g() [ "funclet"(token %cp) ] catchret from %cp to label %join join: ; CHECK: join: ; CHECK: %phi = phi i32 [ [[LoadX]], %[[SplitLeft]] ], [ %y, %right ] %phi = phi i32 [ %x, %left ], [ %y, %right ] call void @h(i32 %phi) br label %exit exit: ret void } ; CHECK-LABEL: @test8( define void @test8() personality i32 (...)* @__CxxFrameHandler3 { entry: invoke void @f() to label %done unwind label %cleanup1 invoke void @f() to label %done unwind label %cleanup2 done: ret void cleanup1: ; CHECK: [[CleanupPad1:%[^ ]+]] = cleanuppad within none [] ; CHECK-NEXT: call void @llvm.bar() ; CHECK-NEXT: cleanupret from [[CleanupPad1]] %cp0 = cleanuppad within none [] br label %cleanupexit cleanup2: ; CHECK: cleanuppad within none [] ; CHECK-NEXT: call void @llvm.bar() ; CHECK-NEXT: unreachable %cp1 = cleanuppad within none [] br label %cleanupexit cleanupexit: call void @llvm.bar() cleanupret from %cp0 unwind label %cleanup2 }