Skip to content

Commit c446ac4

Browse files
gulfemsavruntstellar
authored andcommitted
[Passes] Fix relative lookup table converter pass
This patch fixes the relative table converter pass for the lookup table accesses that are resulted in an instruction sequence, where gep is not immediately followed by a load, such as gep being hoisted outside the loop or another instruction is inserted in between them. The fix inserts the call to load.relative.instrinsic in the original place of load instead of gep. Issue is reported by FreeBSD via https://bugs.freebsd.org/259921. Differential Revision: https://reviews.llvm.org/D115571 (cherry picked from commit e5a8af7)
1 parent 9fb79e6 commit c446ac4

File tree

2 files changed

+84
-0
lines changed

2 files changed

+84
-0
lines changed

llvm/lib/Transforms/Utils/RelLookupTableConverter.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,10 @@ static void convertToRelLookupTable(GlobalVariable &LookupTable) {
144144
Value *Offset =
145145
Builder.CreateShl(Index, ConstantInt::get(IntTy, 2), "reltable.shift");
146146

147+
// Insert the call to load.relative instrinsic before LOAD.
148+
// GEP might not be immediately followed by a LOAD, like it can be hoisted
149+
// outside the loop or another instruction might be inserted them in between.
150+
Builder.SetInsertPoint(Load);
147151
Function *LoadRelIntrinsic = llvm::Intrinsic::getDeclaration(
148152
&M, Intrinsic::load_relative, {Index->getType()});
149153
Value *Base = Builder.CreateBitCast(RelLookupTable, Builder.getInt8PtrTy());

llvm/test/Transforms/RelLookupTableConverter/X86/relative_lookup_table.ll

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,9 @@ target triple = "x86_64-unknown-linux-gnu"
1212
@.str.5 = private unnamed_addr constant [5 x i8] c"str1\00", align 1
1313
@.str.6 = private unnamed_addr constant [5 x i8] c"str2\00", align 1
1414
@.str.7 = private unnamed_addr constant [12 x i8] c"singlevalue\00", align 1
15+
@.str.8 = private unnamed_addr constant [2 x i8] c"a\00", align 1
16+
@.str.9 = private unnamed_addr constant [2 x i8] c"b\00", align 1
17+
@.str.10 = private unnamed_addr constant [2 x i8] c"c\00", align 1
1518

1619
@a1 = external global i32, align 4
1720
@b1 = external global i32, align 4
@@ -56,6 +59,16 @@ target triple = "x86_64-unknown-linux-gnu"
5659
i8* getelementptr inbounds ([4 x i8], [4 x i8]* @.str.2, i32 0, i32 0)
5760
], align 16
5861

62+
@table = internal constant [2 x i8*] [
63+
i8* getelementptr inbounds ([2 x i8], [2 x i8]* @.str.8, i32 0, i32 0),
64+
i8* getelementptr inbounds ([2 x i8], [2 x i8]* @.str.9, i32 0, i32 0)
65+
], align 16
66+
67+
@table2 = internal constant [2 x i8*] [
68+
i8* getelementptr inbounds ([2 x i8], [2 x i8]* @.str.8, i32 0, i32 0),
69+
i8* getelementptr inbounds ([2 x i8], [2 x i8]* @.str.9, i32 0, i32 0)
70+
], align 16
71+
5972
; Lookup table check for integer pointers that have external linkage
6073
; CHECK: @switch.table.external_linkage = private unnamed_addr constant [3 x i32*] [i32* @a1, i32* @b1, i32* @c1], align
6174

@@ -93,6 +106,20 @@ target triple = "x86_64-unknown-linux-gnu"
93106
; CHECK-SAME: ], align 4
94107
;
95108

109+
; Relative lookup table for the loop hoist check test
110+
; CHECK: @reltable.loop_hoist = internal unnamed_addr constant [2 x i32]
111+
; CHECK-SAME: [
112+
; CHECK-SAME: i32 trunc (i64 sub (i64 ptrtoint ([2 x i8]* @.str.8 to i64), i64 ptrtoint ([2 x i32]* @reltable.loop_hoist to i64)) to i32),
113+
; CHECK-SAME: i32 trunc (i64 sub (i64 ptrtoint ([2 x i8]* @.str.9 to i64), i64 ptrtoint ([2 x i32]* @reltable.loop_hoist to i64)) to i32)
114+
; CHECK-SAME: ], align 4
115+
116+
; Relative look up table for the test where gep is not immediately followed by a load check
117+
; CHECK: @reltable.gep_is_not_imm_followed_by_load = internal unnamed_addr constant [2 x i32]
118+
; CHECK-SAME: [
119+
; CHECK-SAME: i32 trunc (i64 sub (i64 ptrtoint ([2 x i8]* @.str.8 to i64), i64 ptrtoint ([2 x i32]* @reltable.gep_is_not_imm_followed_by_load to i64)) to i32),
120+
; CHECK-SAME: i32 trunc (i64 sub (i64 ptrtoint ([2 x i8]* @.str.9 to i64), i64 ptrtoint ([2 x i32]* @reltable.gep_is_not_imm_followed_by_load to i64)) to i32)
121+
; CHECK-SAME: ], align 4
122+
96123
; Lookup table check for integer pointers that have external linkage
97124
define i32* @external_linkage(i32 %cond) {
98125
; CHECK-LABEL: @external_linkage(
@@ -260,6 +287,59 @@ cond.end: ; preds = %entry, %cond.false
260287
ret i8* %cond1
261288
}
262289

290+
; Check to ensure that call @llvm.load.relative is inserted before load, not before gep.
291+
; When a lookup table is accessed inside a loop, and a gep is hosted outside the loop via licm,
292+
; make sure that call @llvm.load.relative is inserted before load.
293+
define i8* @loop_hoist(i32 %x) {
294+
; CHECK-LABEL: @loop_hoist(i32 %x)
295+
; CHECK-NEXT: entry:
296+
; CHECK-NEXT: [[TMP0:%.*]] = icmp sgt i32 [[X:%.*]], 1
297+
; CHECK-NEXT: [[TMP1:%.*]] = getelementptr inbounds [2 x i8], [2 x i8]* @.str.10, i32 0, i32 0
298+
; CHECK-NEXT: [[RELTABLE_SHIFT:%.*]] = shl i32 [[X:%.*]], 2
299+
; CHECK-NEXT: br i1 [[TMP0]], label %if.done, label %if.false
300+
; CHECK: if.false:
301+
; CHECK-NEXT: [[RELTABLE_INTRINSIC:%.*]] = call i8* @llvm.load.relative.i32(i8* bitcast ([2 x i32]* @reltable.loop_hoist to i8*), i32 [[RELTABLE_SHIFT]])
302+
; CHECK-NEXT: br label %if.done
303+
; CHECK: if.done:
304+
; CHECK-NEXT: [[TMP2:%.*]] = phi i8* [ [[TMP1]], %entry ], [ [[RELTABLE_INTRINSIC]], %if.false ]
305+
; CHECK-NEXT: ret i8* [[TMP2]]
306+
;
307+
entry:
308+
%0 = icmp sgt i32 %x, 1
309+
%1 = getelementptr inbounds [2 x i8], [2 x i8]* @.str.10, i32 0, i32 0
310+
%2 = getelementptr [2 x i8*], [2 x i8*]* @table, i32 0, i32 %x
311+
br i1 %0, label %if.done, label %if.false
312+
313+
if.false:
314+
%3 = load i8*, i8** %2
315+
br label %if.done
316+
317+
if.done:
318+
%4 = phi i8* [ %1, %entry ], [ %3, %if.false ]
319+
ret i8* %4
320+
}
321+
322+
; Another check to ensure that call @llvm.load.relative is inserted before load but not before gep.
323+
; When a lookup table is accessed, and gep is not immediately followed by a load (like if there is a function call
324+
; or an exception in between), make sure that call @llvm.load.relative is inserted before load.
325+
; CHECK-LABEL: @may_not_return()
326+
declare void @may_not_return()
327+
328+
define i8* @gep_is_not_imm_followed_by_load(i32 %x) {
329+
; CHECK-LABEL: @gep_is_not_imm_followed_by_load(i32 %x)
330+
; CHECK: entry:
331+
; CHECK-NEXT: [[RELTABLE_SHIFT:%.*]] = shl i32 [[X:%.*]], 2
332+
; CHECK-NEXT: call void @may_not_return()
333+
; CHECK-NEXT: [[RELTABLE_INTRINSIC:%.*]] = call i8* @llvm.load.relative.i32(i8* bitcast ([2 x i32]* @reltable.gep_is_not_imm_followed_by_load to i8*), i32 [[RELTABLE_SHIFT]])
334+
; CHECK-NEXT: ret i8* [[RELTABLE_INTRINSIC]]
335+
;
336+
entry:
337+
%0 = getelementptr [2 x i8*], [2 x i8*]* @table2, i32 0, i32 %x
338+
call void @may_not_return()
339+
%1 = load i8*, i8** %0
340+
ret i8* %1
341+
}
342+
263343
!llvm.module.flags = !{!0, !1}
264344
!0 = !{i32 7, !"PIC Level", i32 2}
265345
!1 = !{i32 1, !"Code Model", i32 1}

0 commit comments

Comments
 (0)