[llvm] GlobalsModRef, ValueTracking: Look through threadlocal.address intrinsic (PR #88418)
Matthias Braun via llvm-commits
llvm-commits at lists.llvm.org
Wed Apr 17 12:00:02 PDT 2024
https://github.com/MatzeB updated https://github.com/llvm/llvm-project/pull/88418
>From 417d51065ada190287c680ef0a4ad599a8f640ea Mon Sep 17 00:00:00 2001
From: Matthias Braun <matze at braunis.de>
Date: Tue, 16 Apr 2024 17:18:11 -0700
Subject: [PATCH 1/2] Add some tests for getUnderlyingObject
---
llvm/unittests/Analysis/ValueTrackingTest.cpp | 72 +++++++++++++++++++
1 file changed, 72 insertions(+)
diff --git a/llvm/unittests/Analysis/ValueTrackingTest.cpp b/llvm/unittests/Analysis/ValueTrackingTest.cpp
index 8738af91b652b8..c59ed041373001 100644
--- a/llvm/unittests/Analysis/ValueTrackingTest.cpp
+++ b/llvm/unittests/Analysis/ValueTrackingTest.cpp
@@ -1247,6 +1247,78 @@ TEST_F(ValueTrackingTest, computePtrAlignment) {
EXPECT_EQ(getKnownAlignment(A, DL, CxtI3, &AC, &DT), Align(16));
}
+TEST_F(ValueTrackingTest, getUnderlyingObjectCastsAliases) {
+ parseAssembly(R"IR(
+ @gvar = global i32 0
+ @alias = alias i32, i32* @gvar
+ @alias_interposable = weak alias i32, i32* @gvar
+ define void @test() {
+ %A = call ptr @llvm.ssa.copy.p0(ptr @gvar)
+ %A2 = call ptr @llvm.ssa.copy.p0(ptr bitcast(ptr @gvar to ptr))
+ %A3 = call ptr addrspace(42) @llvm.ssa.copy.p42(ptr addrspace(42) addrspacecast(ptr @gvar to ptr addrspace(42)))
+ %A4 = call ptr @llvm.ssa.copy.p0(ptr @alias)
+ %A5 = call ptr @llvm.ssa.copy.p0(ptr @alias_interposable)
+ ret void
+ }
+)IR");
+ Value *gvar = A->getOperand(0);
+ EXPECT_EQ(getUnderlyingObject(A->getOperand(0)), gvar);
+ EXPECT_EQ(getUnderlyingObject(A2->getOperand(0)), gvar);
+ EXPECT_EQ(getUnderlyingObject(A3->getOperand(0)), gvar);
+ EXPECT_EQ(getUnderlyingObject(A4->getOperand(0)), gvar);
+ EXPECT_EQ(getUnderlyingObject(A4->getOperand(0)), gvar);
+ // should not skip interposable alias
+ EXPECT_EQ(getUnderlyingObject(A5->getOperand(0)), A5->getOperand(0));
+}
+
+TEST_F(ValueTrackingTest, getUnderlyingObjectIntrinsics) {
+ parseAssembly(R"IR(
+ define void @test(ptr %arg) {
+ ; intrinsic with Return<> arg attribute
+ %A = call ptr @llvm.objc.retain(ptr %arg)
+ %A2 = call ptr @llvm.ssa.copy(ptr %arg)
+ ; special cased intrinsics
+ %A3 = call ptr @llvm.launder.invariant.group(ptr %arg)
+ ret void
+ }
+)IR");
+ Value *arg = F->getArg(0);
+ EXPECT_EQ(getUnderlyingObject(A), arg);
+ EXPECT_EQ(getUnderlyingObject(A2), arg);
+ EXPECT_EQ(getUnderlyingObject(A3), arg);
+}
+
+TEST_F(ValueTrackingTest, getUnderlyingObjectPtrInt) {
+ parseAssembly(R"IR(
+ define void @test(i64 %arg, ptr %arg1) {
+ %A = inttoptr i64 %arg to ptr
+ %t0 = ptrtoint ptr %arg1 to i64
+ %A2 = inttoptr i64 %t0 to ptr
+ ret void
+ }
+)IR");
+ // Should not skip anything here
+ EXPECT_EQ(getUnderlyingObject(A->getOperand(0)), A->getOperand(0));
+ EXPECT_EQ(getUnderlyingObject(A2->getOperand(0)), A2->getOperand(0));
+}
+
+TEST_F(ValueTrackingTest, getUnderlyingObjectPhi) {
+ parseAssembly(R"IR(
+ @gvar = global i32 0
+ define void @test() {
+ entry:
+ %A = call ptr @llvm.ssa.copy.p0(ptr @gvar)
+ br label %block2
+
+ block2:
+ %A2 = phi ptr [ @gvar, %entry ]
+ ret void
+ }
+)IR");
+ Value *gvar = A->getOperand(0);
+ EXPECT_EQ(getUnderlyingObject(A2->getOperand(0)), gvar);
+}
+
TEST_F(ComputeKnownBitsTest, ComputeKnownBits) {
parseAssembly(
"define i32 @test(i32 %a, i32 %b) {\n"
>From 7b06d6b08854f25aabeb35adcab13fadadb87485 Mon Sep 17 00:00:00 2001
From: Matthias Braun <matze at braunis.de>
Date: Thu, 11 Apr 2024 10:33:00 -0700
Subject: [PATCH 2/2] GlobalsModRef, ValueTracking: Look through
threadlocal.address intrinsic
---
llvm/include/llvm/Analysis/ValueTracking.h | 10 +++++-----
llvm/lib/Analysis/GlobalsModRef.cpp | 8 ++++++++
llvm/lib/Analysis/ValueTracking.cpp | 3 +++
.../GlobalsModRef/nonescaping-noalias.ll | 19 +++++++++++++++++++
llvm/unittests/Analysis/ValueTrackingTest.cpp | 4 ++++
5 files changed, 39 insertions(+), 5 deletions(-)
diff --git a/llvm/include/llvm/Analysis/ValueTracking.h b/llvm/include/llvm/Analysis/ValueTracking.h
index e1c41b3b55ccfb..bab7c8868532db 100644
--- a/llvm/include/llvm/Analysis/ValueTracking.h
+++ b/llvm/include/llvm/Analysis/ValueTracking.h
@@ -690,11 +690,11 @@ inline Value *getArgumentAliasingToReturnedPointer(CallBase *Call,
bool isIntrinsicReturningPointerAliasingArgumentWithoutCapturing(
const CallBase *Call, bool MustPreserveNullness);
-/// This method strips off any GEP address adjustments and pointer casts from
-/// the specified value, returning the original object being addressed. Note
-/// that the returned value has pointer type if the specified value does. If
-/// the MaxLookup value is non-zero, it limits the number of instructions to
-/// be stripped off.
+/// This method strips off any GEP address adjustments, pointer casts
+/// or `llvm.threadlocal.address` from the specified value \p V, returning the
+/// original object being addressed. Note that the returned value has pointer
+/// type if the specified value does. If the \p MaxLookup value is non-zero, it
+/// limits the number of instructions to be stripped off.
const Value *getUnderlyingObject(const Value *V, unsigned MaxLookup = 6);
inline Value *getUnderlyingObject(Value *V, unsigned MaxLookup = 6) {
// Force const to avoid infinite recursion.
diff --git a/llvm/lib/Analysis/GlobalsModRef.cpp b/llvm/lib/Analysis/GlobalsModRef.cpp
index 527f19b194eeb9..1ceb1b26294183 100644
--- a/llvm/lib/Analysis/GlobalsModRef.cpp
+++ b/llvm/lib/Analysis/GlobalsModRef.cpp
@@ -344,6 +344,14 @@ bool GlobalsAAResult::AnalyzeUsesOfPointer(Value *V,
if (AnalyzeUsesOfPointer(I, Readers, Writers, OkayStoreDest))
return true;
} else if (auto *Call = dyn_cast<CallBase>(I)) {
+ if (IntrinsicInst *II = dyn_cast<IntrinsicInst>(I)) {
+ if (II->getIntrinsicID() == Intrinsic::threadlocal_address &&
+ V == II->getArgOperand(0)) {
+ if (AnalyzeUsesOfPointer(II, Readers, Writers))
+ return true;
+ continue;
+ }
+ }
// Make sure that this is just the function being called, not that it is
// passing into the function.
if (Call->isDataOperand(&U)) {
diff --git a/llvm/lib/Analysis/ValueTracking.cpp b/llvm/lib/Analysis/ValueTracking.cpp
index ab2f43e1033fa1..1337b838882cb5 100644
--- a/llvm/lib/Analysis/ValueTracking.cpp
+++ b/llvm/lib/Analysis/ValueTracking.cpp
@@ -6252,6 +6252,9 @@ bool llvm::isIntrinsicReturningPointerAliasingArgumentWithoutCapturing(
// MustPreserveNullness (and, at time of writing, they are not), but we
// document this fact out of an abundance of caution.
case Intrinsic::amdgcn_make_buffer_rsrc:
+ // For alias analysis it is best to return the `GlobalValue` representing the
+ // TLS variable.
+ case Intrinsic::threadlocal_address:
return true;
case Intrinsic::ptrmask:
return !MustPreserveNullness;
diff --git a/llvm/test/Analysis/GlobalsModRef/nonescaping-noalias.ll b/llvm/test/Analysis/GlobalsModRef/nonescaping-noalias.ll
index d109b3b8748ba7..f28e73c48b3e8e 100644
--- a/llvm/test/Analysis/GlobalsModRef/nonescaping-noalias.ll
+++ b/llvm/test/Analysis/GlobalsModRef/nonescaping-noalias.ll
@@ -22,6 +22,25 @@ entry:
ret i32 %v
}
+ at g1_tls = internal thread_local global i32 0
+
+define i32 @test1_tls(ptr %param) {
+; Ensure that we can fold a store to a load of a global across a store to
+; a parameter when the global is non-escaping.
+;
+; CHECK-LABEL: @test1_tls(
+; CHECK: %p = call ptr @llvm.threadlocal.address.p0(ptr @g1_tls)
+; CHECK: store i32 42, ptr %p
+; CHECK-NOT: load i32
+; CHECK: ret i32 42
+entry:
+ %p = call ptr @llvm.threadlocal.address(ptr @g1_tls)
+ store i32 42, ptr %p
+ store i32 7, ptr %param
+ %v = load i32, ptr %p
+ ret i32 %v
+}
+
declare ptr @f()
define i32 @test2() {
diff --git a/llvm/unittests/Analysis/ValueTrackingTest.cpp b/llvm/unittests/Analysis/ValueTrackingTest.cpp
index c59ed041373001..08b0ef3b5fb719 100644
--- a/llvm/unittests/Analysis/ValueTrackingTest.cpp
+++ b/llvm/unittests/Analysis/ValueTrackingTest.cpp
@@ -1273,12 +1273,14 @@ TEST_F(ValueTrackingTest, getUnderlyingObjectCastsAliases) {
TEST_F(ValueTrackingTest, getUnderlyingObjectIntrinsics) {
parseAssembly(R"IR(
+ @tlsvar = thread_local global i32 0
define void @test(ptr %arg) {
; intrinsic with Return<> arg attribute
%A = call ptr @llvm.objc.retain(ptr %arg)
%A2 = call ptr @llvm.ssa.copy(ptr %arg)
; special cased intrinsics
%A3 = call ptr @llvm.launder.invariant.group(ptr %arg)
+ %A4 = call ptr @llvm.threadlocal.address(ptr @tlsvar)
ret void
}
)IR");
@@ -1286,6 +1288,8 @@ TEST_F(ValueTrackingTest, getUnderlyingObjectIntrinsics) {
EXPECT_EQ(getUnderlyingObject(A), arg);
EXPECT_EQ(getUnderlyingObject(A2), arg);
EXPECT_EQ(getUnderlyingObject(A3), arg);
+ Value *tlsvar = M->getNamedGlobal("tlsvar");
+ EXPECT_EQ(getUnderlyingObject(A4), tlsvar);
}
TEST_F(ValueTrackingTest, getUnderlyingObjectPtrInt) {
More information about the llvm-commits
mailing list