[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