Gulfem Savrun Yeniceri | e96df3e | 2020-12-29 21:32:13 +0000 | [diff] [blame] | 1 | ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py |
| 2 | ; REQUIRES: x86-registered-target |
| 3 | ; RUN: opt < %s -passes=rel-lookup-table-converter -relocation-model=pic -S | FileCheck %s |
| 4 | 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" |
| 5 | target triple = "x86_64-unknown-linux-gnu" |
| 6 | |
| 7 | @.str = private unnamed_addr constant [5 x i8] c"zero\00", align 1 |
| 8 | @.str.1 = private unnamed_addr constant [4 x i8] c"one\00", align 1 |
| 9 | @.str.2 = private unnamed_addr constant [4 x i8] c"two\00", align 1 |
| 10 | @.str.3 = private unnamed_addr constant [8 x i8] c"default\00", align 1 |
| 11 | @.str.4 = private unnamed_addr constant [6 x i8] c"three\00", align 1 |
| 12 | @.str.5 = private unnamed_addr constant [5 x i8] c"str1\00", align 1 |
| 13 | @.str.6 = private unnamed_addr constant [5 x i8] c"str2\00", align 1 |
| 14 | @.str.7 = private unnamed_addr constant [12 x i8] c"singlevalue\00", align 1 |
| 15 | |
| 16 | @a1 = external global i32, align 4 |
| 17 | @b1 = external global i32, align 4 |
| 18 | @c1 = external global i32, align 4 |
| 19 | @d1 = external global i32, align 4 |
| 20 | |
| 21 | @a2 = internal constant i32 0, align 4 |
| 22 | @b2 = internal constant i32 0, align 4 |
| 23 | @c2 = internal constant i32 0, align 4 |
| 24 | @d2 = internal constant i32 0, align 4 |
| 25 | |
| 26 | @switch.table.external_linkage = private unnamed_addr constant [3 x i32*] [i32* @a1, i32* @b1, i32* @c1], align 8 |
| 27 | |
| 28 | @switch.table.internal_linkage = private unnamed_addr constant [3 x i32*] [i32* @a2, i32* @b2, i32* @c2], align 8 |
| 29 | |
| 30 | @switch.table.string_table = private unnamed_addr constant [3 x i8*] |
| 31 | [ |
| 32 | i8* getelementptr inbounds ([5 x i8], [5 x i8]* @.str, i64 0, i64 0), |
| 33 | i8* getelementptr inbounds ([4 x i8], [4 x i8]* @.str.1, i64 0, i64 0), |
| 34 | i8* getelementptr inbounds ([4 x i8], [4 x i8]* @.str.2, i64 0, i64 0) |
| 35 | ], align 8 |
| 36 | |
| 37 | @switch.table.string_table_holes = private unnamed_addr constant [4 x i8*] |
| 38 | [ |
| 39 | i8* getelementptr inbounds ([5 x i8], [5 x i8]* @.str, i64 0, i64 0), |
| 40 | i8* getelementptr inbounds ([8 x i8], [8 x i8]* @.str.3, i64 0, i64 0), |
| 41 | i8* getelementptr inbounds ([4 x i8], [4 x i8]* @.str.2, i64 0, i64 0), |
| 42 | i8* getelementptr inbounds ([6 x i8], [6 x i8]* @.str.4, i64 0, i64 0) |
| 43 | ], align 8 |
| 44 | |
| 45 | @switch.table.single_value = private unnamed_addr constant [3 x i8*] |
| 46 | [ |
| 47 | i8* getelementptr inbounds ([5 x i8], [5 x i8]* @.str, i64 0, i64 0), |
| 48 | i8* getelementptr inbounds ([4 x i8], [4 x i8]* @.str.1, i64 0, i64 0), |
| 49 | i8* getelementptr inbounds ([4 x i8], [4 x i8]* @.str.2, i64 0, i64 0) |
| 50 | ], align 8 |
| 51 | |
| 52 | @user_defined_lookup_table.table = internal unnamed_addr constant [3 x i8*] |
| 53 | [ |
| 54 | i8* getelementptr inbounds ([5 x i8], [5 x i8]* @.str, i32 0, i32 0), |
| 55 | i8* getelementptr inbounds ([4 x i8], [4 x i8]* @.str.1, i32 0, i32 0), |
| 56 | i8* getelementptr inbounds ([4 x i8], [4 x i8]* @.str.2, i32 0, i32 0) |
| 57 | ], align 16 |
| 58 | |
| 59 | ; Lookup table check for integer pointers that have external linkage |
| 60 | ; CHECK: @switch.table.external_linkage = private unnamed_addr constant [3 x i32*] [i32* @a1, i32* @b1, i32* @c1], align |
| 61 | |
| 62 | ; Lookup table check for integer pointers that have internal linkage |
| 63 | ; CHECK: @reltable.internal_linkage = private unnamed_addr constant [3 x i32] |
| 64 | ; CHECK-SAME: [ |
| 65 | ; CHECK-SAME: i32 trunc (i64 sub (i64 ptrtoint (i32* @a2 to i64), i64 ptrtoint ([3 x i32]* @reltable.internal_linkage to i64)) to i32), |
| 66 | ; CHECK-SAME: i32 trunc (i64 sub (i64 ptrtoint (i32* @b2 to i64), i64 ptrtoint ([3 x i32]* @reltable.internal_linkage to i64)) to i32), |
| 67 | ; CHECK-SAME: i32 trunc (i64 sub (i64 ptrtoint (i32* @c2 to i64), i64 ptrtoint ([3 x i32]* @reltable.internal_linkage to i64)) to i32) |
| 68 | ; CHECK-SAME: ], align 4 |
| 69 | |
| 70 | ; Relative switch lookup table for strings |
| 71 | ; CHECK: @reltable.string_table = private unnamed_addr constant [3 x i32] |
| 72 | ; CHECK-SAME: [ |
| 73 | ; CHECK-SAME: i32 trunc (i64 sub (i64 ptrtoint ([5 x i8]* @.str to i64), i64 ptrtoint ([3 x i32]* @reltable.string_table to i64)) to i32), |
| 74 | ; CHECK-SAME: i32 trunc (i64 sub (i64 ptrtoint ([4 x i8]* @.str.1 to i64), i64 ptrtoint ([3 x i32]* @reltable.string_table to i64)) to i32), |
| 75 | ; CHECK-SAME: i32 trunc (i64 sub (i64 ptrtoint ([4 x i8]* @.str.2 to i64), i64 ptrtoint ([3 x i32]* @reltable.string_table to i64)) to i32) |
| 76 | ; CHECK-SAME: ], align 4 |
| 77 | |
| 78 | ; Relative switch lookup table for strings with holes, where holes are filled with relative offset to default values |
| 79 | ; CHECK: @reltable.string_table_holes = private unnamed_addr constant [4 x i32] |
| 80 | ; CHECK-SAME: [ |
| 81 | ; CHECK-SAME: i32 trunc (i64 sub (i64 ptrtoint ([5 x i8]* @.str to i64), i64 ptrtoint ([4 x i32]* @reltable.string_table_holes to i64)) to i32), |
| 82 | ; CHECK-SAME: i32 trunc (i64 sub (i64 ptrtoint ([8 x i8]* @.str.3 to i64), i64 ptrtoint ([4 x i32]* @reltable.string_table_holes to i64)) to i32), |
| 83 | ; CHECK-SAME: i32 trunc (i64 sub (i64 ptrtoint ([4 x i8]* @.str.2 to i64), i64 ptrtoint ([4 x i32]* @reltable.string_table_holes to i64)) to i32), |
| 84 | ; CHECK-SAME: i32 trunc (i64 sub (i64 ptrtoint ([6 x i8]* @.str.4 to i64), i64 ptrtoint ([4 x i32]* @reltable.string_table_holes to i64)) to i32) |
| 85 | ; CHECK-SAME: ], align 4 |
| 86 | |
| 87 | ; Single value check |
| 88 | ; CHECK: @reltable.single_value = private unnamed_addr constant [3 x i32] |
| 89 | ; CHECK-SAME: [ |
| 90 | ; CHECK-SAME: i32 trunc (i64 sub (i64 ptrtoint ([5 x i8]* @.str to i64), i64 ptrtoint ([3 x i32]* @reltable.single_value to i64)) to i32), |
| 91 | ; CHECK-SAME: i32 trunc (i64 sub (i64 ptrtoint ([4 x i8]* @.str.1 to i64), i64 ptrtoint ([3 x i32]* @reltable.single_value to i64)) to i32), |
| 92 | ; CHECK-SAME: i32 trunc (i64 sub (i64 ptrtoint ([4 x i8]* @.str.2 to i64), i64 ptrtoint ([3 x i32]* @reltable.single_value to i64)) to i32) |
| 93 | ; CHECK-SAME: ], align 4 |
| 94 | ; |
| 95 | |
| 96 | ; Lookup table check for integer pointers that have external linkage |
| 97 | define i32* @external_linkage(i32 %cond) { |
| 98 | ; CHECK-LABEL: @external_linkage( |
| 99 | ; CHECK-NEXT: entry: |
| 100 | ; CHECK-NEXT: [[TMP0:%.*]] = icmp ult i32 [[COND:%.*]], 3 |
| 101 | ; CHECK-NEXT: br i1 [[TMP0]], label [[SWITCH_LOOKUP:%.*]], label [[RETURN:%.*]] |
| 102 | ; CHECK: switch.lookup: |
| 103 | ; CHECK-NEXT: [[SWITCH_GEP:%.*]] = getelementptr inbounds [3 x i32*], [3 x i32*]* @switch.table.external_linkage, i32 0, i32 [[COND:%.*]] |
| 104 | ; CHECK-NEXT: [[SWITCH_LOAD:%.*]] = load i32*, i32** [[SWITCH_GEP]], align 8 |
| 105 | ; CHECK-NEXT: ret i32* [[SWITCH_LOAD]] |
| 106 | ; CHECK: return: |
| 107 | ; CHECK-NEXT: ret i32* @d1 |
| 108 | ; |
| 109 | entry: |
| 110 | %0 = icmp ult i32 %cond, 3 |
| 111 | br i1 %0, label %switch.lookup, label %return |
| 112 | |
| 113 | switch.lookup: ; preds = %entry |
| 114 | %switch.gep = getelementptr inbounds [3 x i32*], [3 x i32*]* @switch.table.external_linkage, i32 0, i32 %cond |
| 115 | %switch.load = load i32*, i32** %switch.gep, align 8 |
| 116 | ret i32* %switch.load |
| 117 | |
| 118 | return: ; preds = %entry |
| 119 | ret i32* @d1 |
| 120 | } |
| 121 | |
| 122 | ; Relative switch lookup table for integer pointers that have internal linkage |
| 123 | define i32* @internal_linkage(i32 %cond) { |
| 124 | ; CHECK-LABEL: @internal_linkage( |
| 125 | ; CHECK-NEXT: entry: |
| 126 | ; CHECK-NEXT: [[TMP0:%.*]] = icmp ult i32 [[COND:%.*]], 3 |
| 127 | ; CHECK-NEXT: br i1 [[TMP0]], label [[SWITCH_LOOKUP:%.*]], label [[RETURN:%.*]] |
| 128 | ; CHECK: switch.lookup: |
| 129 | ; CHECK-NEXT: [[RELTABLE_SHIFT:%.*]] = shl i32 %cond, 2 |
| 130 | ; CHECK-NEXT: [[RELTABLE_INTRINSIC:%.*]] = call i8* @llvm.load.relative.i32(i8* bitcast ([3 x i32]* @reltable.internal_linkage to i8*), i32 [[RELTABLE_SHIFT]]) |
| 131 | ; CHECK-NEXT: [[BIT_CAST:%.*]] = bitcast i8* [[RELTABLE_INTRINSIC]] to i32* |
| 132 | ; CHECK-NEXT: ret i32* [[BIT_CAST]] |
| 133 | ; CHECK: return: |
| 134 | ; CHECK-NEXT: ret i32* @d2 |
| 135 | ; |
| 136 | entry: |
| 137 | %0 = icmp ult i32 %cond, 3 |
| 138 | br i1 %0, label %switch.lookup, label %return |
| 139 | |
| 140 | switch.lookup: ; preds = %entry |
| 141 | %switch.gep = getelementptr inbounds [3 x i32*], [3 x i32*]* @switch.table.internal_linkage, i32 0, i32 %cond |
| 142 | %switch.load = load i32*, i32** %switch.gep, align 8 |
| 143 | ret i32* %switch.load |
| 144 | |
| 145 | return: ; preds = %entry |
| 146 | ret i32* @d2 |
| 147 | } |
| 148 | |
| 149 | ; ; Relative switch lookup table for strings |
| 150 | define i8* @string_table(i32 %cond) { |
| 151 | ; CHECK-LABEL: @string_table( |
| 152 | ; CHECK-NEXT: entry: |
| 153 | ; CHECK-NEXT: [[TMP0:%.*]] = icmp ult i32 [[COND:%.*]], 3 |
| 154 | ; CHECK-NEXT: br i1 [[TMP0]], label [[SWITCH_LOOKUP:%.*]], label [[RETURN:%.*]] |
| 155 | ; CHECK: switch.lookup: |
| 156 | ; CHECK-NEXT: [[RELTABLE_SHIFT:%.*]] = shl i32 %cond, 2 |
| 157 | ; CHECK-NEXT: [[RELTABLE_INTRINSIC:%.*]] = call i8* @llvm.load.relative.i32(i8* bitcast ([3 x i32]* @reltable.string_table to i8*), i32 [[RELTABLE_SHIFT]]) |
| 158 | ; CHECK-NEXT: ret i8* [[RELTABLE_INTRINSIC]] |
| 159 | ; CHECK: return: |
| 160 | ; CHECK-NEXT: ret i8* getelementptr inbounds ([8 x i8], [8 x i8]* @.str.3, i64 0, i64 0) |
| 161 | ; |
| 162 | entry: |
| 163 | %0 = icmp ult i32 %cond, 3 |
| 164 | br i1 %0, label %switch.lookup, label %return |
| 165 | |
| 166 | switch.lookup: ; preds = %entry |
| 167 | %switch.gep = getelementptr inbounds [3 x i8*], [3 x i8*]* @switch.table.string_table, i32 0, i32 %cond |
| 168 | %switch.load = load i8*, i8** %switch.gep, align 8 |
| 169 | ret i8* %switch.load |
| 170 | |
| 171 | return: ; preds = %entry |
| 172 | ret i8* getelementptr inbounds ([8 x i8], [8 x i8]* @.str.3, i64 0, i64 0) |
| 173 | } |
| 174 | |
| 175 | ; Relative switch lookup table for strings with holes, where holes are filled with relative offset to default values |
| 176 | define i8* @string_table_holes(i32 %cond) { |
| 177 | ; CHECK-LABEL: @string_table_holes( |
| 178 | ; CHECK-NEXT: entry: |
| 179 | ; CHECK-NEXT: [[TMP0:%.*]] = icmp ult i32 [[COND:%.*]], 4 |
| 180 | ; CHECK-NEXT: br i1 [[TMP0]], label [[SWITCH_LOOKUP:%.*]], label [[RETURN:%.*]] |
| 181 | ; CHECK: switch.lookup: |
| 182 | ; CHECK-NEXT: [[RELTABLE_SHIFT:%.*]] = shl i32 [[COND]], 2 |
| 183 | ; CHECK-NEXT: [[RELTABLE_INTRINSIC:%.*]] = call i8* @llvm.load.relative.i32(i8* bitcast ([4 x i32]* @reltable.string_table_holes to i8*), i32 [[RELTABLE_SHIFT]]) |
| 184 | ; CHECK-NEXT: ret i8* [[RELTABLE_INTRINSIC]] |
| 185 | ; CHECK: return: |
| 186 | ; CHECK-NEXT: ret i8* getelementptr inbounds ([8 x i8], [8 x i8]* @.str.3, i64 0, i64 0) |
| 187 | ; |
| 188 | entry: |
| 189 | %0 = icmp ult i32 %cond, 4 |
| 190 | br i1 %0, label %switch.lookup, label %return |
| 191 | |
| 192 | switch.lookup: ; preds = %entry |
| 193 | %switch.gep = getelementptr inbounds [4 x i8*], [4 x i8*]* @switch.table.string_table_holes, i32 0, i32 %cond |
| 194 | %switch.load = load i8*, i8** %switch.gep, align 8 |
| 195 | ret i8* %switch.load |
| 196 | |
| 197 | return: ; preds = %entry |
| 198 | ret i8* getelementptr inbounds ([8 x i8], [8 x i8]* @.str.3, i64 0, i64 0) |
| 199 | } |
| 200 | |
| 201 | |
| 202 | ; Single value check |
| 203 | ; If there is a lookup table, where each element contains the same value, |
| 204 | ; a relative lookup should not be generated |
| 205 | define void @single_value(i32 %cond) { |
| 206 | ; CHECK-LABEL: @single_value( |
| 207 | ; CHECK-NEXT: entry: |
| 208 | ; CHECK-NEXT: [[TMP0:%.*]] = icmp ult i32 [[COND:%.*]], 3 |
| 209 | ; CHECK-NEXT: br i1 [[TMP0]], label [[SWITCH_LOOKUP:%.*]], label [[RETURN:%.*]] |
| 210 | ; CHECK: switch.lookup: |
| 211 | ; CHECK-NEXT: [[RELTABLE_SHIFT:%.*]] = shl i32 [[COND]], 2 |
| 212 | ; CHECK-NEXT: [[RELTABLE_INTRINSIC:%.*]] = call i8* @llvm.load.relative.i32(i8* bitcast ([3 x i32]* @reltable.single_value to i8*), i32 [[RELTABLE_SHIFT]]) |
| 213 | ; CHECK: sw.epilog: |
| 214 | ; CHECK-NEXT: [[STR1:%.*]] = phi i8* [ getelementptr inbounds ([5 x i8], [5 x i8]* @.str.5, i64 0, i64 0), %entry ], [ getelementptr inbounds ([12 x i8], [12 x i8]* @.str.7, i64 0, i64 0), %switch.lookup ] |
| 215 | ; CHECK-NEXT: [[STR2:%.*]] = phi i8* [ getelementptr inbounds ([5 x i8], [5 x i8]* @.str.6, i64 0, i64 0), %entry ], [ [[RELTABLE_INTRINSIC]], [[SWITCH_LOOKUP]] ] |
| 216 | ; CHECK-NEXT: ret void |
| 217 | |
| 218 | entry: |
| 219 | %0 = icmp ult i32 %cond, 3 |
| 220 | br i1 %0, label %switch.lookup, label %sw.epilog |
| 221 | |
| 222 | switch.lookup: ; preds = %entry |
| 223 | %switch.gep = getelementptr inbounds [3 x i8*], [3 x i8*]* @switch.table.single_value, i32 0, i32 %cond |
| 224 | %switch.load = load i8*, i8** %switch.gep, align 8 |
| 225 | br label %sw.epilog |
| 226 | |
| 227 | sw.epilog: ; preds = %switch.lookup, %entry |
| 228 | %str1.0 = phi i8* [ getelementptr inbounds ([5 x i8], [5 x i8]* @.str.5, i64 0, i64 0), %entry ], [ getelementptr inbounds ([12 x i8], [12 x i8]* @.str.7, i64 0, i64 0), %switch.lookup ] |
| 229 | %str2.0 = phi i8* [ getelementptr inbounds ([5 x i8], [5 x i8]* @.str.6, i64 0, i64 0), %entry ], [ %switch.load, %switch.lookup ] |
| 230 | ret void |
| 231 | } |
| 232 | |
| 233 | ; Relative lookup table generated for a user-defined lookup table |
| 234 | define i8* @user_defined_lookup_table(i32 %cond) { |
| 235 | ; CHECK-LABEL: @user_defined_lookup_table( |
| 236 | ; CHECK-NEXT: entry: |
| 237 | ; CHECK-NEXT: [[TMP0:%.*]] = icmp sgt i32 [[COND:%.*]], 3 |
| 238 | ; CHECK-NEXT: br i1 [[TMP0]], label [[SWITCH_LOOKUP:%.*]], label [[RETURN:%.*]] |
| 239 | ; CHECK: cond.false: |
| 240 | ; CHECK-NEXT: [[IDX_PROM:%.*]] = sext i32 [[COND]] to i64 |
| 241 | ; CHECK-NEXT: [[RELTABLE_SHIFT:%.*]] = shl i64 [[IDX_PROM]], 2 |
| 242 | ; CHECK-NEXT: [[RELTABLE_INTRINSIC:%.*]] = call i8* @llvm.load.relative.i64(i8* bitcast ([3 x i32]* @reltable.user_defined_lookup_table to i8*), i64 [[RELTABLE_SHIFT]]) |
| 243 | ; CHECK-NEXT: br label %cond.end |
| 244 | ; CHECK: cond.end: |
| 245 | ; CHECK-NEXT: [[COND1:%.*]] = phi i8* [ [[RELTABLE_INTRINSIC]], %cond.false ], [ getelementptr inbounds ([8 x i8], [8 x i8]* @.str.3, i64 0, i64 0), %entry ] |
| 246 | ; CHECK-NEXT: ret i8* [[COND1]] |
| 247 | ; |
| 248 | entry: |
| 249 | %cmp = icmp sgt i32 %cond, 3 |
| 250 | br i1 %cmp, label %cond.end, label %cond.false |
| 251 | |
| 252 | cond.false: ; preds = %entry |
| 253 | %idxprom = sext i32 %cond to i64 |
| 254 | %arrayidx = getelementptr inbounds [3 x i8*], [3 x i8*]* @user_defined_lookup_table.table, i64 0, i64 %idxprom |
| 255 | %0 = load i8*, i8** %arrayidx, align 8, !tbaa !4 |
| 256 | br label %cond.end |
| 257 | |
| 258 | cond.end: ; preds = %entry, %cond.false |
| 259 | %cond1 = phi i8* [ %0, %cond.false ], [ getelementptr inbounds ([8 x i8], [8 x i8]* @.str.3, i64 0, i64 0), %entry ] |
| 260 | ret i8* %cond1 |
| 261 | } |
| 262 | |
| 263 | !llvm.module.flags = !{!0, !1} |
| 264 | !0 = !{i32 7, !"PIC Level", i32 2} |
| 265 | !1 = !{i32 1, !"Code Model", i32 1} |
| 266 | !4 = !{!"any pointer", !5, i64 0} |
| 267 | !5 = !{!"omnipotent char", !6, i64 0} |
| 268 | !6 = !{!"Simple C/C++ TBAA"} |