[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