Compiler projects using llvm
; RUN: opt -mtriple=x86_64-pc-windows-msvc -S -winehprepare -disable-demotion -disable-cleanups < %s | FileCheck %s

declare i32 @__CxxFrameHandler3(...)

declare i32 @__C_specific_handler(...)

declare void @f()

declare i32 @g()

declare void @h(i32)

; CHECK-LABEL: @test1(
define void @test1(i1 %bool) personality i32 (...)* @__C_specific_handler {
entry:
  invoke void @f()
          to label %invoke.cont unwind label %left

invoke.cont:
  invoke void @f()
          to label %exit unwind label %inner

left:
  %0 = cleanuppad within none []
  br i1 %bool, label %shared, label %cleanupret

cleanupret:
  cleanupret from %0 unwind label %right

right:
  %1 = cleanuppad within none []
  br label %shared

shared:
  %x = call i32 @g()
  invoke void @f()
          to label %shared.cont unwind label %inner

shared.cont:
  unreachable

inner:
  %phi = phi i32 [ %x, %shared ], [ 0, %invoke.cont ]
  %i = cleanuppad within none []
  call void @h(i32 %phi)
  unreachable

; CHECK: %phi = phi i32 [ %x, %shared ], [ 0, %invoke.cont ], [ %x.for.left, %shared.for.left ]
; CHECK: %i = cleanuppad within none []
; CHECK: call void @h(i32 %phi)

exit:
  unreachable
}

; CHECK-LABEL: @test2(
define void @test2(i1 %bool) personality i32 (...)* @__C_specific_handler {
entry:
  invoke void @f()
          to label %shared.cont unwind label %left

left:
  %0 = cleanuppad within none []
  br i1 %bool, label %shared, label %cleanupret

cleanupret:
  cleanupret from %0 unwind label %right

right:
  %1 = cleanuppad within none []
  br label %shared

shared:
  %x = call i32 @g()
  invoke void @f()
          to label %shared.cont unwind label %inner

shared.cont:
  unreachable

inner:
  %i = cleanuppad within none []
  call void @h(i32 %x)
  unreachable

; CHECK: %x1 = phi i32 [ %x.for.left, %shared.for.left ], [ %x, %shared ]
; CHECK: %i = cleanuppad within none []
; CHECK: call void @h(i32 %x1)

exit:
  unreachable
}

; CHECK-LABEL: @test4(
define void @test4(i1 %x) personality i32 (...)* @__CxxFrameHandler3 {
entry:
  invoke void @f()
          to label %invoke.cont1 unwind label %left

invoke.cont1:
  invoke void @f()
          to label %exit unwind label %right

left:
  %0 = cleanuppad within none []
  br label %shared

right:
  %1 = cleanuppad within none []
  br i1 %x, label %shared, label %right.other

right.other:
  br label %shared

shared:
  %phi = phi i32 [ 1, %left ], [ 0, %right ], [ -1, %right.other ]
  call void @h(i32 %phi)
  unreachable

; CHECK: %phi = phi i32 [ 0, %right ], [ -1, %right.other ]
; CHECK: call void @h(i32 %phi)

; CHECK: %phi.for.left = phi i32 [ 1, %left ]
; CHECK: call void @h(i32 %phi.for.left)

exit:
  unreachable
}

declare void @__std_terminate()