[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
Sat Dec 6 09:01:33 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/5] [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/5] [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/5] !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/5] !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 {
>From 2775070816d597000d91f9027842d0632a963fed Mon Sep 17 00:00:00 2001
From: Antonio Frighetto <me at antoniofrighetto.com>
Date: Sat, 6 Dec 2025 18:00:18 +0100
Subject: [PATCH 5/5] !fixup drop IsErrnoThreadLocal, check if may be
freestanding
---
.../include/llvm/Analysis/TargetLibraryInfo.h | 11 ++---
llvm/lib/Analysis/BasicAliasAnalysis.cpp | 6 +--
llvm/lib/Analysis/TargetLibraryInfo.cpp | 47 +++++++------------
.../non-tls-does-not-alias-errno.ll | 23 ---------
.../Analysis/TargetLibraryInfoTest.cpp | 27 +++++------
5 files changed, 37 insertions(+), 77 deletions(-)
delete mode 100644 llvm/test/Transforms/InstCombine/non-tls-does-not-alias-errno.ll
diff --git a/llvm/include/llvm/Analysis/TargetLibraryInfo.h b/llvm/include/llvm/Analysis/TargetLibraryInfo.h
index b9ccda022bf2f..f74a161696c38 100644
--- a/llvm/include/llvm/Analysis/TargetLibraryInfo.h
+++ b/llvm/include/llvm/Analysis/TargetLibraryInfo.h
@@ -90,7 +90,6 @@ class TargetLibraryInfoImpl {
bool ShouldExtI32Param, ShouldExtI32Return, ShouldSignExtI32Param, ShouldSignExtI32Return;
unsigned SizeOfInt;
bool IsErrnoFunctionCall;
- bool IsErrnoThreadLocal;
enum AvailabilityState {
StandardName = 3, // (memset to all ones)
@@ -259,7 +258,7 @@ class TargetLibraryInfoImpl {
LLVM_ABI static bool isCallingConvCCompatible(CallBase *CI);
LLVM_ABI static bool isCallingConvCCompatible(Function *Callee);
- LLVM_ABI bool mayBeErrnoGlobal(const GlobalVariable *GV) const;
+ bool isErrnoFunctionCall() const { return IsErrnoFunctionCall; }
};
/// Provides information about what library functions are available for
@@ -606,11 +605,9 @@ class TargetLibraryInfo {
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 `errno` is defined as a function call on known OSes /
+ /// environments.
+ bool isErrnoFunctionCall() const { return Impl->isErrnoFunctionCall(); }
};
/// Analysis pass providing the \c TargetLibraryInfo.
diff --git a/llvm/lib/Analysis/BasicAliasAnalysis.cpp b/llvm/lib/Analysis/BasicAliasAnalysis.cpp
index 381bb285f1f79..b4d16a876dfd1 100644
--- a/llvm/lib/Analysis/BasicAliasAnalysis.cpp
+++ b/llvm/lib/Analysis/BasicAliasAnalysis.cpp
@@ -1879,9 +1879,9 @@ AliasResult BasicAAResult::aliasErrno(const MemoryLocation &Loc,
if (GV->hasLocalLinkage())
return AliasResult::NoAlias;
- // 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))
+ // Neither can errno alias globals where environments define it as a
+ // function call.
+ if (TLI.isErrnoFunctionCall())
return AliasResult::NoAlias;
}
diff --git a/llvm/lib/Analysis/TargetLibraryInfo.cpp b/llvm/lib/Analysis/TargetLibraryInfo.cpp
index be000f6f9c845..23044defc8c59 100644
--- a/llvm/lib/Analysis/TargetLibraryInfo.cpp
+++ b/llvm/lib/Analysis/TargetLibraryInfo.cpp
@@ -905,26 +905,28 @@ 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();
-}
-
static bool initializeIsErrnoFunctionCall(const Triple &T) {
+ // Cannot do any assumptions on errno as far as freestanding / baremetal
+ // environments are concerned.
+ bool IsDarwinOS = T.isOSDarwin();
+ if (T.getOSName() == "none" || T.getEnvironmentName() == "none" ||
+ (!IsDarwinOS && T.getEnvironment() == Triple::UnknownEnvironment))
+ return false;
+
// 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;
+ // OSes / environments.
+ // TODO: Could refine them.
+ bool IsKnownOS = IsDarwinOS || T.isOSFreeBSD();
+ bool IsKnownEnvironment = T.isAndroid() || T.isGNUEnvironment() ||
+ T.isMusl() || T.getEnvironment() == Triple::LLVM ||
+ T.getEnvironment() == Triple::Mlibc ||
+ T.getEnvironment() == Triple::MSVC;
+ return IsKnownOS || IsKnownEnvironment;
}
TargetLibraryInfoImpl::TargetLibraryInfoImpl(const Triple &T,
VectorLibrary VecLib)
- : IsErrnoFunctionCall(initializeIsErrnoFunctionCall(T)),
- IsErrnoThreadLocal(initializeIsErrnoThreadLocal(T)) {
+ : IsErrnoFunctionCall(initializeIsErrnoFunctionCall(T)) {
// Default to everything being available.
memset(AvailableArray, -1, sizeof(AvailableArray));
@@ -936,8 +938,7 @@ TargetLibraryInfoImpl::TargetLibraryInfoImpl(const TargetLibraryInfoImpl &TLI)
ShouldExtI32Return(TLI.ShouldExtI32Return),
ShouldSignExtI32Param(TLI.ShouldSignExtI32Param),
ShouldSignExtI32Return(TLI.ShouldSignExtI32Return),
- SizeOfInt(TLI.SizeOfInt), IsErrnoFunctionCall(TLI.IsErrnoFunctionCall),
- IsErrnoThreadLocal(TLI.IsErrnoThreadLocal) {
+ SizeOfInt(TLI.SizeOfInt), IsErrnoFunctionCall(TLI.IsErrnoFunctionCall) {
memcpy(AvailableArray, TLI.AvailableArray, sizeof(AvailableArray));
VectorDescs = TLI.VectorDescs;
ScalarDescs = TLI.ScalarDescs;
@@ -949,8 +950,7 @@ TargetLibraryInfoImpl::TargetLibraryInfoImpl(TargetLibraryInfoImpl &&TLI)
ShouldExtI32Return(TLI.ShouldExtI32Return),
ShouldSignExtI32Param(TLI.ShouldSignExtI32Param),
ShouldSignExtI32Return(TLI.ShouldSignExtI32Return),
- SizeOfInt(TLI.SizeOfInt), IsErrnoFunctionCall(TLI.IsErrnoFunctionCall),
- IsErrnoThreadLocal(TLI.IsErrnoThreadLocal) {
+ SizeOfInt(TLI.SizeOfInt), IsErrnoFunctionCall(TLI.IsErrnoFunctionCall) {
std::move(std::begin(TLI.AvailableArray), std::end(TLI.AvailableArray),
AvailableArray);
VectorDescs = TLI.VectorDescs;
@@ -965,7 +965,6 @@ TargetLibraryInfoImpl &TargetLibraryInfoImpl::operator=(const TargetLibraryInfoI
ShouldSignExtI32Return = TLI.ShouldSignExtI32Return;
SizeOfInt = TLI.SizeOfInt;
IsErrnoFunctionCall = TLI.IsErrnoFunctionCall;
- IsErrnoThreadLocal = TLI.IsErrnoThreadLocal;
memcpy(AvailableArray, TLI.AvailableArray, sizeof(AvailableArray));
return *this;
}
@@ -978,7 +977,6 @@ TargetLibraryInfoImpl &TargetLibraryInfoImpl::operator=(TargetLibraryInfoImpl &&
ShouldSignExtI32Return = TLI.ShouldSignExtI32Return;
SizeOfInt = TLI.SizeOfInt;
IsErrnoFunctionCall = TLI.IsErrnoFunctionCall;
- IsErrnoThreadLocal = TLI.IsErrnoThreadLocal;
std::move(std::begin(TLI.AvailableArray), std::end(TLI.AvailableArray),
AvailableArray);
return *this;
@@ -1492,15 +1490,6 @@ unsigned TargetLibraryInfoImpl::getSizeTSize(const Module &M) const {
return M.getDataLayout().getIndexSizeInBits(/*AddressSpace=*/0);
}
-bool TargetLibraryInfoImpl::mayBeErrnoGlobal(const GlobalVariable *GV) const {
- assert(GV && "Expecting existing GlobalVariable.");
- if (IsErrnoFunctionCall)
- return false;
- if (!GV->isThreadLocal() && IsErrnoThreadLocal)
- return false;
- return true;
-}
-
TargetLibraryInfoWrapperPass::TargetLibraryInfoWrapperPass()
: ImmutablePass(ID), TLA(TargetLibraryInfoImpl(Triple())) {}
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
deleted file mode 100644
index 95178a9785af1..0000000000000
--- a/llvm/test/Transforms/InstCombine/non-tls-does-not-alias-errno.ll
+++ /dev/null
@@ -1,23 +0,0 @@
-; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 6
-; RUN: opt -S -mtriple=arm64-apple-macos -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: ret i32 42
-;
-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)
diff --git a/llvm/unittests/Analysis/TargetLibraryInfoTest.cpp b/llvm/unittests/Analysis/TargetLibraryInfoTest.cpp
index 796187b6f3c4f..144b327a50ad0 100644
--- a/llvm/unittests/Analysis/TargetLibraryInfoTest.cpp
+++ b/llvm/unittests/Analysis/TargetLibraryInfoTest.cpp
@@ -705,24 +705,21 @@ TEST_F(TargetLibraryInfoTest, ValidProto) {
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));
+ // Errno is defined as a function call on the following OSes / environments.
+ EXPECT_TRUE(TLII(Triple("arm64-apple-macosx")).isErrnoFunctionCall());
+ EXPECT_TRUE(TLII(Triple("arm--linux-androideabi")).isErrnoFunctionCall());
+ EXPECT_TRUE(
+ TLII(Triple("armv7-unknown-freebsd-gnueabihf")).isErrnoFunctionCall());
+ EXPECT_TRUE(TLII(Triple("riscv32-unknown-linux-musl")).isErrnoFunctionCall());
+ EXPECT_TRUE(TLII(Triple("x86_64-pc-windows-msvc")).isErrnoFunctionCall());
+ EXPECT_TRUE(TLII(Triple("x86_64-unknown-linux-gnu")).isErrnoFunctionCall());
// 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));
+ EXPECT_FALSE(TLII(Triple("aarch64-unknown-unknown")).isErrnoFunctionCall());
+ EXPECT_FALSE(TLII(Triple("arm-none-eabi")).isErrnoFunctionCall());
+ EXPECT_FALSE(TLII(Triple("powerpc-none-none")).isErrnoFunctionCall());
+ EXPECT_FALSE(TLII(Triple("x86_64-pc-linux")).isErrnoFunctionCall());
}
namespace {
More information about the llvm-commits
mailing list