| ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --check-globals |
| ; RUN: opt < %s -passes=simplifycfg -simplifycfg-require-and-preserve-domtree=1 -S | FileCheck %s |
| |
| declare void @f() |
| declare void @llvm.foo(i32) nounwind |
| declare void @ProcessCLRException() |
| |
| define void @test1() personality ptr @ProcessCLRException { |
| ; CHECK-LABEL: @test1( |
| ; CHECK-NEXT: entry: |
| ; CHECK-NEXT: invoke void @f() |
| ; CHECK-NEXT: to label [[EXIT:%.*]] unwind label [[EXN_DISPATCH:%.*]] |
| ; CHECK: exn.dispatch: |
| ; CHECK-NEXT: [[CS:%.*]] = catchswitch within none [label %pad1] unwind to caller |
| ; CHECK: pad1: |
| ; CHECK-NEXT: [[CP1:%.*]] = catchpad within [[CS]] [i32 1] |
| ; CHECK-NEXT: call void @llvm.foo(i32 1) |
| ; CHECK-NEXT: catchret from [[CP1]] to label [[EXIT]] |
| ; CHECK: exit: |
| ; CHECK-NEXT: ret void |
| ; |
| entry: |
| invoke void @f() |
| to label %exit unwind label %exn.dispatch |
| exn.dispatch: |
| %cs = catchswitch within none [label %pad1, label %pad2] unwind to caller |
| pad1: |
| %cp1 = catchpad within %cs [i32 1] |
| call void @llvm.foo(i32 1) |
| catchret from %cp1 to label %exit |
| pad2: |
| %cp2 = catchpad within %cs [i32 2] |
| unreachable |
| exit: |
| ret void |
| } |
| ; Remove unreachble catch2, leave catch1 as-is |
| |
| ; Remove both catchpads and the catchswitch from exn.dispatch |
| define void @test2() personality ptr @ProcessCLRException { |
| ; CHECK-LABEL: @test2( |
| ; CHECK-NEXT: entry: |
| ; CHECK-NEXT: call void @f() |
| ; CHECK-NEXT: invoke void @f() |
| ; CHECK-NEXT: to label [[VIA_CATCHSWITCH:%.*]] unwind label [[CLEANUP_INNER:%.*]] |
| ; CHECK: cleanup.inner: |
| ; CHECK-NEXT: [[CP_INNER:%.*]] = cleanuppad within none [] |
| ; CHECK-NEXT: call void @llvm.foo(i32 0) |
| ; CHECK-NEXT: cleanupret from [[CP_INNER]] unwind to caller |
| ; CHECK: via.catchswitch: |
| ; CHECK-NEXT: invoke void @f() |
| ; CHECK-NEXT: to label [[EXIT:%.*]] unwind label [[DISPATCH_INNER:%.*]] |
| ; CHECK: dispatch.inner: |
| ; CHECK-NEXT: [[CS_INNER:%.*]] = catchswitch within none [label %pad.inner] unwind to caller |
| ; CHECK: pad.inner: |
| ; CHECK-NEXT: [[CATCH_INNER:%.*]] = catchpad within [[CS_INNER]] [i32 0] |
| ; CHECK-NEXT: call void @llvm.foo(i32 1) |
| ; CHECK-NEXT: catchret from [[CATCH_INNER]] to label [[EXIT]] |
| ; CHECK: exit: |
| ; CHECK-NEXT: ret void |
| ; |
| entry: |
| invoke void @f() |
| to label %via.cleanup unwind label %exn.dispatch |
| via.cleanup: |
| invoke void @f() |
| to label %via.catchswitch unwind label %cleanup.inner |
| cleanup.inner: |
| %cp.inner = cleanuppad within none [] |
| call void @llvm.foo(i32 0) |
| cleanupret from %cp.inner unwind label %exn.dispatch |
| via.catchswitch: |
| invoke void @f() |
| to label %exit unwind label %dispatch.inner |
| dispatch.inner: |
| %cs.inner = catchswitch within none [label %pad.inner] unwind label %exn.dispatch |
| pad.inner: |
| %catch.inner = catchpad within %cs.inner [i32 0] |
| call void @llvm.foo(i32 1) |
| catchret from %catch.inner to label %exit |
| exn.dispatch: |
| %cs = catchswitch within none [label %pad1, label %pad2] unwind to caller |
| pad1: |
| catchpad within %cs [i32 1] |
| unreachable |
| pad2: |
| catchpad within %cs [i32 2] |
| unreachable |
| exit: |
| ret void |
| } |
| |
| ; Same as @test2, but exn.dispatch catchswitch has an unwind dest that |
| ; preds need to be reidrected to |
| define void @test3() personality ptr @ProcessCLRException { |
| ; CHECK-LABEL: @test3( |
| ; CHECK-NEXT: entry: |
| ; CHECK-NEXT: invoke void @f() |
| ; CHECK-NEXT: to label [[VIA_CLEANUP:%.*]] unwind label [[CLEANUP:%.*]] |
| ; CHECK: via.cleanup: |
| ; CHECK-NEXT: invoke void @f() |
| ; CHECK-NEXT: to label [[VIA_CATCHSWITCH:%.*]] unwind label [[CLEANUP_INNER:%.*]] |
| ; CHECK: cleanup.inner: |
| ; CHECK-NEXT: [[CP_INNER:%.*]] = cleanuppad within none [] |
| ; CHECK-NEXT: call void @llvm.foo(i32 0) |
| ; CHECK-NEXT: cleanupret from [[CP_INNER]] unwind label [[CLEANUP]] |
| ; CHECK: via.catchswitch: |
| ; CHECK-NEXT: invoke void @f() |
| ; CHECK-NEXT: to label [[EXIT:%.*]] unwind label [[DISPATCH_INNER:%.*]] |
| ; CHECK: dispatch.inner: |
| ; CHECK-NEXT: [[CS_INNER:%.*]] = catchswitch within none [label %pad.inner] unwind label [[CLEANUP]] |
| ; CHECK: pad.inner: |
| ; CHECK-NEXT: [[CATCH_INNER:%.*]] = catchpad within [[CS_INNER]] [i32 0] |
| ; CHECK-NEXT: call void @llvm.foo(i32 1) |
| ; CHECK-NEXT: catchret from [[CATCH_INNER]] to label [[EXIT]] |
| ; CHECK: cleanup: |
| ; CHECK-NEXT: [[CP:%.*]] = cleanuppad within none [] |
| ; CHECK-NEXT: call void @llvm.foo(i32 0) |
| ; CHECK-NEXT: cleanupret from [[CP]] unwind to caller |
| ; CHECK: exit: |
| ; CHECK-NEXT: ret void |
| ; |
| entry: |
| invoke void @f() |
| to label %via.cleanup unwind label %exn.dispatch |
| via.cleanup: |
| invoke void @f() |
| to label %via.catchswitch unwind label %cleanup.inner |
| cleanup.inner: |
| %cp.inner = cleanuppad within none [] |
| call void @llvm.foo(i32 0) |
| cleanupret from %cp.inner unwind label %exn.dispatch |
| via.catchswitch: |
| invoke void @f() |
| to label %exit unwind label %dispatch.inner |
| dispatch.inner: |
| %cs.inner = catchswitch within none [label %pad.inner] unwind label %exn.dispatch |
| pad.inner: |
| %catch.inner = catchpad within %cs.inner [i32 0] |
| call void @llvm.foo(i32 1) |
| catchret from %catch.inner to label %exit |
| exn.dispatch: |
| %cs = catchswitch within none [label %pad1, label %pad2] unwind label %cleanup |
| pad1: |
| catchpad within %cs [i32 1] |
| unreachable |
| pad2: |
| catchpad within %cs [i32 2] |
| unreachable |
| cleanup: |
| %cp = cleanuppad within none [] |
| call void @llvm.foo(i32 0) |
| cleanupret from %cp unwind to caller |
| exit: |
| ret void |
| } |
| ;. |
| ; CHECK: attributes #[[ATTR0:[0-9]+]] = { nounwind } |
| ;. |