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 @@ -1523,11 +1523,11 @@ Type *BTy = BPtr->getType()->getPointerElementType(); auto &DL = InnermostLoop->getHeader()->getModule()->getDataLayout(); uint64_t TypeByteSize = DL.getTypeAllocSize(ATy); + bool HasSameSize = TypeByteSize == DL.getTypeAllocSize(BTy); uint64_t Stride = std::abs(StrideAPtr); const SCEVConstant *C = dyn_cast(Dist); if (!C) { - if (!isa(Dist) && - TypeByteSize == DL.getTypeAllocSize(BTy) && + if (!isa(Dist) && HasSameSize && isSafeDependenceDistance(DL, *(PSE.getSE()), *(PSE.getBackedgeTakenCount()), *Dist, Stride, TypeByteSize)) @@ -1542,7 +1542,7 @@ int64_t Distance = Val.getSExtValue(); // Attempt to prove strided accesses independent. - if (std::abs(Distance) > 0 && Stride > 1 && ATy == BTy && + if (std::abs(Distance) > 0 && Stride > 1 && HasSameSize && areStridedAccessesIndependent(std::abs(Distance), Stride, TypeByteSize)) { LLVM_DEBUG(dbgs() << "LAA: Strided accesses are independent\n"); return Dependence::NoDep; @@ -1553,7 +1553,7 @@ bool IsTrueDataDependence = (AIsWrite && !BIsWrite); if (IsTrueDataDependence && EnableForwardingConflictDetection && (couldPreventStoreLoadForward(Val.abs().getZExtValue(), TypeByteSize) || - ATy != BTy)) { + !HasSameSize)) { LLVM_DEBUG(dbgs() << "LAA: Forward but may prevent st->ld forwarding\n"); return Dependence::ForwardButPreventsForwarding; } @@ -1563,21 +1563,19 @@ } // Write to the same location with the same size. - // Could be improved to assert type sizes are the same (i32 == float, etc). if (Val == 0) { - if (ATy == BTy) + if (HasSameSize) return Dependence::Forward; LLVM_DEBUG( - dbgs() << "LAA: Zero dependence difference but different types\n"); + dbgs() << "LAA: Zero dependence difference but different type sizes\n"); return Dependence::Unknown; } assert(Val.isStrictlyPositive() && "Expect a positive value"); - if (ATy != BTy) { - LLVM_DEBUG( - dbgs() - << "LAA: ReadWrite-Write positive dependency with different types\n"); + if (!HasSameSize) { + LLVM_DEBUG(dbgs() << "LAA: ReadWrite-Write positive dependency with " + "different type sizes\n"); return Dependence::Unknown; } diff --git a/llvm/test/Analysis/LoopAccessAnalysis/depend_diff_types.ll b/llvm/test/Analysis/LoopAccessAnalysis/depend_diff_types.ll new file mode 100644 --- /dev/null +++ b/llvm/test/Analysis/LoopAccessAnalysis/depend_diff_types.ll @@ -0,0 +1,128 @@ +; RUN: opt -S -tbaa -loop-accesses -analyze -enable-new-pm=0 < %s | FileCheck %s --check-prefix=CHECK-SAFE +; RUN: opt -S -disable-output -passes='require,require,require,loop(print-access-info)' < %s 2>&1 | FileCheck %s --check-prefix=CHECK-SAFE +; RUN: opt -S -disable-output -store-to-load-forwarding-conflict-detection -passes='require,require,require,loop(print-access-info)' < %s 2>&1 | FileCheck %s --check-prefix=CHECK-UNSAFE + + +; In the function below some of the accesses are done as float types and some +; are done as i32 types. When doing dependence analysis the type should not +; matter if it can be determined that they are the same size. + +; CHECK-SAFE-LABEL: function 'backdep_type_size_equivalence': +; CHECK-SAFE: loop: +; CHECK-SAFE: Memory dependences are safe with a maximum dependence distance of 800 bytes +; CHECK-SAFE: Dependences: +; CHECK-SAFE: Forward: +; CHECK-SAFE: %2 = load float, float* %1, align 8 -> +; CHECK-SAFE: store i32 %7, i32* %0, align 8 + +; CHECK-SAFE: Forward: +; CHECK-SAFE: %2 = load float, float* %1, align 8 -> +; CHECK-SAFE: store float %3, float* %6, align 8 + +; CHECK-SAFE: BackwardVectorizable: +; CHECK-SAFE: store float %3, float* %6, align 8 -> +; CHECK-SAFE: store i32 %7, i32* %0, align 8 + +; CHECK-SAFE: Run-time memory checks: +; CHECK-SAFE: Grouped accesses: + +%int_pair = type { i32, i32 } + +define void @backdep_type_size_equivalence(%int_pair* nocapture %vec, i64 %n) { +entry: + br label %loop + + loop: + %indvars.iv = phi i64 [ 0, %entry ], [ %indvars.iv.next, %loop ] + + ;; Load from vec[indvars.iv].x as float + %0 = getelementptr inbounds %int_pair, %int_pair* %vec, i64 %indvars.iv, i32 0 + %1 = bitcast i32* %0 to float* + %2 = load float, float* %1, align 8 + %3 = fmul fast float %2, 5.0 + + ;; Store to vec[indvars.iv - 100].x as float + %4 = add nsw i64 %indvars.iv, -100 + %5 = getelementptr inbounds %int_pair, %int_pair* %vec, i64 %4, i32 0 + %6 = bitcast i32* %5 to float* + store float %3, float* %6, align 8 + + ;; Store to vec[indvars.iv].x as i32, creating a backward dependency between + ;; the two stores with different element types but the same element size. + %7 = trunc i64 %indvars.iv to i32 + store i32 %7, i32* %0, align 8 + + ;; Store to vec[indvars.iv].y as i32, strided accesses should be independent + ;; between the two stores with different element types but the same element size. + %8 = getelementptr inbounds %int_pair, %int_pair* %vec, i64 %indvars.iv, i32 1 + store i32 %7, i32* %8, align 8 + + ;; Store to vec[indvars.iv + n].y as i32, to verify no dependence in the case + ;; of unknown dependence distance. + %9 = add nuw nsw i64 %indvars.iv, %n + %10 = getelementptr inbounds %int_pair, %int_pair* %vec, i64 %9, i32 1 + store i32 %7, i32* %10, align 8 + + ;; Loop condition. + %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1 + %cond = icmp eq i64 %indvars.iv.next, %n + br i1 %cond, label %exit, label %loop + + exit: + ret void +} + + +; In the function below some of the accesses are done as double types and some +; are done as i64 types. When doing dependence analysis the type should not +; matter if it can be determined that they are the same size. + +; CHECK-UNSAFE-LABEL: function 'neg_dist_dep_type_size_equivalence': +; CHECK-UNSAFE: loop: +; CHECK-UNSAFE: Report: unsafe dependent memory operations in loop. +; CHECK-UNSAFE: Dependences: + +; CHECK-UNSAFE: ForwardButPreventsForwarding: +; CHECK-UNSAFE: store double %3, double* %6, align 8 -> +; CHECK-UNSAFE: %7 = load i64, i64* %0, align 8 + +; CHECK-UNSAFE: BackwardVectorizableButPreventsForwarding: +; CHECK-UNSAFE: %2 = load double, double* %1, align 8 -> +; CHECK-UNSAFE: store double %3, double* %6, align 8 + +; CHECK-UNSAFE: Run-time memory checks: +; CHECK-UNSAFE: Grouped accesses: + +define void @neg_dist_dep_type_size_equivalence(i64* nocapture %vec, i64 %n) { +entry: + br label %loop + + loop: + %indvars.iv = phi i64 [ 0, %entry ], [ %indvars.iv.next, %loop ] + + ;; Load from vec[indvars.iv] as double + %0 = getelementptr i64, i64* %vec, i64 %indvars.iv + %1 = bitcast i64* %0 to double* + %2 = load double, double* %1, align 8 + %3 = fmul fast double %2, 5.0 + + ;; Store to vec[indvars.iv + 101] as double + %4 = add nsw i64 %indvars.iv, 101 + %5 = getelementptr i64, i64* %vec, i64 %4 + %6 = bitcast i64* %5 to double* + store double %3, double* %6, align 8 + + ;; Read from vec[indvars.iv] as i64 creating + ;; a forward but prevents forwarding dependence + ;; with different types but same sizes. + %7 = load i64, i64* %0, align 8 + + ;; Loop condition. + %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1 + %cond = icmp eq i64 %indvars.iv.next, %n + br i1 %cond, label %exit, label %loop + + exit: + ret void +} +