2015-08-13 22:30:10 +08:00
|
|
|
; RUN: opt -mtriple=x86_x64-pc-windows-msvc -S -winehprepare < %s | FileCheck %s
|
|
|
|
|
|
|
|
declare i32 @__CxxFrameHandler3(...)
|
|
|
|
|
|
|
|
declare void @f()
|
|
|
|
|
|
|
|
declare i32 @g()
|
|
|
|
|
|
|
|
declare void @h(i32)
|
|
|
|
|
|
|
|
declare i1 @i()
|
|
|
|
|
|
|
|
; 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 ]
|
2015-08-23 08:26:33 +08:00
|
|
|
%cp = catchpad [] to label %catch unwind label %catchend
|
2015-08-13 22:30:10 +08:00
|
|
|
|
|
|
|
catch:
|
|
|
|
; CHECK: catch:
|
|
|
|
; CHECK: [[Reload:%[^ ]+]] = load i32, i32* [[Slot]]
|
|
|
|
; CHECK-NEXT: call void @h(i32 [[Reload]])
|
|
|
|
call void @h(i32 %phi)
|
2015-08-23 08:26:33 +08:00
|
|
|
catchret %cp to label %exit
|
2015-08-13 22:30:10 +08:00
|
|
|
|
|
|
|
catchend:
|
|
|
|
catchendpad unwind to caller
|
|
|
|
|
|
|
|
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
|
2015-08-23 08:26:33 +08:00
|
|
|
; CHECK: catchpad []
|
2015-08-13 22:30:10 +08:00
|
|
|
%x = phi i32 [ 1, %left ], [ 2, %right ]
|
2015-08-23 08:26:33 +08:00
|
|
|
%cpinner = catchpad [] to label %catch.inner unwind label %catchend.inner
|
2015-08-13 22:30:10 +08:00
|
|
|
|
|
|
|
catch.inner:
|
|
|
|
; Need just one store here because only %y is affected
|
|
|
|
; CHECK: catch.inner:
|
|
|
|
%z = call i32 @g()
|
|
|
|
; CHECK: store i32 %z
|
|
|
|
; CHECK-NEXT: invoke void @f
|
|
|
|
invoke void @f()
|
|
|
|
to label %catchret.inner unwind label %merge.outer
|
|
|
|
|
|
|
|
catchret.inner:
|
2015-08-23 08:26:33 +08:00
|
|
|
catchret %cpinner to label %exit
|
2015-08-13 22:30:10 +08:00
|
|
|
catchend.inner:
|
|
|
|
catchendpad unwind label %merge.outer
|
|
|
|
|
|
|
|
merge.outer:
|
|
|
|
; CHECK: merge.outer:
|
|
|
|
; CHECK-NOT: = phi
|
2015-08-23 08:26:33 +08:00
|
|
|
; CHECK: [[CatchPad:%[^ ]+]] = catchpad []
|
2015-08-13 22:30:10 +08:00
|
|
|
%y = phi i32 [ %x, %catchend.inner ], [ %z, %catch.inner ]
|
2015-08-23 08:26:33 +08:00
|
|
|
%cpouter = catchpad [] to label %catch.outer unwind label %catchend.outer
|
2015-08-13 22:30:10 +08:00
|
|
|
|
|
|
|
catchend.outer:
|
|
|
|
catchendpad unwind to caller
|
|
|
|
|
|
|
|
catch.outer:
|
|
|
|
; 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: catch.outer:
|
|
|
|
; CHECK-DAG: load i32, i32* [[Slot1]]
|
|
|
|
; CHECK-DAG: load i32, i32* [[Slot2]]
|
2015-08-23 08:26:33 +08:00
|
|
|
; CHECK: catchret [[CatchPad]] to label
|
2015-08-13 22:30:10 +08:00
|
|
|
call void @h(i32 %x)
|
|
|
|
call void @h(i32 %y)
|
2015-08-23 08:26:33 +08:00
|
|
|
catchret %cpouter to label %exit
|
2015-08-13 22:30:10 +08:00
|
|
|
|
|
|
|
exit:
|
|
|
|
ret void
|
|
|
|
}
|
|
|
|
|
|
|
|
; CHECK-LABEL: @test3(
|
|
|
|
define void @test3(i1 %B) personality i32 (...)* @__CxxFrameHandler3 {
|
|
|
|
entry:
|
|
|
|
; need to spill parameter %B and def %x since they're used in a funclet
|
|
|
|
; CHECK: entry:
|
|
|
|
; CHECK-DAG: store i1 %B, i1* [[SlotB:%[^ ]+]]
|
|
|
|
; CHECK-DAG: store i32 %x, i32* [[SlotX:%[^ ]+]]
|
|
|
|
; CHECK: invoke void @f
|
|
|
|
%x = call i32 @g()
|
|
|
|
invoke void @f()
|
|
|
|
to label %exit unwind label %catchpad
|
|
|
|
|
|
|
|
catchpad:
|
2015-08-23 08:26:33 +08:00
|
|
|
%cp = catchpad [] to label %catch unwind label %catchend
|
2015-08-13 22:30:10 +08:00
|
|
|
|
|
|
|
catch:
|
|
|
|
; Need to reload %B here
|
|
|
|
; CHECK: catch:
|
|
|
|
; CHECK: [[ReloadB:%[^ ]+]] = load i1, i1* [[SlotB]]
|
|
|
|
; CHECK: br i1 [[ReloadB]]
|
|
|
|
br i1 %B, label %left, label %right
|
|
|
|
left:
|
|
|
|
; Use of %x is in a phi, so need reload here in pred
|
|
|
|
; CHECK: left:
|
|
|
|
; CHECK: [[ReloadX:%[^ ]+]] = load i32, i32* [[SlotX]]
|
|
|
|
; CHECK: br label %merge
|
|
|
|
br label %merge
|
|
|
|
right:
|
|
|
|
br label %merge
|
|
|
|
merge:
|
|
|
|
; CHECK: merge:
|
|
|
|
; CHECK: %phi = phi i32 [ [[ReloadX]], %left ]
|
|
|
|
%phi = phi i32 [ %x, %left ], [ 42, %right ]
|
|
|
|
call void @h(i32 %phi)
|
2015-08-23 08:26:33 +08:00
|
|
|
catchret %cp to label %exit
|
2015-08-13 22:30:10 +08:00
|
|
|
|
|
|
|
catchend:
|
|
|
|
catchendpad unwind to caller
|
|
|
|
|
|
|
|
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:
|
2015-08-23 08:26:33 +08:00
|
|
|
; CHECK-NEXT: catchpad []
|
2015-08-13 22:30:10 +08:00
|
|
|
%phi.inner = phi i32 [ %l, %left ], [ %r, %right ]
|
2015-08-23 08:26:33 +08:00
|
|
|
%cp1 = catchpad [] to label %catch.inner unwind label %catchend.inner
|
2015-08-13 22:30:10 +08:00
|
|
|
catch.inner:
|
2015-08-23 08:26:33 +08:00
|
|
|
catchret %cp1 to label %join
|
2015-08-13 22:30:10 +08:00
|
|
|
catchend.inner:
|
|
|
|
catchendpad unwind label %catchpad.outer
|
|
|
|
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:
|
2015-08-23 08:26:33 +08:00
|
|
|
; CHECK-NEXT: catchpad []
|
2015-08-13 22:30:10 +08:00
|
|
|
%phi.outer = phi i32 [ %phi.inner, %catchend.inner ], [ %j, %join ]
|
2015-08-23 08:26:33 +08:00
|
|
|
%cp2 = catchpad [] to label %catch.outer unwind label %catchend.outer
|
2015-08-13 22:30:10 +08:00
|
|
|
catch.outer:
|
|
|
|
; CHECK: catch.outer:
|
|
|
|
; CHECK: [[Reload:%[^ ]+]] = load i32, i32* [[Slot]]
|
|
|
|
; CHECK: call void @h(i32 [[Reload]])
|
|
|
|
call void @h(i32 %phi.outer)
|
2015-08-23 08:26:33 +08:00
|
|
|
catchret %cp2 to label %exit
|
2015-08-13 22:30:10 +08:00
|
|
|
catchend.outer:
|
|
|
|
catchendpad unwind to caller
|
|
|
|
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:
|
2015-08-23 08:26:33 +08:00
|
|
|
; CHECK-NEXT: cleanuppad []
|
2015-08-13 22:30:10 +08:00
|
|
|
; CHECK: [[CleanupReload:%[^ ]+]] = load i32, i32* [[CleanupSlot]]
|
|
|
|
%phi.cleanup = phi i32 [ 1, %entry ], [ 2, %invoke.cont ]
|
2015-08-23 08:26:33 +08:00
|
|
|
%cp = cleanuppad []
|
2015-08-13 22:30:10 +08:00
|
|
|
%b = call i1 @i()
|
|
|
|
br i1 %b, label %left, label %right
|
|
|
|
|
|
|
|
left:
|
|
|
|
; CHECK: left:
|
|
|
|
; CHECK: call void @h(i32 [[CleanupReload]]
|
|
|
|
call void @h(i32 %phi.cleanup)
|
|
|
|
br label %merge
|
|
|
|
|
|
|
|
right:
|
|
|
|
; CHECK: right:
|
|
|
|
; CHECK: call void @h(i32 [[CleanupReload]]
|
|
|
|
call void @h(i32 %phi.cleanup)
|
|
|
|
br label %merge
|
|
|
|
|
|
|
|
merge:
|
|
|
|
; need store for %phi.catch
|
|
|
|
; CHECK: merge:
|
|
|
|
; CHECK-NEXT: store i32 [[CleanupReload]], i32* [[CatchSlot:%[^ ]+]]
|
2015-08-23 08:26:33 +08:00
|
|
|
; CHECK-NEXT: cleanupret
|
|
|
|
cleanupret %cp unwind label %catchpad
|
2015-08-13 22:30:10 +08:00
|
|
|
|
|
|
|
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 %catchpad
|
|
|
|
|
|
|
|
catchpad:
|
|
|
|
; CHECK: catchpad:
|
2015-08-23 08:26:33 +08:00
|
|
|
; CHECK-NEXT: catchpad []
|
2015-08-13 22:30:10 +08:00
|
|
|
%phi.catch = phi i32 [ %phi.cleanup, %merge ], [ 3, %invoke.cont2 ]
|
2015-08-23 08:26:33 +08:00
|
|
|
%cp2 = catchpad [] to label %catch unwind label %catchend
|
2015-08-13 22:30:10 +08:00
|
|
|
|
|
|
|
catch:
|
|
|
|
; CHECK: catch:
|
|
|
|
; CHECK: [[CatchReload:%[^ ]+]] = load i32, i32* [[CatchSlot]]
|
|
|
|
; CHECK: call void @h(i32 [[CatchReload]]
|
|
|
|
call void @h(i32 %phi.catch)
|
2015-08-23 08:26:33 +08:00
|
|
|
catchret %cp2 to label %exit
|
2015-08-13 22:30:10 +08:00
|
|
|
|
|
|
|
catchend:
|
|
|
|
catchendpad unwind to caller
|
|
|
|
|
|
|
|
exit:
|
|
|
|
ret void
|
|
|
|
}
|
2015-08-17 21:51:37 +08:00
|
|
|
|
|
|
|
; CHECK-LABEL: @test6(
|
|
|
|
define void @test6() personality i32 (...)* @__CxxFrameHandler3 {
|
|
|
|
entry:
|
|
|
|
; Since %x needs to be stored but the edge to loop is critical,
|
|
|
|
; it needs to be split
|
|
|
|
; CHECK: entry:
|
|
|
|
; CHECK: invoke i32 @g
|
|
|
|
; CHECK-NEXT: to label %[[SplitBlock:[^ ]+]] unwind label %to_caller
|
|
|
|
%x = invoke i32 @g()
|
|
|
|
to label %loop unwind label %to_caller
|
|
|
|
; The store should be in the split block
|
|
|
|
; CHECK: [[SplitBlock]]:
|
|
|
|
; CHECK: store i32 %x, i32* [[SpillSlot:%[^ ]+]]
|
|
|
|
; CHECK: br label %loop
|
|
|
|
to_caller:
|
2015-08-23 08:26:33 +08:00
|
|
|
%cp1 = cleanuppad []
|
|
|
|
cleanupret %cp1 unwind to caller
|
2015-08-17 21:51:37 +08:00
|
|
|
loop:
|
|
|
|
invoke void @f()
|
|
|
|
to label %loop unwind label %cleanup
|
|
|
|
cleanup:
|
|
|
|
; CHECK: cleanup:
|
|
|
|
; CHECK: [[Load:%[^ ]+]] = load i32, i32* [[SpillSlot]]
|
|
|
|
; CHECK: call void @h(i32 [[Load]])
|
2015-08-23 08:26:33 +08:00
|
|
|
%cp2 = cleanuppad []
|
2015-08-17 21:51:37 +08:00
|
|
|
call void @h(i32 %x)
|
2015-08-23 08:26:33 +08:00
|
|
|
cleanupret %cp2 unwind to caller
|
2015-08-17 21:51:37 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
; 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:
|
2015-08-23 08:26:33 +08:00
|
|
|
; CHECK-NEXT: %[[CatchPad:[^ ]+]] = catchpad []
|
2015-08-17 21:51:37 +08:00
|
|
|
%x = phi i32 [ 1, %entry ], [ 2, %invoke.cont ]
|
2015-08-23 08:26:33 +08:00
|
|
|
%cp = catchpad [] to label %catch unwind label %catchend
|
2015-08-17 21:51:37 +08:00
|
|
|
catch:
|
|
|
|
%b = call i1 @i()
|
|
|
|
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:
|
2015-08-23 08:26:33 +08:00
|
|
|
; CHECK-NEXT: catchret %[[CatchPad]] to label %[[SplitLeft:[^ ]+]]
|
|
|
|
catchret %cp to label %join
|
2015-08-17 21:51:37 +08:00
|
|
|
; 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: store i32 %y, i32* [[SlotY:%[^ ]+]]
|
2015-08-23 08:26:33 +08:00
|
|
|
; CHECK: catchret %[[CatchPad]] to label %[[SplitRight:[^ ]+]]
|
2015-08-17 21:51:37 +08:00
|
|
|
%y = call i32 @g()
|
2015-08-23 08:26:33 +08:00
|
|
|
catchret %cp to label %join
|
2015-08-17 21:51:37 +08:00
|
|
|
; CHECK: [[SplitRight]]:
|
|
|
|
; CHECK: [[LoadY:%[^ ]+]] = load i32, i32* [[SlotY]]
|
|
|
|
; CHECK: br label %join
|
|
|
|
catchend:
|
|
|
|
catchendpad unwind to caller
|
|
|
|
join:
|
|
|
|
; CHECK: join:
|
|
|
|
; CHECK: %phi = phi i32 [ [[LoadX]], %[[SplitLeft]] ], [ [[LoadY]], %[[SplitRight]] ]
|
|
|
|
%phi = phi i32 [ %x, %left ], [ %y, %right ]
|
|
|
|
call void @h(i32 %phi)
|
|
|
|
br label %exit
|
|
|
|
exit:
|
|
|
|
ret void
|
|
|
|
}
|
2015-08-18 04:56:39 +08:00
|
|
|
|
|
|
|
; 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:
|
2015-08-23 08:26:33 +08:00
|
|
|
; CHECK: [[CleanupPad1:%[^ ]+]] = cleanuppad []
|
2015-08-18 04:56:39 +08:00
|
|
|
; CHECK-NEXT: call void @f()
|
2015-08-23 08:26:33 +08:00
|
|
|
; CHECK-NEXT: cleanupret [[CleanupPad1]]
|
|
|
|
%cp0 = cleanuppad []
|
2015-08-18 04:56:39 +08:00
|
|
|
br label %cleanupexit
|
|
|
|
|
|
|
|
cleanup2:
|
2015-08-23 08:26:33 +08:00
|
|
|
; CHECK: cleanuppad []
|
2015-08-18 04:56:39 +08:00
|
|
|
; CHECK-NEXT: call void @f()
|
|
|
|
; CHECK-NEXT: unreachable
|
2015-08-23 08:26:33 +08:00
|
|
|
%cp1 = cleanuppad []
|
2015-08-18 04:56:39 +08:00
|
|
|
br label %cleanupexit
|
|
|
|
|
|
|
|
cleanupexit:
|
|
|
|
call void @f()
|
2015-08-23 08:26:33 +08:00
|
|
|
cleanupret %cp0 unwind label %cleanup2
|
2015-08-18 04:56:39 +08:00
|
|
|
}
|