|  | ; 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 | 
|  | } |