Skip to content
12 changes: 7 additions & 5 deletions llvm/include/llvm/Analysis/AliasAnalysis.h
Original file line number Diff line number Diff line change
Expand Up @@ -585,7 +585,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 CallBase *Call);

LLVM_ABI ModRefInfo getModRefInfoMask(const MemoryLocation &Loc,
AAQueryInfo &AAQI,
Expand Down Expand Up @@ -748,7 +749,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 CallBase *Call) = 0;

/// @}
//===--------------------------------------------------------------------===//
Expand Down Expand Up @@ -811,8 +812,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 CallBase *Call) override {
return Result.aliasErrno(Loc, Call);
}

ModRefInfo getModRefInfoMask(const MemoryLocation &Loc, AAQueryInfo &AAQI,
Expand Down Expand Up @@ -870,7 +872,7 @@ class AAResultBase {
return AliasResult::MayAlias;
}

AliasResult aliasErrno(const MemoryLocation &Loc, const Module *M) {
AliasResult aliasErrno(const MemoryLocation &Loc, const CallBase *Call) {
return AliasResult::MayAlias;
}

Expand Down
3 changes: 2 additions & 1 deletion llvm/include/llvm/Analysis/BasicAliasAnalysis.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 CallBase *Call);

LLVM_ABI ModRefInfo getModRefInfo(const CallBase *Call,
const MemoryLocation &Loc,
Expand Down
7 changes: 7 additions & 0 deletions llvm/include/llvm/Analysis/TargetLibraryInfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -256,6 +257,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
Expand Down Expand Up @@ -601,6 +604,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.
Expand Down
3 changes: 2 additions & 1 deletion llvm/include/llvm/Analysis/TypeBasedAliasAnalysis.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 CallBase *Call);
LLVM_ABI ModRefInfo getModRefInfoMask(const MemoryLocation &Loc,
AAQueryInfo &AAQI, bool IgnoreLocals);

Expand Down
5 changes: 3 additions & 2 deletions llvm/lib/Analysis/AliasAnalysis.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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 CallBase *Call) {
AliasResult Result = AliasResult::MayAlias;

for (const auto &AA : AAs) {
Result = AA->aliasErrno(Loc, M);
Result = AA->aliasErrno(Loc, Call);
if (Result != AliasResult::MayAlias)
break;
}
Expand Down
21 changes: 18 additions & 3 deletions llvm/lib/Analysis/BasicAliasAnalysis.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1001,7 +1001,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;
}
Expand Down Expand Up @@ -1862,16 +1862,31 @@ AliasResult BasicAAResult::aliasCheckRecursive(
}

AliasResult BasicAAResult::aliasErrno(const MemoryLocation &Loc,
const Module *M) {
const CallBase *Call) {
// 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.
if (Loc.Size.hasValue() &&
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)) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need additional logic for GlobalAlias? Or has it been handled by other places?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't believe so - if a GlobalAlias turns out to be a GlobalVariable, getUnderlyingObject() should tell us that.

// 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, unless targeting freestanding environments, for which we
// do not make any assumptions.
bool IsFreestanding = Call->getFunction()->hasFnAttribute("no-builtins");
if (!IsFreestanding && TLI.isErrnoFunctionCall())
return AliasResult::NoAlias;
}

return AliasResult::MayAlias;
}

Expand Down
19 changes: 16 additions & 3 deletions llvm/lib/Analysis/TargetLibraryInfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -905,8 +905,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));

Expand All @@ -918,7 +929,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;
Expand All @@ -930,7 +941,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;
Expand All @@ -944,6 +955,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;
}
Expand All @@ -955,6 +967,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;
Expand Down
5 changes: 3 additions & 2 deletions llvm/lib/Analysis/TypeBasedAliasAnalysis.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -387,7 +387,7 @@ AliasResult TypeBasedAAResult::alias(const MemoryLocation &LocA,
}

AliasResult TypeBasedAAResult::aliasErrno(const MemoryLocation &Loc,
const Module *M) {
const CallBase *Call) {
if (!shouldUseTBAA())
return AliasResult::MayAlias;

Expand All @@ -397,7 +397,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 =
Call->getModule()->getNamedMetadata("llvm.errno.tbaa");
if (!ErrnoTBAAMD || any_of(ErrnoTBAAMD->operands(), [&](const auto *Node) {
return Aliases(N, Node);
}))
Expand Down
57 changes: 56 additions & 1 deletion llvm/test/Transforms/InstCombine/may-alias-errno.ll
Original file line number Diff line number Diff line change
@@ -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.
Expand Down Expand Up @@ -149,6 +149,61 @@ entry:
ret <vscale x 4 x i32> %v
}

@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
}

@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)
Expand Down
19 changes: 19 additions & 0 deletions llvm/unittests/Analysis/TargetLibraryInfoTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -703,6 +703,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
Expand Down