Index: include/llvm/Analysis/BasicAliasAnalysis.h =================================================================== --- include/llvm/Analysis/BasicAliasAnalysis.h +++ include/llvm/Analysis/BasicAliasAnalysis.h @@ -86,6 +86,14 @@ /// Chases pointers until we find a (constant global) or not. bool pointsToConstantMemory(const MemoryLocation &Loc, bool OrLocal); + /// Checks whether the given locations points to the same buffer and returns + // a pointer to the buffer, else returns nullptr. + bool ModRefSameBuffer(const MemoryLocation &LocA, int64_t ptr1Offset, + const MemoryLocation &LocB, int64_t ptr2Offset); + + /// Returns the distance between 2 memory location if available. + Optional getAddressesDistance(const MemoryLocation &LocA, + int64_t ptr1Offset, const MemoryLocation &LocB, int64_t ptr2Offset); /// Get the location associated with a pointer argument of a callsite. ModRefInfo getArgModRefInfo(ImmutableCallSite CS, unsigned ArgIdx); @@ -141,6 +149,10 @@ using AliasCacheTy = SmallDenseMap; AliasCacheTy AliasCache; + /// Track common Buffer queries to guard against recursion. + typedef std::pair> MemDistancePair; + typedef SmallDenseMap CommonBufferCacheTy; + CommonBufferCacheTy CommonBufferCache; /// Tracks phi nodes we have visited. /// /// When interpret "Value" pointer equality as value equality we need to make @@ -209,6 +221,23 @@ AliasResult aliasCheck(const Value *V1, uint64_t V1Size, AAMDNodes V1AATag, const Value *V2, uint64_t V2Size, AAMDNodes V2AATag, const Value *O1 = nullptr, const Value *O2 = nullptr); + BuffUseResult commonBufferPHI(const PHINode *PN, uint64_t PNSize, + const AAMDNodes &PNAAInfo, int64_t ptr1Offset, + const Value *V2, uint64_t V2Size, + const AAMDNodes &V2AAInfo, int64_t ptr2Offset, + const Value *UnderV2, + Optional& LocDistance); + + BuffUseResult commonBufferSelect(const SelectInst *SI, uint64_t SISize, + const AAMDNodes &SIAAInfo, int64_t ptr1Offset, + const Value *V2, uint64_t V2Size, + const AAMDNodes &V2AAInfo, int64_t ptr2Offset, + const Value *UnderV2, Optional& LocDistance); + + BuffUseResult ModRefSameBufferCheck(const Value *V1, uint64_t V1Size, + AAMDNodes V1AAInfo, int64_t ptr1Offset, const Value *V2, uint64_t V2Size, + AAMDNodes V2AAInfo, int64_t ptr2Offset, Optional& LocDistance, + const Value *O1 = nullptr, const Value *O2 = nullptr); }; /// Analysis pass providing a never-invalidated alias analysis result. Index: lib/Analysis/BasicAliasAnalysis.cpp =================================================================== --- lib/Analysis/BasicAliasAnalysis.cpp +++ lib/Analysis/BasicAliasAnalysis.cpp @@ -620,6 +620,52 @@ return Worklist.empty(); } +#ifndef NDEBUG +static const Function *getParent(const Value *V) { + if (const Instruction *inst = dyn_cast(V)) + return inst->getParent()->getParent(); + + if (const Argument *arg = dyn_cast(V)) + return arg->getParent(); + + return nullptr; +} + +static bool notDifferentParent(const Value *O1, const Value *O2) { + + const Function *F1 = getParent(O1); + const Function *F2 = getParent(O2); + + return !F1 || !F2 || F1 == F2; +} +#endif + +#ifndef CEVA_REMOVED +bool BasicAAResult::ModRefSameBuffer(const MemoryLocation &LocA, + int64_t ptr1Offset, const MemoryLocation &LocB, int64_t ptr2Offset) { + assert(notDifferentParent(LocA.Ptr, LocB.Ptr) && + "ModRefSameBuffer doesn't support interprocedural queries."); + + Optional LocDistance; + BuffUseResult sameBuff = + ModRefSameBufferCheck(LocA.Ptr, LocA.Size, LocA.AATags, ptr1Offset, + LocB.Ptr, LocB.Size, LocB.AATags, ptr2Offset, LocDistance); + return sameBuff == MustUseSameBuff; +} + +Optional +BasicAAResult::getAddressesDistance(const MemoryLocation &LocA, + int64_t ptr1Offset, const MemoryLocation &LocB, int64_t ptr2Offset) { + // LocA-LocB + Optional LocDistance; + BuffUseResult sameBuff = + ModRefSameBufferCheck(LocA.Ptr, LocA.Size, LocA.AATags, ptr1Offset, + LocB.Ptr, LocB.Size, LocB.AATags, ptr2Offset, LocDistance); + + return LocDistance; +} +#endif + /// Returns the behavior when calling the given call site. FunctionModRefBehavior BasicAAResult::getModRefBehavior(ImmutableCallSite CS) { if (CS.doesNotAccessMemory()) @@ -723,6 +769,178 @@ return II && II->getIntrinsicID() == IID; } +/// Returns pointer to the buffer if given locations points to the same buffer. +// else return nullptr. +BuffUseResult BasicAAResult::ModRefSameBufferCheck( + const Value *V1, uint64_t V1Size, AAMDNodes V1AAInfo, int64_t ptr1Offset, + const Value *V2, uint64_t V2Size, AAMDNodes V2AAInfo, int64_t ptr2Offset, + Optional &LocDistance, const Value *O1, const Value *O2) { + // If either of the memory references is empty, it doesn't matter what the + // pointer values are. + if (V1Size == 0 || V2Size == 0) + return NotSameBuff; + + // Strip off any casts if they exist. + V1 = V1->stripPointerCasts(); + V2 = V2->stripPointerCasts(); + + // If V1 or V2 is undef, the result is nullptr. + if (isa(V1) || isa(V2)) + return NotSameBuff; + + // Are we checking for alias of the same value? + // Because we look 'through' phi nodes, we could look at "Value" pointers from + // different iterations. We must therefore make sure that this is not the + // case. The function isValueEqualInPotentialCycles ensures that this cannot + // happen by looking at the visited phi nodes and making sure they cannot + // reach the value. + /*//atheelm: need to support this + if (isValueEqualInPotentialCycles(V1, V2)) { + return MustUseSameBuff; + }*/ + + // Figure out what objects these things are pointing to if we can. + if (O1 == nullptr) + O1 = GetUnderlyingObject(V1, DL, MaxLookupSearchDepth); + + if (O2 == nullptr) + O2 = GetUnderlyingObject(V2, DL, MaxLookupSearchDepth); + + // Null values in the default address space don't point to any object + if (const ConstantPointerNull *CPN = dyn_cast(O1)) + if (CPN->getType()->getAddressSpace() == 0) + return NotSameBuff; + if (const ConstantPointerNull *CPN = dyn_cast(O2)) + if (CPN->getType()->getAddressSpace() == 0) + return NotSameBuff; + + if (O1 != O2) { + // If V1/V2 point to two different objects, we know that + // they are not using the same buffer. + if (isIdentifiedObject(O1) && isIdentifiedObject(O2)) + return NotSameBuff; + + // Constant pointers can't alias with non-const isIdentifiedObject objects. + if ((isa(O1) && isIdentifiedObject(O2) && !isa(O2)) || + (isa(O2) && isIdentifiedObject(O1) && !isa(O1))) + return NotSameBuff; + + // Function arguments can't alias with things that are known to be + // unambigously identified at the function level. + if ((isa(O1) && isIdentifiedFunctionLocal(O2)) || + (isa(O2) && isIdentifiedFunctionLocal(O1))) + return NotSameBuff; + + // Most objects can't alias null. + if ((isa(O2) && isKnownNonNull(O1)) || + (isa(O1) && isKnownNonNull(O2))) + return NotSameBuff; + + // If one pointer is the result of a call/invoke or load and the other is a + // non-escaping local object within the same function, then we know the + // object couldn't escape to a point where the call could return it. + // + // Note that if the pointers are in different functions, there are a + // variety of complications. A call with a nocapture argument may still + // temporary store the nocapture argument's value in a temporary memory + // location if that memory location doesn't escape. Or it may pass a + // nocapture value to other functions as long as they don't capture it. + if (isEscapeSource(O1) && isNonEscapingLocalObject(O2)) + return NotSameBuff; + if (isEscapeSource(O2) && isNonEscapingLocalObject(O1)) + return NotSameBuff; + } + + // Check the cache before climbing up use-def chains. This also terminates + // otherwise infinitely recursive queries. + LocPair Locs(MemoryLocation(V1, V1Size, V1AAInfo), + MemoryLocation(V2, V2Size, V2AAInfo)); + if (V1 > V2) + std::swap(Locs.first, Locs.second); + std::pair Pair = + CommonBufferCache.insert( + std::make_pair(Locs, MemDistancePair(MayUseSameBuff, None))); + if (!Pair.second) { + LocDistance = (Pair.first->second.second); + return Pair.first->second.first; + } + + // FIXME: This isn't aggressively handling alias(GEP, PHI) for example: if the + // GEP can't simplify, we don't even look at the PHI cases. + if (!isa(V1) && isa(V2)) { + std::swap(V1, V2); + std::swap(V1Size, V2Size); + std::swap(O1, O2); + std::swap(V1AAInfo, V2AAInfo); + std::swap(ptr1Offset, ptr2Offset); + } + + if ((O1 == O2)) { + const GEPOperator *GV1 = dyn_cast(V1); + const GEPOperator *GV2 = dyn_cast(V2); + if (GV1 && GV2) { + DecomposedGEP DecompGEP1, DecompGEP2; + bool GEP1MaxLookupReached = + DecomposeGEPExpression(GV1, DecompGEP1, DL, &AC, DT); + bool GEP2MaxLookupReached = + DecomposeGEPExpression(V2, DecompGEP2, DL, &AC, DT); + + int64_t GEP1BaseOffset = + DecompGEP1.StructOffset + DecompGEP1.OtherOffset + ptr1Offset; + int64_t GEP2BaseOffset = + DecompGEP2.StructOffset + DecompGEP2.OtherOffset + ptr2Offset; + LocDistance = GEP2BaseOffset - GEP1BaseOffset; + CommonBufferCache[Locs] = MemDistancePair(MustUseSameBuff, LocDistance); + return MustUseSameBuff; + } else if (GV1) { + + BuffUseResult R = ModRefSameBufferCheck( + O1, MemoryLocation::UnknownSize, AAMDNodes(), ptr1Offset, V2, + MemoryLocation::UnknownSize, V2AAInfo, ptr2Offset, LocDistance, nullptr, O2); + if (R != MayUseSameBuff) { + CommonBufferCache[Locs] = MemDistancePair(MustUseSameBuff, LocDistance); + return R; + } + } + + if (isa(V2) && !isa(V1)) { + std::swap(V1, V2); + std::swap(O1, O2); + std::swap(V1Size, V2Size); + std::swap(V1AAInfo, V2AAInfo); + std::swap(ptr1Offset, ptr2Offset); + } + if (const PHINode *PN = dyn_cast(V1)) { + BuffUseResult Result = commonBufferPHI(PN, V1Size, V1AAInfo, ptr1Offset,V2, V2Size, + V2AAInfo, ptr2Offset, O2, LocDistance); + if (Result != MayUseSameBuff) { + CommonBufferCache[Locs] = MemDistancePair(Result, LocDistance); + return Result; + } + } + + if (isa(V2) && !isa(V1)) { + std::swap(V1, V2); + std::swap(O1, O2); + std::swap(V1Size, V2Size); + std::swap(V1AAInfo, V2AAInfo); + std::swap(ptr1Offset, ptr2Offset); + } + if (const SelectInst *S1 = dyn_cast(V1)) { + BuffUseResult Result = commonBufferSelect(S1, V1Size, V1AAInfo, + ptr1Offset, V2, V2Size, V2AAInfo, ptr2Offset, O2, LocDistance); + if (Result != MayUseSameBuff) { + CommonBufferCache[Locs] = MemDistancePair(Result, LocDistance); + return Result; + } + } + CommonBufferCache[Locs] = MemDistancePair(MustUseSameBuff, None); + return MustUseSameBuff; + } + CommonBufferCache[Locs] = MemDistancePair(NotSameBuff, None); + return NotSameBuff; +} + #ifndef NDEBUG static const Function *getParent(const Value *V) { if (const Instruction *inst = dyn_cast(V)) { @@ -1423,6 +1641,142 @@ // Otherwise, we don't know anything. return MayAlias; } +/// Provides a bunch of ad-hoc rules to disambiguate a Select instruction +/// against another. +BuffUseResult BasicAAResult::commonBufferSelect(const SelectInst *SI, uint64_t SISize, + const AAMDNodes &SIAAInfo, int64_t ptr1Offset, const Value *V2, + uint64_t V2Size, const AAMDNodes &V2AAInfo, int64_t ptr2Offset, + const Value *UnderV2, Optional& LocDistance) { + // If the values are Selects with the same condition, we can do a more precise + // check: just check for aliases between the values on corresponding arms. + if (const SelectInst *SI2 = dyn_cast(V2)) + if (SI->getCondition() == SI2->getCondition()) { + BuffUseResult Alias = ModRefSameBufferCheck(SI->getTrueValue(), SISize, SIAAInfo, + ptr1Offset, SI2->getTrueValue(), V2Size, V2AAInfo, ptr2Offset, LocDistance); + if (Alias != MayUseSameBuff) + return Alias; + BuffUseResult ThisAlias = + ModRefSameBufferCheck(SI->getFalseValue(), SISize, SIAAInfo, + ptr1Offset, SI2->getFalseValue(), V2Size, V2AAInfo, + ptr2Offset, LocDistance); + return ThisAlias; + } + + // If both arms of the Select node NoAlias or MustAlias V2, then returns + // NoAlias / MustAlias. Otherwise, returns MayAlias. + BuffUseResult Alias = + ModRefSameBufferCheck(V2, V2Size, V2AAInfo, ptr1Offset, SI->getTrueValue(), + SISize, SIAAInfo, ptr2Offset, LocDistance, UnderV2); + if (Alias != MayUseSameBuff) + return Alias; + + BuffUseResult ThisAlias = + ModRefSameBufferCheck(V2, V2Size, V2AAInfo, ptr1Offset, + SI->getFalseValue(), SISize, SIAAInfo, ptr2Offset, + LocDistance, UnderV2); + return ThisAlias; +} + +/// Provide a bunch of ad-hoc rules to disambiguate a PHI instruction against +/// another. +BuffUseResult BasicAAResult::commonBufferPHI(const PHINode *PN, uint64_t PNSize, + const AAMDNodes &PNAAInfo, int64_t ptr1Offset, const Value *V2, + uint64_t V2Size, const AAMDNodes &V2AAInfo, int64_t ptr2Offset, + const Value *UnderV2, Optional& LocDistance) { + // Track phi nodes we have visited. We use this information when we determine + // value equivalence. + VisitedPhiBBs.insert(PN->getParent()); + + // If the values are PHIs in the same block, we can do a more precise + // as well as efficient check: just check for aliases between the values + // on corresponding edges. + if (const PHINode *PN2 = dyn_cast(V2)) + if (PN2->getParent() == PN->getParent()) { + LocPair Locs(MemoryLocation(PN, PNSize, PNAAInfo), + MemoryLocation(V2, V2Size, V2AAInfo)); + if (PN > V2) + std::swap(Locs.first, Locs.second); + // Analyse the PHIs' inputs under the assumption that the PHIs are + // NoAlias. + // If the PHIs are May/MustAlias there must be (recursively) an input + // operand from outside the PHIs' cycle that is MayAlias/MustAlias or + // there must be an operation on the PHIs within the PHIs' value cycle + // that causes a MayAlias. + // Pretend the phis do not alias. + const Value* Alias = nullptr; + assert(CommonBufferCache.count(Locs) && + "There must exist an entry for the phi node"); + + for (unsigned i = 0, e = PN->getNumIncomingValues(); i != e; ++i) { + BuffUseResult ThisAlias = + ModRefSameBufferCheck(PN->getIncomingValue(i), PNSize, PNAAInfo, + ptr1Offset, PN2->getIncomingValueForBlock(PN->getIncomingBlock(i)), + V2Size, V2AAInfo, ptr2Offset, LocDistance); + if (ThisAlias != MayUseSameBuff) { + return ThisAlias; + } + } + + } + + SmallPtrSet UniqueSrc; + SmallVector V1Srcs; + bool isRecursive = false; + for (Value *PV1 : PN->incoming_values()) { + if (isa(PV1)) + // If any of the source itself is a PHI, return MayAlias conservatively + // to avoid compile time explosion. The worst possible case is if both + // sides are PHI nodes. In which case, this is O(m x n) time where 'm' + // and 'n' are the number of PHI sources. + return MayUseSameBuff; + + if (EnableRecPhiAnalysis) + if (GEPOperator *PV1GEP = dyn_cast(PV1)) { + // Check whether the incoming value is a GEP that advances the pointer + // result of this PHI node (e.g. in a loop). If this is the case, we + // would recurse and always get a MayAlias. Handle this case specially + // below. + if (PV1GEP->getPointerOperand() == PN && PV1GEP->getNumIndices() == 1 && + isa(PV1GEP->idx_begin())) { + isRecursive = true; + continue; + } + } + + if (UniqueSrc.insert(PV1).second) + V1Srcs.push_back(PV1); + } + + // If this PHI node is recursive, set the size of the accessed memory to + // unknown to represent all the possible values the GEP could advance the + // pointer to. + if (isRecursive) + PNSize = MemoryLocation::UnknownSize; + + BuffUseResult Alias = + ModRefSameBufferCheck(V2, V2Size, V2AAInfo, ptr1Offset, V1Srcs[0], + PNSize, PNAAInfo, ptr2Offset, LocDistance, UnderV2); + + // Early exit if the check of the first PHI source against V2 is MayAlias. + // Other results are not possible. + if (Alias != MayUseSameBuff) + return Alias; + + // If all sources of the PHI node NoAlias or MustAlias V2, then returns + // NoAlias / MustAlias. Otherwise, returns MayAlias. + for (unsigned i = 1, e = V1Srcs.size(); i != e; ++i) { + Value *V = V1Srcs[i]; + + BuffUseResult ThisAlias = + ModRefSameBufferCheck(V2, V2Size, V2AAInfo, ptr1Offset, V, PNSize, + PNAAInfo, ptr2Offset, LocDistance, UnderV2); + if (ThisAlias != MayUseSameBuff) + return ThisAlias; + + return NotSameBuff; + } + return NotSameBuff; +} /// Provides a bunch of ad-hoc rules to disambiguate a Select instruction /// against another.