diff --git a/llvm/include/llvm/ADT/EquivalenceClasses.h b/llvm/include/llvm/ADT/EquivalenceClasses.h index 1a2331c1a0322..ebf160c49296a 100644 --- a/llvm/include/llvm/ADT/EquivalenceClasses.h +++ b/llvm/include/llvm/ADT/EquivalenceClasses.h @@ -293,6 +293,19 @@ template class EquivalenceClasses { return member_iterator(ECV.getLeader()); } + /// Erase the class containing \p V, i.e. erase all members of the class from + /// the set. + void eraseClass(const ElemTy &V) { + if (TheMapping.find(V) == TheMapping.end()) + return; + iterator_range LeaderI = members(V); + for (member_iterator MI = LeaderI.begin(), ME = LeaderI.end(); MI != ME;) { + const ElemTy &ToErase = *MI; + ++MI; + TheMapping.erase(ToErase); + } + } + /// union - Merge the two equivalence sets for the specified values, inserting /// them if they do not already exist in the equivalence set. member_iterator unionSets(const ElemTy &V1, const ElemTy &V2) { diff --git a/llvm/include/llvm/Analysis/LoopAccessAnalysis.h b/llvm/include/llvm/Analysis/LoopAccessAnalysis.h index 52ab38583d5de..21b2850b0f1df 100644 --- a/llvm/include/llvm/Analysis/LoopAccessAnalysis.h +++ b/llvm/include/llvm/Analysis/LoopAccessAnalysis.h @@ -562,8 +562,7 @@ class RuntimePointerChecking { /// Generate the checks and store it. This also performs the grouping /// of pointers to reduce the number of memchecks necessary. - LLVM_ABI void generateChecks(MemoryDepChecker::DepCandidates &DepCands, - bool UseDependencies); + LLVM_ABI void generateChecks(MemoryDepChecker::DepCandidates &DepCands); /// Returns the checks that generateChecks created. They can be used to ensure /// no read/write accesses overlap across all loop iterations. @@ -630,10 +629,8 @@ class RuntimePointerChecking { private: /// Groups pointers such that a single memcheck is required /// between two different groups. This will clear the CheckingGroups vector - /// and re-compute it. We will only group dependecies if \p UseDependencies - /// is true, otherwise we will create a separate group for each pointer. - void groupChecks(MemoryDepChecker::DepCandidates &DepCands, - bool UseDependencies); + /// and re-compute it. + void groupChecks(MemoryDepChecker::DepCandidates &DepCands); /// Generate the checks and return them. SmallVector generateChecks(); diff --git a/llvm/lib/Analysis/LoopAccessAnalysis.cpp b/llvm/lib/Analysis/LoopAccessAnalysis.cpp index 87fae92977cd2..4e18357618498 100644 --- a/llvm/lib/Analysis/LoopAccessAnalysis.cpp +++ b/llvm/lib/Analysis/LoopAccessAnalysis.cpp @@ -526,9 +526,9 @@ SmallVector RuntimePointerChecking::generateChecks() { } void RuntimePointerChecking::generateChecks( - MemoryDepChecker::DepCandidates &DepCands, bool UseDependencies) { + MemoryDepChecker::DepCandidates &DepCands) { assert(Checks.empty() && "Checks is not empty"); - groupChecks(DepCands, UseDependencies); + groupChecks(DepCands); Checks = generateChecks(); } @@ -591,7 +591,7 @@ bool RuntimeCheckingPtrGroup::addPointer(unsigned Index, const SCEV *Start, } void RuntimePointerChecking::groupChecks( - MemoryDepChecker::DepCandidates &DepCands, bool UseDependencies) { + MemoryDepChecker::DepCandidates &DepCands) { // We build the groups from dependency candidates equivalence classes // because: // - We know that pointers in the same equivalence class share @@ -628,19 +628,9 @@ void RuntimePointerChecking::groupChecks( // // In the above case, we have a non-constant distance and an Unknown // dependence between accesses to the same underlying object, and could retry - // with runtime checks. Therefore UseDependencies is false. In this case we - // will use the fallback path and create separate checking groups for all - // pointers. - - // If we don't have the dependency partitions, construct a new - // checking pointer group for each pointer. This is also required - // for correctness, because in this case we can have checking between - // pointers to the same underlying object. - if (!UseDependencies) { - for (unsigned I = 0; I < Pointers.size(); ++I) - CheckingGroups.emplace_back(I, *this); - return; - } + // with runtime checks without dependency information being available. In this + // case we will use the fallback path and create separate checking groups for + // accesses not present in DepCands. unsigned TotalComparisons = 0; @@ -664,6 +654,13 @@ void RuntimePointerChecking::groupChecks( MemoryDepChecker::MemAccessInfo Access(Pointers[I].PointerValue, Pointers[I].IsWritePtr); + // If there is no entry in the dependency partition, there are no potential + // accesses to merge; simply add a new pointer checking group. + if (!DepCands.contains(Access)) { + CheckingGroups.push_back(RuntimeCheckingPtrGroup(I, *this)); + continue; + } + SmallVector Groups; // Because DepCands is constructed by visiting accesses in the order in @@ -841,10 +838,12 @@ class AccessAnalysis { /// (i.e. the pointers have computable bounds). A return value of false means /// we couldn't analyze and generate runtime checks for all pointers in the /// loop, but if \p AllowPartial is set then we will have checks for those - /// pointers we could analyze. + /// pointers we could analyze. \p DepChecker is used to remove unknown + /// dependences from DepCands. bool canCheckPtrAtRT(RuntimePointerChecking &RtCheck, Loop *TheLoop, const DenseMap &Strides, - Value *&UncomputablePtr, bool AllowPartial); + Value *&UncomputablePtr, bool AllowPartial, + const MemoryDepChecker &DepChecker); /// Goes over all memory accesses, checks whether a RT check is needed /// and builds sets of dependent accesses. @@ -1290,7 +1289,7 @@ bool AccessAnalysis::createCheckForAccess( // The id of the dependence set. unsigned DepId; - if (isDependencyCheckNeeded()) { + if (DepCands.contains(Access)) { Value *Leader = DepCands.getLeaderValue(Access).getPointer(); unsigned &LeaderId = DepSetId[Leader]; if (!LeaderId) @@ -1312,7 +1311,7 @@ bool AccessAnalysis::createCheckForAccess( bool AccessAnalysis::canCheckPtrAtRT( RuntimePointerChecking &RtCheck, Loop *TheLoop, const DenseMap &StridesMap, Value *&UncomputablePtr, - bool AllowPartial) { + bool AllowPartial, const MemoryDepChecker &DepChecker) { // Find pointers with computable bounds. We are going to use this information // to place a runtime bound check. bool CanDoRT = true; @@ -1320,7 +1319,28 @@ bool AccessAnalysis::canCheckPtrAtRT( bool MayNeedRTCheck = false; if (!IsRTCheckAnalysisNeeded) return true; - bool IsDepCheckNeeded = isDependencyCheckNeeded(); + if (auto *Deps = DepChecker.getDependences()) { + // If there are unknown dependences, this means runtime checks are needed to + // ensure there's no overlap between accesses to the same underlying object. + // Remove the equivalence classes containing both source and destination + // accesses from DepCands. This ensures runtime checks will be generated + // between those accesses and prevents them from being grouped together. + for (const auto &Dep : *Deps) { + if (Dep.Type != MemoryDepChecker::Dependence::Unknown) { + assert(MemoryDepChecker::Dependence::isSafeForVectorization(Dep.Type) == + MemoryDepChecker::VectorizationSafetyStatus::Safe && + "Should only skip safe dependences"); + continue; + } + Instruction *Src = Dep.getSource(DepChecker); + Instruction *Dst = Dep.getDestination(DepChecker); + DepCands.eraseClass({getPointerOperand(Src), Src->mayWriteToMemory()}); + DepCands.eraseClass({getPointerOperand(Dst), Dst->mayWriteToMemory()}); + } + } else { + CheckDeps.clear(); + DepCands = {}; + } // We assign a consecutive id to access from different alias sets. // Accesses between different groups doesn't need to be checked. @@ -1447,7 +1467,7 @@ bool AccessAnalysis::canCheckPtrAtRT( } if (MayNeedRTCheck && (CanDoRT || AllowPartial)) - RtCheck.generateChecks(DepCands, IsDepCheckNeeded); + RtCheck.generateChecks(DepCands); LLVM_DEBUG(dbgs() << "LAA: We need to do " << RtCheck.getNumberOfChecks() << " pointer comparisons.\n"); @@ -2721,8 +2741,9 @@ bool LoopAccessInfo::analyzeLoop(AAResults *AA, const LoopInfo *LI, // Find pointers with computable bounds. We are going to use this information // to place a runtime bound check. Value *UncomputablePtr = nullptr; - HasCompletePtrRtChecking = Accesses.canCheckPtrAtRT( - *PtrRtChecking, TheLoop, SymbolicStrides, UncomputablePtr, AllowPartial); + HasCompletePtrRtChecking = + Accesses.canCheckPtrAtRT(*PtrRtChecking, TheLoop, SymbolicStrides, + UncomputablePtr, AllowPartial, getDepChecker()); if (!HasCompletePtrRtChecking) { const auto *I = dyn_cast_or_null(UncomputablePtr); recordAnalysis("CantIdentifyArrayBounds", I) @@ -2744,16 +2765,13 @@ bool LoopAccessInfo::analyzeLoop(AAResults *AA, const LoopInfo *LI, if (!DepsAreSafe && DepChecker->shouldRetryWithRuntimeChecks()) { LLVM_DEBUG(dbgs() << "LAA: Retrying with memory checks\n"); - // Clear the dependency checks. We assume they are not needed. - Accesses.resetDepChecks(*DepChecker); - PtrRtChecking->reset(); PtrRtChecking->Need = true; UncomputablePtr = nullptr; - HasCompletePtrRtChecking = - Accesses.canCheckPtrAtRT(*PtrRtChecking, TheLoop, SymbolicStrides, - UncomputablePtr, AllowPartial); + HasCompletePtrRtChecking = Accesses.canCheckPtrAtRT( + *PtrRtChecking, TheLoop, SymbolicStrides, UncomputablePtr, + AllowPartial, getDepChecker()); // Check that we found the bounds for the pointer. if (!HasCompletePtrRtChecking) { @@ -2763,6 +2781,10 @@ bool LoopAccessInfo::analyzeLoop(AAResults *AA, const LoopInfo *LI, LLVM_DEBUG(dbgs() << "LAA: Can't vectorize with memory checks\n"); return false; } + + // Clear the dependency checks. They are no longer needed. + Accesses.resetDepChecks(*DepChecker); + DepsAreSafe = true; } } diff --git a/llvm/test/Analysis/LoopAccessAnalysis/different-access-types-rt-checks.ll b/llvm/test/Analysis/LoopAccessAnalysis/different-access-types-rt-checks.ll index 809472cb543ac..cac1b857063d0 100644 --- a/llvm/test/Analysis/LoopAccessAnalysis/different-access-types-rt-checks.ll +++ b/llvm/test/Analysis/LoopAccessAnalysis/different-access-types-rt-checks.ll @@ -115,20 +115,12 @@ define void @loads_of_same_pointer_with_different_sizes_retry_with_runtime_check ; CHECK-NEXT: %gep.B.iv = getelementptr inbounds i32, ptr %B, i64 %iv ; CHECK-NEXT: Against group GRP2: ; CHECK-NEXT: %gep.A = getelementptr inbounds i8, ptr %A, i64 %iv -; CHECK-NEXT: Check 2: -; CHECK-NEXT: Comparing group GRP0: -; CHECK-NEXT: %gep.B.iv = getelementptr inbounds i32, ptr %B, i64 %iv -; CHECK-NEXT: Against group GRP3: ; CHECK-NEXT: %gep.A = getelementptr inbounds i8, ptr %A, i64 %iv -; CHECK-NEXT: Check 3: +; CHECK-NEXT: Check 2: ; CHECK-NEXT: Comparing group GRP1: ; CHECK-NEXT: %gep.B.inc = getelementptr inbounds i32, ptr %B, i64 %inc ; CHECK-NEXT: Against group GRP2: ; CHECK-NEXT: %gep.A = getelementptr inbounds i8, ptr %A, i64 %iv -; CHECK-NEXT: Check 4: -; CHECK-NEXT: Comparing group GRP1: -; CHECK-NEXT: %gep.B.inc = getelementptr inbounds i32, ptr %B, i64 %inc -; CHECK-NEXT: Against group GRP3: ; CHECK-NEXT: %gep.A = getelementptr inbounds i8, ptr %A, i64 %iv ; CHECK-NEXT: Grouped accesses: ; CHECK-NEXT: Group GRP0: @@ -138,11 +130,9 @@ define void @loads_of_same_pointer_with_different_sizes_retry_with_runtime_check ; CHECK-NEXT: (Low: ((4 * %off) + %B) High: ((4 * %N) + (4 * %off) + %B)) ; CHECK-NEXT: Member: {((4 * %off) + %B),+,4}<%loop> ; CHECK-NEXT: Group GRP2: -; CHECK-NEXT: (Low: %A High: (%N + %A)) -; CHECK-NEXT: Member: {%A,+,1}<%loop> -; CHECK-NEXT: Group GRP3: ; CHECK-NEXT: (Low: %A High: (3 + %N + %A)) ; CHECK-NEXT: Member: {%A,+,1}<%loop> +; 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: diff --git a/llvm/test/Analysis/LoopAccessAnalysis/retry-runtime-checks-after-dependence-analysis-forked-pointers.ll b/llvm/test/Analysis/LoopAccessAnalysis/retry-runtime-checks-after-dependence-analysis-forked-pointers.ll index d1d1ecb2af888..3a5730eb471ed 100644 --- a/llvm/test/Analysis/LoopAccessAnalysis/retry-runtime-checks-after-dependence-analysis-forked-pointers.ll +++ b/llvm/test/Analysis/LoopAccessAnalysis/retry-runtime-checks-after-dependence-analysis-forked-pointers.ll @@ -26,14 +26,9 @@ define void @dependency_check_and_runtime_checks_needed_select_of_invariant_ptrs ; CHECK-NEXT: Check 3: ; CHECK-NEXT: Comparing group GRP1: ; CHECK-NEXT: %select = select i1 %cmp, ptr %b, ptr %c -; CHECK-NEXT: Against group GRP2: -; CHECK-NEXT: %select = select i1 %cmp, ptr %b, ptr %c -; CHECK-NEXT: Check 4: -; CHECK-NEXT: Comparing group GRP1: -; CHECK-NEXT: %select = select i1 %cmp, ptr %b, ptr %c ; CHECK-NEXT: Against group GRP3: ; CHECK-NEXT: %gep.a.iv.off = getelementptr inbounds float, ptr %a, i64 %iv.offset -; CHECK-NEXT: Check 5: +; CHECK-NEXT: Check 4: ; CHECK-NEXT: Comparing group GRP2: ; CHECK-NEXT: %select = select i1 %cmp, ptr %b, ptr %c ; CHECK-NEXT: Against group GRP3: @@ -104,14 +99,9 @@ define void @dependency_check_and_runtime_checks_needed_select_of_ptr_add_recs(p ; CHECK-NEXT: Check 3: ; CHECK-NEXT: Comparing group GRP1: ; CHECK-NEXT: %select = select i1 %cmp, ptr %gep.b, ptr %gep.c -; CHECK-NEXT: Against group GRP2: -; CHECK-NEXT: %select = select i1 %cmp, ptr %gep.b, ptr %gep.c -; CHECK-NEXT: Check 4: -; CHECK-NEXT: Comparing group GRP1: -; CHECK-NEXT: %select = select i1 %cmp, ptr %gep.b, ptr %gep.c ; CHECK-NEXT: Against group GRP3: ; CHECK-NEXT: %gep.a.iv.off = getelementptr inbounds float, ptr %a, i64 %iv.offset -; CHECK-NEXT: Check 5: +; CHECK-NEXT: Check 4: ; CHECK-NEXT: Comparing group GRP2: ; CHECK-NEXT: %select = select i1 %cmp, ptr %gep.b, ptr %gep.c ; CHECK-NEXT: Against group GRP3: diff --git a/llvm/test/Analysis/LoopAccessAnalysis/unknown-dependence-retry-with-runtime-checks.ll b/llvm/test/Analysis/LoopAccessAnalysis/unknown-dependence-retry-with-runtime-checks.ll index 98a9fa586080a..0c0e03843f51e 100644 --- a/llvm/test/Analysis/LoopAccessAnalysis/unknown-dependence-retry-with-runtime-checks.ll +++ b/llvm/test/Analysis/LoopAccessAnalysis/unknown-dependence-retry-with-runtime-checks.ll @@ -18,11 +18,6 @@ define void @test_dependence_with_non_constant_offset_and_other_accesses_to_noal ; CHECK-NEXT: %gep.A.400 = getelementptr inbounds i32, ptr %A.off, i64 %iv ; CHECK-NEXT: Against group GRP1: ; CHECK-NEXT: %gep.A = getelementptr inbounds i8, ptr %A, i64 %iv -; CHECK-NEXT: Check 1: -; CHECK-NEXT: Comparing group GRP2: -; CHECK-NEXT: %gep.B = getelementptr inbounds i8, ptr %B, i64 %iv -; CHECK-NEXT: Against group GRP3: -; CHECK-NEXT: %gep.B.1 = getelementptr inbounds i8, ptr %B, i64 %iv.next ; CHECK-NEXT: Grouped accesses: ; CHECK-NEXT: Group GRP0: ; CHECK-NEXT: (Low: (%off + %A) High: (404 + %off + %A)) @@ -31,11 +26,9 @@ define void @test_dependence_with_non_constant_offset_and_other_accesses_to_noal ; CHECK-NEXT: (Low: %A High: (101 + %A)) ; CHECK-NEXT: Member: {%A,+,1}<%loop> ; CHECK-NEXT: Group GRP2: -; CHECK-NEXT: (Low: %B High: (101 + %B)) -; CHECK-NEXT: Member: {%B,+,1}<%loop> -; CHECK-NEXT: Group GRP3: -; CHECK-NEXT: (Low: (1 + %B) High: (102 + %B)) +; CHECK-NEXT: (Low: %B High: (102 + %B)) ; CHECK-NEXT: Member: {(1 + %B),+,1}<%loop> +; CHECK-NEXT: Member: {%B,+,1}<%loop> ; CHECK-EMPTY: ; CHECK-NEXT: Non vectorizable stores to invariant address were not found in loop. ; CHECK-NEXT: SCEV assumptions: @@ -77,6 +70,7 @@ define void @test_dependence_with_non_constant_offset_and_other_accesses_to_maya ; CHECK-NEXT: Comparing group GRP0: ; CHECK-NEXT: %gep.A.400 = getelementptr inbounds i32, ptr %A.off, i64 %iv ; CHECK-NEXT: Against group GRP1: +; CHECK-NEXT: %gep.B.1 = getelementptr inbounds i8, ptr %B, i64 %iv.next ; CHECK-NEXT: %gep.B = getelementptr inbounds i8, ptr %B, i64 %iv ; CHECK-NEXT: Check 1: ; CHECK-NEXT: Comparing group GRP0: @@ -84,33 +78,22 @@ define void @test_dependence_with_non_constant_offset_and_other_accesses_to_maya ; CHECK-NEXT: Against group GRP2: ; CHECK-NEXT: %gep.A = getelementptr inbounds i8, ptr %A, i64 %iv ; CHECK-NEXT: Check 2: -; CHECK-NEXT: Comparing group GRP0: -; CHECK-NEXT: %gep.A.400 = getelementptr inbounds i32, ptr %A.off, i64 %iv -; CHECK-NEXT: Against group GRP3: -; CHECK-NEXT: %gep.B.1 = getelementptr inbounds i8, ptr %B, i64 %iv.next -; CHECK-NEXT: Check 3: ; CHECK-NEXT: Comparing group GRP1: +; CHECK-NEXT: %gep.B.1 = getelementptr inbounds i8, ptr %B, i64 %iv.next ; CHECK-NEXT: %gep.B = getelementptr inbounds i8, ptr %B, i64 %iv ; CHECK-NEXT: Against group GRP2: ; CHECK-NEXT: %gep.A = getelementptr inbounds i8, ptr %A, i64 %iv -; CHECK-NEXT: Check 4: -; CHECK-NEXT: Comparing group GRP1: -; CHECK-NEXT: %gep.B = getelementptr inbounds i8, ptr %B, i64 %iv -; CHECK-NEXT: Against group GRP3: -; CHECK-NEXT: %gep.B.1 = getelementptr inbounds i8, ptr %B, i64 %iv.next ; CHECK-NEXT: Grouped accesses: ; CHECK-NEXT: Group GRP0: ; CHECK-NEXT: (Low: (%off + %A) High: (404 + %off + %A)) ; CHECK-NEXT: Member: {(%off + %A),+,4}<%loop> ; CHECK-NEXT: Group GRP1: -; CHECK-NEXT: (Low: %B High: (101 + %B)) +; CHECK-NEXT: (Low: %B High: (102 + %B)) +; CHECK-NEXT: Member: {(1 + %B),+,1}<%loop> ; CHECK-NEXT: Member: {%B,+,1}<%loop> ; CHECK-NEXT: Group GRP2: ; CHECK-NEXT: (Low: %A High: (101 + %A)) ; CHECK-NEXT: Member: {%A,+,1}<%loop> -; CHECK-NEXT: Group GRP3: -; CHECK-NEXT: (Low: (1 + %B) High: (102 + %B)) -; CHECK-NEXT: Member: {(1 + %B),+,1}<%loop> ; CHECK-EMPTY: ; CHECK-NEXT: Non vectorizable stores to invariant address were not found in loop. ; CHECK-NEXT: SCEV assumptions: diff --git a/llvm/test/Transforms/LoopVectorize/runtime-checks-difference.ll b/llvm/test/Transforms/LoopVectorize/runtime-checks-difference.ll index b640c1911cb0d..2e42c9fdb82b8 100644 --- a/llvm/test/Transforms/LoopVectorize/runtime-checks-difference.ll +++ b/llvm/test/Transforms/LoopVectorize/runtime-checks-difference.ll @@ -388,28 +388,24 @@ define void @use_diff_checks_when_retrying_with_rt_checks(i64 %off, ptr %dst, pt ; CHECK-LABEL: define void @use_diff_checks_when_retrying_with_rt_checks( ; CHECK-SAME: i64 [[OFF:%.*]], ptr [[DST:%.*]], ptr [[SRC:%.*]]) { ; CHECK-NEXT: [[ENTRY:.*:]] -; CHECK-NEXT: [[SRC2:%.*]] = ptrtoint ptr [[SRC]] to i64 -; CHECK-NEXT: [[DST1:%.*]] = ptrtoint ptr [[DST]] to i64 ; CHECK-NEXT: br i1 false, [[SCALAR_PH:label %.*]], label %[[VECTOR_MEMCHECK:.*]] ; CHECK: [[VECTOR_MEMCHECK]]: -; CHECK-NEXT: [[TMP0:%.*]] = mul i64 [[OFF]], -8 -; CHECK-NEXT: [[DIFF_CHECK:%.*]] = icmp ult i64 [[TMP0]], 32 ; CHECK-NEXT: [[TMP1:%.*]] = shl i64 [[OFF]], 3 -; CHECK-NEXT: [[TMP2:%.*]] = add i64 [[DST1]], [[TMP1]] -; CHECK-NEXT: [[TMP3:%.*]] = sub i64 [[TMP2]], [[SRC2]] -; CHECK-NEXT: [[DIFF_CHECK3:%.*]] = icmp ult i64 [[TMP3]], 32 -; CHECK-NEXT: [[CONFLICT_RDX:%.*]] = or i1 [[DIFF_CHECK]], [[DIFF_CHECK3]] -; CHECK-NEXT: [[TMP4:%.*]] = add i64 [[SRC2]], 8 -; CHECK-NEXT: [[TMP5:%.*]] = sub i64 [[TMP4]], [[DST1]] -; CHECK-NEXT: [[TMP6:%.*]] = sub i64 [[TMP5]], [[TMP1]] -; CHECK-NEXT: [[DIFF_CHECK4:%.*]] = icmp ult i64 [[TMP6]], 32 -; CHECK-NEXT: [[CONFLICT_RDX5:%.*]] = or i1 [[CONFLICT_RDX]], [[DIFF_CHECK4]] -; CHECK-NEXT: [[TMP7:%.*]] = sub i64 [[DST1]], [[SRC2]] -; CHECK-NEXT: [[DIFF_CHECK6:%.*]] = icmp ult i64 [[TMP7]], 32 +; CHECK-NEXT: [[SCEVGEP:%.*]] = getelementptr i8, ptr [[DST]], i64 [[TMP1]] +; CHECK-NEXT: [[TMP2:%.*]] = add i64 [[TMP1]], 8000 +; CHECK-NEXT: [[SCEVGEP1:%.*]] = getelementptr i8, ptr [[DST]], i64 [[TMP2]] +; CHECK-NEXT: [[SCEVGEP2:%.*]] = getelementptr i8, ptr [[DST]], i64 8000 +; CHECK-NEXT: [[SCEVGEP3:%.*]] = getelementptr i8, ptr [[SRC]], i64 8008 +; CHECK-NEXT: [[BOUND0:%.*]] = icmp ult ptr [[SCEVGEP]], [[SCEVGEP2]] +; CHECK-NEXT: [[BOUND1:%.*]] = icmp ult ptr [[DST]], [[SCEVGEP1]] +; CHECK-NEXT: [[CONFLICT_RDX5:%.*]] = and i1 [[BOUND0]], [[BOUND1]] +; CHECK-NEXT: [[BOUND04:%.*]] = icmp ult ptr [[SCEVGEP]], [[SCEVGEP3]] +; CHECK-NEXT: [[BOUND15:%.*]] = icmp ult ptr [[SRC]], [[SCEVGEP1]] +; CHECK-NEXT: [[DIFF_CHECK6:%.*]] = and i1 [[BOUND04]], [[BOUND15]] ; CHECK-NEXT: [[CONFLICT_RDX7:%.*]] = or i1 [[CONFLICT_RDX5]], [[DIFF_CHECK6]] -; CHECK-NEXT: [[TMP8:%.*]] = add i64 [[DST1]], -8 -; CHECK-NEXT: [[TMP9:%.*]] = sub i64 [[TMP8]], [[SRC2]] -; CHECK-NEXT: [[DIFF_CHECK8:%.*]] = icmp ult i64 [[TMP9]], 32 +; CHECK-NEXT: [[BOUND07:%.*]] = icmp ult ptr [[DST]], [[SCEVGEP3]] +; CHECK-NEXT: [[BOUND18:%.*]] = icmp ult ptr [[SRC]], [[SCEVGEP2]] +; CHECK-NEXT: [[DIFF_CHECK8:%.*]] = and i1 [[BOUND07]], [[BOUND18]] ; CHECK-NEXT: [[CONFLICT_RDX9:%.*]] = or i1 [[CONFLICT_RDX7]], [[DIFF_CHECK8]] ; CHECK-NEXT: br i1 [[CONFLICT_RDX9]], [[SCALAR_PH]], [[VECTOR_PH:label %.*]] ;