[polly] r297375 - [ScopDetect/Info] Allow unconditional hoisting of loads from dereferenceable ptrs

Tobias Grosser via llvm-commits llvm-commits at lists.llvm.org
Thu Mar 9 03:36:01 PST 2017


Author: grosser
Date: Thu Mar  9 05:36:00 2017
New Revision: 297375

URL: http://llvm.org/viewvc/llvm-project?rev=297375&view=rev
Log:
[ScopDetect/Info] Allow unconditional hoisting of loads from dereferenceable ptrs

In case LLVM pointers are annotated with !dereferencable attributes/metadata
or LLVM can look at the allocation from which a pointer is derived, we can know
that dereferencing pointers is safe and can be done unconditionally. We use this
information to proof certain pointers as save to hoist and then hoist them
unconditionally.

Added:
    polly/trunk/test/ScopInfo/invariant_load_dereferenceable.ll
Modified:
    polly/trunk/lib/Analysis/ScopDetection.cpp
    polly/trunk/lib/Analysis/ScopInfo.cpp
    polly/trunk/test/Isl/CodeGen/reduction_2.ll

Modified: polly/trunk/lib/Analysis/ScopDetection.cpp
URL: http://llvm.org/viewvc/llvm-project/polly/trunk/lib/Analysis/ScopDetection.cpp?rev=297375&r1=297374&r2=297375&view=diff
==============================================================================
--- polly/trunk/lib/Analysis/ScopDetection.cpp (original)
+++ polly/trunk/lib/Analysis/ScopDetection.cpp Thu Mar  9 05:36:00 2017
@@ -53,6 +53,7 @@
 #include "polly/Support/ScopLocation.h"
 #include "llvm/ADT/Statistic.h"
 #include "llvm/Analysis/AliasAnalysis.h"
+#include "llvm/Analysis/Loads.h"
 #include "llvm/Analysis/LoopInfo.h"
 #include "llvm/Analysis/RegionIterator.h"
 #include "llvm/Analysis/ScalarEvolution.h"
@@ -343,6 +344,8 @@ bool ScopDetection::addOverApproximatedR
 bool ScopDetection::onlyValidRequiredInvariantLoads(
     InvariantLoadsSetTy &RequiredILS, DetectionContext &Context) const {
   Region &CurRegion = Context.CurRegion;
+  const DataLayout &DL =
+      CurRegion.getEntry()->getParent()->getParent()->getDataLayout();
 
   if (!PollyInvariantLoadHoisting && !RequiredILS.empty())
     return false;
@@ -351,10 +354,16 @@ bool ScopDetection::onlyValidRequiredInv
     if (!isHoistableLoad(Load, CurRegion, *LI, *SE, *DT))
       return false;
 
-    for (auto NonAffineRegion : Context.NonAffineSubRegionSet)
+    for (auto NonAffineRegion : Context.NonAffineSubRegionSet) {
+
+      if (isSafeToLoadUnconditionally(Load->getPointerOperand(),
+                                      Load->getAlignment(), DL))
+        continue;
+
       if (NonAffineRegion->contains(Load) &&
           Load->getParent() != NonAffineRegion->getEntry())
         return false;
+    }
   }
 
   Context.RequiredILS.insert(RequiredILS.begin(), RequiredILS.end());

Modified: polly/trunk/lib/Analysis/ScopInfo.cpp
URL: http://llvm.org/viewvc/llvm-project/polly/trunk/lib/Analysis/ScopInfo.cpp?rev=297375&r1=297374&r2=297375&view=diff
==============================================================================
--- polly/trunk/lib/Analysis/ScopInfo.cpp (original)
+++ polly/trunk/lib/Analysis/ScopInfo.cpp Thu Mar  9 05:36:00 2017
@@ -3719,6 +3719,11 @@ __isl_give isl_set *Scop::getNonHoistabl
   if (hasNonHoistableBasePtrInScop(Access, Writes))
     return nullptr;
 
+  auto &DL = getFunction().getParent()->getDataLayout();
+  if (isSafeToLoadUnconditionally(LI->getPointerOperand(), LI->getAlignment(),
+                                  DL))
+    return isl_set_empty(getParamSpace());
+
   // Skip accesses in non-affine subregions as they might not be executed
   // under the same condition as the entry of the non-affine subregion.
   if (BB != LI->getParent())

Modified: polly/trunk/test/Isl/CodeGen/reduction_2.ll
URL: http://llvm.org/viewvc/llvm-project/polly/trunk/test/Isl/CodeGen/reduction_2.ll?rev=297375&r1=297374&r2=297375&view=diff
==============================================================================
--- polly/trunk/test/Isl/CodeGen/reduction_2.ll (original)
+++ polly/trunk/test/Isl/CodeGen/reduction_2.ll Thu Mar  9 05:36:00 2017
@@ -89,15 +89,13 @@ if.end:
 
 declare void @llvm.memset.p0i8.i64(i8* nocapture, i8, i64, i32, i1) nounwind
 
-; Negative test. At the moment we will optimistically assume RED[0] in the conditional after the
-; loop might be invariant and expand the SCoP from the loop to include the conditional. However,
-; during SCoP generation we will realize that RED[0] is in fact not invariant and bail.
+; At some point this was a negative test, where we optimistically assumed RED[0]
+; in the conditional after the loop is invariant and expanded the SCoP from
+; the loop to include the conditional. However, during SCoP generation we
+; realized that RED[0] is in fact not invariant and bailed.
 ;
-; Possible solutions could be:
-;   - Do not optimistically assume it to be invariant (as before this commit), however we would loose
-;     a lot of invariant cases due to possible aliasing.
-;   - Reduce the size of the SCoP if an assumed invariant access is in fact not invariant instead of
-;     rejecting the whole region.
+; Today, LLVM can derive that the load is indeed invariant and Polly uses this
+; information to unconditionally invariant load hoist RED[0].
 ;
-; CHECK-NOT: for (int c0 = 0; c0 <= 1018; c0 += 1)
-; CHECK-NOT:   Stmt_for_body(c0);
+; CHECK: for (int c0 = 0; c0 <= 1018; c0 += 1)
+; CHECK-NEXT:   Stmt_for_body(c0);

Added: polly/trunk/test/ScopInfo/invariant_load_dereferenceable.ll
URL: http://llvm.org/viewvc/llvm-project/polly/trunk/test/ScopInfo/invariant_load_dereferenceable.ll?rev=297375&view=auto
==============================================================================
--- polly/trunk/test/ScopInfo/invariant_load_dereferenceable.ll (added)
+++ polly/trunk/test/ScopInfo/invariant_load_dereferenceable.ll Thu Mar  9 05:36:00 2017
@@ -0,0 +1,112 @@
+; RUN: opt %loadPolly -polly-detect -polly-scops \
+; RUN: -polly-invariant-load-hoisting=true \
+; RUN: -analyze < %s | FileCheck %s
+
+; CHECK-NOT: Function: foo_undereferanceable
+
+; CHECK:       Function: foo_dereferanceable
+
+; CHECK:       Invariant Accesses: {
+; CHECK-NEXT:               ReadAccess :=	[Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:                   [sizeA] -> { Stmt_for_body_j__TO__for_latch_j[i0, i1] -> MemRef_sizeA_ptr[0] };
+; CHECK-NEXT:               Execution Context: [sizeA] -> {  :  }
+; CHECK-NEXT:       }
+
+; CHECK:            MayWriteAccess :=	[Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:               [sizeA] -> { Stmt_for_body_j__TO__for_latch_j[i0, i1] -> MemRef_A[i1, i0] };
+
+; CHECK-NOT: Function: foo_undereferanceable
+
+define void @foo_dereferanceable(double* %A, double* %B, i64* dereferenceable(8) %sizeA_ptr,
+		i32 %lb.i, i32 %lb.j, i32 %ub.i, i32 %ub.j) {
+entry:
+	br label %for.i
+
+for.i:
+	%indvar.i = phi i32 [0, %entry], [%indvar.next.i, %for.latch.i]
+	%indvar.next.i = add i32 %indvar.i, 1
+	%cmp.i = icmp sle i32 %indvar.i, 1024
+	br i1 %cmp.i, label %for.body.i, label %exit
+
+for.body.i:
+	br label %for.j
+
+for.j:
+	%indvar.j = phi i32 [0, %for.body.i], [%indvar.next.j, %for.latch.j]
+	%indvar.next.j = add i32 %indvar.j, 1
+	%cmp.j = icmp sle i32 %indvar.j, 1024
+	br i1 %cmp.j, label %for.body.j, label %for.latch.i
+
+for.body.j:
+	%prod = mul i32 %indvar.j, %indvar.j
+	%cmp = icmp sle i32 %prod, 1024
+	br i1 %cmp, label %stmt, label %for.latch.j
+
+stmt:
+	%sext.i = sext i32 %indvar.i to i64
+	%sext.j = sext i32 %indvar.j to i64
+
+	%sizeA = load i64, i64* %sizeA_ptr
+	%prodA = mul i64 %sext.j, %sizeA
+	%offsetA = add i64 %sext.i, %prodA
+	%ptrA = getelementptr double, double* %A, i64 %offsetA
+	store double 42.0, double* %ptrA
+
+	br label %for.latch.j
+
+for.latch.j:
+	br label %for.j
+
+for.latch.i:
+	br label %for.i
+
+exit:
+	ret void
+}
+
+define void @foo_undereferanceable(double* %A, double* %B, i64* %sizeA_ptr) {
+entry:
+	br label %for.i
+
+for.i:
+	%indvar.i = phi i32 [0, %entry], [%indvar.next.i, %for.latch.i]
+	%indvar.next.i = add i32 %indvar.i, 1
+	%cmp.i = icmp sle i32 %indvar.i, 1024
+	br i1 %cmp.i, label %for.body.i, label %exit
+
+for.body.i:
+	br label %for.j
+
+for.j:
+	%indvar.j = phi i32 [0, %for.body.i], [%indvar.next.j, %for.latch.j]
+	%indvar.next.j = add i32 %indvar.j, 1
+	%cmp.j = icmp sle i32 %indvar.j, 1024
+	br i1 %cmp.j, label %for.body.j, label %for.latch.i
+
+for.body.j:
+	%prod = mul i32 %indvar.j, %indvar.j
+	%cmp = icmp sle i32 %prod, 1024
+	br i1 %cmp, label %stmt, label %for.latch.j
+
+stmt:
+	%sext.i = sext i32 %indvar.i to i64
+	%sext.j = sext i32 %indvar.j to i64
+
+	%sizeA = load i64, i64* %sizeA_ptr
+	%prodA = mul i64 %sext.j, %sizeA
+	%offsetA = add i64 %sext.i, %prodA
+	%ptrA = getelementptr double, double* %A, i64 %offsetA
+	store double 42.0, double* %ptrA
+
+	br label %for.latch.j
+
+for.latch.j:
+	br label %for.j
+
+for.latch.i:
+	br label %for.i
+
+exit:
+	ret void
+}
+




More information about the llvm-commits mailing list