diff options
Diffstat (limited to 'llvm/test/Transforms/SimplifyCFG/switch-on-const.ll')
| -rw-r--r-- | llvm/test/Transforms/SimplifyCFG/switch-on-const.ll | 287 |
1 files changed, 287 insertions, 0 deletions
diff --git a/llvm/test/Transforms/SimplifyCFG/switch-on-const.ll b/llvm/test/Transforms/SimplifyCFG/switch-on-const.ll new file mode 100644 index 0000000..1ab1b5e --- /dev/null +++ b/llvm/test/Transforms/SimplifyCFG/switch-on-const.ll @@ -0,0 +1,287 @@ +; 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 [ 0, [[SWITCH]] ], [ 2, [[ENTRY:%.*]] ] +; 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 +} + +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) } |
