435 lines · plain
1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --check-globals all --version 52; REQUIRES: x86-registered-target3; RUN: opt < %s -passes=rel-lookup-table-converter -relocation-model=pic -S | FileCheck %s4target 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"5target triple = "x86_64-unknown-linux-gnu"6 7@.str = private unnamed_addr constant [5 x i8] c"zero\00", align 18@.str.1 = private unnamed_addr constant [4 x i8] c"one\00", align 19@.str.2 = private unnamed_addr constant [4 x i8] c"two\00", align 110@.str.3 = private unnamed_addr constant [8 x i8] c"default\00", align 111@.str.4 = private unnamed_addr constant [6 x i8] c"three\00", align 112@.str.5 = private unnamed_addr constant [5 x i8] c"str1\00", align 113@.str.6 = private unnamed_addr constant [5 x i8] c"str2\00", align 114@.str.7 = private unnamed_addr constant [12 x i8] c"singlevalue\00", align 115@.str.8 = private unnamed_addr constant [2 x i8] c"a\00", align 116@.str.9 = private unnamed_addr constant [2 x i8] c"b\00", align 117@.str.10 = private unnamed_addr constant [2 x i8] c"c\00", align 118 19@a1 = external global i32, align 420@b1 = external global i32, align 421@c1 = external global i32, align 422@d1 = external global i32, align 423 24@a2 = internal constant i32 0, align 425@b2 = internal constant i32 0, align 426@c2 = internal constant i32 0, align 427@d2 = internal constant i32 0, align 428 29@switch.table.external_linkage = private unnamed_addr constant [3 x ptr] [ptr @a1, ptr @b1, ptr @c1], align 830 31@switch.table.internal_linkage = private unnamed_addr constant [3 x ptr] [ptr @a2, ptr @b2, ptr @c2], align 832 33@switch.table.string_table = private unnamed_addr constant [3 x ptr]34 [35 ptr @.str,36 ptr @.str.1,37 ptr @.str.238 ], align 839 40@switch.table.string_table_holes = private unnamed_addr constant [4 x ptr]41 [42 ptr @.str,43 ptr @.str.3,44 ptr @.str.2,45 ptr @.str.446 ], align 847 48@switch.table.single_value = private unnamed_addr constant [3 x ptr]49 [50 ptr @.str,51 ptr @.str.1,52 ptr @.str.253 ], align 854 55@user_defined_lookup_table.table = internal unnamed_addr constant [3 x ptr]56 [57 ptr @.str,58 ptr @.str.1,59 ptr @.str.260 ], align 1661 62@table = internal constant [2 x ptr] [63 ptr @.str.8,64 ptr @.str.965], align 1666 67@table2 = internal constant [2 x ptr] [68 ptr @.str.8,69 ptr @.str.970], align 1671 72@table3 = internal constant [2 x ptr] [73 ptr @.str.8,74 ptr @.str.975], align 1676 77@table4 = internal constant [2 x ptr] [78 ptr @.str.8,79 ptr @.str.980], align 1681 82@table5 = internal constant [2 x ptr] [83 ptr @.str.8,84 ptr @.str.985], align 1686 87@skip.table = internal constant [4 x ptr] [88 ptr @.str.8,89 ptr null,90 ptr @.str.9,91 ptr null92], align 1693 94@wrong.skip.table = internal constant [4 x ptr] [95 ptr null,96 ptr @.str.8,97 ptr null,98 ptr @.str.999], align 16100 101;.102; CHECK: @.str = private unnamed_addr constant [5 x i8] c"zero\00", align 1103; CHECK: @.str.1 = private unnamed_addr constant [4 x i8] c"one\00", align 1104; CHECK: @.str.2 = private unnamed_addr constant [4 x i8] c"two\00", align 1105; CHECK: @.str.3 = private unnamed_addr constant [8 x i8] c"default\00", align 1106; CHECK: @.str.4 = private unnamed_addr constant [6 x i8] c"three\00", align 1107; CHECK: @.str.5 = private unnamed_addr constant [5 x i8] c"str1\00", align 1108; CHECK: @.str.6 = private unnamed_addr constant [5 x i8] c"str2\00", align 1109; CHECK: @.str.7 = private unnamed_addr constant [12 x i8] c"singlevalue\00", align 1110; CHECK: @.str.8 = private unnamed_addr constant [2 x i8] c"a\00", align 1111; CHECK: @.str.9 = private unnamed_addr constant [2 x i8] c"b\00", align 1112; CHECK: @.str.10 = private unnamed_addr constant [2 x i8] c"c\00", align 1113; CHECK: @a1 = external global i32, align 4114; CHECK: @b1 = external global i32, align 4115; CHECK: @c1 = external global i32, align 4116; CHECK: @d1 = external global i32, align 4117; CHECK: @a2 = internal constant i32 0, align 4118; CHECK: @b2 = internal constant i32 0, align 4119; CHECK: @c2 = internal constant i32 0, align 4120; CHECK: @d2 = internal constant i32 0, align 4121; CHECK: @switch.table.external_linkage = private unnamed_addr constant [3 x ptr] [ptr @a1, ptr @b1, ptr @c1], align 8122; CHECK: @switch.table.internal_linkage.rel = private unnamed_addr constant [3 x i32] [i32 trunc (i64 sub (i64 ptrtoint (ptr @a2 to i64), i64 ptrtoint (ptr @switch.table.internal_linkage.rel to i64)) to i32), i32 trunc (i64 sub (i64 ptrtoint (ptr @b2 to i64), i64 ptrtoint (ptr @switch.table.internal_linkage.rel to i64)) to i32), i32 trunc (i64 sub (i64 ptrtoint (ptr @c2 to i64), i64 ptrtoint (ptr @switch.table.internal_linkage.rel to i64)) to i32)], align 4123; CHECK: @switch.table.string_table.rel = private unnamed_addr constant [3 x i32] [i32 trunc (i64 sub (i64 ptrtoint (ptr @.str to i64), i64 ptrtoint (ptr @switch.table.string_table.rel to i64)) to i32), i32 trunc (i64 sub (i64 ptrtoint (ptr @.str.1 to i64), i64 ptrtoint (ptr @switch.table.string_table.rel to i64)) to i32), i32 trunc (i64 sub (i64 ptrtoint (ptr @.str.2 to i64), i64 ptrtoint (ptr @switch.table.string_table.rel to i64)) to i32)], align 4124; CHECK: @switch.table.string_table_holes.rel = private unnamed_addr constant [4 x i32] [i32 trunc (i64 sub (i64 ptrtoint (ptr @.str to i64), i64 ptrtoint (ptr @switch.table.string_table_holes.rel to i64)) to i32), i32 trunc (i64 sub (i64 ptrtoint (ptr @.str.3 to i64), i64 ptrtoint (ptr @switch.table.string_table_holes.rel to i64)) to i32), i32 trunc (i64 sub (i64 ptrtoint (ptr @.str.2 to i64), i64 ptrtoint (ptr @switch.table.string_table_holes.rel to i64)) to i32), i32 trunc (i64 sub (i64 ptrtoint (ptr @.str.4 to i64), i64 ptrtoint (ptr @switch.table.string_table_holes.rel to i64)) to i32)], align 4125; CHECK: @switch.table.single_value.rel = private unnamed_addr constant [3 x i32] [i32 trunc (i64 sub (i64 ptrtoint (ptr @.str to i64), i64 ptrtoint (ptr @switch.table.single_value.rel to i64)) to i32), i32 trunc (i64 sub (i64 ptrtoint (ptr @.str.1 to i64), i64 ptrtoint (ptr @switch.table.single_value.rel to i64)) to i32), i32 trunc (i64 sub (i64 ptrtoint (ptr @.str.2 to i64), i64 ptrtoint (ptr @switch.table.single_value.rel to i64)) to i32)], align 4126; CHECK: @user_defined_lookup_table.table.rel = internal unnamed_addr constant [3 x i32] [i32 trunc (i64 sub (i64 ptrtoint (ptr @.str to i64), i64 ptrtoint (ptr @user_defined_lookup_table.table.rel to i64)) to i32), i32 trunc (i64 sub (i64 ptrtoint (ptr @.str.1 to i64), i64 ptrtoint (ptr @user_defined_lookup_table.table.rel to i64)) to i32), i32 trunc (i64 sub (i64 ptrtoint (ptr @.str.2 to i64), i64 ptrtoint (ptr @user_defined_lookup_table.table.rel to i64)) to i32)], align 4127; CHECK: @table.rel = internal unnamed_addr constant [2 x i32] [i32 trunc (i64 sub (i64 ptrtoint (ptr @.str.8 to i64), i64 ptrtoint (ptr @table.rel to i64)) to i32), i32 trunc (i64 sub (i64 ptrtoint (ptr @.str.9 to i64), i64 ptrtoint (ptr @table.rel to i64)) to i32)], align 4128; CHECK: @table2.rel = internal unnamed_addr constant [2 x i32] [i32 trunc (i64 sub (i64 ptrtoint (ptr @.str.8 to i64), i64 ptrtoint (ptr @table2.rel to i64)) to i32), i32 trunc (i64 sub (i64 ptrtoint (ptr @.str.9 to i64), i64 ptrtoint (ptr @table2.rel to i64)) to i32)], align 4129; CHECK: @table3.rel = internal unnamed_addr constant [2 x i32] [i32 trunc (i64 sub (i64 ptrtoint (ptr @.str.8 to i64), i64 ptrtoint (ptr @table3.rel to i64)) to i32), i32 trunc (i64 sub (i64 ptrtoint (ptr @.str.9 to i64), i64 ptrtoint (ptr @table3.rel to i64)) to i32)], align 4130; CHECK: @table4 = internal constant [2 x ptr] [ptr @.str.8, ptr @.str.9], align 16131; CHECK: @table5 = internal constant [2 x ptr] [ptr @.str.8, ptr @.str.9], align 16132; CHECK: @skip.table.rel = internal unnamed_addr constant [2 x i32] [i32 trunc (i64 sub (i64 ptrtoint (ptr @.str.8 to i64), i64 ptrtoint (ptr @skip.table.rel to i64)) to i32), i32 trunc (i64 sub (i64 ptrtoint (ptr @.str.9 to i64), i64 ptrtoint (ptr @skip.table.rel to i64)) to i32)], align 4133; CHECK: @wrong.skip.table = internal constant [4 x ptr] [ptr null, ptr @.str.8, ptr null, ptr @.str.9], align 16134;.135define ptr @external_linkage(i32 %cond) {136; CHECK-LABEL: define ptr @external_linkage(137; CHECK-SAME: i32 [[COND:%.*]]) {138; CHECK-NEXT: [[ENTRY:.*:]]139; CHECK-NEXT: [[TMP0:%.*]] = icmp ult i32 [[COND]], 3140; CHECK-NEXT: br i1 [[TMP0]], label %[[SWITCH_LOOKUP:.*]], label %[[RETURN:.*]]141; CHECK: [[SWITCH_LOOKUP]]:142; CHECK-NEXT: [[SWITCH_GEP:%.*]] = getelementptr inbounds [3 x ptr], ptr @switch.table.external_linkage, i32 0, i32 [[COND]]143; CHECK-NEXT: [[SWITCH_LOAD:%.*]] = load ptr, ptr [[SWITCH_GEP]], align 8144; CHECK-NEXT: ret ptr [[SWITCH_LOAD]]145; CHECK: [[RETURN]]:146; CHECK-NEXT: ret ptr @d1147;148entry:149 %0 = icmp ult i32 %cond, 3150 br i1 %0, label %switch.lookup, label %return151 152switch.lookup: ; preds = %entry153 %switch.gep = getelementptr inbounds [3 x ptr], ptr @switch.table.external_linkage, i32 0, i32 %cond154 %switch.load = load ptr, ptr %switch.gep, align 8155 ret ptr %switch.load156 157return: ; preds = %entry158 ret ptr @d1159}160 161; Relative switch lookup table for integer pointers that have internal linkage162define ptr @internal_linkage(i32 %cond) {163; CHECK-LABEL: define ptr @internal_linkage(164; CHECK-SAME: i32 [[COND:%.*]]) {165; CHECK-NEXT: [[ENTRY:.*:]]166; CHECK-NEXT: [[TMP0:%.*]] = icmp ult i32 [[COND]], 3167; CHECK-NEXT: br i1 [[TMP0]], label %[[SWITCH_LOOKUP:.*]], label %[[RETURN:.*]]168; CHECK: [[SWITCH_LOOKUP]]:169; CHECK-NEXT: [[RELTABLE_SHIFT:%.*]] = shl i32 [[COND]], 2170; CHECK-NEXT: [[RELTABLE_INTRINSIC:%.*]] = call ptr @llvm.load.relative.i32(ptr @switch.table.internal_linkage.rel, i32 [[RELTABLE_SHIFT]])171; CHECK-NEXT: ret ptr [[RELTABLE_INTRINSIC]]172; CHECK: [[RETURN]]:173; CHECK-NEXT: ret ptr @d2174;175entry:176 %0 = icmp ult i32 %cond, 3177 br i1 %0, label %switch.lookup, label %return178 179switch.lookup: ; preds = %entry180 %switch.gep = getelementptr inbounds [3 x ptr], ptr @switch.table.internal_linkage, i32 0, i32 %cond181 %switch.load = load ptr, ptr %switch.gep, align 8182 ret ptr %switch.load183 184return: ; preds = %entry185 ret ptr @d2186}187 188; ; Relative switch lookup table for strings189define ptr @string_table(i32 %cond) {190; CHECK-LABEL: define ptr @string_table(191; CHECK-SAME: i32 [[COND:%.*]]) {192; CHECK-NEXT: [[ENTRY:.*:]]193; CHECK-NEXT: [[TMP0:%.*]] = icmp ult i32 [[COND]], 3194; CHECK-NEXT: br i1 [[TMP0]], label %[[SWITCH_LOOKUP:.*]], label %[[RETURN:.*]]195; CHECK: [[SWITCH_LOOKUP]]:196; CHECK-NEXT: [[RELTABLE_SHIFT:%.*]] = shl i32 [[COND]], 2197; CHECK-NEXT: [[RELTABLE_INTRINSIC:%.*]] = call ptr @llvm.load.relative.i32(ptr @switch.table.string_table.rel, i32 [[RELTABLE_SHIFT]])198; CHECK-NEXT: ret ptr [[RELTABLE_INTRINSIC]]199; CHECK: [[RETURN]]:200; CHECK-NEXT: ret ptr @.str.3201;202entry:203 %0 = icmp ult i32 %cond, 3204 br i1 %0, label %switch.lookup, label %return205 206switch.lookup: ; preds = %entry207 %switch.gep = getelementptr inbounds [3 x ptr], ptr @switch.table.string_table, i32 0, i32 %cond208 %switch.load = load ptr, ptr %switch.gep, align 8209 ret ptr %switch.load210 211return: ; preds = %entry212 ret ptr @.str.3213}214 215; Relative switch lookup table for strings with holes, where holes are filled with relative offset to default values216define ptr @string_table_holes(i32 %cond) {217; CHECK-LABEL: define ptr @string_table_holes(218; CHECK-SAME: i32 [[COND:%.*]]) {219; CHECK-NEXT: [[ENTRY:.*:]]220; CHECK-NEXT: [[TMP0:%.*]] = icmp ult i32 [[COND]], 4221; CHECK-NEXT: br i1 [[TMP0]], label %[[SWITCH_LOOKUP:.*]], label %[[RETURN:.*]]222; CHECK: [[SWITCH_LOOKUP]]:223; CHECK-NEXT: [[RELTABLE_SHIFT:%.*]] = shl i32 [[COND]], 2224; CHECK-NEXT: [[RELTABLE_INTRINSIC:%.*]] = call ptr @llvm.load.relative.i32(ptr @switch.table.string_table_holes.rel, i32 [[RELTABLE_SHIFT]])225; CHECK-NEXT: ret ptr [[RELTABLE_INTRINSIC]]226; CHECK: [[RETURN]]:227; CHECK-NEXT: ret ptr @.str.3228;229entry:230 %0 = icmp ult i32 %cond, 4231 br i1 %0, label %switch.lookup, label %return232 233switch.lookup: ; preds = %entry234 %switch.gep = getelementptr inbounds [4 x ptr], ptr @switch.table.string_table_holes, i32 0, i32 %cond235 %switch.load = load ptr, ptr %switch.gep, align 8236 ret ptr %switch.load237 238return: ; preds = %entry239 ret ptr @.str.3240}241 242 243; Single value check244; If there is a lookup table, where each element contains the same value,245; a relative lookup should not be generated246define void @single_value(i32 %cond) {247; CHECK-LABEL: define void @single_value(248; CHECK-SAME: i32 [[COND:%.*]]) {249; CHECK-NEXT: [[ENTRY:.*]]:250; CHECK-NEXT: [[TMP0:%.*]] = icmp ult i32 [[COND]], 3251; CHECK-NEXT: br i1 [[TMP0]], label %[[SWITCH_LOOKUP:.*]], label %[[SW_EPILOG:.*]]252; CHECK: [[SWITCH_LOOKUP]]:253; CHECK-NEXT: [[RELTABLE_SHIFT:%.*]] = shl i32 [[COND]], 2254; CHECK-NEXT: [[RELTABLE_INTRINSIC:%.*]] = call ptr @llvm.load.relative.i32(ptr @switch.table.single_value.rel, i32 [[RELTABLE_SHIFT]])255; CHECK-NEXT: br label %[[SW_EPILOG]]256; CHECK: [[SW_EPILOG]]:257; CHECK-NEXT: [[STR1_0:%.*]] = phi ptr [ @.str.5, %[[ENTRY]] ], [ @.str.7, %[[SWITCH_LOOKUP]] ]258; CHECK-NEXT: [[STR2_0:%.*]] = phi ptr [ @.str.6, %[[ENTRY]] ], [ [[RELTABLE_INTRINSIC]], %[[SWITCH_LOOKUP]] ]259; CHECK-NEXT: ret void260;261 262entry:263 %0 = icmp ult i32 %cond, 3264 br i1 %0, label %switch.lookup, label %sw.epilog265 266switch.lookup: ; preds = %entry267 %switch.gep = getelementptr inbounds [3 x ptr], ptr @switch.table.single_value, i32 0, i32 %cond268 %switch.load = load ptr, ptr %switch.gep, align 8269 br label %sw.epilog270 271sw.epilog: ; preds = %switch.lookup, %entry272 %str1.0 = phi ptr [ @.str.5, %entry ], [ @.str.7, %switch.lookup ]273 %str2.0 = phi ptr [ @.str.6, %entry ], [ %switch.load, %switch.lookup ]274 ret void275}276 277; Relative lookup table generated for a user-defined lookup table278define ptr @user_defined_lookup_table(i32 %cond) {279; CHECK-LABEL: define ptr @user_defined_lookup_table(280; CHECK-SAME: i32 [[COND:%.*]]) {281; CHECK-NEXT: [[ENTRY:.*]]:282; CHECK-NEXT: [[TMP0:%.*]] = icmp sgt i32 [[COND]], 3283; CHECK-NEXT: br i1 [[TMP0]], label %[[COND_END:.*]], label %[[COND_FALSE:.*]]284; CHECK: [[COND_FALSE]]:285; CHECK-NEXT: [[IDX_PROM:%.*]] = sext i32 [[COND]] to i64286; CHECK-NEXT: [[RELTABLE_SHIFT:%.*]] = shl i64 [[IDX_PROM]], 2287; CHECK-NEXT: [[RELTABLE_INTRINSIC:%.*]] = call ptr @llvm.load.relative.i64(ptr @user_defined_lookup_table.table.rel, i64 [[RELTABLE_SHIFT]])288; CHECK-NEXT: br label %[[COND_END]]289; CHECK: [[COND_END]]:290; CHECK-NEXT: [[COND1:%.*]] = phi ptr [ [[RELTABLE_INTRINSIC]], %[[COND_FALSE]] ], [ @.str.3, %[[ENTRY]] ]291; CHECK-NEXT: ret ptr [[COND1]]292;293entry:294 %cmp = icmp sgt i32 %cond, 3295 br i1 %cmp, label %cond.end, label %cond.false296 297cond.false: ; preds = %entry298 %idxprom = sext i32 %cond to i64299 %arrayidx = getelementptr inbounds [3 x ptr], ptr @user_defined_lookup_table.table, i64 0, i64 %idxprom300 %0 = load ptr, ptr %arrayidx, align 8, !tbaa !4301 br label %cond.end302 303cond.end: ; preds = %entry, %cond.false304 %cond1 = phi ptr [ %0, %cond.false ], [ @.str.3, %entry ]305 ret ptr %cond1306}307 308; Check to ensure that call @llvm.load.relative is inserted before load, not before gep.309; When a lookup table is accessed inside a loop, and a gep is hosted outside the loop via licm,310; make sure that call @llvm.load.relative is inserted before load.311define ptr @loop_hoist(i32 %x) {312; CHECK-LABEL: define ptr @loop_hoist(313; CHECK-SAME: i32 [[X:%.*]]) {314; CHECK-NEXT: [[ENTRY:.*]]:315; CHECK-NEXT: [[TMP0:%.*]] = icmp sgt i32 [[X]], 1316; CHECK-NEXT: [[RELTABLE_SHIFT:%.*]] = shl i32 [[X]], 2317; CHECK-NEXT: br i1 [[TMP0]], label %[[IF_DONE:.*]], label %[[IF_FALSE:.*]]318; CHECK: [[IF_FALSE]]:319; CHECK-NEXT: [[RELTABLE_INTRINSIC:%.*]] = call ptr @llvm.load.relative.i32(ptr @table.rel, i32 [[RELTABLE_SHIFT]])320; CHECK-NEXT: br label %[[IF_DONE]]321; CHECK: [[IF_DONE]]:322; CHECK-NEXT: [[TMP2:%.*]] = phi ptr [ @.str.10, %[[ENTRY]] ], [ [[RELTABLE_INTRINSIC]], %[[IF_FALSE]] ]323; CHECK-NEXT: ret ptr [[TMP2]]324;325entry:326 %0 = icmp sgt i32 %x, 1327 %1 = getelementptr [2 x ptr], ptr @table, i32 0, i32 %x328 br i1 %0, label %if.done, label %if.false329 330if.false:331 %2 = load ptr, ptr %1332 br label %if.done333 334if.done:335 %3 = phi ptr [ @.str.10, %entry ], [ %2, %if.false ]336 ret ptr %3337}338 339; Another check to ensure that call @llvm.load.relative is inserted before load but not before gep.340; When a lookup table is accessed, and gep is not immediately followed by a load (like if there is a function call341; or an exception in between), make sure that call @llvm.load.relative is inserted before load.342declare void @may_not_return()343 344define ptr @gep_is_not_imm_followed_by_load(i32 %x) {345; CHECK-LABEL: define ptr @gep_is_not_imm_followed_by_load(346; CHECK-SAME: i32 [[X:%.*]]) {347; CHECK-NEXT: [[ENTRY:.*:]]348; CHECK-NEXT: [[RELTABLE_SHIFT:%.*]] = shl i32 [[X]], 2349; CHECK-NEXT: call void @may_not_return()350; CHECK-NEXT: [[RELTABLE_INTRINSIC:%.*]] = call ptr @llvm.load.relative.i32(ptr @table2.rel, i32 [[RELTABLE_SHIFT]])351; CHECK-NEXT: ret ptr [[RELTABLE_INTRINSIC]]352;353entry:354 %0 = getelementptr [2 x ptr], ptr @table2, i32 0, i32 %x355 call void @may_not_return()356 %1 = load ptr, ptr %0357 ret ptr %1358}359 360define ptr @gep_no_leading_zero(i64 %index) {361; CHECK-LABEL: define ptr @gep_no_leading_zero(362; CHECK-SAME: i64 [[INDEX:%.*]]) {363; CHECK-NEXT: [[RELTABLE_SHIFT:%.*]] = shl i64 [[INDEX]], 2364; CHECK-NEXT: [[LOAD:%.*]] = call ptr @llvm.load.relative.i64(ptr @table3.rel, i64 [[RELTABLE_SHIFT]])365; CHECK-NEXT: ret ptr [[LOAD]]366;367 %gep = getelementptr ptr, ptr @table3, i64 %index368 %load = load ptr, ptr %gep369 ret ptr %load370}371 372define ptr @gep_wrong_stride(i64 %index) {373; CHECK-LABEL: define ptr @gep_wrong_stride(374; CHECK-SAME: i64 [[INDEX:%.*]]) {375; CHECK-NEXT: [[GEP:%.*]] = getelementptr i8, ptr @table4, i64 [[INDEX]]376; CHECK-NEXT: [[LOAD:%.*]] = load ptr, ptr [[GEP]], align 8377; CHECK-NEXT: ret ptr [[LOAD]]378;379 %gep = getelementptr i8, ptr @table4, i64 %index380 %load = load ptr, ptr %gep381 ret ptr %load382}383 384define ptr @gep_wrong_constant_offset(i64 %index) {385; CHECK-LABEL: define ptr @gep_wrong_constant_offset(386; CHECK-SAME: i64 [[INDEX:%.*]]) {387; CHECK-NEXT: [[GEP:%.*]] = getelementptr { ptr, i32 }, ptr @table5, i64 [[INDEX]], i32 1388; CHECK-NEXT: [[LOAD:%.*]] = load ptr, ptr [[GEP]], align 8389; CHECK-NEXT: ret ptr [[LOAD]]390;391 %gep = getelementptr { ptr, i32 }, ptr @table5, i64 %index, i32 1392 %load = load ptr, ptr %gep393 ret ptr %load394}395 396; This is intentionally advancing by two pointers.397define ptr @table_with_skipped_elements(i64 %index) {398; CHECK-LABEL: define ptr @table_with_skipped_elements(399; CHECK-SAME: i64 [[INDEX:%.*]]) {400; CHECK-NEXT: [[RELTABLE_SHIFT:%.*]] = shl i64 [[INDEX]], 2401; CHECK-NEXT: [[LOAD:%.*]] = call ptr @llvm.load.relative.i64(ptr @skip.table.rel, i64 [[RELTABLE_SHIFT]])402; CHECK-NEXT: ret ptr [[LOAD]]403;404 %gep = getelementptr [2 x ptr], ptr @skip.table, i64 %index405 %load = load ptr, ptr %gep406 ret ptr %load407}408 409; Same as previous test, but the elements are at the wrong position in the410; table.411define ptr @table_with_skipped_elements_wrong(i64 %index) {412; CHECK-LABEL: define ptr @table_with_skipped_elements_wrong(413; CHECK-SAME: i64 [[INDEX:%.*]]) {414; CHECK-NEXT: [[GEP:%.*]] = getelementptr [2 x ptr], ptr @wrong.skip.table, i64 [[INDEX]]415; CHECK-NEXT: [[LOAD:%.*]] = load ptr, ptr [[GEP]], align 8416; CHECK-NEXT: ret ptr [[LOAD]]417;418 %gep = getelementptr [2 x ptr], ptr @wrong.skip.table, i64 %index419 %load = load ptr, ptr %gep420 ret ptr %load421}422 423!llvm.module.flags = !{!0, !1}424!0 = !{i32 7, !"PIC Level", i32 2}425!1 = !{i32 1, !"Code Model", i32 1}426!4 = !{!"any pointer", !5, i64 0}427!5 = !{!"omnipotent char", !6, i64 0}428!6 = !{!"Simple C/C++ TBAA"}429;.430; CHECK: attributes #[[ATTR0:[0-9]+]] = { nocallback nofree nosync nounwind willreturn memory(argmem: read) }431;.432; CHECK: [[META0:![0-9]+]] = !{i32 8, !"PIC Level", i32 2}433; CHECK: [[META1:![0-9]+]] = !{i32 1, !"Code Model", i32 1}434;.435