| ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 6 |
| ; RUN: opt -passes='simplifycfg<sink-common-insts>,verify' -S %s | FileCheck %s |
| |
| declare void @clobber1() |
| declare void @clobber2() |
| declare void @f() |
| |
| ; Both bundle operands are variable, so the calls can be sunk and the bundle |
| ; operand merged by a PHI. |
| define void @sink_variable_bundle_operands(i1 %c, i32 %a, i32 %b) { |
| ; CHECK-LABEL: define void @sink_variable_bundle_operands( |
| ; CHECK-SAME: i1 [[C:%.*]], i32 [[A:%.*]], i32 [[B:%.*]]) { |
| ; CHECK-NEXT: [[BB:.*:]] |
| ; CHECK-NEXT: br i1 [[C]], label %[[THEN:.*]], label %[[ELSE:.*]] |
| ; CHECK: [[THEN]]: |
| ; CHECK-NEXT: call void @clobber1() |
| ; CHECK-NEXT: br label %[[EXIT:.*]] |
| ; CHECK: [[ELSE]]: |
| ; CHECK-NEXT: call void @clobber2() |
| ; CHECK-NEXT: br label %[[EXIT]] |
| ; CHECK: [[EXIT]]: |
| ; CHECK-NEXT: [[B_SINK:%.*]] = phi i32 [ [[B]], %[[ELSE]] ], [ [[A]], %[[THEN]] ] |
| ; CHECK-NEXT: call void @f() [ "deopt"(i32 [[B_SINK]]) ] |
| ; CHECK-NEXT: ret void |
| ; |
| bb: |
| br i1 %c, label %then, label %else |
| |
| then: |
| call void @clobber1() |
| call void @f() [ "deopt"(i32 %a) ] |
| br label %exit |
| |
| else: |
| call void @clobber2() |
| call void @f() [ "deopt"(i32 %b) ] |
| br label %exit |
| |
| exit: |
| ret void |
| } |
| |
| ; The bundle operand of the call in %then is constant, so the calls must not be |
| ; sunk. |
| define void @no_sink_constant_bundle_operand_in_then(i1 %c, i32 %b) { |
| ; CHECK-LABEL: define void @no_sink_constant_bundle_operand_in_then( |
| ; CHECK-SAME: i1 [[C:%.*]], i32 [[B:%.*]]) { |
| ; CHECK-NEXT: [[BB:.*:]] |
| ; CHECK-NEXT: br i1 [[C]], label %[[THEN:.*]], label %[[ELSE:.*]] |
| ; CHECK: [[THEN]]: |
| ; CHECK-NEXT: call void @clobber1() |
| ; CHECK-NEXT: call void @f() [ "deopt"(i32 7) ] |
| ; CHECK-NEXT: br label %[[EXIT:.*]] |
| ; CHECK: [[ELSE]]: |
| ; CHECK-NEXT: call void @clobber2() |
| ; CHECK-NEXT: call void @f() [ "deopt"(i32 [[B]]) ] |
| ; CHECK-NEXT: br label %[[EXIT]] |
| ; CHECK: [[EXIT]]: |
| ; CHECK-NEXT: ret void |
| ; |
| bb: |
| br i1 %c, label %then, label %else |
| |
| then: |
| call void @clobber1() |
| call void @f() [ "deopt"(i32 7) ] |
| br label %exit |
| |
| else: |
| call void @clobber2() |
| call void @f() [ "deopt"(i32 %b) ] |
| br label %exit |
| |
| exit: |
| ret void |
| } |
| |
| ; Same as above, with the constant bundle operand in the other predecessor. |
| define void @no_sink_constant_bundle_operand_in_else(i1 %c, i32 %b) { |
| ; CHECK-LABEL: define void @no_sink_constant_bundle_operand_in_else( |
| ; CHECK-SAME: i1 [[C:%.*]], i32 [[B:%.*]]) { |
| ; CHECK-NEXT: [[BB:.*:]] |
| ; CHECK-NEXT: br i1 [[C]], label %[[THEN:.*]], label %[[ELSE:.*]] |
| ; CHECK: [[THEN]]: |
| ; CHECK-NEXT: call void @clobber1() |
| ; CHECK-NEXT: call void @f() [ "deopt"(i32 [[B]]) ] |
| ; CHECK-NEXT: br label %[[EXIT:.*]] |
| ; CHECK: [[ELSE]]: |
| ; CHECK-NEXT: call void @clobber2() |
| ; CHECK-NEXT: call void @f() [ "deopt"(i32 7) ] |
| ; CHECK-NEXT: br label %[[EXIT]] |
| ; CHECK: [[EXIT]]: |
| ; CHECK-NEXT: ret void |
| ; |
| bb: |
| br i1 %c, label %then, label %else |
| |
| then: |
| call void @clobber1() |
| call void @f() [ "deopt"(i32 %b) ] |
| br label %exit |
| |
| else: |
| call void @clobber2() |
| call void @f() [ "deopt"(i32 7) ] |
| br label %exit |
| |
| exit: |
| ret void |
| } |