| ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py | |
| ; RUN: opt < %s -passes=lower-switch -S | FileCheck %s | |
| ; Check that we do not generate redundant comparisons that would have results | |
| ; known at compile time due to limited range of the value being switch'ed over. | |
| define i32 @test1(i32 %val) { | |
| ; CHECK-LABEL: @test1( | |
| ; CHECK-NEXT: entry: | |
| ; CHECK-NEXT: [[TRUNC:%.*]] = trunc i32 [[VAL:%.*]] to i2 | |
| ; CHECK-NEXT: br label [[NODEBLOCK:%.*]] | |
| ; CHECK: NodeBlock: | |
| ; CHECK-NEXT: [[PIVOT:%.*]] = icmp slt i2 [[TRUNC]], 1 | |
| ; CHECK-NEXT: br i1 [[PIVOT]], label [[LEAFBLOCK:%.*]], label [[CASE_1:%.*]] | |
| ; CHECK: LeafBlock: | |
| ; CHECK-NEXT: [[SWITCHLEAF:%.*]] = icmp eq i2 [[TRUNC]], -2 | |
| ; CHECK-NEXT: br i1 [[SWITCHLEAF]], label [[CASE_2:%.*]], label [[CASE_D:%.*]] | |
| ; CHECK: case.1: | |
| ; CHECK-NEXT: [[RES1:%.*]] = call i32 @case1() | |
| ; CHECK-NEXT: br label [[EXIT:%.*]] | |
| ; CHECK: case.2: | |
| ; CHECK-NEXT: [[RES2:%.*]] = call i32 @case2() | |
| ; CHECK-NEXT: br label [[EXIT]] | |
| ; CHECK: case.D: | |
| ; CHECK-NEXT: [[RESD:%.*]] = call i32 @caseD() | |
| ; CHECK-NEXT: br label [[EXIT]] | |
| ; CHECK: exit: | |
| ; CHECK-NEXT: [[RES:%.*]] = phi i32 [ [[RES1]], [[CASE_1]] ], [ [[RES2]], [[CASE_2]] ], [ [[RESD]], [[CASE_D]] ] | |
| ; CHECK-NEXT: ret i32 [[RES]] | |
| ; | |
| entry: | |
| %trunc = trunc i32 %val to i2 | |
| switch i2 %trunc, label %case.D [ | |
| i2 1, label %case.1 ; i2 1 | |
| i2 2, label %case.2 ; i2 -2 | |
| ] | |
| ; It's known that %val can not be less than -2 or greater than 1 | |
| case.1: | |
| %res1 = call i32 @case1() | |
| br label %exit | |
| case.2: | |
| %res2 = call i32 @case2() | |
| br label %exit | |
| case.D: | |
| %resD = call i32 @caseD() | |
| br label %exit | |
| exit: | |
| %res = phi i32 [ %res1, %case.1 ], [ %res2, %case.2 ], [ %resD, %case.D ] | |
| ret i32 %res | |
| } | |
| ; Check that we do not generate redundant comparisons that would have results | |
| ; known at compile time due to limited range of the value being switch'ed over. | |
| define i32 @test2() { | |
| ; CHECK-LABEL: @test2( | |
| ; CHECK-NEXT: entry: | |
| ; CHECK-NEXT: [[VAL:%.*]] = call i32 @getVal(), !range [[RNG0:![0-9]+]] | |
| ; CHECK-NEXT: br label [[NODEBLOCK:%.*]] | |
| ; CHECK: NodeBlock: | |
| ; CHECK-NEXT: [[PIVOT:%.*]] = icmp slt i32 [[VAL]], 2 | |
| ; CHECK-NEXT: br i1 [[PIVOT]], label [[CASE_1:%.*]], label [[LEAFBLOCK:%.*]] | |
| ; CHECK: LeafBlock: | |
| ; CHECK-NEXT: [[SWITCHLEAF:%.*]] = icmp eq i32 [[VAL]], 2 | |
| ; CHECK-NEXT: br i1 [[SWITCHLEAF]], label [[CASE_2:%.*]], label [[CASE_D:%.*]] | |
| ; CHECK: case.1: | |
| ; CHECK-NEXT: [[RES1:%.*]] = call i32 @case1() | |
| ; CHECK-NEXT: br label [[EXIT:%.*]] | |
| ; CHECK: case.2: | |
| ; CHECK-NEXT: [[RES2:%.*]] = call i32 @case2() | |
| ; CHECK-NEXT: br label [[EXIT]] | |
| ; CHECK: case.D: | |
| ; CHECK-NEXT: [[RESD:%.*]] = call i32 @caseD() | |
| ; CHECK-NEXT: br label [[EXIT]] | |
| ; CHECK: exit: | |
| ; CHECK-NEXT: [[RES:%.*]] = phi i32 [ [[RES1]], [[CASE_1]] ], [ [[RES2]], [[CASE_2]] ], [ [[RESD]], [[CASE_D]] ] | |
| ; CHECK-NEXT: ret i32 [[RES]] | |
| ; | |
| entry: | |
| %val = call i32 @getVal(), !range !0 | |
| switch i32 %val, label %case.D [ | |
| i32 1, label %case.1 | |
| i32 2, label %case.2 | |
| ] | |
| ; It's known that %val can not be less than 1 | |
| case.1: | |
| %res1 = call i32 @case1() | |
| br label %exit | |
| case.2: | |
| %res2 = call i32 @case2() | |
| br label %exit | |
| case.D: | |
| %resD = call i32 @caseD() | |
| br label %exit | |
| exit: | |
| %res = phi i32 [ %res1, %case.1 ], [ %res2, %case.2 ], [ %resD, %case.D ] | |
| ret i32 %res | |
| } | |
| ; Corner case: | |
| ; 1) some of the non-default cases are unreachable due to the !range constraint, | |
| ; 2) the default case is unreachable as non-default cases cover the range fully. | |
| define i32 @test3() { | |
| ; CHECK-LABEL: @test3( | |
| ; CHECK-NEXT: entry: | |
| ; CHECK-NEXT: [[VAL:%.*]] = call i32 @getVal(), !range [[RNG1:![0-9]+]] | |
| ; CHECK-NEXT: br label [[LEAFBLOCK:%.*]] | |
| ; CHECK: LeafBlock: | |
| ; CHECK-NEXT: [[SWITCHLEAF:%.*]] = icmp eq i32 [[VAL]], 2 | |
| ; CHECK-NEXT: br i1 [[SWITCHLEAF]], label [[CASE_2:%.*]], label [[CASE_1:%.*]] | |
| ; CHECK: case.1: | |
| ; CHECK-NEXT: [[RES1:%.*]] = call i32 @case1() | |
| ; CHECK-NEXT: br label [[EXIT:%.*]] | |
| ; CHECK: case.2: | |
| ; CHECK-NEXT: [[RES2:%.*]] = call i32 @case2() | |
| ; CHECK-NEXT: br label [[EXIT]] | |
| ; CHECK: exit: | |
| ; CHECK-NEXT: [[RES:%.*]] = phi i32 [ [[RES1]], [[CASE_1]] ], [ [[RES2]], [[CASE_2]] ] | |
| ; CHECK-NEXT: ret i32 [[RES]] | |
| ; | |
| entry: | |
| %val = call i32 @getVal(), !range !1 | |
| switch i32 %val, label %case.D [ | |
| i32 1, label %case.1 | |
| i32 2, label %case.2 | |
| i32 3, label %case.1 | |
| ] | |
| case.1: | |
| %res1 = call i32 @case1() | |
| br label %exit | |
| case.2: | |
| %res2 = call i32 @case2() | |
| br label %exit | |
| case.D: | |
| %resD = call i32 @caseD() | |
| br label %exit | |
| exit: | |
| %res = phi i32 [ %res1, %case.1 ], [ %res2, %case.2 ], [ %resD, %case.D ] | |
| ret i32 %res | |
| } | |
| ; Corner case: | |
| ; 1) some of the non-default cases are unreachable due to the !range constraint, | |
| ; 2) the default case is still reachable as non-default cases do not cover the | |
| ; range fully. | |
| define i32 @test4() { | |
| ; CHECK-LABEL: @test4( | |
| ; CHECK-NEXT: entry: | |
| ; CHECK-NEXT: [[VAL:%.*]] = call i32 @getVal(), !range [[RNG2:![0-9]+]] | |
| ; CHECK-NEXT: br label [[NODEBLOCK:%.*]] | |
| ; CHECK: NodeBlock: | |
| ; CHECK-NEXT: [[PIVOT:%.*]] = icmp slt i32 [[VAL]], 2 | |
| ; CHECK-NEXT: br i1 [[PIVOT]], label [[CASE_1:%.*]], label [[LEAFBLOCK:%.*]] | |
| ; CHECK: LeafBlock: | |
| ; CHECK-NEXT: [[SWITCHLEAF:%.*]] = icmp eq i32 [[VAL]], 2 | |
| ; CHECK-NEXT: br i1 [[SWITCHLEAF]], label [[CASE_2:%.*]], label [[CASE_D:%.*]] | |
| ; CHECK: case.1: | |
| ; CHECK-NEXT: [[RES1:%.*]] = call i32 @case1() | |
| ; CHECK-NEXT: br label [[EXIT:%.*]] | |
| ; CHECK: case.2: | |
| ; CHECK-NEXT: [[RES2:%.*]] = call i32 @case2() | |
| ; CHECK-NEXT: br label [[EXIT]] | |
| ; CHECK: case.D: | |
| ; CHECK-NEXT: [[RESD:%.*]] = call i32 @caseD() | |
| ; CHECK-NEXT: br label [[EXIT]] | |
| ; CHECK: exit: | |
| ; CHECK-NEXT: [[RES:%.*]] = phi i32 [ [[RES1]], [[CASE_1]] ], [ [[RES2]], [[CASE_2]] ], [ [[RESD]], [[CASE_D]] ] | |
| ; CHECK-NEXT: ret i32 [[RES]] | |
| ; | |
| entry: | |
| %val = call i32 @getVal(), !range !2 | |
| switch i32 %val, label %case.D [ | |
| i32 1, label %case.1 | |
| i32 2, label %case.2 | |
| ] | |
| case.1: | |
| %res1 = call i32 @case1() | |
| br label %exit | |
| case.2: | |
| %res2 = call i32 @case2() | |
| br label %exit | |
| case.D: | |
| %resD = call i32 @caseD() | |
| br label %exit | |
| exit: | |
| %res = phi i32 [ %res1, %case.1 ], [ %res2, %case.2 ], [ %resD, %case.D ] | |
| ret i32 %res | |
| } | |
| ; Corner case: | |
| ; 1) some of the non-default cases are unreachable due to the !range constraint, | |
| ; 2) the default case appears to be unreachable as non-default cases cover the | |
| ; range fully, but its basic block actually is reachable from the switch via | |
| ; one of the non-default cases. | |
| define i32 @test5(i1 %cond) { | |
| ; CHECK-LABEL: @test5( | |
| ; CHECK-NEXT: entry: | |
| ; CHECK-NEXT: br i1 [[COND:%.*]], label [[SWITCH:%.*]], label [[CASE_D:%.*]] | |
| ; CHECK: switch: | |
| ; CHECK-NEXT: [[VAL:%.*]] = call i32 @getVal(), !range [[RNG1]] | |
| ; CHECK-NEXT: br label [[NODEBLOCK:%.*]] | |
| ; CHECK: NodeBlock: | |
| ; CHECK-NEXT: [[PIVOT:%.*]] = icmp slt i32 [[VAL]], 3 | |
| ; CHECK-NEXT: br i1 [[PIVOT]], label [[LEAFBLOCK:%.*]], label [[CASE_1:%.*]] | |
| ; CHECK: LeafBlock: | |
| ; CHECK-NEXT: [[SWITCHLEAF:%.*]] = icmp eq i32 [[VAL]], 1 | |
| ; CHECK-NEXT: br i1 [[SWITCHLEAF]], label [[CASE_1]], label [[CASE_D]] | |
| ; CHECK: case.1: | |
| ; CHECK-NEXT: [[RES1:%.*]] = call i32 @case1() | |
| ; CHECK-NEXT: br label [[EXIT:%.*]] | |
| ; CHECK: case.D: | |
| ; CHECK-NEXT: [[DELTA:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ 20, [[LEAFBLOCK]] ] | |
| ; CHECK-NEXT: [[RESD_TMP:%.*]] = call i32 @caseD() | |
| ; CHECK-NEXT: [[RESD:%.*]] = add i32 [[RESD_TMP]], [[DELTA]] | |
| ; CHECK-NEXT: br label [[EXIT]] | |
| ; CHECK: exit: | |
| ; CHECK-NEXT: [[RES:%.*]] = phi i32 [ [[RES1]], [[CASE_1]] ], [ [[RESD]], [[CASE_D]] ] | |
| ; CHECK-NEXT: ret i32 [[RES]] | |
| ; | |
| entry: | |
| br i1 %cond, label %switch, label %case.D | |
| switch: | |
| %val = call i32 @getVal(), !range !1 | |
| switch i32 %val, label %case.D [ | |
| i32 1, label %case.1 | |
| i32 2, label %case.D | |
| i32 3, label %case.1 | |
| ] | |
| case.1: | |
| %res1 = call i32 @case1() | |
| br label %exit | |
| case.D: | |
| %delta = phi i32 [ 0, %entry ], [ 20, %switch ], [ 20, %switch ] | |
| %resD.tmp = call i32 @caseD() | |
| %resD = add i32 %resD.tmp, %delta | |
| br label %exit | |
| exit: | |
| %res = phi i32 [ %res1, %case.1 ], [ %resD, %case.D ] | |
| ret i32 %res | |
| } | |
| ; Corner case: | |
| ; 1) some of the non-default cases are unreachable due to the !range constraint, | |
| ; 2) the default case appears to be unreachable as non-default cases cover the | |
| ; range fully, but its basic block actually is reachable, though, from a | |
| ; different basic block, not the switch itself. | |
| define i32 @test6(i1 %cond) { | |
| ; CHECK-LABEL: @test6( | |
| ; CHECK-NEXT: entry: | |
| ; CHECK-NEXT: br i1 [[COND:%.*]], label [[SWITCH:%.*]], label [[CASE_D:%.*]] | |
| ; CHECK: switch: | |
| ; CHECK-NEXT: [[VAL:%.*]] = call i32 @getVal(), !range [[RNG1]] | |
| ; CHECK-NEXT: br label [[LEAFBLOCK:%.*]] | |
| ; CHECK: LeafBlock: | |
| ; CHECK-NEXT: [[SWITCHLEAF:%.*]] = icmp eq i32 [[VAL]], 2 | |
| ; CHECK-NEXT: br i1 [[SWITCHLEAF]], label [[CASE_2:%.*]], label [[CASE_1:%.*]] | |
| ; CHECK: case.1: | |
| ; CHECK-NEXT: [[RES1:%.*]] = call i32 @case1() | |
| ; CHECK-NEXT: br label [[EXIT:%.*]] | |
| ; CHECK: case.2: | |
| ; CHECK-NEXT: [[RES2:%.*]] = call i32 @case2() | |
| ; CHECK-NEXT: br label [[EXIT]] | |
| ; CHECK: case.D: | |
| ; CHECK-NEXT: [[RESD_TMP:%.*]] = call i32 @caseD() | |
| ; CHECK-NEXT: [[RESD:%.*]] = add i32 [[RESD_TMP]], 0 | |
| ; CHECK-NEXT: br label [[EXIT]] | |
| ; CHECK: exit: | |
| ; CHECK-NEXT: [[RES:%.*]] = phi i32 [ [[RES1]], [[CASE_1]] ], [ [[RES2]], [[CASE_2]] ], [ [[RESD]], [[CASE_D]] ] | |
| ; CHECK-NEXT: ret i32 [[RES]] | |
| ; | |
| entry: | |
| br i1 %cond, label %switch, label %case.D | |
| switch: | |
| %val = call i32 @getVal(), !range !1 | |
| switch i32 %val, label %case.D [ | |
| i32 1, label %case.1 | |
| i32 2, label %case.2 | |
| i32 3, label %case.1 | |
| ] | |
| case.1: | |
| %res1 = call i32 @case1() | |
| br label %exit | |
| case.2: | |
| %res2 = call i32 @case2() | |
| br label %exit | |
| case.D: | |
| %delta = phi i32 [ 0, %entry ], [ 20, %switch ] | |
| %resD.tmp = call i32 @caseD() | |
| %resD = add i32 %resD.tmp, %delta | |
| br label %exit | |
| exit: | |
| %res = phi i32 [ %res1, %case.1 ], [ %res2, %case.2 ], [ %resD, %case.D ] | |
| ret i32 %res | |
| } | |
| ; Corner case: | |
| ; 1) switch appears to have a non-empty set of non-default cases, but all of | |
| ; them reference the default case basic block. | |
| define i32 @test7(i1 %cond) { | |
| ; CHECK-LABEL: @test7( | |
| ; CHECK-NEXT: entry: | |
| ; CHECK-NEXT: br i1 [[COND:%.*]], label [[SWITCH:%.*]], label [[CASE_D:%.*]] | |
| ; CHECK: switch: | |
| ; CHECK-NEXT: [[VAL:%.*]] = call i32 @getVal(), !range [[RNG1]] | |
| ; CHECK-NEXT: br label [[CASE_D]] | |
| ; CHECK: case.D: | |
| ; CHECK-NEXT: [[DELTA:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ 20, [[SWITCH]] ] | |
| ; CHECK-NEXT: [[RESD_TMP:%.*]] = call i32 @caseD() | |
| ; CHECK-NEXT: [[RESD:%.*]] = add i32 [[RESD_TMP]], [[DELTA]] | |
| ; CHECK-NEXT: br label [[EXIT:%.*]] | |
| ; CHECK: exit: | |
| ; CHECK-NEXT: ret i32 [[RESD]] | |
| ; | |
| entry: | |
| br i1 %cond, label %switch, label %case.D | |
| switch: | |
| %val = call i32 @getVal(), !range !1 | |
| switch i32 %val, label %case.D [ | |
| i32 2, label %case.D | |
| ] | |
| case.D: | |
| %delta = phi i32 [ 0, %entry ], [ 20, %switch ], [ 20, %switch ] | |
| %resD.tmp = call i32 @caseD() | |
| %resD = add i32 %resD.tmp, %delta | |
| br label %exit | |
| exit: | |
| ret i32 %resD | |
| } | |
| ; Corner case: | |
| ; 1) some of the non-default cases are unreachable due to the !range constraint, | |
| ; 2) the default case appears to be unreachable as non-default cases cover the | |
| ; range fully, but its basic block actually is reachable from the switch via | |
| ; one of the non-default cases, | |
| ; 3) such cases lie at the boundary of the range of values covered by | |
| ; non-default cases, and if removed, do not change the fact that the rest of | |
| ; the cases fully covers the value range. | |
| define i32 @test8(i1 %cond) { | |
| ; CHECK-LABEL: @test8( | |
| ; CHECK-NEXT: entry: | |
| ; CHECK-NEXT: br i1 [[COND:%.*]], label [[SWITCH:%.*]], label [[CASE_D:%.*]] | |
| ; CHECK: switch: | |
| ; CHECK-NEXT: [[VAL:%.*]] = call i32 @getVal(), !range [[RNG3:![0-9]+]] | |
| ; CHECK-NEXT: br label [[LEAFBLOCK:%.*]] | |
| ; CHECK: LeafBlock: | |
| ; CHECK-NEXT: [[SWITCHLEAF:%.*]] = icmp eq i32 [[VAL]], 2 | |
| ; CHECK-NEXT: br i1 [[SWITCHLEAF]], label [[CASE_2:%.*]], label [[CASE_1:%.*]] | |
| ; CHECK: case.1: | |
| ; CHECK-NEXT: [[RES1:%.*]] = call i32 @case1() | |
| ; CHECK-NEXT: br label [[EXIT:%.*]] | |
| ; CHECK: case.2: | |
| ; CHECK-NEXT: [[RES2:%.*]] = call i32 @case2() | |
| ; CHECK-NEXT: br label [[EXIT]] | |
| ; CHECK: case.D: | |
| ; CHECK-NEXT: [[RESD_TMP:%.*]] = call i32 @caseD() | |
| ; CHECK-NEXT: [[RESD:%.*]] = add i32 [[RESD_TMP]], 0 | |
| ; CHECK-NEXT: br label [[EXIT]] | |
| ; CHECK: exit: | |
| ; CHECK-NEXT: [[RES:%.*]] = phi i32 [ [[RES1]], [[CASE_1]] ], [ [[RES2]], [[CASE_2]] ], [ [[RESD]], [[CASE_D]] ] | |
| ; CHECK-NEXT: ret i32 [[RES]] | |
| ; | |
| entry: | |
| br i1 %cond, label %switch, label %case.D | |
| switch: | |
| %val = call i32 @getVal(), !range !3 | |
| switch i32 %val, label %case.D [ | |
| i32 1, label %case.1 | |
| i32 2, label %case.2 | |
| i32 3, label %case.D | |
| ] | |
| case.1: | |
| %res1 = call i32 @case1() | |
| br label %exit | |
| case.2: | |
| %res2 = call i32 @case2() | |
| br label %exit | |
| case.D: | |
| %delta = phi i32 [ 0, %entry ], [ 20, %switch ], [ 20, %switch ] | |
| %resD.tmp = call i32 @caseD() | |
| %resD = add i32 %resD.tmp, %delta | |
| br label %exit | |
| exit: | |
| %res = phi i32 [ %res1, %case.1 ], [ %res2, %case.2 ], [ %resD, %case.D ] | |
| ret i32 %res | |
| } | |
| ; Corner case: | |
| ; 1) the default case appears to be unreachable as non-default cases cover the | |
| ; range fully, but its basic block actually is reachable from the switch via | |
| ; more than one non-default case. | |
| define i32 @test9(i1 %cond, i2 %val) { | |
| ; CHECK-LABEL: @test9( | |
| ; CHECK-NEXT: entry: | |
| ; CHECK-NEXT: br i1 [[COND:%.*]], label [[SWITCH:%.*]], label [[CASE_D:%.*]] | |
| ; CHECK: switch: | |
| ; CHECK-NEXT: br label [[LEAFBLOCK:%.*]] | |
| ; CHECK: LeafBlock: | |
| ; CHECK-NEXT: [[SWITCHLEAF:%.*]] = icmp sge i2 [[VAL:%.*]], 0 | |
| ; CHECK-NEXT: br i1 [[SWITCHLEAF]], label [[CASE_1:%.*]], label [[CASE_D]] | |
| ; CHECK: case.1: | |
| ; CHECK-NEXT: [[RES1:%.*]] = call i32 @case1() | |
| ; CHECK-NEXT: br label [[EXIT:%.*]] | |
| ; CHECK: case.D: | |
| ; CHECK-NEXT: [[DELTA:%.*]] = phi i32 [ 20, [[LEAFBLOCK]] ], [ 0, [[ENTRY:%.*]] ] | |
| ; CHECK-NEXT: [[RESD_TMP:%.*]] = call i32 @caseD() | |
| ; CHECK-NEXT: [[RESD:%.*]] = add i32 [[RESD_TMP]], [[DELTA]] | |
| ; CHECK-NEXT: br label [[EXIT]] | |
| ; CHECK: exit: | |
| ; CHECK-NEXT: [[RES:%.*]] = phi i32 [ [[RES1]], [[CASE_1]] ], [ [[RESD]], [[CASE_D]] ] | |
| ; CHECK-NEXT: ret i32 [[RES]] | |
| ; | |
| entry: | |
| br i1 %cond, label %switch, label %case.D | |
| switch: | |
| switch i2 %val, label %case.D [ | |
| i2 0, label %case.1 | |
| i2 1, label %case.1 | |
| i2 2, label %case.D | |
| i2 3, label %case.D | |
| ] | |
| case.1: | |
| %res1 = call i32 @case1() | |
| br label %exit | |
| case.D: | |
| %delta = phi i32 [20, %switch ], [ 20, %switch ], [ 20, %switch ], [ 0, %entry ] | |
| %resD.tmp = call i32 @caseD() | |
| %resD = add i32 %resD.tmp, %delta | |
| br label %exit | |
| exit: | |
| %res = phi i32 [ %res1, %case.1 ], [ %resD, %case.D ] | |
| ret i32 %res | |
| } | |
| ; Check that we do not generate redundant comparisons that would have results | |
| ; known at compile time due to limited range of the value being switch'ed over. | |
| define i32 @test10() { | |
| ; CHECK-LABEL: @test10( | |
| ; CHECK-NEXT: entry: | |
| ; CHECK-NEXT: [[VAL:%.*]] = call i32 @getVal() | |
| ; CHECK-NEXT: [[COND_LEFT:%.*]] = icmp sge i32 [[VAL]], 1 | |
| ; CHECK-NEXT: [[COND_RIGHT:%.*]] = icmp sle i32 [[VAL]], 6 | |
| ; CHECK-NEXT: [[COND:%.*]] = and i1 [[COND_LEFT]], [[COND_RIGHT]] | |
| ; CHECK-NEXT: br i1 [[COND]], label [[SWITCH:%.*]], label [[CASE_D:%.*]] | |
| ; CHECK: switch: | |
| ; CHECK-NEXT: br label [[LEAFBLOCK:%.*]] | |
| ; CHECK: LeafBlock: | |
| ; CHECK-NEXT: [[VAL_OFF:%.*]] = add i32 [[VAL]], -3 | |
| ; CHECK-NEXT: [[SWITCHLEAF:%.*]] = icmp ule i32 [[VAL_OFF]], 1 | |
| ; CHECK-NEXT: br i1 [[SWITCHLEAF]], label [[CASE_2:%.*]], label [[CASE_1:%.*]] | |
| ; CHECK: case.1: | |
| ; CHECK-NEXT: [[RES1:%.*]] = call i32 @case1() | |
| ; CHECK-NEXT: br label [[EXIT:%.*]] | |
| ; CHECK: case.2: | |
| ; CHECK-NEXT: [[RES2:%.*]] = call i32 @case2() | |
| ; CHECK-NEXT: br label [[EXIT]] | |
| ; CHECK: case.D: | |
| ; CHECK-NEXT: br label [[EXIT]] | |
| ; CHECK: exit: | |
| ; CHECK-NEXT: [[RES:%.*]] = phi i32 [ [[RES1]], [[CASE_1]] ], [ [[RES2]], [[CASE_2]] ], [ 0, [[CASE_D]] ] | |
| ; CHECK-NEXT: ret i32 [[RES]] | |
| ; | |
| entry: | |
| %val = call i32 @getVal() | |
| %cond.left = icmp sge i32 %val, 1 | |
| %cond.right = icmp sle i32 %val, 6 | |
| %cond = and i1 %cond.left, %cond.right | |
| br i1 %cond, label %switch, label %case.D | |
| switch: | |
| switch i32 %val, label %case.D [ | |
| i32 1, label %case.1 | |
| i32 2, label %case.1 | |
| i32 3, label %case.2 | |
| i32 4, label %case.2 | |
| i32 5, label %case.1 | |
| i32 6, label %case.1 | |
| ] | |
| ; It's known that %val <- [1, 6] | |
| case.1: | |
| %res1 = call i32 @case1() | |
| br label %exit | |
| case.2: | |
| %res2 = call i32 @case2() | |
| br label %exit | |
| case.D: | |
| %resD = phi i32 [ 20, %switch ], [ 0, %entry ] | |
| br label %exit | |
| exit: | |
| %res = phi i32 [ %res1, %case.1 ], [ %res2, %case.2 ], [ %resD, %case.D ] | |
| ret i32 %res | |
| } | |
| ; Check that we do not generate redundant comparisons that would have results | |
| ; known at compile time due to limited range of the value being switch'ed over. | |
| define i32 @test11() { | |
| ; CHECK-LABEL: @test11( | |
| ; CHECK-NEXT: entry: | |
| ; CHECK-NEXT: [[VAL:%.*]] = call i32 @getVal() | |
| ; CHECK-NEXT: [[VAL_ZEXT:%.*]] = zext i32 [[VAL]] to i64 | |
| ; CHECK-NEXT: br label [[NODEBLOCK:%.*]] | |
| ; CHECK: NodeBlock: | |
| ; CHECK-NEXT: [[PIVOT:%.*]] = icmp slt i64 [[VAL_ZEXT]], 1 | |
| ; CHECK-NEXT: br i1 [[PIVOT]], label [[CASE_1:%.*]], label [[LEAFBLOCK:%.*]] | |
| ; CHECK: LeafBlock: | |
| ; CHECK-NEXT: [[SWITCHLEAF:%.*]] = icmp eq i64 [[VAL_ZEXT]], 1 | |
| ; CHECK-NEXT: br i1 [[SWITCHLEAF]], label [[CASE_2:%.*]], label [[CASE_D:%.*]] | |
| ; CHECK: case.1: | |
| ; CHECK-NEXT: [[RES1:%.*]] = call i32 @case1() | |
| ; CHECK-NEXT: br label [[EXIT:%.*]] | |
| ; CHECK: case.2: | |
| ; CHECK-NEXT: [[RES2:%.*]] = call i32 @case2() | |
| ; CHECK-NEXT: br label [[EXIT]] | |
| ; CHECK: case.D: | |
| ; CHECK-NEXT: [[RESD:%.*]] = call i32 @caseD() | |
| ; CHECK-NEXT: br label [[EXIT]] | |
| ; CHECK: exit: | |
| ; CHECK-NEXT: [[RES:%.*]] = phi i32 [ [[RES1]], [[CASE_1]] ], [ [[RES2]], [[CASE_2]] ], [ [[RESD]], [[CASE_D]] ] | |
| ; CHECK-NEXT: ret i32 [[RES]] | |
| ; | |
| entry: | |
| %val = call i32 @getVal() | |
| %val.zext = zext i32 %val to i64 | |
| switch i64 %val.zext, label %case.D [ | |
| i64 0, label %case.1 | |
| i64 1, label %case.2 | |
| ] | |
| ; It's known that %val can not be less than 0 | |
| case.1: | |
| %res1 = call i32 @case1() | |
| br label %exit | |
| case.2: | |
| %res2 = call i32 @case2() | |
| br label %exit | |
| case.D: | |
| %resD = call i32 @caseD() | |
| br label %exit | |
| exit: | |
| %res = phi i32 [ %res1, %case.1 ], [ %res2, %case.2 ], [ %resD, %case.D ] | |
| ret i32 %res | |
| } | |
| ; Check that we do not generate redundant comparisons that would have results | |
| ; known at compile time due to limited range of the value being switch'ed over. | |
| define void @test12(i1 %arg) { | |
| ; CHECK-LABEL: @test12( | |
| ; CHECK-NEXT: entry: | |
| ; CHECK-NEXT: br label [[FOR_BODY:%.*]] | |
| ; CHECK: for.body: | |
| ; CHECK-NEXT: [[INDVAR:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[INC:%.*]], [[LATCH:%.*]] ] | |
| ; CHECK-NEXT: br label [[NODEBLOCK:%.*]] | |
| ; CHECK: NodeBlock: | |
| ; CHECK-NEXT: [[PIVOT:%.*]] = icmp slt i32 [[INDVAR]], 1 | |
| ; CHECK-NEXT: br i1 [[PIVOT]], label [[CASE_1:%.*]], label [[LEAFBLOCK:%.*]] | |
| ; CHECK: LeafBlock: | |
| ; CHECK-NEXT: [[SWITCHLEAF:%.*]] = icmp eq i32 [[INDVAR]], 1 | |
| ; CHECK-NEXT: br i1 [[SWITCHLEAF]], label [[CASE_2:%.*]], label [[LATCH]] | |
| ; CHECK: case.1: | |
| ; CHECK-NEXT: br label [[LATCH]] | |
| ; CHECK: case.2: | |
| ; CHECK-NEXT: br label [[LATCH]] | |
| ; CHECK: latch: | |
| ; CHECK-NEXT: [[INC]] = add nuw nsw i32 [[INDVAR]], 1 | |
| ; CHECK-NEXT: br i1 [[ARG:%.*]], label [[EXIT:%.*]], label [[FOR_BODY]] | |
| ; CHECK: exit: | |
| ; CHECK-NEXT: ret void | |
| ; | |
| entry: | |
| br label %for.body | |
| for.body: | |
| %indvar = phi i32 [ 0, %entry ], [ %inc, %latch ] | |
| switch i32 %indvar, label %latch [ | |
| i32 0, label %case.1 | |
| i32 1, label %case.2 | |
| ] | |
| ; It's known that %indvar can not be less than 0 | |
| case.1: | |
| br label %latch | |
| case.2: | |
| br label %latch | |
| latch: | |
| %inc = add nuw nsw i32 %indvar, 1 | |
| br i1 %arg, label %exit, label %for.body | |
| exit: | |
| ret void | |
| } | |
| ; Check that we do not generate redundant comparisons that would have results | |
| ; known at compile time due to limited range of the value being switch'ed over. | |
| define void @test13(i32 %val) { | |
| ; CHECK-LABEL: @test13( | |
| ; CHECK-NEXT: entry: | |
| ; CHECK-NEXT: [[TMP:%.*]] = and i32 [[VAL:%.*]], 7 | |
| ; CHECK-NEXT: br label [[BB33:%.*]] | |
| ; CHECK: bb33: | |
| ; CHECK-NEXT: br label [[LEAFBLOCK:%.*]] | |
| ; CHECK: LeafBlock: | |
| ; CHECK-NEXT: [[TMP_OFF:%.*]] = add i32 [[TMP]], -2 | |
| ; CHECK-NEXT: [[SWITCHLEAF:%.*]] = icmp ule i32 [[TMP_OFF]], 1 | |
| ; CHECK-NEXT: br i1 [[SWITCHLEAF]], label [[BB34:%.*]], label [[BB35:%.*]] | |
| ; CHECK: bb34: | |
| ; CHECK-NEXT: br label [[BB38:%.*]] | |
| ; CHECK: bb35: | |
| ; CHECK-NEXT: br label [[NODEBLOCK:%.*]] | |
| ; CHECK: NodeBlock: | |
| ; CHECK-NEXT: [[PIVOT:%.*]] = icmp slt i32 [[TMP]], 6 | |
| ; CHECK-NEXT: br i1 [[PIVOT]], label [[LEAFBLOCK1:%.*]], label [[BB37:%.*]] | |
| ; CHECK: LeafBlock1: | |
| ; CHECK-NEXT: [[SWITCHLEAF2:%.*]] = icmp sle i32 [[TMP]], 1 | |
| ; CHECK-NEXT: br i1 [[SWITCHLEAF2]], label [[BB37]], label [[BB38]] | |
| ; CHECK: bb37: | |
| ; CHECK-NEXT: br label [[BB38]] | |
| ; CHECK: bb38: | |
| ; CHECK-NEXT: br label [[BB33]] | |
| ; | |
| entry: | |
| %tmp = and i32 %val, 7 | |
| br label %bb33 | |
| bb33: | |
| switch i32 %tmp, label %bb35 [ | |
| i32 2, label %bb34 | |
| i32 3, label %bb34 | |
| ] | |
| bb34: | |
| br label %bb38 | |
| bb35: | |
| switch i32 %tmp, label %bb38 [ | |
| i32 0, label %bb37 | |
| i32 1, label %bb37 | |
| i32 6, label %bb37 | |
| i32 7, label %bb37 | |
| ] | |
| ; It's known that %tmp <- [0, 1] U [4, 7] | |
| bb37: | |
| br label %bb38 | |
| bb38: | |
| br label %bb33 | |
| } | |
| ; Check that we do not generate redundant comparisons that would have results | |
| ; known at compile time due to limited range of the value being switch'ed over. | |
| define i32 @test14() { | |
| ; CHECK-LABEL: @test14( | |
| ; CHECK-NEXT: entry: | |
| ; CHECK-NEXT: [[TMP:%.*]] = call i32 @getVal(), !range [[RNG4:![0-9]+]] | |
| ; CHECK-NEXT: [[VAL:%.*]] = call i32 @llvm.ctpop.i32(i32 [[TMP]]) | |
| ; CHECK-NEXT: br label [[NODEBLOCK:%.*]] | |
| ; CHECK: NodeBlock: | |
| ; CHECK-NEXT: [[PIVOT:%.*]] = icmp slt i32 [[VAL]], 1 | |
| ; CHECK-NEXT: br i1 [[PIVOT]], label [[CASE_1:%.*]], label [[LEAFBLOCK:%.*]] | |
| ; CHECK: LeafBlock: | |
| ; CHECK-NEXT: [[SWITCHLEAF:%.*]] = icmp eq i32 [[VAL]], 1 | |
| ; CHECK-NEXT: br i1 [[SWITCHLEAF]], label [[CASE_2:%.*]], label [[CASE_D:%.*]] | |
| ; CHECK: case.1: | |
| ; CHECK-NEXT: [[RES1:%.*]] = call i32 @case1() | |
| ; CHECK-NEXT: br label [[EXIT:%.*]] | |
| ; CHECK: case.2: | |
| ; CHECK-NEXT: [[RES2:%.*]] = call i32 @case2() | |
| ; CHECK-NEXT: br label [[EXIT]] | |
| ; CHECK: case.D: | |
| ; CHECK-NEXT: [[RESD:%.*]] = call i32 @caseD() | |
| ; CHECK-NEXT: br label [[EXIT]] | |
| ; CHECK: exit: | |
| ; CHECK-NEXT: [[RES:%.*]] = phi i32 [ [[RES1]], [[CASE_1]] ], [ [[RES2]], [[CASE_2]] ], [ [[RESD]], [[CASE_D]] ] | |
| ; CHECK-NEXT: ret i32 [[RES]] | |
| ; | |
| entry: | |
| %tmp = call i32 @getVal(), !range !4 | |
| %val = call i32 @llvm.ctpop.i32(i32 %tmp) | |
| switch i32 %val, label %case.D [ | |
| i32 0, label %case.1 | |
| i32 1, label %case.2 | |
| ] | |
| ; It's known that %val <- [0, 2] | |
| case.1: | |
| %res1 = call i32 @case1() | |
| br label %exit | |
| case.2: | |
| %res2 = call i32 @case2() | |
| br label %exit | |
| case.D: | |
| %resD = call i32 @caseD() | |
| br label %exit | |
| exit: | |
| %res = phi i32 [ %res1, %case.1 ], [ %res2, %case.2 ], [ %resD, %case.D ] | |
| ret i32 %res | |
| } | |
| ; Check that we do not generate redundant comparisons that would have results | |
| ; known at compile time due to limited range of the value being switch'ed over. | |
| define i32 @test15() { | |
| ; CHECK-LABEL: @test15( | |
| ; CHECK-NEXT: entry: | |
| ; CHECK-NEXT: [[TMP:%.*]] = call i32 @getVal() | |
| ; CHECK-NEXT: [[VAL:%.*]] = urem i32 [[TMP]], 3 | |
| ; CHECK-NEXT: br label [[NODEBLOCK:%.*]] | |
| ; CHECK: NodeBlock: | |
| ; CHECK-NEXT: [[PIVOT:%.*]] = icmp slt i32 [[VAL]], 1 | |
| ; CHECK-NEXT: br i1 [[PIVOT]], label [[CASE_1:%.*]], label [[LEAFBLOCK:%.*]] | |
| ; CHECK: LeafBlock: | |
| ; CHECK-NEXT: [[SWITCHLEAF:%.*]] = icmp eq i32 [[VAL]], 1 | |
| ; CHECK-NEXT: br i1 [[SWITCHLEAF]], label [[CASE_2:%.*]], label [[CASE_D:%.*]] | |
| ; CHECK: case.1: | |
| ; CHECK-NEXT: [[RES1:%.*]] = call i32 @case1() | |
| ; CHECK-NEXT: br label [[EXIT:%.*]] | |
| ; CHECK: case.2: | |
| ; CHECK-NEXT: [[RES2:%.*]] = call i32 @case2() | |
| ; CHECK-NEXT: br label [[EXIT]] | |
| ; CHECK: case.D: | |
| ; CHECK-NEXT: [[RESD:%.*]] = call i32 @caseD() | |
| ; CHECK-NEXT: br label [[EXIT]] | |
| ; CHECK: exit: | |
| ; CHECK-NEXT: [[RES:%.*]] = phi i32 [ [[RES1]], [[CASE_1]] ], [ [[RES2]], [[CASE_2]] ], [ [[RESD]], [[CASE_D]] ] | |
| ; CHECK-NEXT: ret i32 [[RES]] | |
| ; | |
| entry: | |
| %tmp = call i32 @getVal() | |
| %val = urem i32 %tmp, 3 | |
| switch i32 %val, label %case.D [ | |
| i32 0, label %case.1 | |
| i32 1, label %case.2 | |
| ] | |
| ; It's known that %val <- [0, 2] | |
| case.1: | |
| %res1 = call i32 @case1() | |
| br label %exit | |
| case.2: | |
| %res2 = call i32 @case2() | |
| br label %exit | |
| case.D: | |
| %resD = call i32 @caseD() | |
| br label %exit | |
| exit: | |
| %res = phi i32 [ %res1, %case.1 ], [ %res2, %case.2 ], [ %resD, %case.D ] | |
| ret i32 %res | |
| } | |
| ; Check that we do not generate redundant comparisons that would have results | |
| ; known at compile time due to limited range of the value being switch'ed over. | |
| define i32 @test16(float %f) { | |
| ; CHECK-LABEL: @test16( | |
| ; CHECK-NEXT: entry: | |
| ; CHECK-NEXT: [[I:%.*]] = fptosi float [[F:%.*]] to i64 | |
| ; CHECK-NEXT: [[CLAMP_LEFT:%.*]] = call i64 @llvm.smax.i64(i64 [[I]], i64 0) | |
| ; CHECK-NEXT: [[CLAMP:%.*]] = call i64 @llvm.smin.i64(i64 [[CLAMP_LEFT]], i64 3) | |
| ; CHECK-NEXT: br label [[LEAFBLOCK:%.*]] | |
| ; CHECK: LeafBlock: | |
| ; CHECK-NEXT: [[SWITCHLEAF:%.*]] = icmp sge i64 [[CLAMP]], 2 | |
| ; CHECK-NEXT: br i1 [[SWITCHLEAF]], label [[CASE_2:%.*]], label [[CASE_1:%.*]] | |
| ; CHECK: case.1: | |
| ; CHECK-NEXT: [[RES1:%.*]] = call i32 @case1() | |
| ; CHECK-NEXT: br label [[EXIT:%.*]] | |
| ; CHECK: case.2: | |
| ; CHECK-NEXT: [[RES2:%.*]] = call i32 @case2() | |
| ; CHECK-NEXT: br label [[EXIT]] | |
| ; CHECK: exit: | |
| ; CHECK-NEXT: [[RES:%.*]] = phi i32 [ [[RES1]], [[CASE_1]] ], [ [[RES2]], [[CASE_2]] ] | |
| ; CHECK-NEXT: ret i32 [[RES]] | |
| ; | |
| entry: | |
| %i = fptosi float %f to i64 | |
| %clamp.left = call i64 @llvm.smax.i64(i64 %i, i64 0) | |
| %clamp = call i64 @llvm.smin.i64(i64 %clamp.left, i64 3) | |
| switch i64 %clamp, label %case.D [ | |
| i64 0, label %case.1 | |
| i64 1, label %case.1 | |
| i64 2, label %case.2 | |
| i64 3, label %case.2 | |
| ] | |
| ; It's known that %val <- [0, 3] | |
| case.1: | |
| %res1 = call i32 @case1() | |
| br label %exit | |
| case.2: | |
| %res2 = call i32 @case2() | |
| br label %exit | |
| case.D: | |
| %resD = call i32 @caseD() | |
| br label %exit | |
| exit: | |
| %res = phi i32 [ %res1, %case.1 ], [ %res2, %case.2 ], [ %resD, %case.D ] | |
| ret i32 %res | |
| } | |
| declare i32 @case1() | |
| declare i32 @case2() | |
| declare i32 @caseD() | |
| declare i32 @getVal() | |
| declare i32 @llvm.ctpop.i32(i32) | |
| !0 = !{i32 1, i32 257} | |
| !1 = !{i32 2, i32 3} | |
| !2 = !{i32 2, i32 257} | |
| !3 = !{i32 1, i32 3} | |
| !4 = !{i32 0, i32 4} |