[llvm] [BasicAA][TLI] Local-linkage or non-thread-local globals may not alias errno (PR #170290)
Antonio Frighetto via llvm-commits
llvm-commits at lists.llvm.org
Tue Dec 2 09:32:04 PST 2025
https://github.com/antoniofrighetto updated https://github.com/llvm/llvm-project/pull/170290
>From 46df14b6a18b203e3f20e989e88538ead904ed8f Mon Sep 17 00:00:00 2001
From: Antonio Frighetto <me at antoniofrighetto.com>
Date: Tue, 2 Dec 2025 10:16:24 +0100
Subject: [PATCH 1/4] [InstCombine] Precommit tests (NFC)
---
.../Transforms/InstCombine/may-alias-errno.ll | 58 +++++++++++++++++++
.../non-tls-does-not-alias-errno.ll | 24 ++++++++
2 files changed, 82 insertions(+)
create mode 100644 llvm/test/Transforms/InstCombine/non-tls-does-not-alias-errno.ll
diff --git a/llvm/test/Transforms/InstCombine/may-alias-errno.ll b/llvm/test/Transforms/InstCombine/may-alias-errno.ll
index 40fab8024b362..dd73793bf1f47 100644
--- a/llvm/test/Transforms/InstCombine/may-alias-errno.ll
+++ b/llvm/test/Transforms/InstCombine/may-alias-errno.ll
@@ -149,6 +149,64 @@ entry:
ret <vscale x 4 x i32> %v
}
+ at internal_g = internal global i32 0
+
+; errno cannot alias an internal global variable, can do constant store-to-load forwarding.
+define i32 @does_not_alias_errno_internal_global(float %f) {
+; CHECK-LABEL: define i32 @does_not_alias_errno_internal_global(
+; CHECK-SAME: float [[F:%.*]]) {
+; CHECK-NEXT: [[ENTRY:.*:]]
+; CHECK-NEXT: store i32 42, ptr @internal_g, align 4
+; CHECK-NEXT: [[CALL:%.*]] = call float @sinf(float [[F]])
+; CHECK-NEXT: [[V:%.*]] = load i32, ptr @internal_g, align 4
+; CHECK-NEXT: ret i32 [[V]]
+;
+entry:
+ store i32 42, ptr @internal_g, align 4
+ %call = call float @sinf(float %f)
+ %v = load i32, ptr @internal_g, align 4
+ ret i32 %v
+}
+
+ at external_g = external global i32
+
+; errno cannot alias an external global variable unless known to be errno,
+; can do constant store-to-load forwarding.
+define i32 @does_not_alias_errno_external_global_known_by_name(float %f) {
+; CHECK-LABEL: define i32 @does_not_alias_errno_external_global_known_by_name(
+; CHECK-SAME: float [[F:%.*]]) {
+; CHECK-NEXT: [[ENTRY:.*:]]
+; CHECK-NEXT: store i32 42, ptr @external_g, align 4
+; CHECK-NEXT: [[CALL:%.*]] = call float @sinf(float [[F]])
+; CHECK-NEXT: [[V:%.*]] = load i32, ptr @external_g, align 4
+; CHECK-NEXT: ret i32 [[V]]
+;
+entry:
+ store i32 42, ptr @external_g, align 4
+ %call = call float @sinf(float %f)
+ %v = load i32, ptr @external_g, align 4
+ ret i32 %v
+}
+
+ at errno = external global i32
+
+; errno global variable does alias errno, cannot do constant store-to-load forwarding.
+define i32 @does_alias_errno_global(float %f) {
+; CHECK-LABEL: define i32 @does_alias_errno_global(
+; CHECK-SAME: float [[F:%.*]]) {
+; CHECK-NEXT: [[ENTRY:.*:]]
+; CHECK-NEXT: store i32 42, ptr @errno, align 4
+; CHECK-NEXT: [[CALL:%.*]] = call float @sinf(float [[F]])
+; CHECK-NEXT: [[V:%.*]] = load i32, ptr @errno, align 4
+; CHECK-NEXT: ret i32 [[V]]
+;
+entry:
+ store i32 42, ptr @errno, align 4
+ %call = call float @sinf(float %f)
+ %v = load i32, ptr @errno, align 4
+ ret i32 %v
+}
+
declare float @sinf(float) memory(errnomem: write)
declare float @read_errno(ptr) memory(argmem: write, errnomem: read)
declare void @escape(ptr %p)
diff --git a/llvm/test/Transforms/InstCombine/non-tls-does-not-alias-errno.ll b/llvm/test/Transforms/InstCombine/non-tls-does-not-alias-errno.ll
new file mode 100644
index 0000000000000..181882af307e1
--- /dev/null
+++ b/llvm/test/Transforms/InstCombine/non-tls-does-not-alias-errno.ll
@@ -0,0 +1,24 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 6
+; RUN: opt -S -mtriple=aarch64-linux-gnu -passes=instcombine < %s | FileCheck %s
+
+ at errno = external global i32
+
+; non-tls errno global variable does not alias errno when known to be a thread-local variable,
+; can do constant store-to-load forwarding.
+define i32 @does_not_alias_errno_global_known_tls(float %f) {
+; CHECK-LABEL: define i32 @does_not_alias_errno_global_known_tls(
+; CHECK-SAME: float [[F:%.*]]) {
+; CHECK-NEXT: [[ENTRY:.*:]]
+; CHECK-NEXT: store i32 42, ptr @errno, align 4
+; CHECK-NEXT: [[CALL:%.*]] = call float @sinf(float [[F]])
+; CHECK-NEXT: [[V:%.*]] = load i32, ptr @errno, align 4
+; CHECK-NEXT: ret i32 [[V]]
+;
+entry:
+ store i32 42, ptr @errno, align 4
+ %call = call float @sinf(float %f)
+ %v = load i32, ptr @errno, align 4
+ ret i32 %v
+}
+
+declare float @sinf(float) memory(errnomem: write)
>From fee1d591f1f9ec96237b9d411941af9f2efc3f91 Mon Sep 17 00:00:00 2001
From: Antonio Frighetto <me at antoniofrighetto.com>
Date: Sun, 30 Nov 2025 19:30:10 +0100
Subject: [PATCH 2/4] [BasicAA][TLI] Local-linkage or non-thread-local globals
may not alias errno
Errno cannot alias global variables with internal/private-linkage,
neither can it alias external ones unless known to be errno.
Likewise, a non-thread-local global cannot alias errno when known
to be implemented as a thread-local variable.
---
.../include/llvm/Analysis/TargetLibraryInfo.h | 14 +++++++++++
llvm/lib/Analysis/BasicAliasAnalysis.cpp | 18 +++++++++++++-
llvm/lib/Analysis/TargetLibraryInfo.cpp | 24 ++++++++++++++++---
.../Transforms/InstCombine/may-alias-errno.ll | 6 ++---
.../non-tls-does-not-alias-errno.ll | 3 +--
.../Analysis/TargetLibraryInfoTest.cpp | 10 ++++++++
6 files changed, 65 insertions(+), 10 deletions(-)
diff --git a/llvm/include/llvm/Analysis/TargetLibraryInfo.h b/llvm/include/llvm/Analysis/TargetLibraryInfo.h
index 0f98af69f12c6..c2ed7aec684d2 100644
--- a/llvm/include/llvm/Analysis/TargetLibraryInfo.h
+++ b/llvm/include/llvm/Analysis/TargetLibraryInfo.h
@@ -89,6 +89,7 @@ class TargetLibraryInfoImpl {
#include "llvm/Analysis/TargetLibraryInfo.inc"
bool ShouldExtI32Param, ShouldExtI32Return, ShouldSignExtI32Param, ShouldSignExtI32Return;
unsigned SizeOfInt;
+ bool IsErrnoThreadLocal;
enum AvailabilityState {
StandardName = 3, // (memset to all ones)
@@ -256,6 +257,9 @@ class TargetLibraryInfoImpl {
/// conventions.
LLVM_ABI static bool isCallingConvCCompatible(CallBase *CI);
LLVM_ABI static bool isCallingConvCCompatible(Function *Callee);
+
+ LLVM_ABI bool mayBeErrnoGlobal(const GlobalVariable *GV) const;
+ LLVM_ABI bool isErrnoThreadLocal() const { return IsErrnoThreadLocal; }
};
/// Provides information about what library functions are available for
@@ -601,6 +605,16 @@ class TargetLibraryInfo {
bool isKnownVectorFunctionInLibrary(StringRef F) const {
return this->isFunctionVectorizable(F);
}
+
+ /// Returns whether the name of the global variable is associated to the
+ /// representation of the errno storage. Returns true if could not determined.
+ bool mayBeErrnoGlobal(const GlobalVariable *GV) const {
+ return Impl->mayBeErrnoGlobal(GV);
+ }
+
+ /// Returns whether the target C library implements errno as a thread-local
+ /// variable, which is de facto the standard for non-baremetal targets.
+ bool isErrnoThreadLocal() const { return Impl->isErrnoThreadLocal(); }
};
/// Analysis pass providing the \c TargetLibraryInfo.
diff --git a/llvm/lib/Analysis/BasicAliasAnalysis.cpp b/llvm/lib/Analysis/BasicAliasAnalysis.cpp
index f812809e5e0b5..7509b29ad7a64 100644
--- a/llvm/lib/Analysis/BasicAliasAnalysis.cpp
+++ b/llvm/lib/Analysis/BasicAliasAnalysis.cpp
@@ -1870,8 +1870,24 @@ AliasResult BasicAAResult::aliasErrno(const MemoryLocation &Loc,
Loc.Size.getValue().getKnownMinValue() * 8 > TLI.getIntSize())
return AliasResult::NoAlias;
- if (isIdentifiedFunctionLocal(getUnderlyingObject(Loc.Ptr)))
+ const Value *Object = getUnderlyingObject(Loc.Ptr);
+ if (isIdentifiedFunctionLocal(Object))
return AliasResult::NoAlias;
+
+ if (auto *GV = dyn_cast<GlobalVariable>(Object)) {
+ // Errno cannot alias internal/private globals.
+ if (GV->hasLocalLinkage())
+ return AliasResult::NoAlias;
+
+ // Neither can it alias external globals which are known not to represent
+ // errno.
+ if (GV->hasExternalLinkage() && !TLI.mayBeErrnoGlobal(GV))
+ return AliasResult::NoAlias;
+
+ // A non-thread-local global cannot alias a thread-local errno.
+ if (!GV->isThreadLocal() && TLI.isErrnoThreadLocal())
+ return AliasResult::NoAlias;
+ }
return AliasResult::MayAlias;
}
diff --git a/llvm/lib/Analysis/TargetLibraryInfo.cpp b/llvm/lib/Analysis/TargetLibraryInfo.cpp
index 51b1f5874bcb6..35acc5192565b 100644
--- a/llvm/lib/Analysis/TargetLibraryInfo.cpp
+++ b/llvm/lib/Analysis/TargetLibraryInfo.cpp
@@ -905,8 +905,15 @@ static void initialize(TargetLibraryInfoImpl &TLI, const Triple &T,
initializeLibCalls(TLI, T, StandardNames, VecLib);
}
+static bool initializeIsErrnoThreadLocal(const Triple &T) {
+ // Assume errno has thread-local storage for non-baremetal environments.
+ // TODO: Could refine known OSes.
+ return T.isOSDarwin() || T.isOSFreeBSD() || T.isOSLinux() || T.isOSWindows();
+}
+
TargetLibraryInfoImpl::TargetLibraryInfoImpl(const Triple &T,
- VectorLibrary VecLib) {
+ VectorLibrary VecLib)
+ : IsErrnoThreadLocal(initializeIsErrnoThreadLocal(T)) {
// Default to everything being available.
memset(AvailableArray, -1, sizeof(AvailableArray));
@@ -918,7 +925,7 @@ TargetLibraryInfoImpl::TargetLibraryInfoImpl(const TargetLibraryInfoImpl &TLI)
ShouldExtI32Return(TLI.ShouldExtI32Return),
ShouldSignExtI32Param(TLI.ShouldSignExtI32Param),
ShouldSignExtI32Return(TLI.ShouldSignExtI32Return),
- SizeOfInt(TLI.SizeOfInt) {
+ SizeOfInt(TLI.SizeOfInt), IsErrnoThreadLocal(TLI.IsErrnoThreadLocal) {
memcpy(AvailableArray, TLI.AvailableArray, sizeof(AvailableArray));
VectorDescs = TLI.VectorDescs;
ScalarDescs = TLI.ScalarDescs;
@@ -930,7 +937,7 @@ TargetLibraryInfoImpl::TargetLibraryInfoImpl(TargetLibraryInfoImpl &&TLI)
ShouldExtI32Return(TLI.ShouldExtI32Return),
ShouldSignExtI32Param(TLI.ShouldSignExtI32Param),
ShouldSignExtI32Return(TLI.ShouldSignExtI32Return),
- SizeOfInt(TLI.SizeOfInt) {
+ SizeOfInt(TLI.SizeOfInt), IsErrnoThreadLocal(TLI.IsErrnoThreadLocal) {
std::move(std::begin(TLI.AvailableArray), std::end(TLI.AvailableArray),
AvailableArray);
VectorDescs = TLI.VectorDescs;
@@ -944,6 +951,7 @@ TargetLibraryInfoImpl &TargetLibraryInfoImpl::operator=(const TargetLibraryInfoI
ShouldSignExtI32Param = TLI.ShouldSignExtI32Param;
ShouldSignExtI32Return = TLI.ShouldSignExtI32Return;
SizeOfInt = TLI.SizeOfInt;
+ IsErrnoThreadLocal = TLI.IsErrnoThreadLocal;
memcpy(AvailableArray, TLI.AvailableArray, sizeof(AvailableArray));
return *this;
}
@@ -955,6 +963,7 @@ TargetLibraryInfoImpl &TargetLibraryInfoImpl::operator=(TargetLibraryInfoImpl &&
ShouldSignExtI32Param = TLI.ShouldSignExtI32Param;
ShouldSignExtI32Return = TLI.ShouldSignExtI32Return;
SizeOfInt = TLI.SizeOfInt;
+ IsErrnoThreadLocal = TLI.IsErrnoThreadLocal;
std::move(std::begin(TLI.AvailableArray), std::end(TLI.AvailableArray),
AvailableArray);
return *this;
@@ -1468,6 +1477,15 @@ unsigned TargetLibraryInfoImpl::getSizeTSize(const Module &M) const {
return M.getDataLayout().getIndexSizeInBits(/*AddressSpace=*/0);
}
+bool TargetLibraryInfoImpl::mayBeErrnoGlobal(const GlobalVariable *GV) const {
+ // TODO: Should consider C++ mangled names for errno.
+ static constexpr auto ErrnoGlobalNames = {"errno", "__libc_errno"};
+ assert(GV && "Expecting existing GlobalVariable.");
+ if (GV->hasName() && !is_contained(ErrnoGlobalNames, GV->getName()))
+ return false;
+ return true;
+}
+
TargetLibraryInfoWrapperPass::TargetLibraryInfoWrapperPass()
: ImmutablePass(ID), TLA(TargetLibraryInfoImpl(Triple())) {}
diff --git a/llvm/test/Transforms/InstCombine/may-alias-errno.ll b/llvm/test/Transforms/InstCombine/may-alias-errno.ll
index dd73793bf1f47..d4604aae90b79 100644
--- a/llvm/test/Transforms/InstCombine/may-alias-errno.ll
+++ b/llvm/test/Transforms/InstCombine/may-alias-errno.ll
@@ -158,8 +158,7 @@ define i32 @does_not_alias_errno_internal_global(float %f) {
; CHECK-NEXT: [[ENTRY:.*:]]
; CHECK-NEXT: store i32 42, ptr @internal_g, align 4
; CHECK-NEXT: [[CALL:%.*]] = call float @sinf(float [[F]])
-; CHECK-NEXT: [[V:%.*]] = load i32, ptr @internal_g, align 4
-; CHECK-NEXT: ret i32 [[V]]
+; CHECK-NEXT: ret i32 42
;
entry:
store i32 42, ptr @internal_g, align 4
@@ -178,8 +177,7 @@ define i32 @does_not_alias_errno_external_global_known_by_name(float %f) {
; CHECK-NEXT: [[ENTRY:.*:]]
; CHECK-NEXT: store i32 42, ptr @external_g, align 4
; CHECK-NEXT: [[CALL:%.*]] = call float @sinf(float [[F]])
-; CHECK-NEXT: [[V:%.*]] = load i32, ptr @external_g, align 4
-; CHECK-NEXT: ret i32 [[V]]
+; CHECK-NEXT: ret i32 42
;
entry:
store i32 42, ptr @external_g, align 4
diff --git a/llvm/test/Transforms/InstCombine/non-tls-does-not-alias-errno.ll b/llvm/test/Transforms/InstCombine/non-tls-does-not-alias-errno.ll
index 181882af307e1..988b33f002ced 100644
--- a/llvm/test/Transforms/InstCombine/non-tls-does-not-alias-errno.ll
+++ b/llvm/test/Transforms/InstCombine/non-tls-does-not-alias-errno.ll
@@ -11,8 +11,7 @@ define i32 @does_not_alias_errno_global_known_tls(float %f) {
; CHECK-NEXT: [[ENTRY:.*:]]
; CHECK-NEXT: store i32 42, ptr @errno, align 4
; CHECK-NEXT: [[CALL:%.*]] = call float @sinf(float [[F]])
-; CHECK-NEXT: [[V:%.*]] = load i32, ptr @errno, align 4
-; CHECK-NEXT: ret i32 [[V]]
+; CHECK-NEXT: ret i32 42
;
entry:
store i32 42, ptr @errno, align 4
diff --git a/llvm/unittests/Analysis/TargetLibraryInfoTest.cpp b/llvm/unittests/Analysis/TargetLibraryInfoTest.cpp
index 3029f10b1bb29..14332774ae90f 100644
--- a/llvm/unittests/Analysis/TargetLibraryInfoTest.cpp
+++ b/llvm/unittests/Analysis/TargetLibraryInfoTest.cpp
@@ -703,6 +703,16 @@ TEST_F(TargetLibraryInfoTest, ValidProto) {
}
}
+TEST_F(TargetLibraryInfoTest, IsErrnoThreadLocal) {
+ EXPECT_TRUE(TargetLibraryInfoImpl(Triple("x86_64-unknown-linux-gnu")).isErrnoThreadLocal());
+ EXPECT_TRUE(TargetLibraryInfoImpl(Triple("arm64-apple-macosx")).isErrnoThreadLocal());
+ EXPECT_TRUE(TargetLibraryInfoImpl(Triple("x86_64-pc-windows-msvc")).isErrnoThreadLocal());
+ EXPECT_TRUE(TargetLibraryInfoImpl(Triple("x86_64-unknown-freebsd")).isErrnoThreadLocal());
+
+ EXPECT_FALSE(TargetLibraryInfoImpl(Triple("arm-none-eabi")).isErrnoThreadLocal());
+ EXPECT_FALSE(TargetLibraryInfoImpl(Triple("aarch64-unknown-unknown")).isErrnoThreadLocal());
+}
+
namespace {
/// Creates TLI for AArch64 and uses it to get the LibFunc names for the given
>From 06294b91f5889421614a473e02af3d022dd26d26 Mon Sep 17 00:00:00 2001
From: Antonio Frighetto <me at antoniofrighetto.com>
Date: Tue, 2 Dec 2025 14:26:38 +0100
Subject: [PATCH 3/4] !fixup clang-format
---
.../Analysis/TargetLibraryInfoTest.cpp | 20 ++++++++++++-------
1 file changed, 13 insertions(+), 7 deletions(-)
diff --git a/llvm/unittests/Analysis/TargetLibraryInfoTest.cpp b/llvm/unittests/Analysis/TargetLibraryInfoTest.cpp
index 14332774ae90f..b3ca59d579cab 100644
--- a/llvm/unittests/Analysis/TargetLibraryInfoTest.cpp
+++ b/llvm/unittests/Analysis/TargetLibraryInfoTest.cpp
@@ -704,13 +704,19 @@ TEST_F(TargetLibraryInfoTest, ValidProto) {
}
TEST_F(TargetLibraryInfoTest, IsErrnoThreadLocal) {
- EXPECT_TRUE(TargetLibraryInfoImpl(Triple("x86_64-unknown-linux-gnu")).isErrnoThreadLocal());
- EXPECT_TRUE(TargetLibraryInfoImpl(Triple("arm64-apple-macosx")).isErrnoThreadLocal());
- EXPECT_TRUE(TargetLibraryInfoImpl(Triple("x86_64-pc-windows-msvc")).isErrnoThreadLocal());
- EXPECT_TRUE(TargetLibraryInfoImpl(Triple("x86_64-unknown-freebsd")).isErrnoThreadLocal());
-
- EXPECT_FALSE(TargetLibraryInfoImpl(Triple("arm-none-eabi")).isErrnoThreadLocal());
- EXPECT_FALSE(TargetLibraryInfoImpl(Triple("aarch64-unknown-unknown")).isErrnoThreadLocal());
+ EXPECT_TRUE(TargetLibraryInfoImpl(Triple("x86_64-unknown-linux-gnu"))
+ .isErrnoThreadLocal());
+ EXPECT_TRUE(
+ TargetLibraryInfoImpl(Triple("arm64-apple-macosx")).isErrnoThreadLocal());
+ EXPECT_TRUE(TargetLibraryInfoImpl(Triple("x86_64-pc-windows-msvc"))
+ .isErrnoThreadLocal());
+ EXPECT_TRUE(TargetLibraryInfoImpl(Triple("x86_64-unknown-freebsd"))
+ .isErrnoThreadLocal());
+
+ EXPECT_FALSE(
+ TargetLibraryInfoImpl(Triple("arm-none-eabi")).isErrnoThreadLocal());
+ EXPECT_FALSE(TargetLibraryInfoImpl(Triple("aarch64-unknown-unknown"))
+ .isErrnoThreadLocal());
}
namespace {
>From 33dea37e5df02cf1f87f59f442abc6b5872c309e Mon Sep 17 00:00:00 2001
From: Antonio Frighetto <me at antoniofrighetto.com>
Date: Tue, 2 Dec 2025 18:31:16 +0100
Subject: [PATCH 4/4] !fixup move in mayBeErrnoGlobal, use IsErrnoFunctionCall
---
.../include/llvm/Analysis/TargetLibraryInfo.h | 6 +---
llvm/lib/Analysis/BasicAliasAnalysis.cpp | 11 +++---
llvm/lib/Analysis/TargetLibraryInfo.cpp | 27 +++++++++++----
.../Transforms/InstCombine/may-alias-errno.ll | 27 +++------------
.../non-tls-does-not-alias-errno.ll | 2 +-
.../Analysis/TargetLibraryInfoTest.cpp | 34 +++++++++++--------
6 files changed, 51 insertions(+), 56 deletions(-)
diff --git a/llvm/include/llvm/Analysis/TargetLibraryInfo.h b/llvm/include/llvm/Analysis/TargetLibraryInfo.h
index c2ed7aec684d2..b9ccda022bf2f 100644
--- a/llvm/include/llvm/Analysis/TargetLibraryInfo.h
+++ b/llvm/include/llvm/Analysis/TargetLibraryInfo.h
@@ -89,6 +89,7 @@ class TargetLibraryInfoImpl {
#include "llvm/Analysis/TargetLibraryInfo.inc"
bool ShouldExtI32Param, ShouldExtI32Return, ShouldSignExtI32Param, ShouldSignExtI32Return;
unsigned SizeOfInt;
+ bool IsErrnoFunctionCall;
bool IsErrnoThreadLocal;
enum AvailabilityState {
@@ -259,7 +260,6 @@ class TargetLibraryInfoImpl {
LLVM_ABI static bool isCallingConvCCompatible(Function *Callee);
LLVM_ABI bool mayBeErrnoGlobal(const GlobalVariable *GV) const;
- LLVM_ABI bool isErrnoThreadLocal() const { return IsErrnoThreadLocal; }
};
/// Provides information about what library functions are available for
@@ -611,10 +611,6 @@ class TargetLibraryInfo {
bool mayBeErrnoGlobal(const GlobalVariable *GV) const {
return Impl->mayBeErrnoGlobal(GV);
}
-
- /// Returns whether the target C library implements errno as a thread-local
- /// variable, which is de facto the standard for non-baremetal targets.
- bool isErrnoThreadLocal() const { return Impl->isErrnoThreadLocal(); }
};
/// Analysis pass providing the \c TargetLibraryInfo.
diff --git a/llvm/lib/Analysis/BasicAliasAnalysis.cpp b/llvm/lib/Analysis/BasicAliasAnalysis.cpp
index 7509b29ad7a64..381bb285f1f79 100644
--- a/llvm/lib/Analysis/BasicAliasAnalysis.cpp
+++ b/llvm/lib/Analysis/BasicAliasAnalysis.cpp
@@ -1879,15 +1879,12 @@ AliasResult BasicAAResult::aliasErrno(const MemoryLocation &Loc,
if (GV->hasLocalLinkage())
return AliasResult::NoAlias;
- // Neither can it alias external globals which are known not to represent
- // errno.
- if (GV->hasExternalLinkage() && !TLI.mayBeErrnoGlobal(GV))
- return AliasResult::NoAlias;
-
- // A non-thread-local global cannot alias a thread-local errno.
- if (!GV->isThreadLocal() && TLI.isErrnoThreadLocal())
+ // Neither can it alias globals where environments define it as a function
+ // call, nor can a non-thread-local global alias a thread-local errno.
+ if (!TLI.mayBeErrnoGlobal(GV))
return AliasResult::NoAlias;
}
+
return AliasResult::MayAlias;
}
diff --git a/llvm/lib/Analysis/TargetLibraryInfo.cpp b/llvm/lib/Analysis/TargetLibraryInfo.cpp
index 35acc5192565b..be000f6f9c845 100644
--- a/llvm/lib/Analysis/TargetLibraryInfo.cpp
+++ b/llvm/lib/Analysis/TargetLibraryInfo.cpp
@@ -911,9 +911,20 @@ static bool initializeIsErrnoThreadLocal(const Triple &T) {
return T.isOSDarwin() || T.isOSFreeBSD() || T.isOSLinux() || T.isOSWindows();
}
+static bool initializeIsErrnoFunctionCall(const Triple &T) {
+ // Assume errno is implemented as a function call on the following
+ // environments.
+ // TODO: Could refine known environments.
+ return T.isAndroid() || T.isGNUEnvironment() || T.isMusl() ||
+ T.getEnvironment() == Triple::LLVM ||
+ T.getEnvironment() == Triple::Mlibc ||
+ T.getEnvironment() == Triple::MSVC;
+}
+
TargetLibraryInfoImpl::TargetLibraryInfoImpl(const Triple &T,
VectorLibrary VecLib)
- : IsErrnoThreadLocal(initializeIsErrnoThreadLocal(T)) {
+ : IsErrnoFunctionCall(initializeIsErrnoFunctionCall(T)),
+ IsErrnoThreadLocal(initializeIsErrnoThreadLocal(T)) {
// Default to everything being available.
memset(AvailableArray, -1, sizeof(AvailableArray));
@@ -925,7 +936,8 @@ TargetLibraryInfoImpl::TargetLibraryInfoImpl(const TargetLibraryInfoImpl &TLI)
ShouldExtI32Return(TLI.ShouldExtI32Return),
ShouldSignExtI32Param(TLI.ShouldSignExtI32Param),
ShouldSignExtI32Return(TLI.ShouldSignExtI32Return),
- SizeOfInt(TLI.SizeOfInt), IsErrnoThreadLocal(TLI.IsErrnoThreadLocal) {
+ SizeOfInt(TLI.SizeOfInt), IsErrnoFunctionCall(TLI.IsErrnoFunctionCall),
+ IsErrnoThreadLocal(TLI.IsErrnoThreadLocal) {
memcpy(AvailableArray, TLI.AvailableArray, sizeof(AvailableArray));
VectorDescs = TLI.VectorDescs;
ScalarDescs = TLI.ScalarDescs;
@@ -937,7 +949,8 @@ TargetLibraryInfoImpl::TargetLibraryInfoImpl(TargetLibraryInfoImpl &&TLI)
ShouldExtI32Return(TLI.ShouldExtI32Return),
ShouldSignExtI32Param(TLI.ShouldSignExtI32Param),
ShouldSignExtI32Return(TLI.ShouldSignExtI32Return),
- SizeOfInt(TLI.SizeOfInt), IsErrnoThreadLocal(TLI.IsErrnoThreadLocal) {
+ SizeOfInt(TLI.SizeOfInt), IsErrnoFunctionCall(TLI.IsErrnoFunctionCall),
+ IsErrnoThreadLocal(TLI.IsErrnoThreadLocal) {
std::move(std::begin(TLI.AvailableArray), std::end(TLI.AvailableArray),
AvailableArray);
VectorDescs = TLI.VectorDescs;
@@ -951,6 +964,7 @@ TargetLibraryInfoImpl &TargetLibraryInfoImpl::operator=(const TargetLibraryInfoI
ShouldSignExtI32Param = TLI.ShouldSignExtI32Param;
ShouldSignExtI32Return = TLI.ShouldSignExtI32Return;
SizeOfInt = TLI.SizeOfInt;
+ IsErrnoFunctionCall = TLI.IsErrnoFunctionCall;
IsErrnoThreadLocal = TLI.IsErrnoThreadLocal;
memcpy(AvailableArray, TLI.AvailableArray, sizeof(AvailableArray));
return *this;
@@ -963,6 +977,7 @@ TargetLibraryInfoImpl &TargetLibraryInfoImpl::operator=(TargetLibraryInfoImpl &&
ShouldSignExtI32Param = TLI.ShouldSignExtI32Param;
ShouldSignExtI32Return = TLI.ShouldSignExtI32Return;
SizeOfInt = TLI.SizeOfInt;
+ IsErrnoFunctionCall = TLI.IsErrnoFunctionCall;
IsErrnoThreadLocal = TLI.IsErrnoThreadLocal;
std::move(std::begin(TLI.AvailableArray), std::end(TLI.AvailableArray),
AvailableArray);
@@ -1478,10 +1493,10 @@ unsigned TargetLibraryInfoImpl::getSizeTSize(const Module &M) const {
}
bool TargetLibraryInfoImpl::mayBeErrnoGlobal(const GlobalVariable *GV) const {
- // TODO: Should consider C++ mangled names for errno.
- static constexpr auto ErrnoGlobalNames = {"errno", "__libc_errno"};
assert(GV && "Expecting existing GlobalVariable.");
- if (GV->hasName() && !is_contained(ErrnoGlobalNames, GV->getName()))
+ if (IsErrnoFunctionCall)
+ return false;
+ if (!GV->isThreadLocal() && IsErrnoThreadLocal)
return false;
return true;
}
diff --git a/llvm/test/Transforms/InstCombine/may-alias-errno.ll b/llvm/test/Transforms/InstCombine/may-alias-errno.ll
index d4604aae90b79..a9ceae6903239 100644
--- a/llvm/test/Transforms/InstCombine/may-alias-errno.ll
+++ b/llvm/test/Transforms/InstCombine/may-alias-errno.ll
@@ -1,5 +1,5 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 5
-; RUN: opt -S -passes=instcombine < %s | FileCheck %s
+; RUN: opt -S -passes=instcombine -mtriple=aarch64-linux-gnu < %s | FileCheck %s
; sinf clobbering errno, but %p cannot alias errno per C/C++ strict aliasing rules via TBAA.
; Can do constant store-to-load forwarding.
@@ -169,10 +169,10 @@ entry:
@external_g = external global i32
-; errno cannot alias an external global variable unless known to be errno,
+; errno cannot alias an external global variable in GNU environment,
; can do constant store-to-load forwarding.
-define i32 @does_not_alias_errno_external_global_known_by_name(float %f) {
-; CHECK-LABEL: define i32 @does_not_alias_errno_external_global_known_by_name(
+define i32 @does_not_alias_errno_external_known_environment(float %f) {
+; CHECK-LABEL: define i32 @does_not_alias_errno_external_known_environment(
; CHECK-SAME: float [[F:%.*]]) {
; CHECK-NEXT: [[ENTRY:.*:]]
; CHECK-NEXT: store i32 42, ptr @external_g, align 4
@@ -186,25 +186,6 @@ entry:
ret i32 %v
}
- at errno = external global i32
-
-; errno global variable does alias errno, cannot do constant store-to-load forwarding.
-define i32 @does_alias_errno_global(float %f) {
-; CHECK-LABEL: define i32 @does_alias_errno_global(
-; CHECK-SAME: float [[F:%.*]]) {
-; CHECK-NEXT: [[ENTRY:.*:]]
-; CHECK-NEXT: store i32 42, ptr @errno, align 4
-; CHECK-NEXT: [[CALL:%.*]] = call float @sinf(float [[F]])
-; CHECK-NEXT: [[V:%.*]] = load i32, ptr @errno, align 4
-; CHECK-NEXT: ret i32 [[V]]
-;
-entry:
- store i32 42, ptr @errno, align 4
- %call = call float @sinf(float %f)
- %v = load i32, ptr @errno, align 4
- ret i32 %v
-}
-
declare float @sinf(float) memory(errnomem: write)
declare float @read_errno(ptr) memory(argmem: write, errnomem: read)
declare void @escape(ptr %p)
diff --git a/llvm/test/Transforms/InstCombine/non-tls-does-not-alias-errno.ll b/llvm/test/Transforms/InstCombine/non-tls-does-not-alias-errno.ll
index 988b33f002ced..95178a9785af1 100644
--- a/llvm/test/Transforms/InstCombine/non-tls-does-not-alias-errno.ll
+++ b/llvm/test/Transforms/InstCombine/non-tls-does-not-alias-errno.ll
@@ -1,5 +1,5 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 6
-; RUN: opt -S -mtriple=aarch64-linux-gnu -passes=instcombine < %s | FileCheck %s
+; RUN: opt -S -mtriple=arm64-apple-macos -passes=instcombine < %s | FileCheck %s
@errno = external global i32
diff --git a/llvm/unittests/Analysis/TargetLibraryInfoTest.cpp b/llvm/unittests/Analysis/TargetLibraryInfoTest.cpp
index b3ca59d579cab..796187b6f3c4f 100644
--- a/llvm/unittests/Analysis/TargetLibraryInfoTest.cpp
+++ b/llvm/unittests/Analysis/TargetLibraryInfoTest.cpp
@@ -703,20 +703,26 @@ TEST_F(TargetLibraryInfoTest, ValidProto) {
}
}
-TEST_F(TargetLibraryInfoTest, IsErrnoThreadLocal) {
- EXPECT_TRUE(TargetLibraryInfoImpl(Triple("x86_64-unknown-linux-gnu"))
- .isErrnoThreadLocal());
- EXPECT_TRUE(
- TargetLibraryInfoImpl(Triple("arm64-apple-macosx")).isErrnoThreadLocal());
- EXPECT_TRUE(TargetLibraryInfoImpl(Triple("x86_64-pc-windows-msvc"))
- .isErrnoThreadLocal());
- EXPECT_TRUE(TargetLibraryInfoImpl(Triple("x86_64-unknown-freebsd"))
- .isErrnoThreadLocal());
-
- EXPECT_FALSE(
- TargetLibraryInfoImpl(Triple("arm-none-eabi")).isErrnoThreadLocal());
- EXPECT_FALSE(TargetLibraryInfoImpl(Triple("aarch64-unknown-unknown"))
- .isErrnoThreadLocal());
+TEST_F(TargetLibraryInfoTest, IsErrnoGlobal) {
+ using TLII = TargetLibraryInfoImpl;
+ parseAssembly(R"(
+ @global = external global i32
+ )");
+ auto *GV = M->getNamedGlobal("global");
+
+ // Errno is not a global on the following environments.
+ EXPECT_FALSE(TLII(Triple("x86_64-unknown-linux-gnu")).mayBeErrnoGlobal(GV));
+ EXPECT_FALSE(TLII(Triple("x86_64-pc-windows-msvc")).mayBeErrnoGlobal(GV));
+
+ // Errno is thread-local on the following OSes.
+ EXPECT_FALSE(TLII(Triple("arm64-apple-macosx")).mayBeErrnoGlobal(GV));
+ EXPECT_FALSE(TLII(Triple("x86_64-unknown-freebsd")).mayBeErrnoGlobal(GV));
+
+ // Unknown.
+ EXPECT_TRUE(TLII(Triple("arm-none-eabi")).mayBeErrnoGlobal(GV));
+ EXPECT_TRUE(TLII(Triple("aarch64-unknown-unknown")).mayBeErrnoGlobal(GV));
+ GV->setThreadLocalMode(GlobalVariable::GeneralDynamicTLSModel);
+ EXPECT_TRUE(TLII(Triple("x86_64-pc-linux")).mayBeErrnoGlobal(GV));
}
namespace {
More information about the llvm-commits
mailing list