1
0
mirror of https://github.com/RPCS3/llvm-mirror.git synced 2024-11-22 18:54:02 +01:00

[LAA] Avoid generating RT checks for known deps preventing vectorization.

If we found unsafe dependences other than 'unknown', we already know at
compile time that they are unsafe and the runtime checks should always
fail. So we can avoid generating them in those cases.

This should have no negative impact on performance as the runtime checks
that would be created previously should always fail. As a sanity check,
I measured the test-suite, spec2k and spec2k6 and there were no regressions.

Reviewers: Ayal, anemet, hsaito

Reviewed By: Ayal

Differential Revision: https://reviews.llvm.org/D55798

llvm-svn: 349794
This commit is contained in:
Florian Hahn 2018-12-20 18:49:09 +00:00
parent 11388eb454
commit 800a38a203
3 changed files with 23 additions and 13 deletions

View File

@ -104,7 +104,9 @@ public:
// Can vectorize safely without RT checks. All dependences are known to be // Can vectorize safely without RT checks. All dependences are known to be
// safe. // safe.
Safe, Safe,
// Cannot vectorize due to unsafe or unknown dependencies. // Can possibly vectorize with RT checks to overcome unknown dependencies.
PossiblySafeWithRtChecks,
// Cannot vectorize due to known unsafe dependencies.
Unsafe, Unsafe,
}; };
@ -175,7 +177,7 @@ public:
MemoryDepChecker(PredicatedScalarEvolution &PSE, const Loop *L) MemoryDepChecker(PredicatedScalarEvolution &PSE, const Loop *L)
: PSE(PSE), InnermostLoop(L), AccessIdx(0), MaxSafeRegisterWidth(-1U), : PSE(PSE), InnermostLoop(L), AccessIdx(0), MaxSafeRegisterWidth(-1U),
ShouldRetryWithRuntimeCheck(false), FoundNonConstantDistanceDependence(false),
Status(VectorizationSafetyStatus::Safe), RecordDependences(true) {} Status(VectorizationSafetyStatus::Safe), RecordDependences(true) {}
/// Register the location (instructions are given increasing numbers) /// Register the location (instructions are given increasing numbers)
@ -218,7 +220,10 @@ public:
/// In same cases when the dependency check fails we can still /// In same cases when the dependency check fails we can still
/// vectorize the loop with a dynamic array access check. /// vectorize the loop with a dynamic array access check.
bool shouldRetryWithRuntimeCheck() { return ShouldRetryWithRuntimeCheck; } bool shouldRetryWithRuntimeCheck() const {
return FoundNonConstantDistanceDependence &&
Status == VectorizationSafetyStatus::PossiblySafeWithRtChecks;
}
/// Returns the memory dependences. If null is returned we exceeded /// Returns the memory dependences. If null is returned we exceeded
/// the MaxDependences threshold and this information is not /// the MaxDependences threshold and this information is not
@ -280,10 +285,11 @@ private:
/// If we see a non-constant dependence distance we can still try to /// If we see a non-constant dependence distance we can still try to
/// vectorize this loop with runtime checks. /// vectorize this loop with runtime checks.
bool ShouldRetryWithRuntimeCheck; bool FoundNonConstantDistanceDependence;
/// Result of the dependence checks, indicating whether the checked /// Result of the dependence checks, indicating whether the checked
/// dependences are safe for vectorization or not. /// dependences are safe for vectorization, require RT checks or are known to
/// be unsafe.
VectorizationSafetyStatus Status; VectorizationSafetyStatus Status;
//// True if Dependences reflects the dependences in the //// True if Dependences reflects the dependences in the
@ -319,7 +325,8 @@ private:
bool couldPreventStoreLoadForward(uint64_t Distance, uint64_t TypeByteSize); bool couldPreventStoreLoadForward(uint64_t Distance, uint64_t TypeByteSize);
/// Updates the current safety status with \p S. We can go from Safe to /// Updates the current safety status with \p S. We can go from Safe to
/// to Unsafe. /// either PossiblySafeWithRtChecks or Unsafe and from
/// PossiblySafeWithRtChecks to Unsafe.
void mergeInStatus(VectorizationSafetyStatus S); void mergeInStatus(VectorizationSafetyStatus S);
}; };

View File

@ -342,7 +342,7 @@ void RuntimePointerChecking::groupChecks(
// //
// The above case requires that we have an UnknownDependence between // The above case requires that we have an UnknownDependence between
// accesses to the same underlying object. This cannot happen unless // accesses to the same underlying object. This cannot happen unless
// ShouldRetryWithRuntimeCheck is set, and therefore UseDependencies // FoundNonConstantDistanceDependence is set, and therefore UseDependencies
// is also false. In this case we will use the fallback path and create // is also false. In this case we will use the fallback path and create
// separate checking groups for all pointers. // separate checking groups for all pointers.
@ -556,7 +556,7 @@ public:
/// perform dependency checking. /// perform dependency checking.
/// ///
/// Note that this can later be cleared if we retry memcheck analysis without /// Note that this can later be cleared if we retry memcheck analysis without
/// dependency checking (i.e. ShouldRetryWithRuntimeCheck). /// dependency checking (i.e. FoundNonConstantDistanceDependence).
bool isDependencyCheckNeeded() { return !CheckDeps.empty(); } bool isDependencyCheckNeeded() { return !CheckDeps.empty(); }
/// We decided that no dependence analysis would be used. Reset the state. /// We decided that no dependence analysis would be used. Reset the state.
@ -604,8 +604,8 @@ private:
/// ///
/// Note that, this is different from isDependencyCheckNeeded. When we retry /// Note that, this is different from isDependencyCheckNeeded. When we retry
/// memcheck analysis without dependency checking /// memcheck analysis without dependency checking
/// (i.e. ShouldRetryWithRuntimeCheck), isDependencyCheckNeeded is cleared /// (i.e. FoundNonConstantDistanceDependence), isDependencyCheckNeeded is
/// while this remains set if we have potentially dependent accesses. /// cleared while this remains set if we have potentially dependent accesses.
bool IsRTCheckAnalysisNeeded; bool IsRTCheckAnalysisNeeded;
/// The SCEV predicate containing all the SCEV-related assumptions. /// The SCEV predicate containing all the SCEV-related assumptions.
@ -1230,6 +1230,7 @@ MemoryDepChecker::Dependence::isSafeForVectorization(DepType Type) {
return VectorizationSafetyStatus::Safe; return VectorizationSafetyStatus::Safe;
case Unknown: case Unknown:
return VectorizationSafetyStatus::PossiblySafeWithRtChecks;
case ForwardButPreventsForwarding: case ForwardButPreventsForwarding:
case Backward: case Backward:
case BackwardVectorizableButPreventsForwarding: case BackwardVectorizableButPreventsForwarding:
@ -1491,7 +1492,7 @@ MemoryDepChecker::isDependent(const MemAccessInfo &A, unsigned AIdx,
return Dependence::NoDep; return Dependence::NoDep;
LLVM_DEBUG(dbgs() << "LAA: Dependence because of non-constant distance\n"); LLVM_DEBUG(dbgs() << "LAA: Dependence because of non-constant distance\n");
ShouldRetryWithRuntimeCheck = true; FoundNonConstantDistanceDependence = true;
return Dependence::Unknown; return Dependence::Unknown;
} }

View File

@ -117,7 +117,9 @@ loopexit:
ret void ret void
} }
; Check we do generate unnecessary runtime checks. They will always fail. ; Check we do not generate runtime checks if we found a known dependence preventing
; vectorization. In this case, it is a read of c[i-1] followed by a write of c[i].
; The runtime checks would always fail.
; void test_runtime_check2(float *a, float b, unsigned offset, unsigned offset2, unsigned n, float *c) { ; void test_runtime_check2(float *a, float b, unsigned offset, unsigned offset2, unsigned n, float *c) {
; for (unsigned i = 1; i < n; i++) { ; for (unsigned i = 1; i < n; i++) {
@ -127,7 +129,7 @@ loopexit:
; } ; }
; ;
; CHECK-LABEL: test_runtime_check2 ; CHECK-LABEL: test_runtime_check2
; CHECK: <4 x float> ; CHECK-NOT: <4 x float>
define void @test_runtime_check2(float* %a, float %b, i64 %offset, i64 %offset2, i64 %n, float* %c) { define void @test_runtime_check2(float* %a, float %b, i64 %offset, i64 %offset2, i64 %n, float* %c) {
entry: entry:
br label %for.body br label %for.body