Skip to content

Commit aa09dbb

Browse files
authored
[RelLookupTableConverter] Drop unnamed_addr to avoid generating GOTPCREL relocations (#142304)
Follow #72584 (comment), the patch will drop the `unnamed_addr` attribute when generating relative lookup tables. I'm not very confident about this patch, but it does resolve rust-lang/rust#140686, rust-lang/rust#141306 and rust-lang/rust#141737. But I don't think this will result in worse problems. > LLVM provides that the calculation of such a constant initializer will not overflow at link time under the medium code model if x is an unnamed_addr function. However, it does not provide this guarantee for a constant initializer folded into a function body. This intrinsic can be used to avoid the possibility of overflows when loading from such a constant. ([‘llvm.load.relative’ Intrinsic](https://llvm.org/docs/LangRef.html#id2592)) This is my concern. I'm not sure how unnamed_addr provides this guarantee, and I haven't found any test cases.
1 parent 71079fc commit aa09dbb

File tree

2 files changed

+133
-0
lines changed

2 files changed

+133
-0
lines changed

llvm/lib/Transforms/Utils/RelLookupTableConverter.cpp

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,8 +108,24 @@ static GlobalVariable *createRelLookupTable(Function &Func,
108108
uint64_t Idx = 0;
109109
SmallVector<Constant *, 64> RelLookupTableContents(NumElts);
110110

111+
Triple TT = M.getTargetTriple();
112+
// FIXME: This should be removed in the future.
113+
bool ShouldDropUnnamedAddr =
114+
// Drop unnamed_addr to avoid matching pattern in
115+
// `handleIndirectSymViaGOTPCRel`, which generates GOTPCREL relocations
116+
// not supported by the GNU linker and LLD versions below 18 on aarch64.
117+
TT.isAArch64()
118+
// Apple's ld64 (and ld-prime on Xcode 15.2) miscompile something on
119+
// x86_64-apple-darwin. See
120+
// https://github.com/rust-lang/rust/issues/140686 and
121+
// https://github.com/rust-lang/rust/issues/141306.
122+
|| (TT.isX86() && TT.isOSDarwin());
123+
111124
for (Use &Operand : LookupTableArr->operands()) {
112125
Constant *Element = cast<Constant>(Operand);
126+
if (ShouldDropUnnamedAddr)
127+
if (auto *GlobalElement = dyn_cast<GlobalValue>(Element))
128+
GlobalElement->setUnnamedAddr(GlobalValue::UnnamedAddr::None);
113129
Type *IntPtrTy = M.getDataLayout().getIntPtrType(M.getContext());
114130
Constant *Base = llvm::ConstantExpr::getPtrToInt(RelLookupTable, IntPtrTy);
115131
Constant *Target = llvm::ConstantExpr::getPtrToInt(Element, IntPtrTy);
Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --check-globals all --version 5
2+
; RUN: opt < %s -passes=rel-lookup-table-converter -relocation-model=pic -mtriple=x86_64-apple-darwin -S | FileCheck -check-prefix=x86_64-apple-darwin %s
3+
; RUN: opt < %s -passes=rel-lookup-table-converter -relocation-model=pic -mtriple=aarch64 -S | FileCheck -check-prefix=aarch64 %s
4+
; RUN: opt < %s -passes=rel-lookup-table-converter -relocation-model=pic -mtriple=x86_64 -S | FileCheck -check-prefix=x86_64 %s
5+
6+
@a0 = private unnamed_addr constant i32 0
7+
@a1 = private unnamed_addr constant i32 1
8+
@a2 = private unnamed_addr constant i32 2
9+
@load_relative_1.table = private unnamed_addr constant [3 x ptr] [ptr @a0, ptr @a1, ptr @a2]
10+
11+
@x0 = internal unnamed_addr constant i64 0
12+
@x1 = internal unnamed_addr constant i64 1
13+
@x2 = internal unnamed_addr constant i64 2
14+
@x3 = internal unnamed_addr constant i64 3
15+
@y0 = internal unnamed_addr constant ptr @x3
16+
@y1 = internal unnamed_addr constant ptr @x2
17+
@y2 = internal unnamed_addr constant ptr @x1
18+
@y3 = internal unnamed_addr constant ptr @x0
19+
@load_relative_2.table = private unnamed_addr constant [4 x ptr] [ptr @y3, ptr @y2, ptr @y1, ptr @y0]
20+
21+
;.
22+
; x86_64-apple-darwin: @a0 = private constant i32 0
23+
; x86_64-apple-darwin: @a1 = private constant i32 1
24+
; x86_64-apple-darwin: @a2 = private constant i32 2
25+
; x86_64-apple-darwin: @load_relative_1.table.rel = private unnamed_addr constant [3 x i32] [i32 trunc (i64 sub (i64 ptrtoint (ptr @a0 to i64), i64 ptrtoint (ptr @load_relative_1.table.rel to i64)) to i32), i32 trunc (i64 sub (i64 ptrtoint (ptr @a1 to i64), i64 ptrtoint (ptr @load_relative_1.table.rel to i64)) to i32), i32 trunc (i64 sub (i64 ptrtoint (ptr @a2 to i64), i64 ptrtoint (ptr @load_relative_1.table.rel to i64)) to i32)], align 4
26+
; x86_64-apple-darwin: @x0 = internal unnamed_addr constant i64 0
27+
; x86_64-apple-darwin: @x1 = internal unnamed_addr constant i64 1
28+
; x86_64-apple-darwin: @x2 = internal unnamed_addr constant i64 2
29+
; x86_64-apple-darwin: @x3 = internal unnamed_addr constant i64 3
30+
; x86_64-apple-darwin: @y0 = internal constant ptr @x3
31+
; x86_64-apple-darwin: @y1 = internal constant ptr @x2
32+
; x86_64-apple-darwin: @y2 = internal constant ptr @x1
33+
; x86_64-apple-darwin: @y3 = internal constant ptr @x0
34+
; x86_64-apple-darwin: @load_relative_2.table.rel = private unnamed_addr constant [4 x i32] [i32 trunc (i64 sub (i64 ptrtoint (ptr @y3 to i64), i64 ptrtoint (ptr @load_relative_2.table.rel to i64)) to i32), i32 trunc (i64 sub (i64 ptrtoint (ptr @y2 to i64), i64 ptrtoint (ptr @load_relative_2.table.rel to i64)) to i32), i32 trunc (i64 sub (i64 ptrtoint (ptr @y1 to i64), i64 ptrtoint (ptr @load_relative_2.table.rel to i64)) to i32), i32 trunc (i64 sub (i64 ptrtoint (ptr @y0 to i64), i64 ptrtoint (ptr @load_relative_2.table.rel to i64)) to i32)], align 4
35+
;.
36+
; aarch64: @a0 = private constant i32 0
37+
; aarch64: @a1 = private constant i32 1
38+
; aarch64: @a2 = private constant i32 2
39+
; aarch64: @load_relative_1.table.rel = private unnamed_addr constant [3 x i32] [i32 trunc (i64 sub (i64 ptrtoint (ptr @a0 to i64), i64 ptrtoint (ptr @load_relative_1.table.rel to i64)) to i32), i32 trunc (i64 sub (i64 ptrtoint (ptr @a1 to i64), i64 ptrtoint (ptr @load_relative_1.table.rel to i64)) to i32), i32 trunc (i64 sub (i64 ptrtoint (ptr @a2 to i64), i64 ptrtoint (ptr @load_relative_1.table.rel to i64)) to i32)], align 4
40+
; aarch64: @x0 = internal unnamed_addr constant i64 0
41+
; aarch64: @x1 = internal unnamed_addr constant i64 1
42+
; aarch64: @x2 = internal unnamed_addr constant i64 2
43+
; aarch64: @x3 = internal unnamed_addr constant i64 3
44+
; aarch64: @y0 = internal constant ptr @x3
45+
; aarch64: @y1 = internal constant ptr @x2
46+
; aarch64: @y2 = internal constant ptr @x1
47+
; aarch64: @y3 = internal constant ptr @x0
48+
; aarch64: @load_relative_2.table.rel = private unnamed_addr constant [4 x i32] [i32 trunc (i64 sub (i64 ptrtoint (ptr @y3 to i64), i64 ptrtoint (ptr @load_relative_2.table.rel to i64)) to i32), i32 trunc (i64 sub (i64 ptrtoint (ptr @y2 to i64), i64 ptrtoint (ptr @load_relative_2.table.rel to i64)) to i32), i32 trunc (i64 sub (i64 ptrtoint (ptr @y1 to i64), i64 ptrtoint (ptr @load_relative_2.table.rel to i64)) to i32), i32 trunc (i64 sub (i64 ptrtoint (ptr @y0 to i64), i64 ptrtoint (ptr @load_relative_2.table.rel to i64)) to i32)], align 4
49+
;.
50+
; x86_64: @a0 = private unnamed_addr constant i32 0
51+
; x86_64: @a1 = private unnamed_addr constant i32 1
52+
; x86_64: @a2 = private unnamed_addr constant i32 2
53+
; x86_64: @load_relative_1.table.rel = private unnamed_addr constant [3 x i32] [i32 trunc (i64 sub (i64 ptrtoint (ptr @a0 to i64), i64 ptrtoint (ptr @load_relative_1.table.rel to i64)) to i32), i32 trunc (i64 sub (i64 ptrtoint (ptr @a1 to i64), i64 ptrtoint (ptr @load_relative_1.table.rel to i64)) to i32), i32 trunc (i64 sub (i64 ptrtoint (ptr @a2 to i64), i64 ptrtoint (ptr @load_relative_1.table.rel to i64)) to i32)], align 4
54+
; x86_64: @x0 = internal unnamed_addr constant i64 0
55+
; x86_64: @x1 = internal unnamed_addr constant i64 1
56+
; x86_64: @x2 = internal unnamed_addr constant i64 2
57+
; x86_64: @x3 = internal unnamed_addr constant i64 3
58+
; x86_64: @y0 = internal unnamed_addr constant ptr @x3
59+
; x86_64: @y1 = internal unnamed_addr constant ptr @x2
60+
; x86_64: @y2 = internal unnamed_addr constant ptr @x1
61+
; x86_64: @y3 = internal unnamed_addr constant ptr @x0
62+
; x86_64: @load_relative_2.table.rel = private unnamed_addr constant [4 x i32] [i32 trunc (i64 sub (i64 ptrtoint (ptr @y3 to i64), i64 ptrtoint (ptr @load_relative_2.table.rel to i64)) to i32), i32 trunc (i64 sub (i64 ptrtoint (ptr @y2 to i64), i64 ptrtoint (ptr @load_relative_2.table.rel to i64)) to i32), i32 trunc (i64 sub (i64 ptrtoint (ptr @y1 to i64), i64 ptrtoint (ptr @load_relative_2.table.rel to i64)) to i32), i32 trunc (i64 sub (i64 ptrtoint (ptr @y0 to i64), i64 ptrtoint (ptr @load_relative_2.table.rel to i64)) to i32)], align 4
63+
;.
64+
define ptr @load_relative_1(i64 %offset) {
65+
; x86_64-apple-darwin-LABEL: define ptr @load_relative_1(
66+
; x86_64-apple-darwin-SAME: i64 [[OFFSET:%.*]]) {
67+
; x86_64-apple-darwin-NEXT: [[RELTABLE_SHIFT:%.*]] = shl i64 [[OFFSET]], 2
68+
; x86_64-apple-darwin-NEXT: [[RELTABLE_INTRINSIC:%.*]] = call ptr @llvm.load.relative.i64(ptr @load_relative_1.table.rel, i64 [[RELTABLE_SHIFT]])
69+
; x86_64-apple-darwin-NEXT: ret ptr [[RELTABLE_INTRINSIC]]
70+
;
71+
; aarch64-LABEL: define ptr @load_relative_1(
72+
; aarch64-SAME: i64 [[OFFSET:%.*]]) {
73+
; aarch64-NEXT: [[RELTABLE_SHIFT:%.*]] = shl i64 [[OFFSET]], 2
74+
; aarch64-NEXT: [[RELTABLE_INTRINSIC:%.*]] = call ptr @llvm.load.relative.i64(ptr @load_relative_1.table.rel, i64 [[RELTABLE_SHIFT]])
75+
; aarch64-NEXT: ret ptr [[RELTABLE_INTRINSIC]]
76+
;
77+
; x86_64-LABEL: define ptr @load_relative_1(
78+
; x86_64-SAME: i64 [[OFFSET:%.*]]) {
79+
; x86_64-NEXT: [[RELTABLE_SHIFT:%.*]] = shl i64 [[OFFSET]], 2
80+
; x86_64-NEXT: [[RELTABLE_INTRINSIC:%.*]] = call ptr @llvm.load.relative.i64(ptr @load_relative_1.table.rel, i64 [[RELTABLE_SHIFT]])
81+
; x86_64-NEXT: ret ptr [[RELTABLE_INTRINSIC]]
82+
;
83+
%gep = getelementptr inbounds [3 x ptr], ptr @load_relative_1.table, i64 0, i64 %offset
84+
%load = load ptr, ptr %gep
85+
ret ptr %load
86+
}
87+
88+
define ptr @load_relative_2(i64 %offset) {
89+
; x86_64-apple-darwin-LABEL: define ptr @load_relative_2(
90+
; x86_64-apple-darwin-SAME: i64 [[OFFSET:%.*]]) {
91+
; x86_64-apple-darwin-NEXT: [[RELTABLE_SHIFT:%.*]] = shl i64 [[OFFSET]], 2
92+
; x86_64-apple-darwin-NEXT: [[RELTABLE_INTRINSIC:%.*]] = call ptr @llvm.load.relative.i64(ptr @load_relative_2.table.rel, i64 [[RELTABLE_SHIFT]])
93+
; x86_64-apple-darwin-NEXT: ret ptr [[RELTABLE_INTRINSIC]]
94+
;
95+
; aarch64-LABEL: define ptr @load_relative_2(
96+
; aarch64-SAME: i64 [[OFFSET:%.*]]) {
97+
; aarch64-NEXT: [[RELTABLE_SHIFT:%.*]] = shl i64 [[OFFSET]], 2
98+
; aarch64-NEXT: [[RELTABLE_INTRINSIC:%.*]] = call ptr @llvm.load.relative.i64(ptr @load_relative_2.table.rel, i64 [[RELTABLE_SHIFT]])
99+
; aarch64-NEXT: ret ptr [[RELTABLE_INTRINSIC]]
100+
;
101+
; x86_64-LABEL: define ptr @load_relative_2(
102+
; x86_64-SAME: i64 [[OFFSET:%.*]]) {
103+
; x86_64-NEXT: [[RELTABLE_SHIFT:%.*]] = shl i64 [[OFFSET]], 2
104+
; x86_64-NEXT: [[RELTABLE_INTRINSIC:%.*]] = call ptr @llvm.load.relative.i64(ptr @load_relative_2.table.rel, i64 [[RELTABLE_SHIFT]])
105+
; x86_64-NEXT: ret ptr [[RELTABLE_INTRINSIC]]
106+
;
107+
%gep = getelementptr inbounds [4 x ptr], ptr @load_relative_2.table, i64 0, i64 %offset
108+
%load = load ptr, ptr %gep
109+
ret ptr %load
110+
}
111+
;.
112+
; x86_64-apple-darwin: attributes #[[ATTR0:[0-9]+]] = { nocallback nofree nosync nounwind willreturn memory(argmem: read) }
113+
;.
114+
; aarch64: attributes #[[ATTR0:[0-9]+]] = { nocallback nofree nosync nounwind willreturn memory(argmem: read) }
115+
;.
116+
; x86_64: attributes #[[ATTR0:[0-9]+]] = { nocallback nofree nosync nounwind willreturn memory(argmem: read) }
117+
;.

0 commit comments

Comments
 (0)