Skip to content

Commit f9f62ef

Browse files
[AA] Refine ModRefInfo taking into account errnomem location
Ensure alias analyses mask out `errnomem` location, refining the resulting modref info, when the given access/location does not alias errno. This may occur either when TBAA proves there is no alias with errno (e.g., float TBAA for the same root would be disjoint with the int-only compatible TBAA node for errno); or if the memory access size is larger than the integer size, or when the underlying object is a potentially-escaping alloca. Previous discussion: https://discourse.llvm.org/t/rfc-modelling-errno-memory-effects/82972.
1 parent 341cdbc commit f9f62ef

File tree

7 files changed

+206
-1
lines changed

7 files changed

+206
-1
lines changed

llvm/include/llvm/Analysis/AliasAnalysis.h

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -585,6 +585,7 @@ class AAResults {
585585
LLVM_ABI AliasResult alias(const MemoryLocation &LocA,
586586
const MemoryLocation &LocB, AAQueryInfo &AAQI,
587587
const Instruction *CtxI = nullptr);
588+
LLVM_ABI AliasResult aliasErrno(const MemoryLocation &Loc, const Module *M);
588589

589590
LLVM_ABI ModRefInfo getModRefInfoMask(const MemoryLocation &Loc,
590591
AAQueryInfo &AAQI,
@@ -744,6 +745,11 @@ class LLVM_ABI AAResults::Concept {
744745
const MemoryLocation &LocB, AAQueryInfo &AAQI,
745746
const Instruction *CtxI) = 0;
746747

748+
/// Returns an AliasResult indicating whether a specific memory location
749+
/// aliases errno.
750+
virtual AliasResult aliasErrno(const MemoryLocation &Loc,
751+
const Module *M) = 0;
752+
747753
/// @}
748754
//===--------------------------------------------------------------------===//
749755
/// \name Simple mod/ref information
@@ -805,6 +811,10 @@ template <typename AAResultT> class AAResults::Model final : public Concept {
805811
return Result.alias(LocA, LocB, AAQI, CtxI);
806812
}
807813

814+
AliasResult aliasErrno(const MemoryLocation &Loc, const Module *M) override {
815+
return Result.aliasErrno(Loc, M);
816+
}
817+
808818
ModRefInfo getModRefInfoMask(const MemoryLocation &Loc, AAQueryInfo &AAQI,
809819
bool IgnoreLocals) override {
810820
return Result.getModRefInfoMask(Loc, AAQI, IgnoreLocals);
@@ -860,6 +870,10 @@ class AAResultBase {
860870
return AliasResult::MayAlias;
861871
}
862872

873+
AliasResult aliasErrno(const MemoryLocation &Loc, const Module *M) {
874+
return AliasResult::MayAlias;
875+
}
876+
863877
ModRefInfo getModRefInfoMask(const MemoryLocation &Loc, AAQueryInfo &AAQI,
864878
bool IgnoreLocals) {
865879
return ModRefInfo::ModRef;

llvm/include/llvm/Analysis/BasicAliasAnalysis.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,8 @@ class BasicAAResult : public AAResultBase {
7373
const MemoryLocation &LocB, AAQueryInfo &AAQI,
7474
const Instruction *CtxI);
7575

76+
LLVM_ABI AliasResult aliasErrno(const MemoryLocation &Loc, const Module *M);
77+
7678
LLVM_ABI ModRefInfo getModRefInfo(const CallBase *Call,
7779
const MemoryLocation &Loc,
7880
AAQueryInfo &AAQI);

llvm/include/llvm/Analysis/TypeBasedAliasAnalysis.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ class TypeBasedAAResult : public AAResultBase {
5050
LLVM_ABI AliasResult alias(const MemoryLocation &LocA,
5151
const MemoryLocation &LocB, AAQueryInfo &AAQI,
5252
const Instruction *CtxI);
53+
LLVM_ABI AliasResult aliasErrno(const MemoryLocation &Loc, const Module *M);
5354
LLVM_ABI ModRefInfo getModRefInfoMask(const MemoryLocation &Loc,
5455
AAQueryInfo &AAQI, bool IgnoreLocals);
5556

llvm/lib/Analysis/AliasAnalysis.cpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,18 @@ AliasResult AAResults::alias(const MemoryLocation &LocA,
148148
return Result;
149149
}
150150

151+
AliasResult AAResults::aliasErrno(const MemoryLocation &Loc, const Module *M) {
152+
AliasResult Result = AliasResult::MayAlias;
153+
154+
for (const auto &AA : AAs) {
155+
Result = AA->aliasErrno(Loc, M);
156+
if (Result != AliasResult::MayAlias)
157+
break;
158+
}
159+
160+
return Result;
161+
}
162+
151163
ModRefInfo AAResults::getModRefInfoMask(const MemoryLocation &Loc,
152164
bool IgnoreLocals) {
153165
SimpleAAQueryInfo AAQIP(*this);

llvm/lib/Analysis/BasicAliasAnalysis.cpp

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -951,7 +951,8 @@ ModRefInfo BasicAAResult::getModRefInfo(const CallBase *Call,
951951
return ModRefInfo::NoModRef;
952952

953953
ModRefInfo ArgMR = ME.getModRef(IRMemLocation::ArgMem);
954-
ModRefInfo OtherMR = ME.getWithoutLoc(IRMemLocation::ArgMem).getModRef();
954+
ModRefInfo ErrnoMR = ME.getModRef(IRMemLocation::ErrnoMem);
955+
ModRefInfo OtherMR = ME.getModRef(IRMemLocation::Other);
955956

956957
// An identified function-local object that does not escape can only be
957958
// accessed via call arguments. Reduce OtherMR (which includes accesses to
@@ -997,6 +998,15 @@ ModRefInfo BasicAAResult::getModRefInfo(const CallBase *Call,
997998
}
998999

9991000
ModRefInfo Result = ArgMR | OtherMR;
1001+
1002+
// Refine accesses to errno memory.
1003+
if ((ErrnoMR | Result) != Result) {
1004+
if (AAQI.AAR.aliasErrno(Loc, Call->getModule()) != AliasResult::NoAlias) {
1005+
// Exclusion conditions do not hold, this memory location may alias errno.
1006+
Result |= ErrnoMR;
1007+
}
1008+
}
1009+
10001010
if (!isModAndRefSet(Result))
10011011
return Result;
10021012

@@ -1851,6 +1861,19 @@ AliasResult BasicAAResult::aliasCheckRecursive(
18511861
return AliasResult::MayAlias;
18521862
}
18531863

1864+
AliasResult BasicAAResult::aliasErrno(const MemoryLocation &Loc,
1865+
const Module *M) {
1866+
// There cannot be any alias with errno if the given memory location is an
1867+
// identified function-local object, or the size of the memory access is
1868+
// larger than the integer size.
1869+
if (Loc.Size.hasValue() && Loc.Size.getValue() * 8 > TLI.getIntSize())
1870+
return AliasResult::NoAlias;
1871+
1872+
if (isIdentifiedFunctionLocal(getUnderlyingObject(Loc.Ptr)))
1873+
return AliasResult::NoAlias;
1874+
return AliasResult::MayAlias;
1875+
}
1876+
18541877
/// Check whether two Values can be considered equivalent.
18551878
///
18561879
/// If the values may come from different cycle iterations, this will also

llvm/lib/Analysis/TypeBasedAliasAnalysis.cpp

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,7 @@
115115
#include "llvm/IR/InstrTypes.h"
116116
#include "llvm/IR/LLVMContext.h"
117117
#include "llvm/IR/Metadata.h"
118+
#include "llvm/IR/Module.h"
118119
#include "llvm/InitializePasses.h"
119120
#include "llvm/Pass.h"
120121
#include "llvm/Support/Casting.h"
@@ -385,6 +386,25 @@ AliasResult TypeBasedAAResult::alias(const MemoryLocation &LocA,
385386
return AliasResult::NoAlias;
386387
}
387388

389+
AliasResult TypeBasedAAResult::aliasErrno(const MemoryLocation &Loc,
390+
const Module *M) {
391+
if (!shouldUseTBAA())
392+
return AliasResult::MayAlias;
393+
394+
const auto *N = Loc.AATags.TBAA;
395+
if (!N)
396+
return AliasResult::MayAlias;
397+
398+
// There cannot be any alias with errno if TBAA proves the given memory
399+
// location does not alias errno.
400+
const auto *ErrnoTBAAMD = M->getNamedMetadata("llvm.errno.tbaa");
401+
if (!ErrnoTBAAMD || any_of(ErrnoTBAAMD->operands(), [&](const auto *Node) {
402+
return Aliases(N, Node);
403+
}))
404+
return AliasResult::MayAlias;
405+
return AliasResult::NoAlias;
406+
}
407+
388408
ModRefInfo TypeBasedAAResult::getModRefInfoMask(const MemoryLocation &Loc,
389409
AAQueryInfo &AAQI,
390410
bool IgnoreLocals) {
Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,133 @@
1+
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 5
2+
; RUN: opt -S -passes=instcombine < %s | FileCheck %s
3+
4+
; sinf clobbering errno, but %p cannot alias errno per C/C++ strict aliasing rules via TBAA.
5+
; Can do constant store-to-load forwarding.
6+
define float @does_not_alias_errno(ptr %p, float %f) {
7+
; CHECK-LABEL: define float @does_not_alias_errno(
8+
; CHECK-SAME: ptr [[P:%.*]], float [[F:%.*]]) {
9+
; CHECK-NEXT: [[ENTRY:.*:]]
10+
; CHECK-NEXT: store float 0.000000e+00, ptr [[P]], align 4, !tbaa [[TBAA4:![0-9]+]]
11+
; CHECK-NEXT: [[CALL:%.*]] = call float @sinf(float [[F]])
12+
; CHECK-NEXT: ret float 0.000000e+00
13+
;
14+
entry:
15+
store float 0.000000e+00, ptr %p, align 4, !tbaa !4
16+
%call = call float @sinf(float %f)
17+
%0 = load float, ptr %p, align 4, !tbaa !4
18+
ret float %0
19+
}
20+
21+
; sinf clobbering errno, but %p is alloca memory, wich can never aliases errno.
22+
; Can do constant store-to-load forwarding.
23+
define float @does_not_alias_errno_2(float %f) {
24+
; CHECK-LABEL: define float @does_not_alias_errno_2(
25+
; CHECK-SAME: float [[F:%.*]]) {
26+
; CHECK-NEXT: [[ENTRY:.*:]]
27+
; CHECK-NEXT: [[P:%.*]] = alloca float, align 4
28+
; CHECK-NEXT: call void @escape(ptr nonnull [[P]])
29+
; CHECK-NEXT: store float 0.000000e+00, ptr [[P]], align 4
30+
; CHECK-NEXT: [[TMP1:%.*]] = call float @sinf(float [[F]])
31+
; CHECK-NEXT: ret float 0.000000e+00
32+
;
33+
entry:
34+
%p = alloca float
35+
call void @escape(ptr %p)
36+
store float 0.0, ptr %p
37+
call float @sinf(float %f)
38+
%v = load float, ptr %p
39+
ret float %v
40+
}
41+
42+
; sinf clobbering errno, but %p is memory accessed w/ size larger than errno.
43+
; Can do constant store-to-load forwarding.
44+
define double @does_not_alias_errno_3(ptr %p, float %f) {
45+
; CHECK-LABEL: define double @does_not_alias_errno_3(
46+
; CHECK-SAME: ptr [[P:%.*]], float [[F:%.*]]) {
47+
; CHECK-NEXT: [[ENTRY:.*:]]
48+
; CHECK-NEXT: call void @escape(ptr [[P]])
49+
; CHECK-NEXT: store double 0.000000e+00, ptr [[P]], align 8
50+
; CHECK-NEXT: [[TMP1:%.*]] = call float @sinf(float [[F]])
51+
; CHECK-NEXT: ret double 0.000000e+00
52+
;
53+
entry:
54+
call void @escape(ptr %p)
55+
store double 0.0, ptr %p
56+
call float @sinf(float %f)
57+
%v = load double, ptr %p
58+
ret double %v
59+
}
60+
61+
; %p may alias errno, but read_errno does not clobber errno.
62+
; Can do constant store-to-load forwarding.
63+
define float @may_alias_errno_does_not_clobber(ptr %p, ptr byval(i8) %q) {
64+
; CHECK-LABEL: define float @may_alias_errno_does_not_clobber(
65+
; CHECK-SAME: ptr [[P:%.*]], ptr byval(i8) [[Q:%.*]]) {
66+
; CHECK-NEXT: [[ENTRY:.*:]]
67+
; CHECK-NEXT: store float 0.000000e+00, ptr [[P]], align 4
68+
; CHECK-NEXT: [[CALL:%.*]] = call float @read_errno(ptr nonnull [[Q]])
69+
; CHECK-NEXT: ret float 0.000000e+00
70+
;
71+
entry:
72+
store float 0.000000e+00, ptr %p, align 4
73+
%call = call float @read_errno(ptr %q)
74+
%0 = load float, ptr %p, align 4
75+
ret float %0
76+
}
77+
78+
; sinf clobbering errno, unknown TBAA info, %p may alias errno.
79+
; Cannot do constant store-to-load forwarding.
80+
define float @may_alias_errno(ptr %p, float %f) {
81+
; CHECK-LABEL: define float @may_alias_errno(
82+
; CHECK-SAME: ptr [[P:%.*]], float [[F:%.*]]) {
83+
; CHECK-NEXT: [[ENTRY:.*:]]
84+
; CHECK-NEXT: store float 0.000000e+00, ptr [[P]], align 4
85+
; CHECK-NEXT: [[CALL:%.*]] = call float @sinf(float [[F]])
86+
; CHECK-NEXT: [[TMP0:%.*]] = load float, ptr [[P]], align 4
87+
; CHECK-NEXT: ret float [[TMP0]]
88+
;
89+
entry:
90+
store float 0.000000e+00, ptr %p, align 4
91+
%call = call float @sinf(float %f)
92+
%0 = load float, ptr %p, align 4
93+
ret float %0
94+
}
95+
96+
; sinf clobbering errno, %p, a integer pointer, may alias errno.
97+
; Cannot do constant store-to-load forwarding.
98+
define i32 @may_alias_errno_2(ptr %p, float %f) {
99+
; CHECK-LABEL: define i32 @may_alias_errno_2(
100+
; CHECK-SAME: ptr [[P:%.*]], float [[F:%.*]]) {
101+
; CHECK-NEXT: [[ENTRY:.*:]]
102+
; CHECK-NEXT: store i32 0, ptr [[P]], align 4, !tbaa [[TBAA0:![0-9]+]]
103+
; CHECK-NEXT: [[CALL:%.*]] = call float @sinf(float [[F]])
104+
; CHECK-NEXT: [[TMP0:%.*]] = load i32, ptr [[P]], align 4, !tbaa [[TBAA0]]
105+
; CHECK-NEXT: ret i32 [[TMP0]]
106+
;
107+
entry:
108+
store i32 0, ptr %p, align 4, !tbaa !0
109+
%call = call float @sinf(float %f)
110+
%0 = load i32, ptr %p, align 4, !tbaa !0
111+
ret i32 %0
112+
}
113+
114+
declare float @sinf(float) memory(errnomem: write)
115+
declare float @read_errno(ptr) memory(argmem: write, errnomem: read)
116+
declare void @escape(ptr %p)
117+
118+
!llvm.errno.tbaa = !{!0}
119+
120+
!0 = !{!1, !1, i64 0}
121+
!1 = !{!"int", !2, i64 0}
122+
!2 = !{!"omnipotent char", !3, i64 0}
123+
!3 = !{!"Simple C/C++ TBAA"}
124+
!4 = !{!5, !5, i64 0}
125+
!5 = !{!"float", !2, i64 0}
126+
;.
127+
; CHECK: [[TBAA0]] = !{[[META1:![0-9]+]], [[META1]], i64 0}
128+
; CHECK: [[META1]] = !{!"int", [[META2:![0-9]+]], i64 0}
129+
; CHECK: [[META2]] = !{!"omnipotent char", [[META3:![0-9]+]], i64 0}
130+
; CHECK: [[META3]] = !{!"Simple C/C++ TBAA"}
131+
; CHECK: [[TBAA4]] = !{[[META5:![0-9]+]], [[META5]], i64 0}
132+
; CHECK: [[META5]] = !{!"float", [[META2]], i64 0}
133+
;.

0 commit comments

Comments
 (0)