[llvm] [RelLookupTableConverter] Restore X86/relative_lookup_table.ll and add AArch64 test (PR #223494)

via llvm-commits llvm-commits at lists.llvm.org
Mon Sep 14 11:53:43 PDT 2026


https://github.com/PiJoules created https://github.com/llvm/llvm-project/pull/223494

Move relative_lookup_table.ll back to X86/ and restore the original assertions, undoing manual edits to generated check lines and addressing post-commit review feedback on #222809.

Add llvm/test/Transforms/RelLookupTableConverter/AArch64/relative_lookup_table.ll as the dedicated AArch64 equivalent with clean, autogenerated checks.

>From 6f0a9c170a53cce7a294a595e8f50405249890f9 Mon Sep 17 00:00:00 2001
From: Leonard Chan <leonardchan at google.com>
Date: Mon, 14 Sep 2026 18:38:34 +0000
Subject: [PATCH] [RelLookupTableConverter] Restore
 X86/relative_lookup_table.ll and add AArch64 test

Move relative_lookup_table.ll back to X86/ and restore the original
assertions, undoing manual edits to generated check lines and addressing
post-commit review feedback on #222809.

Add llvm/test/Transforms/RelLookupTableConverter/AArch64/relative_lookup_table.ll
as the dedicated AArch64 equivalent with clean, autogenerated checks.
---
 .../AArch64/relative_lookup_table.ll          | 405 ++++++++++++++++++
 .../{ => X86}/relative_lookup_table.ll        |  27 +-
 2 files changed, 418 insertions(+), 14 deletions(-)
 create mode 100644 llvm/test/Transforms/RelLookupTableConverter/AArch64/relative_lookup_table.ll
 rename llvm/test/Transforms/RelLookupTableConverter/{ => X86}/relative_lookup_table.ll (95%)

diff --git a/llvm/test/Transforms/RelLookupTableConverter/AArch64/relative_lookup_table.ll b/llvm/test/Transforms/RelLookupTableConverter/AArch64/relative_lookup_table.ll
new file mode 100644
index 0000000000000..c00954002ef5f
--- /dev/null
+++ b/llvm/test/Transforms/RelLookupTableConverter/AArch64/relative_lookup_table.ll
@@ -0,0 +1,405 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --check-globals all --version 5
+; REQUIRES: aarch64-registered-target
+; RUN: opt < %s -passes=rel-lookup-table-converter -relocation-model=pic -mtriple=aarch64-unknown-linux-gnu -S | FileCheck %s
+target datalayout = "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128"
+
+ at .str = private unnamed_addr constant [5 x i8] c"zero\00", align 1
+ at .str.1 = private unnamed_addr constant [4 x i8] c"one\00", align 1
+ at .str.2 = private unnamed_addr constant [4 x i8] c"two\00", align 1
+ at .str.3 = private unnamed_addr constant [8 x i8] c"default\00", align 1
+ at .str.4 = private unnamed_addr constant [6 x i8] c"three\00", align 1
+ at .str.5 = private unnamed_addr constant [5 x i8] c"str1\00", align 1
+ at .str.6 = private unnamed_addr constant [5 x i8] c"str2\00", align 1
+ at .str.7 = private unnamed_addr constant [12 x i8] c"singlevalue\00", align 1
+ at .str.8 = private unnamed_addr constant [2 x i8] c"a\00", align 1
+ at .str.9 = private unnamed_addr constant [2 x i8] c"b\00", align 1
+ at .str.10 = private unnamed_addr constant [2 x i8] c"c\00", align 1
+
+ at a1 = external global i32, align 4
+ at b1 = external global i32, align 4
+ at c1 = external global i32, align 4
+ at d1 = external global i32, align 4
+
+ at a2 = internal constant i32 0, align 4
+ at b2 = internal constant i32 0, align 4
+ at c2 = internal constant i32 0, align 4
+ at d2 = internal constant i32 0, align 4
+
+ at switch.table.external_linkage = private unnamed_addr constant [3 x ptr] [ptr @a1, ptr @b1, ptr @c1], align 8
+
+ at switch.table.internal_linkage = private unnamed_addr constant [3 x ptr] [ptr @a2, ptr @b2, ptr @c2], align 8
+
+ at switch.table.string_table = private unnamed_addr constant [3 x ptr]
+  [
+  ptr @.str,
+  ptr @.str.1,
+  ptr @.str.2
+  ], align 8
+
+ at switch.table.string_table_holes = private unnamed_addr constant [4 x ptr]
+  [
+  ptr @.str,
+  ptr @.str.3,
+  ptr @.str.2,
+  ptr @.str.4
+  ], align 8
+
+ at switch.table.single_value = private unnamed_addr constant [3 x ptr]
+  [
+  ptr @.str,
+  ptr @.str.1,
+  ptr @.str.2
+  ], align 8
+
+ at user_defined_lookup_table.table = internal unnamed_addr constant [3 x ptr]
+  [
+  ptr @.str,
+  ptr @.str.1,
+  ptr @.str.2
+  ], align 8
+
+ at table = internal unnamed_addr constant [2 x ptr] [ptr @.str.8, ptr @.str.9], align 16
+ at table2 = internal unnamed_addr constant [2 x ptr] [ptr @.str.8, ptr @.str.9], align 16
+ at table3 = internal unnamed_addr constant [2 x ptr] [ptr @.str.8, ptr @.str.9], align 16
+
+; A relative lookup should not be generated since the elements have external linkage
+ at table4 = internal constant [2 x ptr] [ptr @.str.8, ptr @.str.9], align 16
+
+; A relative lookup should not be generated since the elements are not ConstantExpr
+ at table5 = internal constant [2 x ptr] [ptr @.str.8, ptr @.str.9], align 16
+
+; A relative lookup should not be generated since the elements have external linkage
+;.
+; CHECK: @.str = private constant [5 x i8] c"zero\00", align 1
+; CHECK: @.str.1 = private constant [4 x i8] c"one\00", align 1
+; CHECK: @.str.2 = private constant [4 x i8] c"two\00", align 1
+; CHECK: @.str.3 = private constant [8 x i8] c"default\00", align 1
+; CHECK: @.str.4 = private constant [6 x i8] c"three\00", align 1
+; CHECK: @.str.5 = private unnamed_addr constant [5 x i8] c"str1\00", align 1
+; CHECK: @.str.6 = private unnamed_addr constant [5 x i8] c"str2\00", align 1
+; CHECK: @.str.7 = private unnamed_addr constant [12 x i8] c"singlevalue\00", align 1
+; CHECK: @.str.8 = private constant [2 x i8] c"a\00", align 1
+; CHECK: @.str.9 = private constant [2 x i8] c"b\00", align 1
+; CHECK: @.str.10 = private unnamed_addr constant [2 x i8] c"c\00", align 1
+; CHECK: @a1 = external global i32, align 4
+; CHECK: @b1 = external global i32, align 4
+; CHECK: @c1 = external global i32, align 4
+; CHECK: @d1 = external global i32, align 4
+; CHECK: @a2 = internal constant i32 0, align 4
+; CHECK: @b2 = internal constant i32 0, align 4
+; CHECK: @c2 = internal constant i32 0, align 4
+; CHECK: @d2 = internal constant i32 0, align 4
+; CHECK: @switch.table.external_linkage = private unnamed_addr constant [3 x ptr] [ptr @a1, ptr @b1, ptr @c1], align 8
+; 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 4
+; 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 4
+; 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 4
+; 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 4
+; 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 4
+; 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 4
+; 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 4
+; 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 4
+; CHECK: @table4 = internal constant [2 x ptr] [ptr @.str.8, ptr @.str.9], align 16
+; CHECK: @table5 = internal constant [2 x ptr] [ptr @.str.8, ptr @.str.9], align 16
+; 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 4
+; CHECK: @wrong.skip.table = internal unnamed_addr constant [4 x ptr] [ptr null, ptr @.str.8, ptr null, ptr @.str.9], align 16
+;.
+define ptr @external_linkage(i32 %cond) {
+; CHECK-LABEL: define ptr @external_linkage(
+; CHECK-SAME: i32 [[COND:%.*]]) {
+; CHECK-NEXT:  [[ENTRY:.*:]]
+; CHECK-NEXT:    [[TMP0:%.*]] = icmp ult i32 [[COND]], 3
+; CHECK-NEXT:    br i1 [[TMP0]], label %[[SWITCH_LOOKUP:.*]], label %[[RETURN:.*]]
+; CHECK:       [[SWITCH_LOOKUP]]:
+; CHECK-NEXT:    [[SWITCH_GEP:%.*]] = getelementptr inbounds [3 x ptr], ptr @switch.table.external_linkage, i32 0, i32 [[COND]]
+; CHECK-NEXT:    [[SWITCH_LOAD:%.*]] = load ptr, ptr [[SWITCH_GEP]], align 8
+; CHECK-NEXT:    ret ptr [[SWITCH_LOAD]]
+; CHECK:       [[RETURN]]:
+; CHECK-NEXT:    ret ptr @d1
+;
+entry:
+  %0 = icmp ult i32 %cond, 3
+  br i1 %0, label %switch.lookup, label %return
+
+switch.lookup:
+  %switch.gep = getelementptr inbounds [3 x ptr], ptr @switch.table.external_linkage, i32 0, i32 %cond
+  %switch.load = load ptr, ptr %switch.gep, align 8
+  ret ptr %switch.load
+
+return:
+  ret ptr @d1
+}
+
+; Relative lookup table generated for internal linkage globals
+define ptr @internal_linkage(i32 %cond) {
+; CHECK-LABEL: define ptr @internal_linkage(
+; CHECK-SAME: i32 [[COND:%.*]]) {
+; CHECK-NEXT:  [[ENTRY:.*:]]
+; CHECK-NEXT:    [[TMP0:%.*]] = icmp ult i32 [[COND]], 3
+; CHECK-NEXT:    br i1 [[TMP0]], label %[[SWITCH_LOOKUP:.*]], label %[[RETURN:.*]]
+; CHECK:       [[SWITCH_LOOKUP]]:
+; CHECK-NEXT:    [[RELTABLE_SHIFT:%.*]] = shl i32 [[COND]], 2
+; CHECK-NEXT:    [[RELTABLE_INTRINSIC:%.*]] = call ptr @llvm.load.relative.i32(ptr @switch.table.internal_linkage.rel, i32 [[RELTABLE_SHIFT]])
+; CHECK-NEXT:    ret ptr [[RELTABLE_INTRINSIC]]
+; CHECK:       [[RETURN]]:
+; CHECK-NEXT:    ret ptr @d2
+;
+entry:
+  %0 = icmp ult i32 %cond, 3
+  br i1 %0, label %switch.lookup, label %return
+
+switch.lookup:
+  %switch.gep = getelementptr inbounds [3 x ptr], ptr @switch.table.internal_linkage, i32 0, i32 %cond
+  %switch.load = load ptr, ptr %switch.gep, align 8
+  ret ptr %switch.load
+
+return:
+  ret ptr @d2
+}
+
+; Relative switch lookup table for strings
+define ptr @string_table(i32 %cond) {
+; CHECK-LABEL: define ptr @string_table(
+; CHECK-SAME: i32 [[COND:%.*]]) {
+; CHECK-NEXT:  [[ENTRY:.*:]]
+; CHECK-NEXT:    [[TMP0:%.*]] = icmp ult i32 [[COND]], 3
+; CHECK-NEXT:    br i1 [[TMP0]], label %[[SWITCH_LOOKUP:.*]], label %[[RETURN:.*]]
+; CHECK:       [[SWITCH_LOOKUP]]:
+; CHECK-NEXT:    [[RELTABLE_SHIFT:%.*]] = shl i32 [[COND]], 2
+; CHECK-NEXT:    [[RELTABLE_INTRINSIC:%.*]] = call ptr @llvm.load.relative.i32(ptr @switch.table.string_table.rel, i32 [[RELTABLE_SHIFT]])
+; CHECK-NEXT:    ret ptr [[RELTABLE_INTRINSIC]]
+; CHECK:       [[RETURN]]:
+; CHECK-NEXT:    ret ptr @.str.3
+;
+entry:
+  %0 = icmp ult i32 %cond, 3
+  br i1 %0, label %switch.lookup, label %return
+
+switch.lookup:
+  %switch.gep = getelementptr inbounds [3 x ptr], ptr @switch.table.string_table, i32 0, i32 %cond
+  %switch.load = load ptr, ptr %switch.gep, align 8
+  ret ptr %switch.load
+
+return:
+  ret ptr @.str.3
+}
+
+; Relative switch lookup table with holes
+define ptr @string_table_holes(i32 %cond) {
+; CHECK-LABEL: define ptr @string_table_holes(
+; CHECK-SAME: i32 [[COND:%.*]]) {
+; CHECK-NEXT:  [[ENTRY:.*:]]
+; CHECK-NEXT:    [[TMP0:%.*]] = icmp ult i32 [[COND]], 4
+; CHECK-NEXT:    br i1 [[TMP0]], label %[[SWITCH_LOOKUP:.*]], label %[[RETURN:.*]]
+; CHECK:       [[SWITCH_LOOKUP]]:
+; CHECK-NEXT:    [[RELTABLE_SHIFT:%.*]] = shl i32 [[COND]], 2
+; CHECK-NEXT:    [[RELTABLE_INTRINSIC:%.*]] = call ptr @llvm.load.relative.i32(ptr @switch.table.string_table_holes.rel, i32 [[RELTABLE_SHIFT]])
+; CHECK-NEXT:    ret ptr [[RELTABLE_INTRINSIC]]
+; CHECK:       [[RETURN]]:
+; CHECK-NEXT:    ret ptr @.str.3
+;
+entry:
+  %0 = icmp ult i32 %cond, 4
+  br i1 %0, label %switch.lookup, label %return
+
+switch.lookup:
+  %switch.gep = getelementptr inbounds [4 x ptr], ptr @switch.table.string_table_holes, i32 0, i32 %cond
+  %switch.load = load ptr, ptr %switch.gep, align 8
+  ret ptr %switch.load
+
+return:
+  ret ptr @.str.3
+}
+
+; When a pointer and a value are produced by the switch and they both use
+; lookup tables, a relative lookup is generated for the pointer table, and
+; a relative lookup should not be generated
+define void @single_value(i32 %cond)  {
+; CHECK-LABEL: define void @single_value(
+; CHECK-SAME: i32 [[COND:%.*]]) {
+; CHECK-NEXT:  [[ENTRY:.*]]:
+; CHECK-NEXT:    [[TMP0:%.*]] = icmp ult i32 [[COND]], 3
+; CHECK-NEXT:    br i1 [[TMP0]], label %[[SWITCH_LOOKUP:.*]], label %[[SW_EPILOG:.*]]
+; CHECK:       [[SWITCH_LOOKUP]]:
+; CHECK-NEXT:    [[RELTABLE_SHIFT:%.*]] = shl i32 [[COND]], 2
+; CHECK-NEXT:    [[RELTABLE_INTRINSIC:%.*]] = call ptr @llvm.load.relative.i32(ptr @switch.table.single_value.rel, i32 [[RELTABLE_SHIFT]])
+; CHECK-NEXT:    br label %[[SW_EPILOG]]
+; CHECK:       [[SW_EPILOG]]:
+; CHECK-NEXT:    [[STR1_0:%.*]] = phi ptr [ @.str.5, %[[ENTRY]] ], [ @.str.7, %[[SWITCH_LOOKUP]] ]
+; CHECK-NEXT:    [[STR2_0:%.*]] = phi ptr [ @.str.6, %[[ENTRY]] ], [ [[RELTABLE_INTRINSIC]], %[[SWITCH_LOOKUP]] ]
+; CHECK-NEXT:    ret void
+;
+entry:
+  %0 = icmp ult i32 %cond, 3
+  br i1 %0, label %switch.lookup, label %sw.epilog
+
+switch.lookup:
+  %switch.gep = getelementptr inbounds [3 x ptr], ptr @switch.table.single_value, i32 0, i32 %cond
+  %switch.load = load ptr, ptr %switch.gep, align 8
+  br label %sw.epilog
+
+sw.epilog:
+  %str1.0 = phi ptr [ @.str.5, %entry ], [ @.str.7, %switch.lookup ]
+  %str2.0 = phi ptr [ @.str.6, %entry ], [ %switch.load, %switch.lookup ]
+  ret void
+}
+
+; Relative lookup table generated for a user-defined lookup table
+define ptr @user_defined_lookup_table(i32 %cond)  {
+; CHECK-LABEL: define ptr @user_defined_lookup_table(
+; CHECK-SAME: i32 [[COND:%.*]]) {
+; CHECK-NEXT:  [[ENTRY:.*]]:
+; CHECK-NEXT:    [[CMP:%.*]] = icmp sgt i32 [[COND]], 3
+; CHECK-NEXT:    br i1 [[CMP]], label %[[COND_END:.*]], label %[[COND_FALSE:.*]]
+; CHECK:       [[COND_FALSE]]:
+; CHECK-NEXT:    [[IDXPROM:%.*]] = sext i32 [[COND]] to i64
+; CHECK-NEXT:    [[RELTABLE_SHIFT:%.*]] = shl i64 [[IDXPROM]], 2
+; CHECK-NEXT:    [[RELTABLE_INTRINSIC:%.*]] = call ptr @llvm.load.relative.i64(ptr @user_defined_lookup_table.table.rel, i64 [[RELTABLE_SHIFT]])
+; CHECK-NEXT:    br label %[[COND_END]]
+; CHECK:       [[COND_END]]:
+; CHECK-NEXT:    [[COND1:%.*]] = phi ptr [ [[RELTABLE_INTRINSIC]], %[[COND_FALSE]] ], [ @.str.3, %[[ENTRY]] ]
+; CHECK-NEXT:    ret ptr [[COND1]]
+;
+entry:
+  %cmp = icmp sgt i32 %cond, 3
+  br i1 %cmp, label %cond.end, label %cond.false
+
+cond.false:
+  %idxprom = sext i32 %cond to i64
+  %arrayidx = getelementptr inbounds [3 x ptr], ptr @user_defined_lookup_table.table, i64 0, i64 %idxprom
+  %0 = load ptr, ptr %arrayidx, align 8, !tbaa !4
+  br label %cond.end
+
+cond.end:
+  %cond1 = phi ptr [ %0, %cond.false ], [ @.str.3, %entry ]
+  ret ptr %cond1
+}
+
+; Check to ensure that call @llvm.load.relative is inserted before load, not before gep.
+; When a lookup table is accessed inside a loop, and a gep is hosted outside the loop via licm,
+; make sure that call @llvm.load.relative is inserted before load.
+define ptr @loop_hoist(i32 %x) {
+; CHECK-LABEL: define ptr @loop_hoist(
+; CHECK-SAME: i32 [[X:%.*]]) {
+; CHECK-NEXT:  [[ENTRY:.*]]:
+; CHECK-NEXT:    [[TMP0:%.*]] = icmp sgt i32 [[X]], 1
+; CHECK-NEXT:    [[RELTABLE_SHIFT:%.*]] = shl i32 [[X]], 2
+; CHECK-NEXT:    br i1 [[TMP0]], label %[[IF_DONE:.*]], label %[[IF_FALSE:.*]]
+; CHECK:       [[IF_FALSE]]:
+; CHECK-NEXT:    [[RELTABLE_INTRINSIC:%.*]] = call ptr @llvm.load.relative.i32(ptr @table.rel, i32 [[RELTABLE_SHIFT]])
+; CHECK-NEXT:    br label %[[IF_DONE]]
+; CHECK:       [[IF_DONE]]:
+; CHECK-NEXT:    [[TMP1:%.*]] = phi ptr [ @.str.10, %[[ENTRY]] ], [ [[RELTABLE_INTRINSIC]], %[[IF_FALSE]] ]
+; CHECK-NEXT:    ret ptr [[TMP1]]
+;
+entry:
+  %0 = icmp sgt i32 %x, 1
+  %1 = getelementptr [2 x ptr], ptr @table, i32 0, i32 %x
+  br i1 %0, label %if.done, label %if.false
+
+if.false:
+  %2 = load ptr, ptr %1
+  br label %if.done
+
+if.done:
+  %3 = phi ptr [ @.str.10, %entry ], [ %2, %if.false ]
+  ret ptr %3
+}
+
+; Another check to ensure that call @llvm.load.relative is inserted before load but not before gep.
+; When a lookup table is accessed, and gep is not immediately followed by a load (like if there is a function call
+; or an exception in between), make sure that call @llvm.load.relative is inserted before load.
+declare void @may_not_return()
+
+define ptr @gep_is_not_imm_followed_by_load(i32 %x) {
+; CHECK-LABEL: define ptr @gep_is_not_imm_followed_by_load(
+; CHECK-SAME: i32 [[X:%.*]]) {
+; CHECK-NEXT:  [[ENTRY:.*:]]
+; CHECK-NEXT:    [[RELTABLE_SHIFT:%.*]] = shl i32 [[X]], 2
+; CHECK-NEXT:    call void @may_not_return()
+; CHECK-NEXT:    [[RELTABLE_INTRINSIC:%.*]] = call ptr @llvm.load.relative.i32(ptr @table2.rel, i32 [[RELTABLE_SHIFT]])
+; CHECK-NEXT:    ret ptr [[RELTABLE_INTRINSIC]]
+;
+entry:
+  %0 = getelementptr [2 x ptr], ptr @table2, i32 0, i32 %x
+  call void @may_not_return()
+  %1 = load ptr, ptr %0
+  ret ptr %1
+}
+
+define ptr @gep_no_leading_zero(i64 %index) {
+; CHECK-LABEL: define ptr @gep_no_leading_zero(
+; CHECK-SAME: i64 [[INDEX:%.*]]) {
+; CHECK-NEXT:    [[RELTABLE_SHIFT:%.*]] = shl i64 [[INDEX]], 2
+; CHECK-NEXT:    [[RELTABLE_INTRINSIC:%.*]] = call ptr @llvm.load.relative.i64(ptr @table3.rel, i64 [[RELTABLE_SHIFT]])
+; CHECK-NEXT:    ret ptr [[RELTABLE_INTRINSIC]]
+;
+  %gep = getelementptr ptr, ptr @table3, i64 %index
+  %load = load ptr, ptr %gep
+  ret ptr %load
+}
+
+define ptr @gep_wrong_stride(i64 %index) {
+; CHECK-LABEL: define ptr @gep_wrong_stride(
+; CHECK-SAME: i64 [[INDEX:%.*]]) {
+; CHECK-NEXT:    [[GEP:%.*]] = getelementptr i8, ptr @table4, i64 [[INDEX]]
+; CHECK-NEXT:    [[LOAD:%.*]] = load ptr, ptr [[GEP]], align 8
+; CHECK-NEXT:    ret ptr [[LOAD]]
+;
+  %gep = getelementptr i8, ptr @table4, i64 %index
+  %load = load ptr, ptr %gep
+  ret ptr %load
+}
+
+define ptr @gep_wrong_constant_offset(i64 %index) {
+; CHECK-LABEL: define ptr @gep_wrong_constant_offset(
+; CHECK-SAME: i64 [[INDEX:%.*]]) {
+; CHECK-NEXT:    [[GEP:%.*]] = getelementptr { ptr, i32 }, ptr @table5, i64 [[INDEX]], i32 1
+; CHECK-NEXT:    [[LOAD:%.*]] = load ptr, ptr [[GEP]], align 8
+; CHECK-NEXT:    ret ptr [[LOAD]]
+;
+  %gep = getelementptr { ptr, i32 }, ptr @table5, i64 %index, i32 1
+  %load = load ptr, ptr %gep
+  ret ptr %load
+}
+
+; This is intentionally advancing by two pointers.
+ at skip.table = internal unnamed_addr constant [4 x ptr] [ptr @.str.8, ptr null, ptr @.str.9, ptr null], align 16
+define ptr @table_with_skipped_elements(i64 %index) {
+; CHECK-LABEL: define ptr @table_with_skipped_elements(
+; CHECK-SAME: i64 [[INDEX:%.*]]) {
+; CHECK-NEXT:    [[RELTABLE_SHIFT:%.*]] = shl i64 [[INDEX]], 2
+; CHECK-NEXT:    [[RELTABLE_INTRINSIC:%.*]] = call ptr @llvm.load.relative.i64(ptr @skip.table.rel, i64 [[RELTABLE_SHIFT]])
+; CHECK-NEXT:    ret ptr [[RELTABLE_INTRINSIC]]
+;
+  %gep = getelementptr [2 x ptr], ptr @skip.table, i64 %index
+  %load = load ptr, ptr %gep
+  ret ptr %load
+}
+
+; Same as previous test, but the elements are at the wrong position in the
+; table.
+ at wrong.skip.table = internal unnamed_addr constant [4 x ptr] [ptr null, ptr @.str.8, ptr null, ptr @.str.9], align 16
+define ptr @table_with_skipped_elements_wrong(i64 %index) {
+; CHECK-LABEL: define ptr @table_with_skipped_elements_wrong(
+; CHECK-SAME: i64 [[INDEX:%.*]]) {
+; CHECK-NEXT:    [[GEP:%.*]] = getelementptr [2 x ptr], ptr @wrong.skip.table, i64 [[INDEX]]
+; CHECK-NEXT:    [[LOAD:%.*]] = load ptr, ptr [[GEP]], align 8
+; CHECK-NEXT:    ret ptr [[LOAD]]
+;
+  %gep = getelementptr [2 x ptr], ptr @wrong.skip.table, i64 %index
+  %load = load ptr, ptr %gep
+  ret ptr %load
+}
+
+!llvm.module.flags = !{!0, !1}
+!0 = !{i32 7, !"PIC Level", i32 2}
+!1 = !{i32 1, !"Code Model", i32 1}
+!4 = !{!"any pointer", !5, i64 0}
+!5 = !{!"omnipotent char", !6, i64 0}
+!6 = !{!"Simple C/C++ TBAA"}
+;.
+; CHECK: attributes #[[ATTR0:[0-9]+]] = { nocallback nofree nosync nounwind willreturn memory(argmem: read) }
+;.
+; CHECK: [[META0:![0-9]+]] = !{i32 8, !"PIC Level", i32 2}
+; CHECK: [[META1:![0-9]+]] = !{i32 1, !"Code Model", i32 1}
+;.
diff --git a/llvm/test/Transforms/RelLookupTableConverter/relative_lookup_table.ll b/llvm/test/Transforms/RelLookupTableConverter/X86/relative_lookup_table.ll
similarity index 95%
rename from llvm/test/Transforms/RelLookupTableConverter/relative_lookup_table.ll
rename to llvm/test/Transforms/RelLookupTableConverter/X86/relative_lookup_table.ll
index a900a0728c239..efd644543c016 100644
--- a/llvm/test/Transforms/RelLookupTableConverter/relative_lookup_table.ll
+++ b/llvm/test/Transforms/RelLookupTableConverter/X86/relative_lookup_table.ll
@@ -1,9 +1,8 @@
 ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --check-globals all --version 5
 ; REQUIRES: x86-registered-target
-; REQUIRES: aarch64-registered-target
-; RUN: opt < %s -passes=rel-lookup-table-converter -relocation-model=pic -mtriple=x86_64-unknown-linux-gnu -S | FileCheck %s
-; RUN: opt < %s -passes=rel-lookup-table-converter -relocation-model=pic -mtriple=aarch64-unknown-linux-gnu -S | FileCheck %s
+; RUN: opt < %s -passes=rel-lookup-table-converter -relocation-model=pic -S | FileCheck %s
 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"
+target triple = "x86_64-unknown-linux-gnu"
 
 @.str = private unnamed_addr constant [5 x i8] c"zero\00", align 1
 @.str.1 = private unnamed_addr constant [4 x i8] c"one\00", align 1
@@ -100,17 +99,17 @@ target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f3
 ], align 16
 
 ;.
-; CHECK: @.str = private {{.*}}constant [5 x i8] c"zero\00", align 1
-; CHECK: @.str.1 = private {{.*}}constant [4 x i8] c"one\00", align 1
-; CHECK: @.str.2 = private {{.*}}constant [4 x i8] c"two\00", align 1
-; CHECK: @.str.3 = private {{.*}}constant [8 x i8] c"default\00", align 1
-; CHECK: @.str.4 = private {{.*}}constant [6 x i8] c"three\00", align 1
-; CHECK: @.str.5 = private {{.*}}constant [5 x i8] c"str1\00", align 1
-; CHECK: @.str.6 = private {{.*}}constant [5 x i8] c"str2\00", align 1
-; CHECK: @.str.7 = private {{.*}}constant [12 x i8] c"singlevalue\00", align 1
-; CHECK: @.str.8 = private {{.*}}constant [2 x i8] c"a\00", align 1
-; CHECK: @.str.9 = private {{.*}}constant [2 x i8] c"b\00", align 1
-; CHECK: @.str.10 = private {{.*}}constant [2 x i8] c"c\00", align 1
+; CHECK: @.str = private unnamed_addr constant [5 x i8] c"zero\00", align 1
+; CHECK: @.str.1 = private unnamed_addr constant [4 x i8] c"one\00", align 1
+; CHECK: @.str.2 = private unnamed_addr constant [4 x i8] c"two\00", align 1
+; CHECK: @.str.3 = private unnamed_addr constant [8 x i8] c"default\00", align 1
+; CHECK: @.str.4 = private unnamed_addr constant [6 x i8] c"three\00", align 1
+; CHECK: @.str.5 = private unnamed_addr constant [5 x i8] c"str1\00", align 1
+; CHECK: @.str.6 = private unnamed_addr constant [5 x i8] c"str2\00", align 1
+; CHECK: @.str.7 = private unnamed_addr constant [12 x i8] c"singlevalue\00", align 1
+; CHECK: @.str.8 = private unnamed_addr constant [2 x i8] c"a\00", align 1
+; CHECK: @.str.9 = private unnamed_addr constant [2 x i8] c"b\00", align 1
+; CHECK: @.str.10 = private unnamed_addr constant [2 x i8] c"c\00", align 1
 ; CHECK: @a1 = external global i32, align 4
 ; CHECK: @b1 = external global i32, align 4
 ; CHECK: @c1 = external global i32, align 4



More information about the llvm-commits mailing list