1 ; RUN: opt < %s -simplifycfg -S | FileCheck %s 2 3 target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64-S128" 4 target triple = "x86_64-unknown-linux-gnu" 5 6 ; The table for @f 7 ; CHECK: @switch.table = private unnamed_addr constant [7 x i32] [i32 55, i32 123, i32 0, i32 -1, i32 27, i32 62, i32 1] 8 9 ; The int table for @h 10 ; CHECK: @switch.table1 = private unnamed_addr constant [4 x i8] c"*\09X\05" 11 12 ; The float table for @h 13 ; CHECK: @switch.table2 = private unnamed_addr constant [4 x float] [float 0x40091EB860000000, float 0x3FF3BE76C0000000, float 0x4012449BA0000000, float 0x4001AE1480000000] 14 15 ; The table for @foostring 16 ; CHECK: @switch.table3 = private unnamed_addr constant [4 x i8*] [i8* getelementptr inbounds ([4 x i8]* @.str, i64 0, i64 0), i8* getelementptr inbounds ([4 x i8]* @.str1, i64 0, i64 0), i8* getelementptr inbounds ([4 x i8]* @.str2, i64 0, i64 0), i8* getelementptr inbounds ([4 x i8]* @.str3, i64 0, i64 0)] 17 18 ; A simple int-to-int selection switch. 19 ; It is dense enough to be replaced by table lookup. 20 ; The result is directly by a ret from an otherwise empty bb, 21 ; so we return early, directly from the lookup bb. 22 23 define i32 @f(i32 %c) nounwind uwtable readnone { 24 entry: 25 switch i32 %c, label %sw.default [ 26 i32 42, label %return 27 i32 43, label %sw.bb1 28 i32 44, label %sw.bb2 29 i32 45, label %sw.bb3 30 i32 46, label %sw.bb4 31 i32 47, label %sw.bb5 32 i32 48, label %sw.bb6 33 ] 34 35 sw.bb1: br label %return 36 sw.bb2: br label %return 37 sw.bb3: br label %return 38 sw.bb4: br label %return 39 sw.bb5: br label %return 40 sw.bb6: br label %return 41 sw.default: br label %return 42 return: 43 %retval.0 = phi i32 [ 15, %sw.default ], [ 1, %sw.bb6 ], [ 62, %sw.bb5 ], [ 27, %sw.bb4 ], [ -1, %sw.bb3 ], [ 0, %sw.bb2 ], [ 123, %sw.bb1 ], [ 55, %entry ] 44 ret i32 %retval.0 45 46 ; CHECK: @f 47 ; CHECK: entry: 48 ; CHECK-NEXT: %switch.tableidx = sub i32 %c, 42 49 ; CHECK-NEXT: %0 = icmp ult i32 %switch.tableidx, 7 50 ; CHECK-NEXT: br i1 %0, label %switch.lookup, label %return 51 ; CHECK: switch.lookup: 52 ; CHECK-NEXT: %switch.gep = getelementptr inbounds [7 x i32]* @switch.table, i32 0, i32 %switch.tableidx 53 ; CHECK-NEXT: %switch.load = load i32* %switch.gep 54 ; CHECK-NEXT: ret i32 %switch.load 55 ; CHECK: return: 56 ; CHECK-NEXT: ret i32 15 57 } 58 59 ; A switch used to initialize two variables, an i8 and a float. 60 61 declare void @dummy(i8 signext, float) 62 define void @h(i32 %x) { 63 entry: 64 switch i32 %x, label %sw.default [ 65 i32 0, label %sw.epilog 66 i32 1, label %sw.bb1 67 i32 2, label %sw.bb2 68 i32 3, label %sw.bb3 69 ] 70 71 sw.bb1: br label %sw.epilog 72 sw.bb2: br label %sw.epilog 73 sw.bb3: br label %sw.epilog 74 sw.default: br label %sw.epilog 75 76 sw.epilog: 77 %a.0 = phi i8 [ 7, %sw.default ], [ 5, %sw.bb3 ], [ 88, %sw.bb2 ], [ 9, %sw.bb1 ], [ 42, %entry ] 78 %b.0 = phi float [ 0x4023FAE140000000, %sw.default ], [ 0x4001AE1480000000, %sw.bb3 ], [ 0x4012449BA0000000, %sw.bb2 ], [ 0x3FF3BE76C0000000, %sw.bb1 ], [ 0x40091EB860000000, %entry ] 79 call void @dummy(i8 signext %a.0, float %b.0) 80 ret void 81 82 ; CHECK: @h 83 ; CHECK: entry: 84 ; CHECK-NEXT: %switch.tableidx = sub i32 %x, 0 85 ; CHECK-NEXT: %0 = icmp ult i32 %switch.tableidx, 4 86 ; CHECK-NEXT: br i1 %0, label %switch.lookup, label %sw.epilog 87 ; CHECK: switch.lookup: 88 ; CHECK-NEXT: %switch.gep = getelementptr inbounds [4 x i8]* @switch.table1, i32 0, i32 %switch.tableidx 89 ; CHECK-NEXT: %switch.load = load i8* %switch.gep 90 ; CHECK-NEXT: %switch.gep1 = getelementptr inbounds [4 x float]* @switch.table2, i32 0, i32 %switch.tableidx 91 ; CHECK-NEXT: %switch.load2 = load float* %switch.gep1 92 ; CHECK-NEXT: br label %sw.epilog 93 ; CHECK: sw.epilog: 94 ; CHECK-NEXT: %a.0 = phi i8 [ %switch.load, %switch.lookup ], [ 7, %entry ] 95 ; CHECK-NEXT: %b.0 = phi float [ %switch.load2, %switch.lookup ], [ 0x4023FAE140000000, %entry ] 96 ; CHECK-NEXT: call void @dummy(i8 signext %a.0, float %b.0) 97 ; CHECK-NEXT: ret void 98 } 99 100 101 ; Switch used to return a string. 102 103 @.str = private unnamed_addr constant [4 x i8] c"foo\00", align 1 104 @.str1 = private unnamed_addr constant [4 x i8] c"bar\00", align 1 105 @.str2 = private unnamed_addr constant [4 x i8] c"baz\00", align 1 106 @.str3 = private unnamed_addr constant [4 x i8] c"qux\00", align 1 107 @.str4 = private unnamed_addr constant [6 x i8] c"error\00", align 1 108 109 define i8* @foostring(i32 %x) { 110 entry: 111 switch i32 %x, label %sw.default [ 112 i32 0, label %return 113 i32 1, label %sw.bb1 114 i32 2, label %sw.bb2 115 i32 3, label %sw.bb3 116 ] 117 118 sw.bb1: br label %return 119 sw.bb2: br label %return 120 sw.bb3: br label %return 121 sw.default: br label %return 122 123 return: 124 %retval.0 = phi i8* [ getelementptr inbounds ([6 x i8]* @.str4, i64 0, i64 0), %sw.default ], 125 [ getelementptr inbounds ([4 x i8]* @.str3, i64 0, i64 0), %sw.bb3 ], 126 [ getelementptr inbounds ([4 x i8]* @.str2, i64 0, i64 0), %sw.bb2 ], 127 [ getelementptr inbounds ([4 x i8]* @.str1, i64 0, i64 0), %sw.bb1 ], 128 [ getelementptr inbounds ([4 x i8]* @.str, i64 0, i64 0), %entry ] 129 ret i8* %retval.0 130 131 ; CHECK: @foostring 132 ; CHECK: entry: 133 ; CHECK-NEXT: %switch.tableidx = sub i32 %x, 0 134 ; CHECK-NEXT: %0 = icmp ult i32 %switch.tableidx, 4 135 ; CHECK-NEXT: br i1 %0, label %switch.lookup, label %return 136 ; CHECK: switch.lookup: 137 ; CHECK-NEXT: %switch.gep = getelementptr inbounds [4 x i8*]* @switch.table3, i32 0, i32 %switch.tableidx 138 ; CHECK-NEXT: %switch.load = load i8** %switch.gep 139 ; CHECK-NEXT: ret i8* %switch.load 140 } 141