Skip to content

Commit dede19c

Browse files
authored
GlobalOpt: Handle threadlocal.address intrinsic (#88454)
This changes `GlobalOpt` to skip/look-through `threadlocal.address` intrinsic where apropriate. This fixes issue #73314
1 parent 3590ede commit dede19c

File tree

7 files changed

+50
-17
lines changed

7 files changed

+50
-17
lines changed

llvm/include/llvm/Transforms/Utils/GlobalStatus.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,9 @@ class Value;
2424
///
2525
bool isSafeToDestroyConstant(const Constant *C);
2626

27-
/// As we analyze each global, keep track of some information about it. If we
28-
/// find out that the address of the global is taken, none of this info will be
29-
/// accurate.
27+
/// As we analyze each global or thread-local variable, keep track of some
28+
/// information about it. If we find out that the address of the global is
29+
/// taken, none of this info will be accurate.
3030
struct GlobalStatus {
3131
/// True if the global's address is used in a comparison.
3232
bool IsCompared = false;

llvm/lib/Transforms/IPO/GlobalOpt.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -306,6 +306,10 @@ static bool CleanupConstantGlobalUsers(GlobalVariable *GV,
306306
APInt Offset(DL.getIndexTypeSizeInBits(PtrOp->getType()), 0);
307307
PtrOp = PtrOp->stripAndAccumulateConstantOffsets(
308308
DL, Offset, /* AllowNonInbounds */ true);
309+
if (IntrinsicInst *II = dyn_cast<IntrinsicInst>(PtrOp)) {
310+
if (II->getIntrinsicID() == Intrinsic::threadlocal_address)
311+
PtrOp = II->getArgOperand(0);
312+
}
309313
if (PtrOp == GV) {
310314
if (auto *Value = ConstantFoldLoadFromConst(Init, Ty, Offset, DL)) {
311315
LI->replaceAllUsesWith(Value);
@@ -318,6 +322,9 @@ static bool CleanupConstantGlobalUsers(GlobalVariable *GV,
318322
} else if (MemIntrinsic *MI = dyn_cast<MemIntrinsic>(U)) { // memset/cpy/mv
319323
if (getUnderlyingObject(MI->getRawDest()) == GV)
320324
EraseFromParent(MI);
325+
} else if (IntrinsicInst *II = dyn_cast<IntrinsicInst>(U)) {
326+
if (II->getIntrinsicID() == Intrinsic::threadlocal_address)
327+
append_range(WorkList, II->users());
321328
}
322329
}
323330

llvm/lib/Transforms/Utils/GlobalStatus.cpp

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -172,9 +172,14 @@ static bool analyzeGlobalAux(const Value *V, GlobalStatus &GS,
172172
return true;
173173
GS.StoredType = GlobalStatus::Stored;
174174
} else if (const auto *CB = dyn_cast<CallBase>(I)) {
175-
if (!CB->isCallee(&U))
176-
return true;
177-
GS.IsLoaded = true;
175+
if (CB->getIntrinsicID() == Intrinsic::threadlocal_address) {
176+
if (analyzeGlobalAux(I, GS, VisitedUsers))
177+
return true;
178+
} else {
179+
if (!CB->isCallee(&U))
180+
return true;
181+
GS.IsLoaded = true;
182+
}
178183
} else {
179184
return true; // Any other non-load instruction might take address!
180185
}
Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,23 @@
1+
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 4
12
; RUN: opt < %s -passes=globalopt -S | FileCheck %s
23

3-
; CHECK-NOT: global
44
@X = internal global i32 4 ; <ptr> [#uses=1]
55

66
define i32 @foo() {
7-
%V = load i32, ptr @X ; <i32> [#uses=1]
8-
ret i32 %V
7+
; CHECK-LABEL: define i32 @foo() local_unnamed_addr {
8+
; CHECK-NEXT: ret i32 4
9+
;
10+
%V = load i32, ptr @X ; <i32> [#uses=1]
11+
ret i32 %V
12+
}
13+
14+
@X_tls = internal thread_local global i32 13
15+
16+
define i32 @bar() {
17+
; CHECK-LABEL: define i32 @bar() local_unnamed_addr {
18+
; CHECK-NEXT: ret i32 13
19+
;
20+
%p = call ptr @llvm.threadlocal.address(ptr @X_tls)
21+
%v = load i32, ptr %p
22+
ret i32 %v
923
}

llvm/test/Transforms/GlobalOpt/constantfold-initializers.ll

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -72,11 +72,12 @@ entry:
7272
}
7373

7474
@threadlocalptr = global ptr null, align 4
75-
; CHECK: @threadlocalptr = global ptr null, align 4
75+
; CHECK: @threadlocalptr = local_unnamed_addr global ptr null, align 4
7676
@threadlocalvar = external thread_local global i32
7777
define internal void @test5() {
7878
entry:
79-
store ptr @threadlocalvar, ptr @threadlocalptr, align 4
79+
%p = call ptr @llvm.threadlocal.address(ptr @threadlocalvar)
80+
store ptr %p, ptr @threadlocalptr, align 4
8081
ret void
8182
}
8283

llvm/test/Transforms/GlobalOpt/stored-once-forward-value.ll

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,12 +39,14 @@ define i32 @dom_arg(i32 %a) {
3939

4040
define ptr @dom_thread_local_global() {
4141
; CHECK-LABEL: @dom_thread_local_global(
42-
; CHECK-NEXT: store ptr @tl, ptr @g3, align 8
42+
; CHECK-NEXT: [[P:%.*]] = call ptr @llvm.threadlocal.address.p0(ptr @tl)
43+
; CHECK-NEXT: store ptr [[P]], ptr @g3, align 8
4344
; CHECK-NEXT: call void @b()
4445
; CHECK-NEXT: [[R:%.*]] = load ptr, ptr @g3, align 8
4546
; CHECK-NEXT: ret ptr [[R]]
4647
;
47-
store ptr @tl, ptr @g3
48+
%p = call ptr @llvm.threadlocal.address(ptr @tl)
49+
store ptr %p, ptr @g3
4850
call void @b()
4951
%r = load ptr, ptr @g3
5052
ret ptr %r

llvm/test/Transforms/GlobalOpt/tls.ll

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,14 +15,16 @@ declare void @start_thread(ptr)
1515
define i32 @f() {
1616
entry:
1717
; Set @ip to point to x[1] for thread 1.
18-
store ptr getelementptr inbounds ([100 x i32], ptr @x, i64 0, i64 1), ptr @ip, align 8
18+
%p = call ptr @llvm.threadlocal.address(ptr @x)
19+
%addr = getelementptr inbounds [100 x i32], ptr %p, i64 0, i64 1
20+
store ptr %addr, ptr @ip, align 8
1921

2022
; Run g on a new thread.
2123
tail call void @start_thread(ptr @g) nounwind
2224
tail call void @wait() nounwind
2325

2426
; Reset x[1] for thread 1.
25-
store i32 0, ptr getelementptr inbounds ([100 x i32], ptr @x, i64 0, i64 1), align 4
27+
store i32 0, ptr %addr, align 4
2628

2729
; Read the value of @ip, which now points at x[1] for thread 2.
2830
%0 = load ptr, ptr @ip, align 8
@@ -39,10 +41,12 @@ entry:
3941
define internal void @g() nounwind uwtable {
4042
entry:
4143
; Set @ip to point to x[1] for thread 2.
42-
store ptr getelementptr inbounds ([100 x i32], ptr @x, i64 0, i64 1), ptr @ip, align 8
44+
%p = call ptr @llvm.threadlocal.address(ptr @x)
45+
%addr = getelementptr inbounds [100 x i32], ptr %p, i64 0, i64 1
46+
store ptr %addr, ptr @ip, align 8
4347

4448
; Store 50 in x[1] for thread 2.
45-
store i32 50, ptr getelementptr inbounds ([100 x i32], ptr @x, i64 0, i64 1), align 4
49+
store i32 50, ptr %addr, align 4
4650

4751
tail call void @signal() nounwind
4852
ret void

0 commit comments

Comments
 (0)