Index: test/Transforms/SimplifyCFG/switch-dead-default.ll =================================================================== --- test/Transforms/SimplifyCFG/switch-dead-default.ll +++ test/Transforms/SimplifyCFG/switch-dead-default.ll @@ -1,11 +1,20 @@ -; RUN: opt %s -S -simplifycfg | FileCheck %s +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py +; RUN: opt %s -S -simplifycfg -O3 | FileCheck %s +target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" declare void @foo(i32) define void @test(i1 %a) { -; CHECK-LABEL: @test -; CHECK: br i1 [[IGNORE:%.*]], label %true, label %false +; CHECK-LABEL: @test( +; CHECK-NEXT: br i1 [[A:%.*]], label [[TRUE:%.*]], label [[FALSE:%.*]] +; CHECK: true: +; CHECK-NEXT: tail call void @foo(i32 1) +; CHECK-NEXT: ret void +; CHECK: false: +; CHECK-NEXT: tail call void @foo(i32 3) +; CHECK-NEXT: ret void +; switch i1 %a, label %default [i1 1, label %true - i1 0, label %false] + i1 0, label %false] true: call void @foo(i32 1) ret void @@ -15,14 +24,35 @@ default: call void @foo(i32 2) ret void -} +} define void @test2(i2 %a) { -; CHECK-LABEL: @test2 +; CHECK-LABEL: @test2( +; CHECK-NEXT: switch i2 [[A:%.*]], label [[DEFAULT1:%.*]] [ +; CHECK-NEXT: i2 0, label [[CASE0:%.*]] +; CHECK-NEXT: i2 1, label [[CASE1:%.*]] +; CHECK-NEXT: i2 -2, label [[CASE2:%.*]] +; CHECK-NEXT: i2 -1, label [[CASE3:%.*]] +; CHECK-NEXT: ] +; CHECK: case0: +; CHECK-NEXT: tail call void @foo(i32 0) +; CHECK-NEXT: ret void +; CHECK: case1: +; CHECK-NEXT: tail call void @foo(i32 1) +; CHECK-NEXT: ret void +; CHECK: case2: +; CHECK-NEXT: tail call void @foo(i32 2) +; CHECK-NEXT: ret void +; CHECK: case3: +; CHECK-NEXT: tail call void @foo(i32 3) +; CHECK-NEXT: ret void +; CHECK: default1: +; CHECK-NEXT: unreachable +; switch i2 %a, label %default [i2 0, label %case0 - i2 1, label %case1 - i2 2, label %case2 - i2 3, label %case3] + i2 1, label %case1 + i2 2, label %case2 + i2 3, label %case3] case0: call void @foo(i32 0) ret void @@ -36,19 +66,35 @@ call void @foo(i32 3) ret void default: -; CHECK-LABEL: default1: -; CHECK-NEXT: unreachable call void @foo(i32 4) ret void -} +} ; This one is a negative test - we know the value of the default, ; but that's about it define void @test3(i2 %a) { -; CHECK-LABEL: @test3 +; CHECK-LABEL: @test3( +; CHECK-NEXT: switch i2 [[A:%.*]], label [[DEFAULT:%.*]] [ +; CHECK-NEXT: i2 0, label [[CASE0:%.*]] +; CHECK-NEXT: i2 1, label [[CASE1:%.*]] +; CHECK-NEXT: i2 -2, label [[CASE2:%.*]] +; CHECK-NEXT: ] +; CHECK: case0: +; CHECK-NEXT: tail call void @foo(i32 0) +; CHECK-NEXT: ret void +; CHECK: case1: +; CHECK-NEXT: tail call void @foo(i32 1) +; CHECK-NEXT: ret void +; CHECK: case2: +; CHECK-NEXT: tail call void @foo(i32 2) +; CHECK-NEXT: ret void +; CHECK: default: +; CHECK-NEXT: tail call void @foo(i32 0) +; CHECK-NEXT: ret void +; switch i2 %a, label %default [i2 0, label %case0 - i2 1, label %case1 - i2 2, label %case2] + i2 1, label %case1 + i2 2, label %case2] case0: call void @foo(i32 0) @@ -60,18 +106,30 @@ call void @foo(i32 2) ret void default: -; CHECK-LABEL: default: -; CHECK-NEXT: call void @foo call void @foo(i32 0) ret void -} +} ; Negative test - check for possible overflow when computing ; number of possible cases. define void @test4(i128 %a) { -; CHECK-LABEL: @test4 +; CHECK-LABEL: @test4( +; CHECK-NEXT: switch i128 [[A:%.*]], label [[DEFAULT:%.*]] [ +; CHECK-NEXT: i128 0, label [[CASE0:%.*]] +; CHECK-NEXT: i128 1, label [[CASE1:%.*]] +; CHECK-NEXT: ] +; CHECK: case0: +; CHECK-NEXT: tail call void @foo(i32 0) +; CHECK-NEXT: ret void +; CHECK: case1: +; CHECK-NEXT: tail call void @foo(i32 1) +; CHECK-NEXT: ret void +; CHECK: default: +; CHECK-NEXT: tail call void @foo(i32 0) +; CHECK-NEXT: ret void +; switch i128 %a, label %default [i128 0, label %case0 - i128 1, label %case1] + i128 1, label %case1] case0: call void @foo(i32 0) @@ -80,20 +138,28 @@ call void @foo(i32 1) ret void default: -; CHECK-LABEL: default: -; CHECK-NEXT: call void @foo call void @foo(i32 0) ret void -} +} ; All but one bit known zero define void @test5(i8 %a) { -; CHECK-LABEL: @test5 -; CHECK: br i1 [[IGNORE:%.*]], label %true, label %false - %cmp = icmp ult i8 %a, 2 +; CHECK-LABEL: @test5( +; CHECK-NEXT: [[CMP:%.*]] = icmp ult i8 [[A:%.*]], 2 +; CHECK-NEXT: tail call void @llvm.assume(i1 [[CMP]]) +; CHECK-NEXT: [[SWITCH:%.*]] = icmp eq i8 [[A]], 1 +; CHECK-NEXT: br i1 [[SWITCH]], label [[TRUE:%.*]], label [[FALSE:%.*]] +; CHECK: true: +; CHECK-NEXT: tail call void @foo(i32 1) +; CHECK-NEXT: ret void +; CHECK: false: +; CHECK-NEXT: tail call void @foo(i32 3) +; CHECK-NEXT: ret void +; + %cmp = icmp ult i8 %a, 2 call void @llvm.assume(i1 %cmp) switch i8 %a, label %default [i8 1, label %true - i8 0, label %false] + i8 0, label %false] true: call void @foo(i32 1) ret void @@ -103,18 +169,27 @@ default: call void @foo(i32 2) ret void -} +} ;; All but one bit known one define void @test6(i8 %a) { -; CHECK-LABEL: @test6 -; CHECK: @llvm.assume -; CHECK: br i1 [[IGNORE:%.*]], label %true, label %false +; CHECK-LABEL: @test6( +; CHECK-NEXT: [[CMP:%.*]] = icmp ugt i8 [[A:%.*]], -3 +; CHECK-NEXT: tail call void @llvm.assume(i1 [[CMP]]) +; CHECK-NEXT: [[SWITCH:%.*]] = icmp eq i8 [[A]], -1 +; CHECK-NEXT: br i1 [[SWITCH]], label [[TRUE:%.*]], label [[FALSE:%.*]] +; CHECK: true: +; CHECK-NEXT: tail call void @foo(i32 1) +; CHECK-NEXT: ret void +; CHECK: false: +; CHECK-NEXT: tail call void @foo(i32 3) +; CHECK-NEXT: ret void +; %and = and i8 %a, 254 - %cmp = icmp eq i8 %and, 254 + %cmp = icmp eq i8 %and, 254 call void @llvm.assume(i1 %cmp) switch i8 %a, label %default [i8 255, label %true - i8 254, label %false] + i8 254, label %false] true: call void @foo(i32 1) ret void @@ -129,15 +204,24 @@ ; Check that we can eliminate both dead cases and dead defaults ; within a single run of simplify-cfg define void @test7(i8 %a) { -; CHECK-LABEL: @test7 -; CHECK: @llvm.assume -; CHECK: br i1 [[IGNORE:%.*]], label %true, label %false +; CHECK-LABEL: @test7( +; CHECK-NEXT: [[CMP:%.*]] = icmp ugt i8 [[A:%.*]], -3 +; CHECK-NEXT: tail call void @llvm.assume(i1 [[CMP]]) +; CHECK-NEXT: [[SWITCH:%.*]] = icmp eq i8 [[A]], -1 +; CHECK-NEXT: br i1 [[SWITCH]], label [[TRUE:%.*]], label [[FALSE:%.*]] +; CHECK: true: +; CHECK-NEXT: tail call void @foo(i32 1) +; CHECK-NEXT: ret void +; CHECK: false: +; CHECK-NEXT: tail call void @foo(i32 3) +; CHECK-NEXT: ret void +; %and = and i8 %a, 254 - %cmp = icmp eq i8 %and, 254 + %cmp = icmp eq i8 %and, 254 call void @llvm.assume(i1 %cmp) switch i8 %a, label %default [i8 255, label %true - i8 254, label %false - i8 0, label %also_dead] + i8 254, label %false + i8 0, label %also_dead] true: call void @foo(i32 1) ret void @@ -154,17 +238,18 @@ ;; All but one bit known undef ;; Note: This is currently testing an optimization which doesn't trigger. The -;; case this is protecting against is that a bit could be assumed both zero +;; case this is protecting against is that a bit could be assumed both zero ;; *or* one given we know it's undef. ValueTracking doesn't do this today, ;; but it doesn't hurt to confirm. define void @test8(i8 %a) { ; CHECK-LABEL: @test8( -; CHECK: switch i8 +; CHECK-NEXT: unreachable +; %and = and i8 %a, 254 %cmp = icmp eq i8 %and, undef call void @llvm.assume(i1 %cmp) switch i8 %a, label %default [i8 255, label %true - i8 254, label %false] + i8 254, label %false] true: call void @foo(i32 1) ret void Index: test/Transforms/SimplifyCFG/switch-genfori8.ll =================================================================== --- /dev/null +++ test/Transforms/SimplifyCFG/switch-genfori8.ll @@ -0,0 +1,149 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py +; RUN: opt -S -passes='simplify-cfg' < %s | FileCheck %s +; Using a Zig driver https://gist.github.com/shawnl/8137f62f7dbcfd539f6cf1925387cd38 +;after-patch, covered lookup table: 509.8MiB/sec +;lookup table, not covered, only valid digits to prime the branch predictor: 437.8MiB/sec +;lookup table, not covered, random bytes: 242.0MiB/sec +;before-patch, no lookup table: 205.4MiB/sec + +; ModuleID = 'chartodigit.c' +source_filename = "chartodigit.c" +target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-pc-linux-gnu" + +; Function Attrs: norecurse nounwind readnone uwtable +define dso_local zeroext i8 @char_to_digit(i8 zeroext) local_unnamed_addr #0 { +; CHECK-LABEL: @char_to_digit( +; CHECK-NEXT: switch i8 [[TMP0:%.*]], label [[TMP17:%.*]] [ +; CHECK-NEXT: i8 48, label [[TMP18:%.*]] +; CHECK-NEXT: i8 49, label [[TMP2:%.*]] +; CHECK-NEXT: i8 50, label [[TMP3:%.*]] +; CHECK-NEXT: i8 51, label [[TMP4:%.*]] +; CHECK-NEXT: i8 52, label [[TMP5:%.*]] +; CHECK-NEXT: i8 53, label [[TMP6:%.*]] +; CHECK-NEXT: i8 54, label [[TMP7:%.*]] +; CHECK-NEXT: i8 55, label [[TMP8:%.*]] +; CHECK-NEXT: i8 56, label [[TMP9:%.*]] +; CHECK-NEXT: i8 57, label [[TMP10:%.*]] +; CHECK-NEXT: i8 97, label [[TMP11:%.*]] +; CHECK-NEXT: i8 98, label [[TMP12:%.*]] +; CHECK-NEXT: i8 99, label [[TMP13:%.*]] +; CHECK-NEXT: i8 100, label [[TMP14:%.*]] +; CHECK-NEXT: i8 101, label [[TMP15:%.*]] +; CHECK-NEXT: i8 102, label [[TMP16:%.*]] +; CHECK-NEXT: ] +; CHECK: 2: +; CHECK-NEXT: br label [[TMP18]] +; CHECK: 3: +; CHECK-NEXT: br label [[TMP18]] +; CHECK: 4: +; CHECK-NEXT: br label [[TMP18]] +; CHECK: 5: +; CHECK-NEXT: br label [[TMP18]] +; CHECK: 6: +; CHECK-NEXT: br label [[TMP18]] +; CHECK: 7: +; CHECK-NEXT: br label [[TMP18]] +; CHECK: 8: +; CHECK-NEXT: br label [[TMP18]] +; CHECK: 9: +; CHECK-NEXT: br label [[TMP18]] +; CHECK: 10: +; CHECK-NEXT: br label [[TMP18]] +; CHECK: 11: +; CHECK-NEXT: br label [[TMP18]] +; CHECK: 12: +; CHECK-NEXT: br label [[TMP18]] +; CHECK: 13: +; CHECK-NEXT: br label [[TMP18]] +; CHECK: 14: +; CHECK-NEXT: br label [[TMP18]] +; CHECK: 15: +; CHECK-NEXT: br label [[TMP18]] +; CHECK: 16: +; CHECK-NEXT: br label [[TMP18]] +; CHECK: 17: +; CHECK-NEXT: br label [[TMP18]] +; CHECK: 18: +; CHECK-NEXT: [[TMP19:%.*]] = phi i8 [ -1, [[TMP17]] ], [ 15, [[TMP16]] ], [ 14, [[TMP15]] ], [ 13, [[TMP14]] ], [ 12, [[TMP13]] ], [ 11, [[TMP12]] ], [ 10, [[TMP11]] ], [ 9, [[TMP10]] ], [ 8, [[TMP9]] ], [ 7, [[TMP8]] ], [ 6, [[TMP7]] ], [ 5, [[TMP6]] ], [ 4, [[TMP5]] ], [ 3, [[TMP4]] ], [ 2, [[TMP3]] ], [ 1, [[TMP2]] ], [ 0, [[TMP1:%.*]] ] +; CHECK-NEXT: ret i8 [[TMP19]] +; + switch i8 %0, label %17 [ + i8 48, label %18 + i8 49, label %2 + i8 50, label %3 + i8 51, label %4 + i8 52, label %5 + i8 53, label %6 + i8 54, label %7 + i8 55, label %8 + i8 56, label %9 + i8 57, label %10 + i8 97, label %11 + i8 98, label %12 + i8 99, label %13 + i8 100, label %14 + i8 101, label %15 + i8 102, label %16 + ] + +;