diff --git a/llvm/lib/Analysis/LoopAccessAnalysis.cpp b/llvm/lib/Analysis/LoopAccessAnalysis.cpp --- a/llvm/lib/Analysis/LoopAccessAnalysis.cpp +++ b/llvm/lib/Analysis/LoopAccessAnalysis.cpp @@ -144,7 +144,6 @@ const ValueToValueMap &PtrToStride, Value *Ptr) { const SCEV *OrigSCEV = PSE.getSCEV(Ptr); - // If there is an entry in the map return the SCEV of the pointer with the // symbolic stride replaced by one. ValueToValueMap::const_iterator SI = PtrToStride.find(Ptr); @@ -671,6 +670,7 @@ SmallVector WorkList; WorkList.push_back(StartPtr); + ScalarEvolution &SE = *PSE.getSE(); while (!WorkList.empty()) { Value *Ptr = WorkList.pop_back_val(); if (!Visited.insert(Ptr).second) @@ -683,8 +683,26 @@ PN->getParent() != InnermostLoop.getHeader()) { for (const Use &Inc : PN->incoming_values()) WorkList.push_back(Inc); - } else + } else { + auto *GEP = dyn_cast(Ptr); + if (GEP && GEP->getNumOperands() == 2) { + if (auto *SI = dyn_cast(GEP->getOperand(0))) { + const SCEV *BaseA = SE.getSCEV(SI->getOperand(1)); + const SCEV *BaseB = SE.getSCEV(SI->getOperand(2)); + const SCEV *Offset = SE.getSCEV(GEP->getOperand(1)); + if (SE.getTypeSizeInBits(Offset->getType()) < + SE.getTypeSizeInBits(BaseA->getType())) + Offset = SE.getSignExtendExpr( + Offset, SE.getEffectiveSCEVType(BaseA->getType())); + auto *PtrA = SE.getAddExpr(BaseA, Offset, SCEV::FlagNUW); + auto *PtrB = SE.getAddExpr(BaseB, Offset, SCEV::FlagNUW); + AddPointer(Ptr, PtrA); + AddPointer(Ptr, PtrB); + continue; + } + } AddPointer(Ptr, replaceSymbolicStrideSCEV(PSE, SymbolicStrides, Ptr)); + } } } @@ -763,14 +781,20 @@ SmallVector AccessInfos; for (const auto &A : AS) { Value *Ptr = A.getValue(); - const SCEV *PtrScev = replaceSymbolicStrideSCEV(PSE, StridesMap, Ptr); - bool IsWrite = Accesses.count(MemAccessInfo(Ptr, true, PtrScev)); - - if (IsWrite) - ++NumWritePtrChecks; - else - ++NumReadPtrChecks; - AccessInfos.emplace_back(Ptr, IsWrite, PtrScev); + SmallVector Infos; + visitPointers(Ptr, *TheLoop, PSE, StridesMap, + [&Infos](Value *Ptr, const SCEV *PtrExpr) { + Infos.emplace_back(Ptr, true, PtrExpr); + }); + for (auto &Tmp : Infos) { + bool IsWrite = Accesses.count(Tmp); + + if (IsWrite) + ++NumWritePtrChecks; + else + ++NumReadPtrChecks; + AccessInfos.emplace_back(Ptr, IsWrite, Tmp.getPtrExpr()); + } } // We do not need runtime checks for this alias set, if there are no writes @@ -933,64 +957,68 @@ if (UseDeferred && !IsReadOnlyPtr) continue; - const SCEV *PtrExpr = - replaceSymbolicStrideSCEV(PSE, SymbolicStrides, Ptr); - // Otherwise, the pointer must be in the PtrAccessSet, either as a - // read or a write. - assert(((IsReadOnlyPtr && UseDeferred) || IsWrite || - S.count(MemAccessInfo(Ptr, false, PtrExpr))) && - "Alias-set pointer not in the access set?"); - - MemAccessInfo Access(Ptr, IsWrite, PtrExpr); - DepCands.insert(Access); - - // Memorize read-only pointers for later processing and skip them in - // the first round (they need to be checked after we have seen all - // write pointers). Note: we also mark pointer that are not - // consecutive as "read-only" pointers (so that we check - // "a[b[i]] +="). Hence, we need the second check for "!IsWrite". - if (!UseDeferred && IsReadOnlyPtr) { - DeferredAccesses.insert(Access); - continue; - } - - // If this is a write - check other reads and writes for conflicts. If - // this is a read only check other writes for conflicts (but only if - // there is no other write to the ptr - this is an optimization to - // catch "a[i] = a[i] + " without having to do a dependence check). - if ((IsWrite || IsReadOnlyPtr) && SetHasWrite) { - CheckDeps.push_back(Access); - IsRTCheckAnalysisNeeded = true; - } - - if (IsWrite) - SetHasWrite = true; - - // Create sets of pointers connected by a shared alias set and - // underlying object. - typedef SmallVector ValueVector; - ValueVector TempObjects; - - getUnderlyingObjects(Ptr, TempObjects, LI); - LLVM_DEBUG(dbgs() - << "Underlying objects for pointer " << *Ptr << "\n"); - for (const Value *UnderlyingObj : TempObjects) { - // nullptr never alias, don't join sets for pointer that have "null" - // in their UnderlyingObjects list. - if (isa(UnderlyingObj) && - !NullPointerIsDefined( - TheLoop->getHeader()->getParent(), - UnderlyingObj->getType()->getPointerAddressSpace())) - continue; - - UnderlyingObjToAccessMap::iterator Prev = - ObjToLastAccess.find(UnderlyingObj); - if (Prev != ObjToLastAccess.end()) - DepCands.unionSets(Access, Prev->second); - - ObjToLastAccess[UnderlyingObj] = Access; - LLVM_DEBUG(dbgs() << " " << *UnderlyingObj << "\n"); - } + visitPointers( + Ptr, *TheLoop, PSE, SymbolicStrides, + [&](Value *Ptr, const SCEV *PtrExpr) { + MemAccessInfo Access(Ptr, IsWrite, PtrExpr); + // Otherwise, the pointer must be in the PtrAccessSet, either as + // a read or a write. + assert(((IsReadOnlyPtr && UseDeferred) || IsWrite || + S.count(Access)) && + "Alias-set pointer not in the access set?"); + + DepCands.insert(Access); + + // Memorize read-only pointers for later processing and skip + // them in the first round (they need to be checked after we + // have seen all write pointers). Note: we also mark pointer + // that are not consecutive as "read-only" pointers (so that we + // check "a[b[i]] +="). Hence, we need the second check for + // "!IsWrite". + if (!UseDeferred && IsReadOnlyPtr) { + DeferredAccesses.insert(Access); + return; + } + + // If this is a write - check other reads and writes for + // conflicts. If this is a read only check other writes for + // conflicts (but only if there is no other write to the ptr - + // this is an optimization to catch "a[i] = a[i] + " without + // having to do a dependence check). + if ((IsWrite || IsReadOnlyPtr) && SetHasWrite) { + CheckDeps.push_back(Access); + IsRTCheckAnalysisNeeded = true; + } + + if (IsWrite) + SetHasWrite = true; + + // Create sets of pointers connected by a shared alias set and + // underlying object. + typedef SmallVector ValueVector; + ValueVector TempObjects; + + getUnderlyingObjects(Ptr, TempObjects, LI); + LLVM_DEBUG(dbgs() << "Underlying objects for pointer " << *Ptr + << "\n"); + for (const Value *UnderlyingObj : TempObjects) { + // nullptr never alias, don't join sets for pointer that have + // "null" in their UnderlyingObjects list. + if (isa(UnderlyingObj) && + !NullPointerIsDefined( + TheLoop->getHeader()->getParent(), + UnderlyingObj->getType()->getPointerAddressSpace())) + continue; + + UnderlyingObjToAccessMap::iterator Prev = + ObjToLastAccess.find(UnderlyingObj); + if (Prev != ObjToLastAccess.end()) + DepCands.unionSets(Access, Prev->second); + + ObjToLastAccess[UnderlyingObj] = Access; + LLVM_DEBUG(dbgs() << " " << *UnderlyingObj << "\n"); + } + }); } } } diff --git a/llvm/test/Analysis/LoopAccessAnalysis/memcheck-wrapping-pointers.ll b/llvm/test/Analysis/LoopAccessAnalysis/memcheck-wrapping-pointers.ll --- a/llvm/test/Analysis/LoopAccessAnalysis/memcheck-wrapping-pointers.ll +++ b/llvm/test/Analysis/LoopAccessAnalysis/memcheck-wrapping-pointers.ll @@ -29,16 +29,16 @@ ; CHECK-NEXT: Run-time memory checks: ; CHECK-NEXT: Check 0: ; CHECK-NEXT: Comparing group -; CHECK-NEXT: %arrayidx = getelementptr inbounds i32, i32* %a, i64 %idxprom -; CHECK-NEXT: Against group ; CHECK-NEXT: %arrayidx4 = getelementptr inbounds i32, i32* %b, i64 %conv11 +; CHECK-NEXT: Against group +; CHECK-NEXT: %arrayidx = getelementptr inbounds i32, i32* %a, i64 %idxprom ; CHECK-NEXT: Grouped accesses: ; CHECK-NEXT: Group -; CHECK-NEXT: (Low: (4 + %a) High: (4 + (4 * (1 umax %x)) + %a)) -; CHECK-NEXT: Member: {(4 + %a),+,4}<%for.body> -; CHECK-NEXT: Group ; CHECK-NEXT: (Low: %b High: ((4 * (1 umax %x)) + %b)) ; CHECK-NEXT: Member: {%b,+,4}<%for.body> +; CHECK-NEXT: Group +; CHECK-NEXT: (Low: (4 + %a) High: (4 + (4 * (1 umax %x)) + %a)) +; CHECK-NEXT: Member: {(4 + %a),+,4}<%for.body> ; CHECK: Non vectorizable stores to invariant address were not found in loop. ; CHECK-NEXT: SCEV assumptions: ; CHECK-NEXT: {1,+,1}<%for.body> Added Flags: