Skip to content

Commit e0586e2

Browse files
dianqktstellar
authored andcommitted
[RelLookupTableConverter] Drop unnamed_addr to avoid generating GOTPCREL relocations (llvm#142304)
Follow llvm#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. (cherry picked from commit aa09dbb)
1 parent 7759bb5 commit e0586e2

File tree

2 files changed

+136
-0
lines changed

2 files changed

+136
-0
lines changed

llvm/lib/Transforms/Utils/RelLookupTableConverter.cpp

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
#include "llvm/IR/IRBuilder.h"
1919
#include "llvm/IR/Instructions.h"
2020
#include "llvm/IR/Module.h"
21+
#include "llvm/TargetParser/Triple.h"
2122

2223
using namespace llvm;
2324

@@ -108,8 +109,24 @@ static GlobalVariable *createRelLookupTable(Function &Func,
108109
uint64_t Idx = 0;
109110
SmallVector<Constant *, 64> RelLookupTableContents(NumElts);
110111

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

0 commit comments

Comments
 (0)