[ZoneAlgo] Allow two writes that write identical values into same array slot
authorTobias Grosser <tobias@grosser.es>
Mon, 7 Aug 2017 22:01:29 +0000 (22:01 +0000)
committerTobias Grosser <tobias@grosser.es>
Mon, 7 Aug 2017 22:01:29 +0000 (22:01 +0000)
Two write statements which write into the very same array slot generally are
conflicting. However, in case the value that is written is identical, this
does not cause any problem. Hence, allow such write pairs in this specific
situation.

llvm-svn: 310311

polly/lib/Transform/ZoneAlgo.cpp
polly/test/ForwardOpTree/forward_load_double_write.ll [new file with mode: 0644]

index c6e2771..d8618a5 100644 (file)
@@ -284,6 +284,29 @@ ZoneAlgorithm::ZoneAlgorithm(const char *PassName, Scop *S, LoopInfo *LI)
   ScatterSpace = getScatterSpace(Schedule);
 }
 
+/// Check if all stores in @p Stmt store the very same value.
+///
+/// TODO: In the future we may want to extent this to make the checks
+///       specific to different memory locations.
+static bool onlySameValueWrites(ScopStmt *Stmt) {
+  Value *V = nullptr;
+
+  for (auto *MA : *Stmt) {
+    if (!MA->isLatestArrayKind() || !MA->isMustWrite() ||
+        !MA->isOriginalArrayKind())
+      continue;
+
+    if (!V) {
+      V = MA->getAccessValue();
+      continue;
+    }
+
+    if (V != MA->getAccessValue())
+      return false;
+  }
+  return true;
+}
+
 bool ZoneAlgorithm::isCompatibleStmt(ScopStmt *Stmt) {
   auto Stores = makeEmptyUnionMap();
   auto Loads = makeEmptyUnionMap();
@@ -338,11 +361,13 @@ bool ZoneAlgorithm::isCompatibleStmt(ScopStmt *Stmt) {
     if (!isl_union_map_is_disjoint(Stores.keep(), AccRel.keep())) {
       OptimizationRemarkMissed R(PassName, "StoreAfterStore",
                                  MA->getAccessInstruction());
-      R << "store after store of same element in same statement";
-      R << " (previous stores: " << Stores;
-      R << ", storing: " << AccRel << ")";
-      S->getFunction().getContext().diagnose(R);
-      return false;
+      if (!onlySameValueWrites(Stmt)) {
+        R << "store after store of same element in same statement";
+        R << " (previous stores: " << Stores;
+        R << ", storing: " << AccRel << ")";
+        S->getFunction().getContext().diagnose(R);
+        return false;
+      }
     }
 
     Stores = give(isl_union_map_union(Stores.take(), AccRel.take()));
diff --git a/polly/test/ForwardOpTree/forward_load_double_write.ll b/polly/test/ForwardOpTree/forward_load_double_write.ll
new file mode 100644 (file)
index 0000000..168a4f8
--- /dev/null
@@ -0,0 +1,56 @@
+; RUN: opt %loadPolly -polly-optree -analyze < %s | FileCheck %s -match-full-lines
+;
+; Rematerialize a load even in case two writes of identical values are in
+; one scop statement.
+;
+define void @func(i32 %n, double* noalias nonnull %A, double* noalias nonnull %B) {
+entry:
+  br label %for
+
+for:
+  %j = phi i32 [0, %entry], [%j.inc, %inc]
+  %j.cmp = icmp slt i32 %j, %n
+  br i1 %j.cmp, label %bodyA, label %exit
+
+    bodyA:
+      %B_idx = getelementptr inbounds double, double* %B, i32 %j
+      %val = load double, double* %B_idx
+      br label %bodyB
+
+    bodyB:
+      %A_idx = getelementptr inbounds double, double* %A, i32 %j
+      store double %val, double* %A_idx
+      store double %val, double* %A_idx
+      br label %inc
+
+inc:
+  %j.inc = add nuw nsw i32 %j, 1
+  br label %for
+
+exit:
+  br label %return
+
+return:
+  ret void
+}
+
+
+; CHECK: Statistics {
+; CHECK:     Known loads forwarded: 1
+; CHECK:     Operand trees forwarded: 1
+; CHECK:     Statements with forwarded operand trees: 1
+; CHECK: }
+
+; CHECK:      Stmt_bodyB
+; CHECK-NEXT:         ReadAccess :=       [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:             null;
+; CHECK-NEXT:        new: [n] -> { Stmt_bodyB[i0] -> MemRef_B[i0] };
+; CHECK-NEXT:         MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:             [n] -> { Stmt_bodyB[i0] -> MemRef_A[i0] };
+; CHECK-NEXT:         MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:             [n] -> { Stmt_bodyB[i0] -> MemRef_A[i0] };
+; CHECK-NEXT:         Instructions {
+; CHECK-NEXT:               %val = load double, double* %B_idx
+; CHECK-NEXT:               store double %val, double* %A_idx
+; CHECK-NEXT:               store double %val, double* %A_idx
+; CHECK-NEXT:         }