diff options
Diffstat (limited to 'llvm/lib/Analysis/BasicAliasAnalysis.cpp')
-rw-r--r-- | llvm/lib/Analysis/BasicAliasAnalysis.cpp | 69 |
1 files changed, 49 insertions, 20 deletions
diff --git a/llvm/lib/Analysis/BasicAliasAnalysis.cpp b/llvm/lib/Analysis/BasicAliasAnalysis.cpp index 6eac30f..72db289 100644 --- a/llvm/lib/Analysis/BasicAliasAnalysis.cpp +++ b/llvm/lib/Analysis/BasicAliasAnalysis.cpp @@ -555,17 +555,17 @@ struct BasicAAResult::DecomposedGEP { APInt Offset; // Scaled variable (non-constant) indices. SmallVector<VariableGEPIndex, 4> VarIndices; - // Are all operations inbounds GEPs or non-indexing operations? - // (std::nullopt iff expression doesn't involve any geps) - std::optional<bool> InBounds; + // Nowrap flags common to all GEP operations involved in expression. + GEPNoWrapFlags NWFlags = GEPNoWrapFlags::all(); void dump() const { print(dbgs()); dbgs() << "\n"; } void print(raw_ostream &OS) const { - OS << "(DecomposedGEP Base=" << Base->getName() - << ", Offset=" << Offset + OS << ", inbounds=" << (NWFlags.isInBounds() ? "1" : "0") + << ", nuw=" << (NWFlags.hasNoUnsignedWrap() ? "1" : "0") + << "(DecomposedGEP Base=" << Base->getName() << ", Offset=" << Offset << ", VarIndices=["; for (size_t i = 0; i < VarIndices.size(); i++) { if (i != 0) @@ -644,12 +644,8 @@ BasicAAResult::DecomposeGEPExpression(const Value *V, const DataLayout &DL, return Decomposed; } - // Track whether we've seen at least one in bounds gep, and if so, whether - // all geps parsed were in bounds. - if (Decomposed.InBounds == std::nullopt) - Decomposed.InBounds = GEPOp->isInBounds(); - else if (!GEPOp->isInBounds()) - Decomposed.InBounds = false; + // Track the common nowrap flags for all GEPs we see. + Decomposed.NWFlags &= GEPOp->getNoWrapFlags(); assert(GEPOp->getSourceElementType()->isSized() && "GEP must be sized"); @@ -1112,6 +1108,13 @@ AliasResult BasicAAResult::aliasGEP( if (DecompGEP1.Base == GEP1 && DecompGEP2.Base == V2) return AliasResult::MayAlias; + // Swap GEP1 and GEP2 if GEP2 has more variable indices. + if (DecompGEP1.VarIndices.size() < DecompGEP2.VarIndices.size()) { + std::swap(DecompGEP1, DecompGEP2); + std::swap(V1Size, V2Size); + std::swap(UnderlyingV1, UnderlyingV2); + } + // Subtract the GEP2 pointer from the GEP1 pointer to find out their // symbolic difference. subtractDecomposedGEPs(DecompGEP1, DecompGEP2, AAQI); @@ -1120,20 +1123,19 @@ AliasResult BasicAAResult::aliasGEP( // for the two to alias, then we can assume noalias. // TODO: Remove !isScalable() once BasicAA fully support scalable location // size - if (*DecompGEP1.InBounds && DecompGEP1.VarIndices.empty() && + + if (DecompGEP1.NWFlags.isInBounds() && DecompGEP1.VarIndices.empty() && V2Size.hasValue() && !V2Size.isScalable() && DecompGEP1.Offset.sge(V2Size.getValue()) && isBaseOfObject(DecompGEP2.Base)) return AliasResult::NoAlias; - if (isa<GEPOperator>(V2)) { - // Symmetric case to above. - if (*DecompGEP2.InBounds && DecompGEP1.VarIndices.empty() && - V1Size.hasValue() && !V1Size.isScalable() && - DecompGEP1.Offset.sle(-V1Size.getValue()) && - isBaseOfObject(DecompGEP1.Base)) - return AliasResult::NoAlias; - } + // Symmetric case to above. + if (DecompGEP2.NWFlags.isInBounds() && DecompGEP1.VarIndices.empty() && + V1Size.hasValue() && !V1Size.isScalable() && + DecompGEP1.Offset.sle(-V1Size.getValue()) && + isBaseOfObject(DecompGEP1.Base)) + return AliasResult::NoAlias; // For GEPs with identical offsets, we can preserve the size and AAInfo // when performing the alias check on the underlying objects. @@ -1239,6 +1241,20 @@ AliasResult BasicAAResult::aliasGEP( } } + // If the difference between pointers is Offset +<nuw> Indices then we know + // that the addition does not wrap the pointer index type (add nuw) and the + // constant Offset is a lower bound on the distance between the pointers. We + // can then prove NoAlias via Offset u>= VLeftSize. + // + + + + // | BaseOffset | +<nuw> Indices | + // ---------------->|-------------------->| + // |-->V2Size | |-------> V1Size + // LHS RHS + if (!DecompGEP1.VarIndices.empty() && + DecompGEP1.NWFlags.hasNoUnsignedWrap() && V2Size.hasValue() && + !V2Size.isScalable() && DecompGEP1.Offset.uge(V2Size.getValue())) + return AliasResult::NoAlias; + // Bail on analysing scalable LocationSize if (V1Size.isScalable() || V2Size.isScalable()) return AliasResult::MayAlias; @@ -1843,6 +1859,11 @@ bool BasicAAResult::isValueEqualInPotentialCycles(const Value *V, void BasicAAResult::subtractDecomposedGEPs(DecomposedGEP &DestGEP, const DecomposedGEP &SrcGEP, const AAQueryInfo &AAQI) { + // Drop nuw flag from GEP if subtraction of constant offsets overflows in an + // unsigned sense. + if (DestGEP.Offset.ult(SrcGEP.Offset)) + DestGEP.NWFlags = DestGEP.NWFlags.withoutNoUnsignedWrap(); + DestGEP.Offset -= SrcGEP.Offset; for (const VariableGEPIndex &Src : SrcGEP.VarIndices) { // Find V in Dest. This is N^2, but pointer indices almost never have more @@ -1865,6 +1886,11 @@ void BasicAAResult::subtractDecomposedGEPs(DecomposedGEP &DestGEP, // If we found it, subtract off Scale V's from the entry in Dest. If it // goes to zero, remove the entry. if (Dest.Scale != Src.Scale) { + // Drop nuw flag from GEP if subtraction of V's Scale overflows in an + // unsigned sense. + if (Dest.Scale.ult(Src.Scale)) + DestGEP.NWFlags = DestGEP.NWFlags.withoutNoUnsignedWrap(); + Dest.Scale -= Src.Scale; Dest.IsNSW = false; } else { @@ -1879,6 +1905,9 @@ void BasicAAResult::subtractDecomposedGEPs(DecomposedGEP &DestGEP, VariableGEPIndex Entry = {Src.Val, Src.Scale, Src.CxtI, Src.IsNSW, /* IsNegated */ true}; DestGEP.VarIndices.push_back(Entry); + + // Drop nuw flag when we have unconsumed variable indices from SrcGEP. + DestGEP.NWFlags = DestGEP.NWFlags.withoutNoUnsignedWrap(); } } } |