Skip to content

Commit 846411b

Browse files
committed
Drop nuw flag in some cases when subtracting GEPs
1 parent f2fad1b commit 846411b

File tree

3 files changed

+121
-15
lines changed

3 files changed

+121
-15
lines changed

llvm/include/llvm/Analysis/BasicAliasAnalysis.h

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -122,8 +122,7 @@ class BasicAAResult : public AAResultBase {
122122
bool isValueEqualInPotentialCycles(const Value *V1, const Value *V2,
123123
const AAQueryInfo &AAQI);
124124

125-
void subtractDecomposedGEPs(DecomposedGEP &DestGEP,
126-
const DecomposedGEP &SrcGEP,
125+
void subtractDecomposedGEPs(DecomposedGEP &DestGEP, DecomposedGEP &SrcGEP,
127126
const AAQueryInfo &AAQI);
128127

129128
AliasResult aliasGEP(const GEPOperator *V1, LocationSize V1Size,

llvm/lib/Analysis/BasicAliasAnalysis.cpp

Lines changed: 28 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -527,6 +527,8 @@ struct VariableGEPIndex {
527527
return Scale == Other.Scale;
528528
}
529529

530+
bool isSubtracted() const { return IsNegated || Scale.isNegative(); }
531+
530532
void dump() const {
531533
print(dbgs());
532534
dbgs() << "\n";
@@ -561,8 +563,8 @@ struct BasicAAResult::DecomposedGEP {
561563
dbgs() << "\n";
562564
}
563565
void print(raw_ostream &OS) const {
564-
OS << "(DecomposedGEP Base=" << Base->getName()
565-
<< ", Offset=" << Offset
566+
OS << "(DecomposedGEP Base=" << Base->getName() << ", Offset=" << Offset
567+
<< ", nuw=" << ((NWFlags && NWFlags->hasNoUnsignedWrap()) ? "1" : "0")
566568
<< ", VarIndices=[";
567569
for (size_t i = 0; i < VarIndices.size(); i++) {
568570
if (i != 0)
@@ -1238,27 +1240,26 @@ AliasResult BasicAAResult::aliasGEP(
12381240
}
12391241
}
12401242

1241-
// If the difference between pointers is Offset +<nuw> Indices (the variable
1242-
// indices all come from nuw GEPs) then we know that the addition does not
1243-
// wrap the pointer index type (add nuw) and the constant Offset is a lower
1244-
// bound on the distance between the pointers. We can then prove NoAlias via
1245-
// Offset u>= VLeftSize.
1243+
// If the difference between pointers is Offset +<nuw> Indices then we know
1244+
// that the addition does not wrap the pointer index type (add nuw) and the
1245+
// constant Offset is a lower bound on the distance between the pointers. We
1246+
// can then prove NoAlias via Offset u>= VLeftSize.
12461247
// + + +
12471248
// | BaseOffset | +<nuw> Indices |
12481249
// ---------------->|-------------------->|
12491250
// |-->VLeftSize | |-------> VRightSize
12501251
// LHS RHS
12511252
if (!DecompGEP1.VarIndices.empty() &&
12521253
llvm::all_of(DecompGEP1.VarIndices, [&](const VariableGEPIndex &V) {
1253-
return V.IsNegated == DecompGEP1.VarIndices.front().IsNegated;
1254+
return V.isSubtracted() == DecompGEP1.VarIndices.front().isSubtracted();
12541255
})) {
1255-
APInt Off = DecompGEP1.Offset;
1256+
const APInt &Off = DecompGEP1.Offset;
12561257
bool Swapped = Off.isNegative();
12571258
LocationSize VLeftSize = Swapped ? V1Size : V2Size;
1258-
DecomposedGEP &DecompRight = Swapped ? DecompGEP2 : DecompGEP1;
1259+
const DecomposedGEP &DecompRight = Swapped ? DecompGEP2 : DecompGEP1;
12591260

1260-
bool IndicesFromRight = DecompGEP1.VarIndices.front().IsNegated == Swapped;
1261-
if (IndicesFromRight && DecompRight.NWFlags->hasNoUnsignedWrap())
1261+
bool IndicesAdded = DecompGEP1.VarIndices.front().isSubtracted() == Swapped;
1262+
if (IndicesAdded && DecompRight.NWFlags->hasNoUnsignedWrap())
12621263
if (VLeftSize.hasValue() && !VLeftSize.isScalable() &&
12631264
Off.abs().uge(VLeftSize.getValue()))
12641265
return AliasResult::NoAlias;
@@ -1866,8 +1867,15 @@ bool BasicAAResult::isValueEqualInPotentialCycles(const Value *V,
18661867

18671868
/// Computes the symbolic difference between two de-composed GEPs.
18681869
void BasicAAResult::subtractDecomposedGEPs(DecomposedGEP &DestGEP,
1869-
const DecomposedGEP &SrcGEP,
1870+
DecomposedGEP &SrcGEP,
18701871
const AAQueryInfo &AAQI) {
1872+
// Drop nuw flag from GEP if subtraction of constant offsets overflows in an
1873+
// unsigned sense.
1874+
if (DestGEP.Offset.ult(SrcGEP.Offset))
1875+
DestGEP.NWFlags = DestGEP.NWFlags->withoutNoUnsignedWrap();
1876+
else if (SrcGEP.Offset.ult(DestGEP.Offset) && SrcGEP.NWFlags)
1877+
SrcGEP.NWFlags = SrcGEP.NWFlags->withoutNoUnsignedWrap();
1878+
18711879
DestGEP.Offset -= SrcGEP.Offset;
18721880
for (const VariableGEPIndex &Src : SrcGEP.VarIndices) {
18731881
// Find V in Dest. This is N^2, but pointer indices almost never have more
@@ -1890,6 +1898,13 @@ void BasicAAResult::subtractDecomposedGEPs(DecomposedGEP &DestGEP,
18901898
// If we found it, subtract off Scale V's from the entry in Dest. If it
18911899
// goes to zero, remove the entry.
18921900
if (Dest.Scale != Src.Scale) {
1901+
// Drop nuw flag from GEP if subtraction of V's Scale overflows in an
1902+
// unsigned sense.
1903+
if (Dest.Scale.ult(Src.Scale))
1904+
DestGEP.NWFlags = DestGEP.NWFlags->withoutNoUnsignedWrap();
1905+
else if (SrcGEP.NWFlags)
1906+
SrcGEP.NWFlags = SrcGEP.NWFlags->withoutNoUnsignedWrap();
1907+
18931908
Dest.Scale -= Src.Scale;
18941909
Dest.IsNSW = false;
18951910
} else {

llvm/test/Analysis/BasicAA/gep-nuw-alias.ll

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,3 +140,95 @@ define void @test_struct_nuw(ptr %st, i64 %i) {
140140
ret void
141141
}
142142

143+
; CHECK-LABEL: constant_offset_overflow
144+
;
145+
; If subtraction of constant offsets could overflow in an unsigned sense, we
146+
; cannot prove the lower bound between the GEPs and so they may still alias.
147+
;
148+
; CHECK-DAG: MayAlias: i32* %a, i32* %b
149+
150+
define void @constant_offset_overflow(ptr %p, i64 %i) {
151+
%a = getelementptr i8, ptr %p, i64 -8
152+
%add = getelementptr nuw i8, ptr %p, i64 4
153+
%b = getelementptr nuw i8, ptr %add, i64 %i
154+
155+
load i32, ptr %a
156+
load i32, ptr %b
157+
158+
ret void
159+
}
160+
161+
; CHECK-LABEL: constant_offset_overflow_rev_order
162+
;
163+
; Same as above test, just verifying correct behaviour when GEPs encountered
164+
; in the reverse order;
165+
;
166+
; CHECK-DAG: MayAlias: i32* %a, i32* %b
167+
168+
define void @constant_offset_overflow_rev_order(ptr %p, i64 %i) {
169+
%a = getelementptr i8, ptr %p, i64 -8
170+
%add = getelementptr nuw i8, ptr %p, i64 4
171+
%b = getelementptr nuw i8, ptr %add, i64 %i
172+
173+
load i32, ptr %b
174+
load i32, ptr %a
175+
176+
ret void
177+
}
178+
179+
; CHECK-LABEL: equal_var_idx_noalias
180+
;
181+
; If GEPs have equal variable indices, we can prove NoAlias when the Scale of
182+
; the RHS GEP is greater, as in this scenario the constant lower bound holds.
183+
;
184+
; CHECK-DAG: NoAlias: i32* %a, i32* %b
185+
186+
define void @equal_var_idx_noalias(ptr %p, i64 %i) {
187+
%a = getelementptr i8, ptr %p, i64 %i
188+
189+
%add = getelementptr nuw i8, ptr %p, i64 4
190+
%b = getelementptr nuw i16, ptr %add, i64 %i
191+
192+
load i32, ptr %a
193+
load i32, ptr %b
194+
195+
ret void
196+
}
197+
198+
; CHECK-LABEL: equal_var_idx_alias
199+
;
200+
; If GEPs have equal variable indices, we cannot prove NoAlias when the Scale of
201+
; the RHS GEP is ult Scale of the LHS GEP.
202+
;
203+
; CHECK-DAG: MayAlias: i32* %a, i32* %b
204+
205+
define void @equal_var_idx_alias(ptr %p, i64 %i) {
206+
%a = getelementptr i32, ptr %p, i64 %i
207+
208+
%add = getelementptr nuw i8, ptr %p, i64 4
209+
%b = getelementptr nuw i16, ptr %add, i64 %i
210+
211+
load i32, ptr %b
212+
load i32, ptr %a
213+
214+
ret void
215+
}
216+
217+
; CHECK-LABEL: both_var_idx
218+
;
219+
; If the RHS GEP has unmatched variable indices, we cannot prove a constant
220+
; lower bound between GEPs.
221+
;
222+
; CHECK-DAG: MayAlias: i32* %a, i32* %b
223+
224+
define void @both_var_idx(ptr %p, i64 %i, i64 %j) {
225+
%a = getelementptr i8, ptr %p, i64 %i
226+
227+
%add = getelementptr nuw i8, ptr %p, i64 4
228+
%b = getelementptr nuw i8, ptr %add, i64 %j
229+
230+
load i32, ptr %a
231+
load i32, ptr %b
232+
233+
ret void
234+
}

0 commit comments

Comments
 (0)