Index: include/llvm/Analysis/AliasAnalysis.h =================================================================== --- include/llvm/Analysis/AliasAnalysis.h +++ include/llvm/Analysis/AliasAnalysis.h @@ -91,6 +91,16 @@ MustAlias, }; +enum BuffUseResult { + /// the two locations cant use the same memory block + NotSameBuff = 0, + /// The two locations may or may not use the same memory block. This is the + /// least precise result. + MayUseSameBuff, + /// The two locations precisely use the same memory block. + MustUseSameBuff + +}; /// Flags indicating whether a memory access modifies or references memory. /// /// This is no access at all, a modification, a reference, or both @@ -374,6 +384,16 @@ return pointsToConstantMemory(MemoryLocation(P), OrLocal); } + /// Checks whether the given locations points to the same buffer. + bool ModRefSameBuffer(const MemoryLocation &LocA, int64_t ptr1Offset, + const MemoryLocation &LocB, int64_t ptr2Offset); + + /// A convenience wrapper around the \c ModRefSameBuffer helper interface. + bool ModRefSameBuffer(const Value *V1, int64_t ptr1Offset, const Value *V2, + int64_t ptr2Offset) { + return ModRefSameBuffer(MemoryLocation(V1), ptr1Offset, MemoryLocation(V2), + ptr2Offset); + } /// @} //===--------------------------------------------------------------------===// /// \name Simple mod/ref information @@ -391,6 +411,17 @@ /// Return the behavior when calling the given function. FunctionModRefBehavior getModRefBehavior(const Function *F); + /// Return the Distance between 2 address. + Optional getAddressesDistance(const MemoryLocation &LocA, + int64_t ptr1Offset, + const MemoryLocation &LocB, + int64_t ptr2Offset); + + Optional getAddressesDistance(const Value *V1, int64_t ptr1Offset, + const Value *V2, int64_t ptr2Offset) { + return getAddressesDistance(MemoryLocation(V1), ptr1Offset, + MemoryLocation(V2), ptr2Offset); + } /// Checks if the specified call is known to never read or write memory. /// @@ -758,6 +789,10 @@ virtual bool pointsToConstantMemory(const MemoryLocation &Loc, bool OrLocal) = 0; + /// Checks whether the given locations points to the same buffer. + virtual bool ModRefSameBuffer(const MemoryLocation &LocA, int64_t ptr1Offset, + const MemoryLocation &LocB, + int64_t ptr2Offset) = 0; /// @} //===--------------------------------------------------------------------===// /// \name Simple mod/ref information @@ -788,6 +823,11 @@ virtual ModRefInfo getModRefInfo(ImmutableCallSite CS1, ImmutableCallSite CS2) = 0; + /// Return the Distance between 2 address. + virtual Optional getAddressesDistance(const MemoryLocation &LocA, + int64_t ptr1Offset, + const MemoryLocation &LocB, + int64_t ptr2Offset) = 0; /// @} }; @@ -817,6 +857,11 @@ bool OrLocal) override { return Result.pointsToConstantMemory(Loc, OrLocal); } + bool ModRefSameBuffer(const MemoryLocation &LocA, int64_t ptr1Offset, + const MemoryLocation &LocB, + int64_t ptr2Offset) override { + return Result.ModRefSameBuffer(LocA, ptr1Offset, LocB, ptr2Offset); + } ModRefInfo getArgModRefInfo(ImmutableCallSite CS, unsigned ArgIdx) override { return Result.getArgModRefInfo(CS, ArgIdx); @@ -839,6 +884,12 @@ ImmutableCallSite CS2) override { return Result.getModRefInfo(CS1, CS2); } + Optional getAddressesDistance(const MemoryLocation &LocA, + int64_t ptr1Offset, + const MemoryLocation &LocB, + int64_t ptr2Offset) override { + return Result.getAddressesDistance(LocA, ptr1Offset, LocB, ptr2Offset); + } }; /// A CRTP-driven "mixin" base class to help implement the function alias @@ -892,6 +943,12 @@ : CurrentResult.pointsToConstantMemory(Loc, OrLocal); } + bool ModRefSameBuffer(const MemoryLocation &LocA, int64_t ptr1Offset, + const MemoryLocation &LocB, int64_t ptr2Offset) { + return AAR ? AAR->ModRefSameBuffer(LocA, ptr1Offset, LocB, ptr2Offset) + : CurrentResult.ModRefSameBuffer(LocA, ptr1Offset, LocB, + ptr2Offset); + } ModRefInfo getArgModRefInfo(ImmutableCallSite CS, unsigned ArgIdx) { return AAR ? AAR->getArgModRefInfo(CS, ArgIdx) : CurrentResult.getArgModRefInfo(CS, ArgIdx); } @@ -912,6 +969,14 @@ ModRefInfo getModRefInfo(ImmutableCallSite CS1, ImmutableCallSite CS2) { return AAR ? AAR->getModRefInfo(CS1, CS2) : CurrentResult.getModRefInfo(CS1, CS2); } + Optional getAddressesDistance(const MemoryLocation &LocA, + int64_t ptr1Offset, + const MemoryLocation &LocB, + int64_t ptr2Offset) { + return AAR ? AAR->getAddressesDistance(LocA, ptr1Offset, LocB, ptr2Offset) + : CurrentResult.getAddressesDistance(LocA, ptr1Offset, LocB, + ptr2Offset); + } }; explicit AAResultBase() = default; @@ -941,6 +1006,10 @@ bool pointsToConstantMemory(const MemoryLocation &Loc, bool OrLocal) { return false; } + bool ModRefSameBuffer(const MemoryLocation &LocA, int64_t ptr1Offset, + const MemoryLocation &LocB, int64_t ptr2Offset) { + return false; + } ModRefInfo getArgModRefInfo(ImmutableCallSite CS, unsigned ArgIdx) { return ModRefInfo::ModRef; @@ -961,6 +1030,12 @@ ModRefInfo getModRefInfo(ImmutableCallSite CS1, ImmutableCallSite CS2) { return ModRefInfo::ModRef; } + Optional getAddressesDistance(const MemoryLocation &LocA, + int64_t ptr1Offset, + const MemoryLocation &LocB, + int64_t ptr2Offset) { + return None; + } }; /// Return true if this pointer is returned by a noalias function. 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 + // true, else returns false. + 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. + using MemDistancePair = std::pair>; + using CommonBufferCacheTy = SmallDenseMap; + 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/AliasAnalysis.cpp =================================================================== --- lib/Analysis/AliasAnalysis.cpp +++ lib/Analysis/AliasAnalysis.cpp @@ -118,6 +118,29 @@ return false; } +bool AAResults::ModRefSameBuffer(const MemoryLocation &LocA, int64_t ptr1Offset, + const MemoryLocation &LocB, + int64_t ptr2Offset) { + for (const auto &AA : AAs) + if (AA->ModRefSameBuffer(LocA, ptr1Offset, LocB, ptr2Offset)) + return true; + + return false; +} + +Optional AAResults::getAddressesDistance(const MemoryLocation &LocA, + int64_t ptr1Offset, + const MemoryLocation &LocB, + int64_t ptr2Offset) { + for (const auto &AA : AAs) { + Optional res = + AA->getAddressesDistance(LocA, ptr1Offset, LocB, ptr2Offset); + if (res != None) + return res; + } + + return None; +} ModRefInfo AAResults::getArgModRefInfo(ImmutableCallSite CS, unsigned ArgIdx) { ModRefInfo Result = ModRefInfo::ModRef; Index: lib/Analysis/BasicAliasAnalysis.cpp =================================================================== --- lib/Analysis/BasicAliasAnalysis.cpp +++ lib/Analysis/BasicAliasAnalysis.cpp @@ -746,6 +746,202 @@ } #endif +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; +} + +/// 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; +} + AliasResult BasicAAResult::alias(const MemoryLocation &LocA, const MemoryLocation &LocB) { assert(notDifferentParent(LocA.Ptr, LocB.Ptr) && @@ -1423,6 +1619,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 MayUseSameBuff 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 MayUseSameBuff. 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 MayUseSameBuff. + // Other results are not possible. + if (Alias != MayUseSameBuff) + return Alias; + + // If all sources of the PHI node NotSameBuff or MustUseSameBuff V2, then returns + // NotSameBuff / MustUseSameBuff. Otherwise, returns MayUseSameBuff. + 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.