| ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py | |
| ; RUN: opt < %s -passes=simplifycfg -simplifycfg-require-and-preserve-domtree=1 -S | FileCheck %s | |
| ; Test basic folding to a conditional branch. | |
| define i32 @foo(i64 %x, i64 %y) nounwind { | |
| ; CHECK-LABEL: @foo( | |
| ; CHECK-NEXT: entry: | |
| ; CHECK-NEXT: [[EQ:%.*]] = icmp eq i64 [[X:%.*]], [[Y:%.*]] | |
| ; CHECK-NEXT: br i1 [[EQ]], label [[B:%.*]], label [[SWITCH:%.*]] | |
| ; CHECK: switch: | |
| ; CHECK-NEXT: [[LT:%.*]] = icmp slt i64 [[X]], [[Y]] | |
| ; CHECK-NEXT: br i1 [[LT]], label [[A:%.*]], label [[B]] | |
| ; CHECK: common.ret: | |
| ; CHECK-NEXT: [[COMMON_RET_OP:%.*]] = phi i32 [ 1, [[A]] ], [ [[RETVAL:%.*]], [[B]] ] | |
| ; CHECK-NEXT: ret i32 [[COMMON_RET_OP]] | |
| ; CHECK: a: | |
| ; CHECK-NEXT: tail call void @bees.a() #[[ATTR0:[0-9]+]] | |
| ; CHECK-NEXT: br label [[COMMON_RET:%.*]] | |
| ; CHECK: b: | |
| ; CHECK-NEXT: [[RETVAL]] = phi i32 [ 2, [[ENTRY:%.*]] ], [ 0, [[SWITCH]] ] | |
| ; CHECK-NEXT: tail call void @bees.b() #[[ATTR0]] | |
| ; CHECK-NEXT: br label [[COMMON_RET]] | |
| ; | |
| entry: | |
| %eq = icmp eq i64 %x, %y | |
| br i1 %eq, label %b, label %switch | |
| switch: | |
| %lt = icmp slt i64 %x, %y | |
| %qux = select i1 %lt, i32 0, i32 2 | |
| switch i32 %qux, label %bees [ | |
| i32 0, label %a | |
| i32 1, label %b | |
| i32 2, label %b | |
| ] | |
| a: | |
| tail call void @bees.a() nounwind | |
| ret i32 1 | |
| b: | |
| %retval = phi i32 [0, %switch], [0, %switch], [2, %entry] | |
| tail call void @bees.b() nounwind | |
| ret i32 %retval | |
| bees: | |
| tail call void @llvm.trap() nounwind | |
| unreachable | |
| } | |
| ; Test basic folding to an unconditional branch. | |
| define i32 @bar(i64 %x, i64 %y) nounwind { | |
| ; CHECK-LABEL: @bar( | |
| ; CHECK-NEXT: entry: | |
| ; CHECK-NEXT: tail call void @bees.a() #[[ATTR0]] | |
| ; CHECK-NEXT: ret i32 0 | |
| ; | |
| entry: | |
| %lt = icmp slt i64 %x, %y | |
| %qux = select i1 %lt, i32 0, i32 2 | |
| switch i32 %qux, label %bees [ | |
| i32 0, label %a | |
| i32 1, label %b | |
| i32 2, label %a | |
| ] | |
| a: | |
| %retval = phi i32 [0, %entry], [0, %entry], [1, %b] | |
| tail call void @bees.a() nounwind | |
| ret i32 0 | |
| b: | |
| tail call void @bees.b() nounwind | |
| br label %a | |
| bees: | |
| tail call void @llvm.trap() nounwind | |
| unreachable | |
| } | |
| ; Test the edge case where both values from the select are the default case. | |
| define void @bazz(i64 %x, i64 %y) nounwind { | |
| ; CHECK-LABEL: @bazz( | |
| ; CHECK-NEXT: entry: | |
| ; CHECK-NEXT: tail call void @bees.b() #[[ATTR0]] | |
| ; CHECK-NEXT: ret void | |
| ; | |
| entry: | |
| %lt = icmp slt i64 %x, %y | |
| %qux = select i1 %lt, i32 10, i32 12 | |
| switch i32 %qux, label %b [ | |
| i32 0, label %a | |
| i32 1, label %bees | |
| i32 2, label %bees | |
| ] | |
| a: | |
| tail call void @bees.a() nounwind | |
| ret void | |
| b: | |
| tail call void @bees.b() nounwind | |
| ret void | |
| bees: | |
| tail call void @llvm.trap() | |
| unreachable | |
| } | |
| ; Test the edge case where both values from the select are equal. | |
| define void @quux(i64 %x, i64 %y) nounwind { | |
| ; CHECK-LABEL: @quux( | |
| ; CHECK-NEXT: entry: | |
| ; CHECK-NEXT: tail call void @bees.a() #[[ATTR0]] | |
| ; CHECK-NEXT: ret void | |
| ; | |
| entry: | |
| %lt = icmp slt i64 %x, %y | |
| %qux = select i1 %lt, i32 0, i32 0 | |
| switch i32 %qux, label %b [ | |
| i32 0, label %a | |
| i32 1, label %bees | |
| i32 2, label %bees | |
| ] | |
| a: | |
| tail call void @bees.a() nounwind | |
| ret void | |
| b: | |
| tail call void @bees.b() nounwind | |
| ret void | |
| bees: | |
| tail call void @llvm.trap() | |
| unreachable | |
| } | |
| ; A final test, for phi node munging. | |
| define i32 @xyzzy(i64 %x, i64 %y) { | |
| ; CHECK-LABEL: @xyzzy( | |
| ; CHECK-NEXT: entry: | |
| ; CHECK-NEXT: [[EQ:%.*]] = icmp eq i64 [[X:%.*]], [[Y:%.*]] | |
| ; CHECK-NEXT: [[LT:%.*]] = icmp slt i64 [[X]], [[Y]] | |
| ; CHECK-NEXT: [[SPEC_SELECT:%.*]] = select i1 [[LT]], i32 -1, i32 1 | |
| ; CHECK-NEXT: [[COMMON_RET_OP:%.*]] = select i1 [[EQ]], i32 0, i32 [[SPEC_SELECT]] | |
| ; CHECK-NEXT: ret i32 [[COMMON_RET_OP]] | |
| ; | |
| entry: | |
| %eq = icmp eq i64 %x, %y | |
| br i1 %eq, label %r, label %cont | |
| cont: | |
| %lt = icmp slt i64 %x, %y | |
| %qux = select i1 %lt, i32 0, i32 2 | |
| switch i32 %qux, label %bees [ | |
| i32 0, label %a | |
| i32 1, label %r | |
| i32 2, label %r | |
| ] | |
| r: | |
| %val = phi i32 [0, %entry], [1, %cont], [1, %cont] | |
| ret i32 %val | |
| a: | |
| ret i32 -1 | |
| bees: | |
| tail call void @llvm.trap() | |
| unreachable | |
| } | |
| define void @pr165179(i1 %cond) { | |
| ; CHECK-LABEL: @pr165179( | |
| ; CHECK-NEXT: entry: | |
| ; CHECK-NEXT: br i1 [[COND:%.*]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]] | |
| ; CHECK: if.then: | |
| ; CHECK-NEXT: tail call void @bees.a() #[[ATTR0]] | |
| ; CHECK-NEXT: br label [[SWITCHBB:%.*]] | |
| ; CHECK: if.else: | |
| ; CHECK-NEXT: tail call void @bees.b() #[[ATTR0]] | |
| ; CHECK-NEXT: br label [[SWITCHBB]] | |
| ; CHECK: exit: | |
| ; CHECK-NEXT: tail call void @bees.a() #[[ATTR0]] | |
| ; CHECK-NEXT: ret void | |
| ; | |
| entry: | |
| br i1 %cond, label %if.then, label %if.else | |
| if.then: | |
| tail call void @bees.a() nounwind | |
| br label %switchbb | |
| if.else: | |
| tail call void @bees.b() nounwind | |
| br label %switchbb | |
| switchbb: | |
| %cond1 = phi i32 [ 1, %if.else ], [ -1, %if.then ] | |
| switch i32 %cond1, label %default [ | |
| i32 1, label %exit | |
| i32 -1, label %exit | |
| ] | |
| exit: | |
| tail call void @bees.a() nounwind | |
| ret void | |
| default: | |
| tail call void @bees.b() nounwind | |
| ret void | |
| } | |
| define void @switch_remove_dead_case_phi(i1 %cond1, i1 %cond2) { | |
| ; CHECK-LABEL: @switch_remove_dead_case_phi( | |
| ; CHECK-NEXT: entry: | |
| ; CHECK-NEXT: br i1 [[COND1:%.*]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]] | |
| ; CHECK: if.then: | |
| ; CHECK-NEXT: tail call void @bees.a() #[[ATTR0]] | |
| ; CHECK-NEXT: br i1 [[COND2:%.*]], label [[SWITCHBB:%.*]], label [[IF_ELSE]] | |
| ; CHECK: if.else: | |
| ; CHECK-NEXT: [[PHI:%.*]] = phi i32 [ 3, [[ENTRY:%.*]] ], [ -1, [[IF_THEN]] ] | |
| ; CHECK-NEXT: tail call void @bees.b() #[[ATTR0]] | |
| ; CHECK-NEXT: br label [[SWITCHBB]] | |
| ; CHECK: switchbb: | |
| ; CHECK-NEXT: [[COND:%.*]] = phi i32 [ [[PHI]], [[IF_ELSE]] ], [ 5, [[IF_THEN]] ] | |
| ; CHECK-NEXT: [[COND3:%.*]] = icmp eq i32 [[COND]], -1 | |
| ; CHECK-NEXT: br i1 [[COND3]], label [[EXIT:%.*]], label [[DEFAULT:%.*]] | |
| ; CHECK: common.ret: | |
| ; CHECK-NEXT: ret void | |
| ; CHECK: exit: | |
| ; CHECK-NEXT: tail call void @bees.a() #[[ATTR0]] | |
| ; CHECK-NEXT: br label [[COMMON_RET:%.*]] | |
| ; CHECK: default: | |
| ; CHECK-NEXT: tail call void @bees.b() #[[ATTR0]] | |
| ; CHECK-NEXT: br label [[COMMON_RET]] | |
| ; | |
| entry: | |
| br i1 %cond1, label %if.then, label %if.else | |
| if.then: | |
| tail call void @bees.a() nounwind | |
| br i1 %cond2, label %switchbb, label %if.else | |
| if.else: | |
| %phi = phi i32 [ 3, %entry ], [ -1, %if.then ] | |
| tail call void @bees.b() nounwind | |
| br label %switchbb | |
| switchbb: | |
| %cond = phi i32 [ %phi, %if.else ], [ 5, %if.then ] | |
| switch i32 %cond, label %default [ | |
| i32 1, label %exit | |
| i32 -1, label %exit | |
| ] | |
| exit: | |
| tail call void @bees.a() nounwind | |
| ret void | |
| default: | |
| tail call void @bees.b() nounwind | |
| ret void | |
| } | |
| define void @switch_remove_dead_case_select(i1 %cond1, i1 %cond2) { | |
| ; CHECK-LABEL: @switch_remove_dead_case_select( | |
| ; CHECK-NEXT: entry: | |
| ; CHECK-NEXT: [[X:%.*]] = select i1 [[COND1:%.*]], i32 -1, i32 3 | |
| ; CHECK-NEXT: [[Y:%.*]] = select i1 [[COND2:%.*]], i32 [[X]], i32 5 | |
| ; CHECK-NEXT: [[COND:%.*]] = icmp eq i32 [[Y]], -1 | |
| ; CHECK-NEXT: br i1 [[COND]], label [[EXIT:%.*]], label [[DEFAULT:%.*]] | |
| ; CHECK: common.ret: | |
| ; CHECK-NEXT: ret void | |
| ; CHECK: exit: | |
| ; CHECK-NEXT: tail call void @bees.a() #[[ATTR0]] | |
| ; CHECK-NEXT: br label [[COMMON_RET:%.*]] | |
| ; CHECK: default: | |
| ; CHECK-NEXT: tail call void @bees.b() #[[ATTR0]] | |
| ; CHECK-NEXT: br label [[COMMON_RET]] | |
| ; | |
| entry: | |
| %x = select i1 %cond1, i32 -1, i32 3 | |
| %y = select i1 %cond2, i32 %x, i32 5 | |
| switch i32 %y, label %default [ | |
| i32 1, label %exit | |
| i32 -1, label %exit | |
| ] | |
| exit: | |
| tail call void @bees.a() nounwind | |
| ret void | |
| default: | |
| tail call void @bees.b() nounwind | |
| ret void | |
| } | |
| @G = constant i16 zeroinitializer, align 1 | |
| ; Make sure we don't remove edges when the condition is a unresolved constant expression. | |
| define i16 @switch_on_nonimmediate_constant_expr() { | |
| ; CHECK-LABEL: @switch_on_nonimmediate_constant_expr( | |
| ; CHECK-NEXT: entry: | |
| ; CHECK-NEXT: [[SWITCH_SELECTCMP:%.*]] = icmp eq i32 ptrtoint (ptr @G to i32), 2 | |
| ; CHECK-NEXT: [[SWITCH_SELECT:%.*]] = select i1 [[SWITCH_SELECTCMP]], i16 456, i16 789 | |
| ; CHECK-NEXT: [[SWITCH_SELECTCMP1:%.*]] = icmp eq i32 ptrtoint (ptr @G to i32), 1 | |
| ; CHECK-NEXT: [[SWITCH_SELECT2:%.*]] = select i1 [[SWITCH_SELECTCMP1]], i16 123, i16 [[SWITCH_SELECT]] | |
| ; CHECK-NEXT: ret i16 [[SWITCH_SELECT2]] | |
| ; | |
| entry: | |
| switch i32 ptrtoint (ptr @G to i32), label %sw.default [ | |
| i32 1, label %sw.bb | |
| i32 2, label %sw.bb1 | |
| ] | |
| sw.bb: | |
| ret i16 123 | |
| sw.bb1: | |
| ret i16 456 | |
| sw.default: | |
| ret i16 789 | |
| } | |
| declare void @llvm.trap() nounwind noreturn | |
| declare void @bees.a() nounwind | |
| declare void @bees.b() nounwind | |
| ; CHECK: attributes #1 = { cold noreturn nounwind memory(inaccessiblemem: write) } |