[llvm] eae5a88 - [BasicAA][TLI] Treat local-linkage globals or known environments as not aliasing errno (#170290)

via llvm-commits llvm-commits at lists.llvm.org
Mon Aug 24 00:16:59 PDT 2026


Author: Antonio Frighetto
Date: 2026-08-24T09:16:54+02:00
New Revision: eae5a883a339e67804dd663ae8867113969e9cbf

URL: https://github.com/llvm/llvm-project/commit/eae5a883a339e67804dd663ae8867113969e9cbf
DIFF: https://github.com/llvm/llvm-project/commit/eae5a883a339e67804dd663ae8867113969e9cbf.diff

LOG: [BasicAA][TLI] Treat local-linkage globals or known environments as not aliasing errno (#170290)

Errno cannot alias global variables with internal/private-linkage,
neither can it aliases globals on known environments, where errno is
known to be defined as a function call – unless targeting
freestanding/baremetal environments.

Added: 
    

Modified: 
    llvm/include/llvm/Analysis/AliasAnalysis.h
    llvm/include/llvm/Analysis/BasicAliasAnalysis.h
    llvm/include/llvm/Analysis/TargetLibraryInfo.h
    llvm/include/llvm/Analysis/TypeBasedAliasAnalysis.h
    llvm/lib/Analysis/AliasAnalysis.cpp
    llvm/lib/Analysis/BasicAliasAnalysis.cpp
    llvm/lib/Analysis/TargetLibraryInfo.cpp
    llvm/lib/Analysis/TypeBasedAliasAnalysis.cpp
    llvm/test/Transforms/InstCombine/may-alias-errno.ll
    llvm/unittests/Analysis/TargetLibraryInfoTest.cpp

Removed: 
    


################################################################################
diff  --git a/llvm/include/llvm/Analysis/AliasAnalysis.h b/llvm/include/llvm/Analysis/AliasAnalysis.h
index 20e1cb72be234..041ca0bd4327b 100644
--- a/llvm/include/llvm/Analysis/AliasAnalysis.h
+++ b/llvm/include/llvm/Analysis/AliasAnalysis.h
@@ -582,7 +582,8 @@ class AAResults {
   LLVM_ABI AliasResult alias(const MemoryLocation &LocA,
                              const MemoryLocation &LocB, AAQueryInfo &AAQI,
                              const Instruction *CtxI = nullptr);
-  LLVM_ABI AliasResult aliasErrno(const MemoryLocation &Loc, const Module *M);
+  LLVM_ABI AliasResult aliasErrno(const MemoryLocation &Loc,
+                                  const Instruction *CtxI);
 
   LLVM_ABI ModRefInfo getModRefInfoMask(const MemoryLocation &Loc,
                                         AAQueryInfo &AAQI,
@@ -765,7 +766,7 @@ class LLVM_ABI AAResults::Concept {
   /// Returns an AliasResult indicating whether a specific memory location
   /// aliases errno.
   virtual AliasResult aliasErrno(const MemoryLocation &Loc,
-                                 const Module *M) = 0;
+                                 const Instruction *CtxI) = 0;
 
   /// @}
   //===--------------------------------------------------------------------===//
@@ -834,8 +835,9 @@ template <typename AAResultT> class AAResults::Model final : public Concept {
     return Result.alias(LocA, LocB, AAQI, CtxI);
   }
 
-  AliasResult aliasErrno(const MemoryLocation &Loc, const Module *M) override {
-    return Result.aliasErrno(Loc, M);
+  AliasResult aliasErrno(const MemoryLocation &Loc,
+                         const Instruction *CtxI) override {
+    return Result.aliasErrno(Loc, CtxI);
   }
 
   ModRefInfo getModRefInfoMask(const MemoryLocation &Loc, AAQueryInfo &AAQI,
@@ -898,7 +900,7 @@ class AAResultBase {
     return AliasResult::MayAlias;
   }
 
-  AliasResult aliasErrno(const MemoryLocation &Loc, const Module *M) {
+  AliasResult aliasErrno(const MemoryLocation &Loc, const Instruction *CtxI) {
     return AliasResult::MayAlias;
   }
 

diff  --git a/llvm/include/llvm/Analysis/BasicAliasAnalysis.h b/llvm/include/llvm/Analysis/BasicAliasAnalysis.h
index 66e6292c7785e..e42792548e5eb 100644
--- a/llvm/include/llvm/Analysis/BasicAliasAnalysis.h
+++ b/llvm/include/llvm/Analysis/BasicAliasAnalysis.h
@@ -73,7 +73,8 @@ class BasicAAResult : public AAResultBase {
                              const MemoryLocation &LocB, AAQueryInfo &AAQI,
                              const Instruction *CtxI);
 
-  LLVM_ABI AliasResult aliasErrno(const MemoryLocation &Loc, const Module *M);
+  LLVM_ABI AliasResult aliasErrno(const MemoryLocation &Loc,
+                                  const Instruction *CtxI);
 
   using AAResultBase::getModRefInfo;
   LLVM_ABI ModRefInfo getModRefInfo(const CallBase *Call,

diff  --git a/llvm/include/llvm/Analysis/TargetLibraryInfo.h b/llvm/include/llvm/Analysis/TargetLibraryInfo.h
index 483d0364cbf97..0a736feb2530a 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;
 
   enum AvailabilityState {
     StandardName = 3, // (memset to all ones)
@@ -260,6 +261,8 @@ class TargetLibraryInfoImpl {
   /// conventions.
   LLVM_ABI static bool isCallingConvCCompatible(CallBase *CI);
   LLVM_ABI static bool isCallingConvCCompatible(Function *Callee);
+
+  bool isErrnoFunctionCall() const { return IsErrnoFunctionCall; }
 };
 
 /// Provides information about what library functions are available for
@@ -599,6 +602,10 @@ class TargetLibraryInfo {
   bool isKnownVectorFunctionInLibrary(StringRef F) const {
     return this->isFunctionVectorizable(F);
   }
+
+  /// Returns whether `errno` is defined as a function call on known
+  /// environments.
+  bool isErrnoFunctionCall() const { return Impl->isErrnoFunctionCall(); }
 };
 
 /// Analysis pass providing the \c TargetLibraryInfo.

diff  --git a/llvm/include/llvm/Analysis/TypeBasedAliasAnalysis.h b/llvm/include/llvm/Analysis/TypeBasedAliasAnalysis.h
index 515aabd5cceab..d2f9b7b035b4e 100644
--- a/llvm/include/llvm/Analysis/TypeBasedAliasAnalysis.h
+++ b/llvm/include/llvm/Analysis/TypeBasedAliasAnalysis.h
@@ -50,7 +50,8 @@ class TypeBasedAAResult : public AAResultBase {
   LLVM_ABI AliasResult alias(const MemoryLocation &LocA,
                              const MemoryLocation &LocB, AAQueryInfo &AAQI,
                              const Instruction *CtxI);
-  LLVM_ABI AliasResult aliasErrno(const MemoryLocation &Loc, const Module *M);
+  LLVM_ABI AliasResult aliasErrno(const MemoryLocation &Loc,
+                                  const Instruction *CtxI);
   LLVM_ABI ModRefInfo getModRefInfoMask(const MemoryLocation &Loc,
                                         AAQueryInfo &AAQI, bool IgnoreLocals);
 

diff  --git a/llvm/lib/Analysis/AliasAnalysis.cpp b/llvm/lib/Analysis/AliasAnalysis.cpp
index cb4061d079aa7..f2b73c974a35c 100644
--- a/llvm/lib/Analysis/AliasAnalysis.cpp
+++ b/llvm/lib/Analysis/AliasAnalysis.cpp
@@ -148,11 +148,12 @@ AliasResult AAResults::alias(const MemoryLocation &LocA,
   return Result;
 }
 
-AliasResult AAResults::aliasErrno(const MemoryLocation &Loc, const Module *M) {
+AliasResult AAResults::aliasErrno(const MemoryLocation &Loc,
+                                  const Instruction *CtxI) {
   AliasResult Result = AliasResult::MayAlias;
 
   for (const auto &AA : AAs) {
-    Result = AA->aliasErrno(Loc, M);
+    Result = AA->aliasErrno(Loc, CtxI);
     if (Result != AliasResult::MayAlias)
       break;
   }

diff  --git a/llvm/lib/Analysis/BasicAliasAnalysis.cpp b/llvm/lib/Analysis/BasicAliasAnalysis.cpp
index 7df62577e04db..480d4046e04ff 100644
--- a/llvm/lib/Analysis/BasicAliasAnalysis.cpp
+++ b/llvm/lib/Analysis/BasicAliasAnalysis.cpp
@@ -1024,7 +1024,7 @@ ModRefInfo BasicAAResult::getModRefInfo(const CallBase *Call,
 
   // Refine accesses to errno memory.
   if ((ErrnoMR | Result) != Result) {
-    if (AAQI.AAR.aliasErrno(Loc, Call->getModule()) != AliasResult::NoAlias) {
+    if (AAQI.AAR.aliasErrno(Loc, Call) != AliasResult::NoAlias) {
       // Exclusion conditions do not hold, this memory location may alias errno.
       Result |= ErrnoMR;
     }
@@ -1905,7 +1905,14 @@ AliasResult BasicAAResult::aliasCheckRecursive(
 }
 
 AliasResult BasicAAResult::aliasErrno(const MemoryLocation &Loc,
-                                      const Module *M) {
+                                      const Instruction *CtxI) {
+  // Do not make any assumptions when targeting freestanding environments (e.g.,
+  // in the context of baremetal LTO, errno may have been internalized or
+  // otherwise promoted to a local variable).
+  bool IsFreestanding = CtxI->getFunction()->hasFnAttribute("no-builtins");
+  if (IsFreestanding)
+    return AliasResult::MayAlias;
+
   // There cannot be any alias with errno if the given memory location is an
   // identified function-local object, or the size of the memory access is
   // larger than the integer size.
@@ -1913,8 +1920,21 @@ 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 errno alias globals where environments define it as a
+    // function call.
+    if (TLI.isErrnoFunctionCall())
+      return AliasResult::NoAlias;
+  }
+
   return AliasResult::MayAlias;
 }
 

diff  --git a/llvm/lib/Analysis/TargetLibraryInfo.cpp b/llvm/lib/Analysis/TargetLibraryInfo.cpp
index efde1ba49f9bc..5ff83f19b2e24 100644
--- a/llvm/lib/Analysis/TargetLibraryInfo.cpp
+++ b/llvm/lib/Analysis/TargetLibraryInfo.cpp
@@ -896,8 +896,19 @@ static void initialize(TargetLibraryInfoImpl &TLI, const Triple &T,
   initializeLibCalls(TLI, T, StandardNames, VecLib);
 }
 
+static bool initializeIsErrnoFunctionCall(const Triple &T) {
+  // Assume errno is implemented as a function call on the following
+  // known environments.
+  // TODO: Could refine them.
+  return T.isOSDarwin() || 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) {
+                                             VectorLibrary VecLib)
+    : IsErrnoFunctionCall(initializeIsErrnoFunctionCall(T)) {
   // Default to everything being available.
   memset(AvailableArray, -1, sizeof(AvailableArray));
 
@@ -909,7 +920,7 @@ TargetLibraryInfoImpl::TargetLibraryInfoImpl(const TargetLibraryInfoImpl &TLI)
       ShouldExtI32Return(TLI.ShouldExtI32Return),
       ShouldSignExtI32Param(TLI.ShouldSignExtI32Param),
       ShouldSignExtI32Return(TLI.ShouldSignExtI32Return),
-      SizeOfInt(TLI.SizeOfInt) {
+      SizeOfInt(TLI.SizeOfInt), IsErrnoFunctionCall(TLI.IsErrnoFunctionCall) {
   memcpy(AvailableArray, TLI.AvailableArray, sizeof(AvailableArray));
   VectorDescs = TLI.VectorDescs;
   ScalarDescs = TLI.ScalarDescs;
@@ -921,7 +932,7 @@ TargetLibraryInfoImpl::TargetLibraryInfoImpl(TargetLibraryInfoImpl &&TLI)
       ShouldExtI32Return(TLI.ShouldExtI32Return),
       ShouldSignExtI32Param(TLI.ShouldSignExtI32Param),
       ShouldSignExtI32Return(TLI.ShouldSignExtI32Return),
-      SizeOfInt(TLI.SizeOfInt) {
+      SizeOfInt(TLI.SizeOfInt), IsErrnoFunctionCall(TLI.IsErrnoFunctionCall) {
   std::move(std::begin(TLI.AvailableArray), std::end(TLI.AvailableArray),
             AvailableArray);
   VectorDescs = TLI.VectorDescs;
@@ -935,6 +946,7 @@ TargetLibraryInfoImpl &TargetLibraryInfoImpl::operator=(const TargetLibraryInfoI
   ShouldSignExtI32Param = TLI.ShouldSignExtI32Param;
   ShouldSignExtI32Return = TLI.ShouldSignExtI32Return;
   SizeOfInt = TLI.SizeOfInt;
+  IsErrnoFunctionCall = TLI.IsErrnoFunctionCall;
   memcpy(AvailableArray, TLI.AvailableArray, sizeof(AvailableArray));
   return *this;
 }
@@ -946,6 +958,7 @@ TargetLibraryInfoImpl &TargetLibraryInfoImpl::operator=(TargetLibraryInfoImpl &&
   ShouldSignExtI32Param = TLI.ShouldSignExtI32Param;
   ShouldSignExtI32Return = TLI.ShouldSignExtI32Return;
   SizeOfInt = TLI.SizeOfInt;
+  IsErrnoFunctionCall = TLI.IsErrnoFunctionCall;
   std::move(std::begin(TLI.AvailableArray), std::end(TLI.AvailableArray),
             AvailableArray);
   return *this;

diff  --git a/llvm/lib/Analysis/TypeBasedAliasAnalysis.cpp b/llvm/lib/Analysis/TypeBasedAliasAnalysis.cpp
index 7aae654feecea..dbe4ccac7801d 100644
--- a/llvm/lib/Analysis/TypeBasedAliasAnalysis.cpp
+++ b/llvm/lib/Analysis/TypeBasedAliasAnalysis.cpp
@@ -372,7 +372,7 @@ AliasResult TypeBasedAAResult::alias(const MemoryLocation &LocA,
 }
 
 AliasResult TypeBasedAAResult::aliasErrno(const MemoryLocation &Loc,
-                                          const Module *M) {
+                                          const Instruction *CtxI) {
   if (!shouldUseTBAA())
     return AliasResult::MayAlias;
 
@@ -382,7 +382,8 @@ AliasResult TypeBasedAAResult::aliasErrno(const MemoryLocation &Loc,
 
   // There cannot be any alias with errno if TBAA proves the given memory
   // location does not alias errno.
-  const auto *ErrnoTBAAMD = M->getNamedMetadata("llvm.errno.tbaa");
+  const auto *ErrnoTBAAMD =
+      CtxI->getModule()->getNamedMetadata("llvm.errno.tbaa");
   if (!ErrnoTBAAMD || any_of(ErrnoTBAAMD->operands(), [&](const auto *Node) {
         return Aliases(N, Node);
       }))

diff  --git a/llvm/test/Transforms/InstCombine/may-alias-errno.ll b/llvm/test/Transforms/InstCombine/may-alias-errno.ll
index 804c396818b14..803f11d35ad4e 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.
@@ -164,6 +164,61 @@ 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:    ret i32 42
+;
+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 in GNU environment,
+; can do constant store-to-load forwarding.
+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
+; CHECK-NEXT:    [[CALL:%.*]] = call float @sinf(float [[F]])
+; CHECK-NEXT:    ret i32 42
+;
+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
+}
+
+; Do not make any assumptions when may be targeting freestanding
+; environments (which implies nobuiltin).
+define i32 @may_alias_errno_nobuiltin(float %f) "no-builtins" {
+; CHECK-LABEL: define i32 @may_alias_errno_nobuiltin(
+; CHECK-SAME: float [[F:%.*]]) #[[ATTR0:[0-9]+]] {
+; 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
+}
+
 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/unittests/Analysis/TargetLibraryInfoTest.cpp b/llvm/unittests/Analysis/TargetLibraryInfoTest.cpp
index 6394c446720ca..5e8f076049817 100644
--- a/llvm/unittests/Analysis/TargetLibraryInfoTest.cpp
+++ b/llvm/unittests/Analysis/TargetLibraryInfoTest.cpp
@@ -698,6 +698,25 @@ TEST_F(TargetLibraryInfoTest, ValidProto) {
   }
 }
 
+TEST_F(TargetLibraryInfoTest, IsErrnoGlobal) {
+  using TLII = TargetLibraryInfoImpl;
+
+  // Errno is defined as a function call on the following 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_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 {
 
 /// Creates TLI for AArch64 and uses it to get the LibFunc names for the given


        


More information about the llvm-commits mailing list