diff --git a/llvm/include/llvm/Analysis/LoopAccessAnalysis.h b/llvm/include/llvm/Analysis/LoopAccessAnalysis.h index e39c371b41ec5..ca01db664207f 100644 --- a/llvm/include/llvm/Analysis/LoopAccessAnalysis.h +++ b/llvm/include/llvm/Analysis/LoopAccessAnalysis.h @@ -435,8 +435,10 @@ class RuntimePointerChecking { /// Reset the state of the pointer runtime information. void reset() { Need = false; + AlwaysFalse = false; Pointers.clear(); Checks.clear(); + CheckingGroups.clear(); } /// Insert a pointer and calculate the start and end SCEVs. @@ -493,6 +495,8 @@ class RuntimePointerChecking { /// This flag indicates if we need to add the runtime check. bool Need = false; + bool AlwaysFalse = false; + /// Information about the pointers that may require checking. SmallVector Pointers; diff --git a/llvm/include/llvm/Analysis/ScalarEvolution.h b/llvm/include/llvm/Analysis/ScalarEvolution.h index 5828cc156cc78..7e5fbb8287e14 100644 --- a/llvm/include/llvm/Analysis/ScalarEvolution.h +++ b/llvm/include/llvm/Analysis/ScalarEvolution.h @@ -1346,6 +1346,12 @@ class ScalarEvolution { } }; + void setExprScope(const Loop *L); + + void clearExprScope(); + + bool isScopedExpr(const SCEV *S); + private: /// A CallbackVH to arrange for ScalarEvolution to be notified whenever a /// Value is deleted. @@ -1435,6 +1441,14 @@ class ScalarEvolution { /// Memoized values for the getConstantMultiple DenseMap ConstantMultipleCache; + /// When not nullptr, this indicates the scope for which an expression needs + /// to be valid for. This allows creation of SCEV expressions that only need + /// to be valid in a specific loop, allowing to use more specific no-wrap + /// flags. + const Loop *ExprScope = nullptr; + + SmallVector ScopedExprs; + /// Return the Value set from which the SCEV expr is generated. ArrayRef getSCEVValues(const SCEV *S); diff --git a/llvm/lib/Analysis/LoopAccessAnalysis.cpp b/llvm/lib/Analysis/LoopAccessAnalysis.cpp index b0d29e2409f76..4126bc092d4cb 100644 --- a/llvm/lib/Analysis/LoopAccessAnalysis.cpp +++ b/llvm/lib/Analysis/LoopAccessAnalysis.cpp @@ -17,6 +17,7 @@ #include "llvm/ADT/EquivalenceClasses.h" #include "llvm/ADT/PointerIntPair.h" #include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/ScopeExit.h" #include "llvm/ADT/SetVector.h" #include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/SmallSet.h" @@ -208,7 +209,8 @@ void RuntimePointerChecking::insert(Loop *Lp, Value *Ptr, const SCEV *PtrExpr, PredicatedScalarEvolution &PSE, bool NeedsFreeze) { ScalarEvolution *SE = PSE.getSE(); - + SE->setExprScope(Lp); + auto ClearOnExit = make_scope_exit([SE]() { SE->clearExprScope(); }); const SCEV *ScStart; const SCEV *ScEnd; @@ -222,6 +224,10 @@ void RuntimePointerChecking::insert(Loop *Lp, Value *Ptr, const SCEV *PtrExpr, ScStart = AR->getStart(); ScEnd = AR->evaluateAtIteration(Ex, *SE); const SCEV *Step = AR->getStepRecurrence(*SE); + if (AR->getNoWrapFlags(SCEV::FlagNUW) && SE->isScopedExpr(ScEnd)) { + if (auto *Comm = dyn_cast(ScEnd)) + const_cast(Comm)->setNoWrapFlags(SCEV::FlagNUW); + } // For expressions with negative step, the upper bound is ScStart and the // lower bound is ScEnd. @@ -243,7 +249,13 @@ void RuntimePointerChecking::insert(Loop *Lp, Value *Ptr, const SCEV *PtrExpr, auto &DL = Lp->getHeader()->getModule()->getDataLayout(); Type *IdxTy = DL.getIndexType(Ptr->getType()); const SCEV *EltSizeSCEV = SE->getStoreSizeOfExpr(IdxTy, AccessTy); - ScEnd = SE->getAddExpr(ScEnd, EltSizeSCEV); + // TODO: this computes one-past-the-end. ScEnd + EltSizeSCEV - 1 is the last + // accessed byte. Not entirely sure if one-past-the-end must also not wrap? If + // it does, could compute and use last accessed byte instead. + if (SE->isScopedExpr(ScEnd)) + ScEnd = SE->getAddExpr(ScEnd, EltSizeSCEV, SCEV::FlagNUW); + else + ScEnd = SE->getAddExpr(ScEnd, EltSizeSCEV, SCEV::FlagNUW); Pointers.emplace_back(Ptr, ScStart, ScEnd, WritePtr, DepSetId, ASId, PtrExpr, NeedsFreeze); @@ -378,6 +390,11 @@ SmallVector RuntimePointerChecking::generateChecks() { if (needsChecking(CGI, CGJ)) { tryToCreateDiffCheck(CGI, CGJ); Checks.push_back(std::make_pair(&CGI, &CGJ)); + if (SE->isKnownPredicate(CmpInst::ICMP_UGT, CGI.High, CGJ.Low) && + SE->isKnownPredicate(CmpInst::ICMP_ULE, CGI.Low, CGJ.High)) { + AlwaysFalse = true; + return {}; + } } } } @@ -1273,6 +1290,7 @@ bool AccessAnalysis::canCheckPtrAtRT(RuntimePointerChecking &RtCheck, // If we can do run-time checks, but there are no checks, no runtime checks // are needed. This can happen when all pointers point to the same underlying // object for example. + CanDoRT &= !RtCheck.AlwaysFalse; RtCheck.Need = CanDoRT ? RtCheck.getNumberOfChecks() != 0 : MayNeedRTCheck; bool CanDoRTIfNeeded = !RtCheck.Need || CanDoRT; diff --git a/llvm/lib/Analysis/ScalarEvolution.cpp b/llvm/lib/Analysis/ScalarEvolution.cpp index 93f885c5d5ad8..9916714b2854c 100644 --- a/llvm/lib/Analysis/ScalarEvolution.cpp +++ b/llvm/lib/Analysis/ScalarEvolution.cpp @@ -2981,6 +2981,26 @@ const SCEV *ScalarEvolution::getAddExpr(SmallVectorImpl &Ops, return getOrCreateAddExpr(Ops, ComputeFlags(Ops)); } +void ScalarEvolution::setExprScope(const Loop *L) { + assert(!ExprScope && "cannot overwrite existing expression scope"); + ExprScope = L; +} + +void ScalarEvolution::clearExprScope() { ExprScope = nullptr; } + +bool ScalarEvolution::isScopedExpr(const SCEV *S) { + if (!ExprScope || !isa(S)) + return false; + + FoldingSetNodeID ID; + ID.AddInteger(S->getSCEVType()); + for (const SCEV *Op : S->operands()) + ID.AddPointer(Op); + ID.AddPointer(ExprScope); + void *IP = nullptr; + return UniqueSCEVs.FindNodeOrInsertPos(ID, IP); +} + const SCEV * ScalarEvolution::getOrCreateAddExpr(ArrayRef Ops, SCEV::NoWrapFlags Flags) { @@ -2988,6 +3008,8 @@ ScalarEvolution::getOrCreateAddExpr(ArrayRef Ops, ID.AddInteger(scAddExpr); for (const SCEV *Op : Ops) ID.AddPointer(Op); + if (ExprScope) + ID.AddPointer(ExprScope); void *IP = nullptr; SCEVAddExpr *S = static_cast(UniqueSCEVs.FindNodeOrInsertPos(ID, IP)); @@ -3034,6 +3056,8 @@ ScalarEvolution::getOrCreateMulExpr(ArrayRef Ops, ID.AddInteger(scMulExpr); for (const SCEV *Op : Ops) ID.AddPointer(Op); + if (ExprScope) + ID.AddPointer(ExprScope); void *IP = nullptr; SCEVMulExpr *S = static_cast(UniqueSCEVs.FindNodeOrInsertPos(ID, IP)); @@ -14746,12 +14770,15 @@ PredicatedScalarEvolution::PredicatedScalarEvolution(ScalarEvolution &SE, void ScalarEvolution::registerUser(const SCEV *User, ArrayRef Ops) { - for (const auto *Op : Ops) + for (const auto *Op : Ops) { // We do not expect that forgetting cached data for SCEVConstants will ever // open any prospects for sharpening or introduce any correctness issues, // so we don't bother storing their dependencies. if (!isa(Op)) SCEVUsers[Op].insert(User); + assert((ExprScope || !isScopedExpr(Op)) && + "Non-scoped expression cannot have scoped operands!"); + } } const SCEV *PredicatedScalarEvolution::getSCEV(Value *V) { diff --git a/llvm/test/Analysis/LoopAccessAnalysis/forked-pointers.ll b/llvm/test/Analysis/LoopAccessAnalysis/forked-pointers.ll index cd388b4ee87f2..a61c6dcc7af4d 100644 --- a/llvm/test/Analysis/LoopAccessAnalysis/forked-pointers.ll +++ b/llvm/test/Analysis/LoopAccessAnalysis/forked-pointers.ll @@ -24,7 +24,7 @@ define void @forked_ptrs_simple(ptr nocapture readonly %Base1, ptr nocapture rea ; CHECK-NEXT: %select = select i1 %cmp, ptr %gep.1, ptr %gep.2 ; CHECK-NEXT: Grouped accesses: ; CHECK-NEXT: Group [[GRP1]]: -; CHECK-NEXT: (Low: %Dest High: (400 + %Dest)) +; CHECK-NEXT: (Low: %Dest High: (400 + %Dest)) ; CHECK-NEXT: Member: {%Dest,+,4}<%loop> ; CHECK-NEXT: Member: {%Dest,+,4}<%loop> ; CHECK-NEXT: Group [[GRP2]]: @@ -58,7 +58,7 @@ define void @forked_ptrs_simple(ptr nocapture readonly %Base1, ptr nocapture rea ; RECURSE-NEXT: %select = select i1 %cmp, ptr %gep.1, ptr %gep.2 ; RECURSE-NEXT: Grouped accesses: ; RECURSE-NEXT: Group [[GRP4]]: -; RECURSE-NEXT: (Low: %Dest High: (400 + %Dest)) +; RECURSE-NEXT: (Low: %Dest High: (400 + %Dest)) ; RECURSE-NEXT: Member: {%Dest,+,4}<%loop> ; RECURSE-NEXT: Member: {%Dest,+,4}<%loop> ; RECURSE-NEXT: Group [[GRP5]]: @@ -132,10 +132,10 @@ define dso_local void @forked_ptrs_different_base_same_offset(ptr nocapture read ; CHECK-NEXT: %.sink.in = getelementptr inbounds float, ptr %spec.select, i64 %indvars.iv ; CHECK-NEXT: Grouped accesses: ; CHECK-NEXT: Group [[GRP7]]: -; CHECK-NEXT: (Low: %Dest High: (400 + %Dest)) +; CHECK-NEXT: (Low: %Dest High: (400 + %Dest)) ; CHECK-NEXT: Member: {%Dest,+,4}<%for.body> ; CHECK-NEXT: Group [[GRP8]]: -; CHECK-NEXT: (Low: %Preds High: (400 + %Preds)) +; CHECK-NEXT: (Low: %Preds High: (400 + %Preds)) ; CHECK-NEXT: Member: {%Preds,+,4}<%for.body> ; CHECK-NEXT: Group [[GRP9]]: ; CHECK-NEXT: (Low: %Base2 High: (400 + %Base2)) @@ -171,10 +171,10 @@ define dso_local void @forked_ptrs_different_base_same_offset(ptr nocapture read ; RECURSE-NEXT: %.sink.in = getelementptr inbounds float, ptr %spec.select, i64 %indvars.iv ; RECURSE-NEXT: Grouped accesses: ; RECURSE-NEXT: Group [[GRP11]]: -; RECURSE-NEXT: (Low: %Dest High: (400 + %Dest)) +; RECURSE-NEXT: (Low: %Dest High: (400 + %Dest)) ; RECURSE-NEXT: Member: {%Dest,+,4}<%for.body> ; RECURSE-NEXT: Group [[GRP12]]: -; RECURSE-NEXT: (Low: %Preds High: (400 + %Preds)) +; RECURSE-NEXT: (Low: %Preds High: (400 + %Preds)) ; RECURSE-NEXT: Member: {%Preds,+,4}<%for.body> ; RECURSE-NEXT: Group [[GRP13]]: ; RECURSE-NEXT: (Low: %Base2 High: (400 + %Base2)) @@ -232,10 +232,10 @@ define dso_local void @forked_ptrs_different_base_same_offset_64b(ptr nocapture ; CHECK-NEXT: %.sink.in = getelementptr inbounds double, ptr %spec.select, i64 %indvars.iv ; CHECK-NEXT: Grouped accesses: ; CHECK-NEXT: Group [[GRP15]]: -; CHECK-NEXT: (Low: %Dest High: (800 + %Dest)) +; CHECK-NEXT: (Low: %Dest High: (800 + %Dest)) ; CHECK-NEXT: Member: {%Dest,+,8}<%for.body> ; CHECK-NEXT: Group [[GRP16]]: -; CHECK-NEXT: (Low: %Preds High: (400 + %Preds)) +; CHECK-NEXT: (Low: %Preds High: (400 + %Preds)) ; CHECK-NEXT: Member: {%Preds,+,4}<%for.body> ; CHECK-NEXT: Group [[GRP17]]: ; CHECK-NEXT: (Low: %Base2 High: (800 + %Base2)) @@ -271,10 +271,10 @@ define dso_local void @forked_ptrs_different_base_same_offset_64b(ptr nocapture ; RECURSE-NEXT: %.sink.in = getelementptr inbounds double, ptr %spec.select, i64 %indvars.iv ; RECURSE-NEXT: Grouped accesses: ; RECURSE-NEXT: Group [[GRP19]]: -; RECURSE-NEXT: (Low: %Dest High: (800 + %Dest)) +; RECURSE-NEXT: (Low: %Dest High: (800 + %Dest)) ; RECURSE-NEXT: Member: {%Dest,+,8}<%for.body> ; RECURSE-NEXT: Group [[GRP20]]: -; RECURSE-NEXT: (Low: %Preds High: (400 + %Preds)) +; RECURSE-NEXT: (Low: %Preds High: (400 + %Preds)) ; RECURSE-NEXT: Member: {%Preds,+,4}<%for.body> ; RECURSE-NEXT: Group [[GRP21]]: ; RECURSE-NEXT: (Low: %Base2 High: (800 + %Base2)) @@ -332,10 +332,10 @@ define dso_local void @forked_ptrs_different_base_same_offset_23b(ptr nocapture ; CHECK-NEXT: %.sink.in = getelementptr inbounds i23, ptr %spec.select, i64 %indvars.iv ; CHECK-NEXT: Grouped accesses: ; CHECK-NEXT: Group [[GRP23]]: -; CHECK-NEXT: (Low: %Dest High: (399 + %Dest)) +; CHECK-NEXT: (Low: %Dest High: (399 + %Dest)) ; CHECK-NEXT: Member: {%Dest,+,4}<%for.body> ; CHECK-NEXT: Group [[GRP24]]: -; CHECK-NEXT: (Low: %Preds High: (400 + %Preds)) +; CHECK-NEXT: (Low: %Preds High: (400 + %Preds)) ; CHECK-NEXT: Member: {%Preds,+,4}<%for.body> ; CHECK-NEXT: Group [[GRP25]]: ; CHECK-NEXT: (Low: %Base2 High: (399 + %Base2)) @@ -371,10 +371,10 @@ define dso_local void @forked_ptrs_different_base_same_offset_23b(ptr nocapture ; RECURSE-NEXT: %.sink.in = getelementptr inbounds i23, ptr %spec.select, i64 %indvars.iv ; RECURSE-NEXT: Grouped accesses: ; RECURSE-NEXT: Group [[GRP27]]: -; RECURSE-NEXT: (Low: %Dest High: (399 + %Dest)) +; RECURSE-NEXT: (Low: %Dest High: (399 + %Dest)) ; RECURSE-NEXT: Member: {%Dest,+,4}<%for.body> ; RECURSE-NEXT: Group [[GRP28]]: -; RECURSE-NEXT: (Low: %Preds High: (400 + %Preds)) +; RECURSE-NEXT: (Low: %Preds High: (400 + %Preds)) ; RECURSE-NEXT: Member: {%Preds,+,4}<%for.body> ; RECURSE-NEXT: Group [[GRP29]]: ; RECURSE-NEXT: (Low: %Base2 High: (399 + %Base2)) @@ -432,10 +432,10 @@ define dso_local void @forked_ptrs_different_base_same_offset_6b(ptr nocapture r ; CHECK-NEXT: %.sink.in = getelementptr inbounds i6, ptr %spec.select, i64 %indvars.iv ; CHECK-NEXT: Grouped accesses: ; CHECK-NEXT: Group [[GRP31]]: -; CHECK-NEXT: (Low: %Dest High: (100 + %Dest)) +; CHECK-NEXT: (Low: %Dest High: (100 + %Dest)) ; CHECK-NEXT: Member: {%Dest,+,1}<%for.body> ; CHECK-NEXT: Group [[GRP32]]: -; CHECK-NEXT: (Low: %Preds High: (400 + %Preds)) +; CHECK-NEXT: (Low: %Preds High: (400 + %Preds)) ; CHECK-NEXT: Member: {%Preds,+,4}<%for.body> ; CHECK-NEXT: Group [[GRP33]]: ; CHECK-NEXT: (Low: %Base2 High: (100 + %Base2)) @@ -471,10 +471,10 @@ define dso_local void @forked_ptrs_different_base_same_offset_6b(ptr nocapture r ; RECURSE-NEXT: %.sink.in = getelementptr inbounds i6, ptr %spec.select, i64 %indvars.iv ; RECURSE-NEXT: Grouped accesses: ; RECURSE-NEXT: Group [[GRP35]]: -; RECURSE-NEXT: (Low: %Dest High: (100 + %Dest)) +; RECURSE-NEXT: (Low: %Dest High: (100 + %Dest)) ; RECURSE-NEXT: Member: {%Dest,+,1}<%for.body> ; RECURSE-NEXT: Group [[GRP36]]: -; RECURSE-NEXT: (Low: %Preds High: (400 + %Preds)) +; RECURSE-NEXT: (Low: %Preds High: (400 + %Preds)) ; RECURSE-NEXT: Member: {%Preds,+,4}<%for.body> ; RECURSE-NEXT: Group [[GRP37]]: ; RECURSE-NEXT: (Low: %Base2 High: (100 + %Base2)) @@ -535,7 +535,7 @@ define dso_local void @forked_ptrs_different_base_same_offset_possible_poison(pt ; CHECK-NEXT: (Low: %Dest High: (400 + %Dest)) ; CHECK-NEXT: Member: {%Dest,+,4}<%for.body> ; CHECK-NEXT: Group [[GRP40]]: -; CHECK-NEXT: (Low: %Preds High: (400 + %Preds)) +; CHECK-NEXT: (Low: %Preds High: (400 + %Preds)) ; CHECK-NEXT: Member: {%Preds,+,4}<%for.body> ; CHECK-NEXT: Group [[GRP41]]: ; CHECK-NEXT: (Low: %Base2 High: (400 + %Base2)) @@ -574,7 +574,7 @@ define dso_local void @forked_ptrs_different_base_same_offset_possible_poison(pt ; RECURSE-NEXT: (Low: %Dest High: (400 + %Dest)) ; RECURSE-NEXT: Member: {%Dest,+,4}<%for.body> ; RECURSE-NEXT: Group [[GRP44]]: -; RECURSE-NEXT: (Low: %Preds High: (400 + %Preds)) +; RECURSE-NEXT: (Low: %Preds High: (400 + %Preds)) ; RECURSE-NEXT: Member: {%Preds,+,4}<%for.body> ; RECURSE-NEXT: Group [[GRP45]]: ; RECURSE-NEXT: (Low: %Base2 High: (400 + %Base2)) @@ -696,10 +696,10 @@ define dso_local void @forked_ptrs_add_to_offset(ptr nocapture readonly %Base, p ; CHECK-NEXT: %arrayidx3 = getelementptr inbounds float, ptr %Base, i64 %offset ; CHECK-NEXT: Grouped accesses: ; CHECK-NEXT: Group [[GRP47]]: -; CHECK-NEXT: (Low: %Dest High: (400 + %Dest)) +; CHECK-NEXT: (Low: %Dest High: (400 + %Dest)) ; CHECK-NEXT: Member: {%Dest,+,4}<%for.body> ; CHECK-NEXT: Group [[GRP48]]: -; CHECK-NEXT: (Low: %Preds High: (400 + %Preds)) +; CHECK-NEXT: (Low: %Preds High: (400 + %Preds)) ; CHECK-NEXT: Member: {%Preds,+,4}<%for.body> ; CHECK-NEXT: Group [[GRP49]]: ; CHECK-NEXT: (Low: ((4 * %extra_offset) + %Base) High: (404 + (4 * %extra_offset) + %Base)) @@ -764,10 +764,10 @@ define dso_local void @forked_ptrs_sub_from_offset(ptr nocapture readonly %Base, ; CHECK-NEXT: %arrayidx3 = getelementptr inbounds float, ptr %Base, i64 %offset ; CHECK-NEXT: Grouped accesses: ; CHECK-NEXT: Group [[GRP50]]: -; CHECK-NEXT: (Low: %Dest High: (400 + %Dest)) +; CHECK-NEXT: (Low: %Dest High: (400 + %Dest)) ; CHECK-NEXT: Member: {%Dest,+,4}<%for.body> ; CHECK-NEXT: Group [[GRP51]]: -; CHECK-NEXT: (Low: %Preds High: (400 + %Preds)) +; CHECK-NEXT: (Low: %Preds High: (400 + %Preds)) ; CHECK-NEXT: Member: {%Preds,+,4}<%for.body> ; CHECK-NEXT: Group [[GRP52]]: ; CHECK-NEXT: (Low: ((-4 * %extra_offset) + %Base) High: (404 + (-4 * %extra_offset) + %Base)) @@ -832,10 +832,10 @@ define dso_local void @forked_ptrs_add_sub_offset(ptr nocapture readonly %Base, ; CHECK-NEXT: %arrayidx3 = getelementptr inbounds float, ptr %Base, i64 %offset ; CHECK-NEXT: Grouped accesses: ; CHECK-NEXT: Group [[GRP53]]: -; CHECK-NEXT: (Low: %Dest High: (400 + %Dest)) +; CHECK-NEXT: (Low: %Dest High: (400 + %Dest)) ; CHECK-NEXT: Member: {%Dest,+,4}<%for.body> ; CHECK-NEXT: Group [[GRP54]]: -; CHECK-NEXT: (Low: %Preds High: (400 + %Preds)) +; CHECK-NEXT: (Low: %Preds High: (400 + %Preds)) ; CHECK-NEXT: Member: {%Preds,+,4}<%for.body> ; CHECK-NEXT: Group [[GRP55]]: ; CHECK-NEXT: (Low: ((4 * %to_add) + (-4 * %to_sub) + %Base) High: (404 + (4 * %to_add) + (-4 * %to_sub) + %Base)) @@ -1256,7 +1256,7 @@ define void @sc_add_expr_ice(ptr %Base1, ptr %Base2, i64 %N) { ; CHECK-NEXT: %fptr = getelementptr inbounds double, ptr %Base2, i64 %sel ; CHECK-NEXT: Grouped accesses: ; CHECK-NEXT: Group [[GRP56]]: -; CHECK-NEXT: (Low: %Base1 High: (8 + %Base1)) +; CHECK-NEXT: (Low: %Base1 High: (8 + %Base1)) ; CHECK-NEXT: Member: %Base1 ; CHECK-NEXT: Group [[GRP57]]: ; CHECK-NEXT: (Low: %Base2 High: ((8 * %N) + %Base2)) @@ -1283,7 +1283,7 @@ define void @sc_add_expr_ice(ptr %Base1, ptr %Base2, i64 %N) { ; RECURSE-NEXT: %fptr = getelementptr inbounds double, ptr %Base2, i64 %sel ; RECURSE-NEXT: Grouped accesses: ; RECURSE-NEXT: Group [[GRP58]]: -; RECURSE-NEXT: (Low: %Base1 High: (8 + %Base1)) +; RECURSE-NEXT: (Low: %Base1 High: (8 + %Base1)) ; RECURSE-NEXT: Member: %Base1 ; RECURSE-NEXT: Group [[GRP59]]: ; RECURSE-NEXT: (Low: %Base2 High: ((8 * %N) + %Base2)) @@ -1351,7 +1351,7 @@ define void @forked_ptrs_with_different_base(ptr nocapture readonly %Preds, ptr ; CHECK-NEXT: (Low: %2 High: (63992 + %2)) ; CHECK-NEXT: Member: {%2,+,8}<%for.body> ; CHECK-NEXT: Group [[GRP61]]: -; CHECK-NEXT: (Low: %Preds High: (31996 + %Preds)) +; CHECK-NEXT: (Low: %Preds High: (31996 + %Preds)) ; CHECK-NEXT: Member: {%Preds,+,4}<%for.body> ; CHECK-NEXT: Group [[GRP62]]: ; CHECK-NEXT: (Low: %0 High: (63992 + %0)) @@ -1395,7 +1395,7 @@ define void @forked_ptrs_with_different_base(ptr nocapture readonly %Preds, ptr ; RECURSE-NEXT: (Low: %2 High: (63992 + %2)) ; RECURSE-NEXT: Member: {%2,+,8}<%for.body> ; RECURSE-NEXT: Group [[GRP65]]: -; RECURSE-NEXT: (Low: %Preds High: (31996 + %Preds)) +; RECURSE-NEXT: (Low: %Preds High: (31996 + %Preds)) ; RECURSE-NEXT: Member: {%Preds,+,4}<%for.body> ; RECURSE-NEXT: Group [[GRP66]]: ; RECURSE-NEXT: (Low: %0 High: (63992 + %0)) diff --git a/llvm/test/Analysis/LoopAccessAnalysis/loops-with-indirect-reads-and-writes.ll b/llvm/test/Analysis/LoopAccessAnalysis/loops-with-indirect-reads-and-writes.ll index fd4f417e57b63..02c5fd1adc5fb 100644 --- a/llvm/test/Analysis/LoopAccessAnalysis/loops-with-indirect-reads-and-writes.ll +++ b/llvm/test/Analysis/LoopAccessAnalysis/loops-with-indirect-reads-and-writes.ll @@ -101,7 +101,7 @@ define void @test_indirect_read_loop_also_modifies_pointer_array(ptr noundef %ar ; CHECK-NEXT: (Low: {(64 + %arr),+,64}<%loop.1> High: {(8064 + %arr),+,64}<%loop.1>) ; CHECK-NEXT: Member: {{\{\{}}(64 + %arr),+,64}<%loop.1>,+,8}<%loop.2> ; CHECK-NEXT: Group [[GRP2]]: -; CHECK-NEXT: (Low: %arr High: (8000 + %arr)) +; CHECK-NEXT: (Low: %arr High: (8000 + %arr)) ; CHECK-NEXT: Member: {%arr,+,8}<%loop.2> ; CHECK-EMPTY: ; CHECK-NEXT: Non vectorizable stores to invariant address were not found in loop. @@ -169,7 +169,7 @@ define void @test_indirect_write_loop_also_modifies_pointer_array(ptr noundef %a ; CHECK-NEXT: (Low: {(64 + %arr),+,64}<%loop.1> High: {(8064 + %arr),+,64}<%loop.1>) ; CHECK-NEXT: Member: {{\{\{}}(64 + %arr),+,64}<%loop.1>,+,8}<%loop.2> ; CHECK-NEXT: Group [[GRP4]]: -; CHECK-NEXT: (Low: %arr High: (8000 + %arr)) +; CHECK-NEXT: (Low: %arr High: (8000 + %arr)) ; CHECK-NEXT: Member: {%arr,+,8}<%loop.2> ; CHECK-EMPTY: ; CHECK-NEXT: Non vectorizable stores to invariant address were not found in loop. diff --git a/llvm/test/Analysis/LoopAccessAnalysis/memcheck-off-by-one-error.ll b/llvm/test/Analysis/LoopAccessAnalysis/memcheck-off-by-one-error.ll index 4a9f004cb44a7..0cd83da79caed 100644 --- a/llvm/test/Analysis/LoopAccessAnalysis/memcheck-off-by-one-error.ll +++ b/llvm/test/Analysis/LoopAccessAnalysis/memcheck-off-by-one-error.ll @@ -19,8 +19,8 @@ ; store a value at *%op touched memory under *%src. ;CHECK: function 'fastCopy': -;CHECK: (Low: %op High: (32 + %op)) -;CHECK: (Low: %src High: (32 + %src)) +;CHECK: (Low: %op High: (32 + %op)) +;CHECK: (Low: %src High: (32 + %src)) define void @fastCopy(ptr nocapture readonly %src, ptr nocapture %op) { entry: diff --git a/llvm/test/Analysis/LoopAccessAnalysis/memcheck-store-vs-alloc-size.ll b/llvm/test/Analysis/LoopAccessAnalysis/memcheck-store-vs-alloc-size.ll index 6bb1d21b90809..59f3dcd6b6137 100644 --- a/llvm/test/Analysis/LoopAccessAnalysis/memcheck-store-vs-alloc-size.ll +++ b/llvm/test/Analysis/LoopAccessAnalysis/memcheck-store-vs-alloc-size.ll @@ -6,8 +6,8 @@ ; Here, we use i19 instead of i64 because it has a different alloc size to its store size. ;CHECK: function 'fastCopy': -;CHECK: (Low: %op High: (27 + %op)) -;CHECK: (Low: %src High: (27 + %src)) +;CHECK: (Low: %op High: (27 + %op)) +;CHECK: (Low: %src High: (27 + %src)) define void @fastCopy(ptr nocapture readonly %src, ptr nocapture %op) { entry: diff --git a/llvm/test/Analysis/LoopAccessAnalysis/number-of-memchecks.ll b/llvm/test/Analysis/LoopAccessAnalysis/number-of-memchecks.ll index d4287612399ba..ea968113126fa 100644 --- a/llvm/test/Analysis/LoopAccessAnalysis/number-of-memchecks.ll +++ b/llvm/test/Analysis/LoopAccessAnalysis/number-of-memchecks.ll @@ -95,15 +95,15 @@ for.end: ; preds = %for.body ; CHECK-NEXT: %arrayidxB = getelementptr inbounds i16, ptr %b, i64 %ind ; CHECK-NEXT: Grouped accesses: ; CHECK-NEXT: Group {{.*}}[[ZERO]]: -; CHECK-NEXT: (Low: %c High: (80 + %c)) +; CHECK-NEXT: (Low: %c High: (80 + %c)) ; CHECK-NEXT: Member: {(2 + %c),+,4} ; CHECK-NEXT: Member: {%c,+,4} ; CHECK-NEXT: Group {{.*}}[[ONE]]: -; CHECK-NEXT: (Low: %a High: (42 + %a)) +; CHECK-NEXT: (Low: %a High: (42 + %a)) ; CHECK-NEXT: Member: {(2 + %a),+,2} ; CHECK-NEXT: Member: {%a,+,2} ; CHECK-NEXT: Group {{.*}}[[TWO]]: -; CHECK-NEXT: (Low: %b High: (40 + %b)) +; CHECK-NEXT: (Low: %b High: (40 + %b)) ; CHECK-NEXT: Member: {%b,+,2} define void @testg(ptr %a, @@ -167,7 +167,7 @@ for.end: ; preds = %for.body ; CHECK-NEXT: %arrayidxB = getelementptr i16, ptr %b, i64 %ind ; CHECK-NEXT: Grouped accesses: ; CHECK-NEXT: Group {{.*}}[[ZERO]]: -; CHECK-NEXT: (Low: %c High: (80 + %c)) +; CHECK-NEXT: (Low: %c High: (80 + %c)) ; CHECK-NEXT: Member: {(2 + %c),+,4} ; CHECK-NEXT: Member: {%c,+,4} ; CHECK-NEXT: Group {{.*}}[[ONE]]: diff --git a/llvm/test/Analysis/LoopAccessAnalysis/pointer-phis.ll b/llvm/test/Analysis/LoopAccessAnalysis/pointer-phis.ll index a214451bfd3fd..2f24aacfafb90 100644 --- a/llvm/test/Analysis/LoopAccessAnalysis/pointer-phis.ll +++ b/llvm/test/Analysis/LoopAccessAnalysis/pointer-phis.ll @@ -277,14 +277,6 @@ define i32 @store_with_pointer_phi_incoming_phi(ptr %A, ptr %B, ptr %C, i1 %c.0, ; CHECK-NEXT: %arrayidx = getelementptr inbounds double, ptr %A, i64 %iv ; CHECK-NEXT: ptr %A ; CHECK-NEXT: Grouped accesses: -; CHECK-NEXT: Group [[GRP4]]: -; CHECK-NEXT: (Low: %C High: (8 + %C)) -; CHECK-NEXT: Member: %C -; CHECK-NEXT: Group [[GRP5]]: -; CHECK-NEXT: (Low: %B High: (8 + %B)) -; CHECK-NEXT: Member: %B -; CHECK-NEXT: Group [[GRP6]]: -; CHECK-NEXT: (Low: %A High: (256000 + %A)) ; CHECK-NEXT: Member: {%A,+,8}<%loop.header> ; CHECK-NEXT: Member: %A ; CHECK-EMPTY: @@ -360,7 +352,6 @@ define i32 @store_with_pointer_phi_incoming_phi_irreducible_cycle(ptr %A, ptr %B ; CHECK-NEXT: %arrayidx = getelementptr inbounds double, ptr %A, i64 %iv ; CHECK-NEXT: ptr %A ; CHECK-NEXT: Grouped accesses: -; CHECK-NEXT: Group [[GRP7]]: ; CHECK-NEXT: (Low: %C High: (8 + %C)) ; CHECK-NEXT: Member: %C ; CHECK-NEXT: Group [[GRP8]]: @@ -368,6 +359,16 @@ define i32 @store_with_pointer_phi_incoming_phi_irreducible_cycle(ptr %A, ptr %B ; CHECK-NEXT: Member: %B ; CHECK-NEXT: Group [[GRP9]]: ; CHECK-NEXT: (Low: %A High: (256000 + %A)) +======= +; CHECK-NEXT: Group [[GRP7]]: +; CHECK-NEXT: (Low: %C High: (8 + %C)) +; CHECK-NEXT: Member: %C +; CHECK-NEXT: Group [[GRP8]]: +; CHECK-NEXT: (Low: %B High: (8 + %B)) +; CHECK-NEXT: Member: %B +; CHECK-NEXT: Group [[GRP9]]: +; CHECK-NEXT: (Low: %A High: (256000 + %A)) +>>>>>>> b250dd10a54f ([SCEV,LAA] Introduce scoped SCEV, use in LAA computations (WIP).) ; CHECK-NEXT: Member: {%A,+,8}<%loop.header> ; CHECK-NEXT: Member: %A ; CHECK-EMPTY: @@ -532,7 +533,6 @@ define void @phi_load_store_memdep_check(i1 %c, ptr %A, ptr %B, ptr %C) { ; CHECK-NEXT: ptr %B ; CHECK-NEXT: ptr %B ; CHECK-NEXT: Grouped accesses: -; CHECK-NEXT: Group [[GRP10]]: ; CHECK-NEXT: (Low: %A High: (2 + %A)) ; CHECK-NEXT: Member: %A ; CHECK-NEXT: Member: %A @@ -542,6 +542,18 @@ define void @phi_load_store_memdep_check(i1 %c, ptr %A, ptr %B, ptr %C) { ; CHECK-NEXT: Member: %C ; CHECK-NEXT: Group [[GRP12]]: ; CHECK-NEXT: (Low: %B High: (2 + %B)) +======= +; CHECK-NEXT: Group [[GRP10]]: +; CHECK-NEXT: (Low: %A High: (2 + %A)) +; CHECK-NEXT: Member: %A +; CHECK-NEXT: Member: %A +; CHECK-NEXT: Group [[GRP11]]: +; CHECK-NEXT: (Low: %C High: (2 + %C)) +; CHECK-NEXT: Member: %C +; CHECK-NEXT: Member: %C +; CHECK-NEXT: Group [[GRP12]]: +; CHECK-NEXT: (Low: %B High: (2 + %B)) +>>>>>>> b250dd10a54f ([SCEV,LAA] Introduce scoped SCEV, use in LAA computations (WIP).) ; CHECK-NEXT: Member: %B ; CHECK-NEXT: Member: %B ; CHECK-EMPTY: diff --git a/llvm/test/Analysis/LoopAccessAnalysis/positive-dependence-distance-different-access-sizes.ll b/llvm/test/Analysis/LoopAccessAnalysis/positive-dependence-distance-different-access-sizes.ll index 08e0bae7f05ba..9d68a860ff1a1 100644 --- a/llvm/test/Analysis/LoopAccessAnalysis/positive-dependence-distance-different-access-sizes.ll +++ b/llvm/test/Analysis/LoopAccessAnalysis/positive-dependence-distance-different-access-sizes.ll @@ -18,10 +18,10 @@ define void @test_distance_positive_independent_via_trip_count(ptr %A) { ; CHECK-NEXT: %gep.A = getelementptr inbounds i8, ptr %A, i64 %iv ; CHECK-NEXT: Grouped accesses: ; CHECK-NEXT: Group [[GRP1]]: -; CHECK-NEXT: (Low: (400 + %A) High: (804 + %A)) +; CHECK-NEXT: (Low: (400 + %A) High: (804 + %A)) ; CHECK-NEXT: Member: {(400 + %A),+,4}<%loop> ; CHECK-NEXT: Group [[GRP2]]: -; CHECK-NEXT: (Low: %A High: (101 + %A)) +; CHECK-NEXT: (Low: %A High: (101 + %A)) ; CHECK-NEXT: Member: {%A,+,1}<%loop> ; CHECK-EMPTY: ; CHECK-NEXT: Non vectorizable stores to invariant address were not found in loop. @@ -53,21 +53,10 @@ exit: define void @test_distance_positive_backwards(ptr %A) { ; CHECK-LABEL: 'test_distance_positive_backwards' ; CHECK-NEXT: loop: -; CHECK-NEXT: Memory dependences are safe with run-time checks +; CHECK-NEXT: Report: cannot check memory dependencies at runtime ; CHECK-NEXT: Dependences: ; CHECK-NEXT: Run-time memory checks: -; CHECK-NEXT: Check 0: -; CHECK-NEXT: Comparing group ([[GRP3:0x[0-9a-f]+]]): -; CHECK-NEXT: %gep.A.400 = getelementptr inbounds i32, ptr %A.1, i64 %iv -; CHECK-NEXT: Against group ([[GRP4:0x[0-9a-f]+]]): -; CHECK-NEXT: %gep.A = getelementptr inbounds i8, ptr %A, i64 %iv ; CHECK-NEXT: Grouped accesses: -; CHECK-NEXT: Group [[GRP3]]: -; CHECK-NEXT: (Low: (1 + %A) High: (405 + %A)) -; CHECK-NEXT: Member: {(1 + %A),+,4}<%loop> -; CHECK-NEXT: Group [[GRP4]]: -; CHECK-NEXT: (Low: %A High: (101 + %A)) -; CHECK-NEXT: Member: {%A,+,1}<%loop> ; CHECK-EMPTY: ; CHECK-NEXT: Non vectorizable stores to invariant address were not found in loop. ; CHECK-NEXT: SCEV assumptions: @@ -100,16 +89,16 @@ define void @test_distance_positive_via_assume(ptr %A, i64 %off) { ; CHECK-NEXT: Dependences: ; CHECK-NEXT: Run-time memory checks: ; CHECK-NEXT: Check 0: -; CHECK-NEXT: Comparing group ([[GRP5:0x[0-9a-f]+]]): +; CHECK-NEXT: Comparing group ([[GRP3:0x[0-9a-f]+]]): ; CHECK-NEXT: %gep.A.400 = getelementptr inbounds i32, ptr %A.off, i64 %iv -; CHECK-NEXT: Against group ([[GRP6:0x[0-9a-f]+]]): +; CHECK-NEXT: Against group ([[GRP4:0x[0-9a-f]+]]): ; CHECK-NEXT: %gep.A = getelementptr inbounds i8, ptr %A, i64 %iv ; CHECK-NEXT: Grouped accesses: -; CHECK-NEXT: Group [[GRP5]]: +; CHECK-NEXT: Group [[GRP3]]: ; CHECK-NEXT: (Low: (%off + %A) High: (404 + %off + %A)) ; CHECK-NEXT: Member: {(%off + %A),+,4}<%loop> -; CHECK-NEXT: Group [[GRP6]]: -; CHECK-NEXT: (Low: %A High: (101 + %A)) +; CHECK-NEXT: Group [[GRP4]]: +; CHECK-NEXT: (Low: %A High: (101 + %A)) ; CHECK-NEXT: Member: {%A,+,1}<%loop> ; CHECK-EMPTY: ; CHECK-NEXT: Non vectorizable stores to invariant address were not found in loop. diff --git a/llvm/test/Analysis/LoopAccessAnalysis/reverse-memcheck-bounds.ll b/llvm/test/Analysis/LoopAccessAnalysis/reverse-memcheck-bounds.ll index 1496e1b0be82b..ff7754e8e3fb9 100644 --- a/llvm/test/Analysis/LoopAccessAnalysis/reverse-memcheck-bounds.ll +++ b/llvm/test/Analysis/LoopAccessAnalysis/reverse-memcheck-bounds.ll @@ -15,7 +15,7 @@ target datalayout = "e-m:e-i64:64-i128:128-n32:64-S128" target triple = "aarch64" ; CHECK: function 'f': -; CHECK: (Low: (20000 + %a) High: (60004 + %a)) +; CHECK: (Low: (20000 + %a) High: (60004 + %a)) @B = common global ptr null, align 8 @A = common global ptr null, align 8 diff --git a/llvm/test/Analysis/LoopAccessAnalysis/scoped-scevs.ll b/llvm/test/Analysis/LoopAccessAnalysis/scoped-scevs.ll new file mode 100644 index 0000000000000..478a4bdb53978 --- /dev/null +++ b/llvm/test/Analysis/LoopAccessAnalysis/scoped-scevs.ll @@ -0,0 +1,189 @@ +; NOTE: Assertions have been autogenerated by utils/update_analyze_test_checks.py UTC_ARGS: --version 4 +; RUN: opt -passes='print,print' -disable-output %s 2>&1 | FileCheck --check-prefixes=LAA,SCOPED,AFTER %s +; RUN: opt -passes='print,print,print' -disable-output %s 2>&1 | FileCheck --check-prefixes=BEFORE,LAA,NOSCOPED,AFTER %s + +target datalayout = "e-m:o-i64:64-i128:128-n32:64-S128" + +declare void @use(ptr) + +; Check that scoped expressions created by LAA do not interfere with non-scoped +; SCEVs with the same operands. The tests first run print to +; populate the SCEV cache. They contain a GEP computing A+405, which is the end +; of the accessed range, before and/or after the loop. No nuw flags should be +; added to them in the second print output. + +define ptr @test_ptr_range_end_computed_before_and_after_loop(ptr %A) { +; BEFORE-LABEL: 'test_ptr_range_end_computed_before_and_after_loop' +; BEFORE-NEXT: Classifying expressions for: @test_ptr_range_end_computed_before_and_after_loop +; BEFORE: %x = getelementptr inbounds i8, ptr %A, i64 405 +; BEFORE-NEXT: --> (405 + %A) U: full-set S: full-set +; BEFORE: %y = getelementptr inbounds i8, ptr %A, i64 405 +; BEFORE-NEXT: --> (405 + %A) U: full-set S: full-set +; +; LAA-LABEL: 'test_ptr_range_end_computed_before_and_after_loop' +; LAA-NEXT: loop: +; LAA-NEXT: Memory dependences are safe with run-time checks +; LAA-NEXT: Dependences: +; LAA-NEXT: Run-time memory checks: +; LAA-NEXT: Check 0: +; LAA-NEXT: Comparing group ([[GRP1:0x[0-9a-f]+]]): +; LAA-NEXT: %gep.A.400 = getelementptr inbounds i32, ptr %A.1, i64 %iv +; LAA-NEXT: Against group ([[GRP2:0x[0-9a-f]+]]): +; LAA-NEXT: %gep.A = getelementptr inbounds i8, ptr %A, i64 %iv +; LAA-NEXT: Grouped accesses: +; LAA-NEXT: Group [[GRP1]]: +; LAA-NEXT: (Low: (1 + %A) High: (405 + %A)) +; LAA-NEXT: Member: {(1 + %A),+,4}<%loop> +; LAA-NEXT: Group [[GRP2]]: +; SCOPED-NEXT: (Low: %A High: (101 + %A)) +; NOSCOPED-NEXT: (Low: %A High: (101 + %A)) +; LAA-NEXT: Member: {%A,+,1}<%loop> +; LAA-EMPTY: +; LAA-NEXT: Non vectorizable stores to invariant address were not found in loop. +; LAA-NEXT: SCEV assumptions: +; LAA-EMPTY: +; LAA-NEXT: Expressions re-written: +; +; AFTER-LABEL: 'test_ptr_range_end_computed_before_and_after_loop' +; AFTER-NEXT: Classifying expressions for: @test_ptr_range_end_computed_before_and_after_loop +; AFTER: %x = getelementptr inbounds i8, ptr %A, i64 405 +; AFTER-NEXT: --> (405 + %A) U: full-set S: full-set +; AFTER: %y = getelementptr inbounds i8, ptr %A, i64 405 +; AFTER-NEXT: --> (405 + %A) U: full-set S: full-set +entry: + %A.1 = getelementptr inbounds i8, ptr %A, i64 1 + %x = getelementptr inbounds i8, ptr %A, i64 405 + call void @use(ptr %x) + br label %loop + +loop: + %iv = phi i64 [ 0, %entry ], [ %iv.next, %loop ] + %gep.A.400 = getelementptr inbounds i32, ptr %A.1, i64 %iv + %gep.A = getelementptr inbounds i8, ptr %A, i64 %iv + %l = load i8, ptr %gep.A, align 1 + %ext = zext i8 %l to i32 + store i32 %ext, ptr %gep.A.400, align 4 + %iv.next = add nuw nsw i64 %iv, 1 + %ec = icmp eq i64 %iv, 100 + br i1 %ec, label %exit, label %loop + +exit: + %y = getelementptr inbounds i8, ptr %A, i64 405 + ret ptr %y +} + +define void @test_ptr_range_end_computed_before_loop(ptr %A) { +; BEFORE-LABEL: 'test_ptr_range_end_computed_before_loop' +; BEFORE-NEXT: Classifying expressions for: @test_ptr_range_end_computed_before_loop +; BEFORE-NEXT: %A.1 = getelementptr inbounds i8, ptr %A, i64 1 +; BEFORE-NEXT: --> (1 + %A) U: full-set S: full-set +; BEFORE-NEXT: %x = getelementptr inbounds i8, ptr %A, i64 405 +; +; LAA-LABEL: 'test_ptr_range_end_computed_before_loop' +; LAA-NEXT: loop: +; LAA-NEXT: Memory dependences are safe with run-time checks +; LAA-NEXT: Dependences: +; LAA-NEXT: Run-time memory checks: +; LAA-NEXT: Check 0: +; LAA-NEXT: Comparing group ([[GRP3:0x[0-9a-f]+]]): +; LAA-NEXT: %gep.A.400 = getelementptr inbounds i32, ptr %A.1, i64 %iv +; LAA-NEXT: Against group ([[GRP4:0x[0-9a-f]+]]): +; LAA-NEXT: %gep.A = getelementptr inbounds i8, ptr %A, i64 %iv +; LAA-NEXT: Grouped accesses: +; LAA-NEXT: Group [[GRP3]]: +; LAA-NEXT: (Low: (1 + %A) High: (405 + %A)) +; LAA-NEXT: Member: {(1 + %A),+,4}<%loop> +; LAA-NEXT: Group [[GRP4]]: +; SCOPED-NEXT: (Low: %A High: (101 + %A)) +; NOSCOPED-NEXT: (Low: %A High: (101 + %A)) +; LAA-NEXT: Member: {%A,+,1}<%loop> +; LAA-EMPTY: +; LAA-NEXT: Non vectorizable stores to invariant address were not found in loop. +; LAA-NEXT: SCEV assumptions: +; LAA-EMPTY: +; LAA-NEXT: Expressions re-written: +; +; AFTER-LABEL: Classifying expressions for: @test_ptr_range_end_computed_before_loop +; AFTER-NEXT: %A.1 = getelementptr inbounds i8, ptr %A, i64 1 +; AFTER-NEXT: --> (1 + %A) U: full-set S: full-set +; AFTER-NEXT: %x = getelementptr inbounds i8, ptr %A, i64 405 +; +entry: + %A.1 = getelementptr inbounds i8, ptr %A, i64 1 + %x = getelementptr inbounds i8, ptr %A, i64 405 + call void @use(ptr %x) + br label %loop + +loop: + %iv = phi i64 [ 0, %entry ], [ %iv.next, %loop ] + %gep.A.400 = getelementptr inbounds i32, ptr %A.1, i64 %iv + %gep.A = getelementptr inbounds i8, ptr %A, i64 %iv + %l = load i8, ptr %gep.A, align 1 + %ext = zext i8 %l to i32 + store i32 %ext, ptr %gep.A.400, align 4 + %iv.next = add nuw nsw i64 %iv, 1 + %ec = icmp eq i64 %iv, 100 + br i1 %ec, label %exit, label %loop + +exit: + ret void +} + +define ptr @test_ptr_range_end_computed_after_loop(ptr %A) { +; BEFORE-LABEL: 'test_ptr_range_end_computed_after_loop' +; BEFORE-NEXT: Classifying expressions for: @test_ptr_range_end_computed_after_loop +; BEFORE: %y = getelementptr inbounds i8, ptr %A, i64 405 +; BEFORE-NEXT: --> (405 + %A) U: full-set S: full-set +; +; LAA-LABEL: 'test_ptr_range_end_computed_after_loop' +; LAA-NEXT: loop: +; SCOPED-NEXT: Report: cannot check memory dependencies at runtime +; SCOPED-NEXT: Dependences: +; SCOPED-NEXT: Run-time memory checks: +; SCOPED-NEXT: Grouped accesses: +; +; NOSCOPED-NEXT: Memory dependences are safe with run-time checks +; NOSCOPED-NEXT: Dependences: +; NOSCOPED-NEXT: Run-time memory checks: +; NOSCOPED-NEXT: Check 0: +; NOSCOPED-NEXT: Comparing group ([[GRP5:0x[0-9a-f]+]]): +; NOSCOPED-NEXT: %gep.A.400 = getelementptr inbounds i32, ptr %A.1, i64 %iv +; NOSCOPED-NEXT: Against group ([[GRP6:0x[0-9a-f]+]]): +; NOSCOPED-NEXT: %gep.A = getelementptr inbounds i8, ptr %A, i64 %iv +; NOSCOPED-NEXT: Grouped accesses: +; NOSCOPED-NEXT: Group [[GRP5]]: +; NOSCOPED-NEXT: (Low: (1 + %A) High: (405 + %A)) +; NOSCOPED-NEXT: Member: {(1 + %A),+,4}<%loop> +; NOSCOPED-NEXT: Group [[GRP6]]: +; NOSCOPED-NEXT: (Low: %A High: (101 + %A)) +; NOSCOPED-NEXT: Member: {%A,+,1}<%loop> +; LAA-EMPTY: +; LAA-NEXT: Non vectorizable stores to invariant address were not found in loop. +; LAA-NEXT: SCEV assumptions: +; LAA-EMPTY: +; LAA-NEXT: Expressions re-written: +; +; AFTER-LABEL: 'test_ptr_range_end_computed_after_loop' +; AFTER-NEXT: Classifying expressions for: @test_ptr_range_end_computed_after_loop +; AFTER: %y = getelementptr inbounds i8, ptr %A, i64 405 +; AFTER-NEXT: --> (405 + %A) U: full-set S: full-set +; +entry: + %A.1 = getelementptr inbounds i8, ptr %A, i64 1 + br label %loop + +loop: + %iv = phi i64 [ 0, %entry ], [ %iv.next, %loop ] + %gep.A.400 = getelementptr inbounds i32, ptr %A.1, i64 %iv + %gep.A = getelementptr inbounds i8, ptr %A, i64 %iv + %l = load i8, ptr %gep.A, align 1 + %ext = zext i8 %l to i32 + store i32 %ext, ptr %gep.A.400, align 4 + %iv.next = add nuw nsw i64 %iv, 1 + %ec = icmp eq i64 %iv, 100 + br i1 %ec, label %exit, label %loop + +exit: + %y = getelementptr inbounds i8, ptr %A, i64 405 + ret ptr %y +}