[polly] r302805 - [Simplify] Remove identical scalar writes.

Michael Kruse via llvm-commits llvm-commits at lists.llvm.org
Thu May 11 08:07:38 PDT 2017


Author: meinersbur
Date: Thu May 11 10:07:38 2017
New Revision: 302805

URL: http://llvm.org/viewvc/llvm-project?rev=302805&view=rev
Log:
[Simplify] Remove identical scalar writes.

After DeLICM, it is possible to have two writes of the same value to
the same location in the same statement when it determined that those
writes do not conflict (write the same value).

Teach -polly-simplify to remove one of the writes. It interferes with
the pattern matching of matrix-multiplication kernels and also seem
to not be optimized away by LLVM.

The algorthm is simple, has O(n^2) behaviour (n = max number of
MemoryAccesses in a statement) and only matches the most obvious cases,
but seem to be enough to pattern-match Boost ublas gemm.

Not handled cases include:
- StoreInst instructions (a.k.a. explicit writes), since the value might
  be loaded or overwritten between the two stores.
- PHINode, especially LCSSA, when the PHI value matches with on other's.
- Partial writes (in preparation)

Added:
    polly/trunk/test/Simplify/identical.ll
    polly/trunk/test/Simplify/identical_3phi.ll
    polly/trunk/test/Simplify/identical_3phi___%for---%return.jscop
    polly/trunk/test/Simplify/identical_3phi___%for---%return.jscop.transformed
    polly/trunk/test/Simplify/identical___%for---%return.jscop
    polly/trunk/test/Simplify/identical___%for---%return.jscop.transformed
Modified:
    polly/trunk/lib/Transform/Simplify.cpp

Modified: polly/trunk/lib/Transform/Simplify.cpp
URL: http://llvm.org/viewvc/llvm-project/polly/trunk/lib/Transform/Simplify.cpp?rev=302805&r1=302804&r2=302805&view=diff
==============================================================================
--- polly/trunk/lib/Transform/Simplify.cpp (original)
+++ polly/trunk/lib/Transform/Simplify.cpp Thu May 11 10:07:38 2017
@@ -31,15 +31,46 @@ STATISTIC(PairUnequalAccRels, "Number of
                               "of different access relations");
 STATISTIC(InBetweenStore, "Number of Load-Store pairs NOT removed because "
                           "there is another store between them");
+STATISTIC(TotalIdenticalWritesRemoved,
+          "Number of double writes removed in any SCoP");
 STATISTIC(TotalRedundantWritesRemoved,
           "Number of writes of same value removed in any SCoP");
 STATISTIC(TotalStmtsRemoved, "Number of statements removed in any SCoP");
 
+/// Find the llvm::Value that is written by a MemoryAccess. Return nullptr if
+/// there is no such unique value.
+static Value *getWrittenScalar(MemoryAccess *WA) {
+  assert(WA->isWrite());
+
+  if (WA->isOriginalAnyPHIKind()) {
+    Value *Result = nullptr;
+    for (auto Incoming : WA->getIncoming()) {
+      assert(Incoming.second);
+
+      if (!Result) {
+        Result = Incoming.second;
+        continue;
+      }
+
+      if (Result == Incoming.second)
+        continue;
+
+      return nullptr;
+    }
+    return Result;
+  }
+
+  return WA->getAccessInstruction();
+}
+
 class Simplify : public ScopPass {
 private:
   /// The last/current SCoP that is/has been processed.
   Scop *S;
 
+  /// Number of double writes removed from this SCoP.
+  int IdenticalWritesRemoved = 0;
+
   /// Number of redundant writes removed from this SCoP.
   int RedundantWritesRemoved = 0;
 
@@ -48,7 +79,8 @@ private:
 
   /// Return whether at least one simplification has been applied.
   bool isModified() const {
-    return RedundantWritesRemoved > 0 || StmtsRemoved > 0;
+    return IdenticalWritesRemoved > 0 || RedundantWritesRemoved > 0 ||
+           StmtsRemoved > 0;
   }
 
   MemoryAccess *getReadAccessForValue(ScopStmt *Stmt, llvm::Value *Val) {
@@ -122,6 +154,75 @@ private:
     return nullptr;
   }
 
+  /// If there are two writes in the same statement that write the same value to
+  /// the same location, remove one of them.
+  ///
+  /// This currently handles only implicit writes (writes which logically occur
+  /// at the end of a statement when all StoreInst and LoadInst have been
+  /// executed), to avoid interference with other memory accesses.
+  ///
+  /// Two implicit writes have no defined order. It can be produced by DeLICM
+  /// when it determined that both write the same value.
+  void removeIdenticalWrites() {
+    for (auto &Stmt : *S) {
+      // Delay actual removal to not invalidate iterators.
+      SmallPtrSet<MemoryAccess *, 4> StoresToRemove;
+
+      auto Domain = give(Stmt.getDomain());
+
+      // TODO: This has quadratic runtime. Accesses could be grouped by
+      // getAccessValue() to avoid.
+      for (auto *WA1 : Stmt) {
+        if (!WA1->isMustWrite())
+          continue;
+        if (!WA1->isOriginalScalarKind())
+          continue;
+        if (StoresToRemove.count(WA1))
+          continue;
+
+        auto *WrittenScalar1 = getWrittenScalar(WA1);
+        if (!WrittenScalar1)
+          continue;
+
+        for (auto *WA2 : Stmt) {
+          if (WA1 == WA2)
+            continue;
+          if (!WA2->isMustWrite())
+            continue;
+          if (!WA2->isOriginalScalarKind())
+            continue;
+          if (StoresToRemove.count(WA2))
+            continue;
+
+          auto *WrittenScalar2 = getWrittenScalar(WA2);
+          if (WrittenScalar1 != WrittenScalar2)
+            continue;
+
+          auto AccRel1 = give(isl_map_intersect_domain(WA1->getAccessRelation(),
+                                                       Domain.copy()));
+          auto AccRel2 = give(isl_map_intersect_domain(WA2->getAccessRelation(),
+                                                       Domain.copy()));
+          if (isl_map_is_equal(AccRel1.keep(), AccRel2.keep()) != isl_bool_true)
+            continue;
+
+          DEBUG(dbgs() << "Remove identical writes:\n");
+          DEBUG(dbgs() << "  First write  (kept)   : " << WA1 << '\n');
+          DEBUG(dbgs() << "  Second write (removed): " << WA2 << '\n');
+          StoresToRemove.insert(WA2);
+        }
+      }
+
+      for (auto *WA : StoresToRemove) {
+        auto *Stmt = WA->getStatement();
+
+        Stmt->removeSingleMemoryAccess(WA);
+
+        IdenticalWritesRemoved++;
+        TotalIdenticalWritesRemoved++;
+      }
+    }
+  }
+
   /// Remove writes that just write the same value already stored in the
   /// element.
   void removeRedundantWrites() {
@@ -211,6 +312,8 @@ private:
   /// Print simplification statistics to @p OS.
   void printStatistics(llvm::raw_ostream &OS, int Indent = 0) const {
     OS.indent(Indent) << "Statistics {\n";
+    OS.indent(Indent + 4) << "Identical writes removed: "
+                          << IdenticalWritesRemoved << '\n';
     OS.indent(Indent + 4) << "Redundant writes removed: "
                           << RedundantWritesRemoved << "\n";
     OS.indent(Indent + 4) << "Stmts removed: " << StmtsRemoved << "\n";
@@ -245,6 +348,9 @@ public:
     this->S = &S;
     ScopsProcessed++;
 
+    DEBUG(dbgs() << "Removing identical writes...\n");
+    removeIdenticalWrites();
+
     DEBUG(dbgs() << "Removing redundant writes...\n");
     removeRedundantWrites();
 

Added: polly/trunk/test/Simplify/identical.ll
URL: http://llvm.org/viewvc/llvm-project/polly/trunk/test/Simplify/identical.ll?rev=302805&view=auto
==============================================================================
--- polly/trunk/test/Simplify/identical.ll (added)
+++ polly/trunk/test/Simplify/identical.ll Thu May 11 10:07:38 2017
@@ -0,0 +1,56 @@
+; RUN: opt %loadPolly -polly-import-jscop -polly-import-jscop-dir=%S -polly-import-jscop-postfix=transformed -polly-simplify -analyze < %s | FileCheck -match-full-lines %s
+;
+; Remove identical writes
+; (two stores in the same statement that write the same value to the same
+; destination)
+;
+; for (int j = 0; j < n; j += 1) {
+; body:
+;   val = 21.0 + 21.0;
+;   A[1] = val;
+;   A[1] = val;
+;
+; user:
+;   A[0] = A[1];
+; }
+;
+define void @identical(i32 %n, double* noalias nonnull %A) {
+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 %body, label %exit
+
+    body:
+      %val = fadd double 21.0, 21.0
+      br label %user
+
+    user:
+      %phi = phi double [%val, %body]
+      %add = fadd double %val, %phi
+      store double %add, double* %A
+      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:     Identical writes removed: 1
+; CHECK: }
+
+; CHECK:      Stmt_body
+; CHECK-NEXT:     MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:            [n] -> { Stmt_body[i0] -> MemRef_phi__phi[] };
+; CHECK-NEXT:       new: [n] -> { Stmt_body[i0] -> MemRef_A[1] };
+; CHECK-NEXT: Stmt_user

Added: polly/trunk/test/Simplify/identical_3phi.ll
URL: http://llvm.org/viewvc/llvm-project/polly/trunk/test/Simplify/identical_3phi.ll?rev=302805&view=auto
==============================================================================
--- polly/trunk/test/Simplify/identical_3phi.ll (added)
+++ polly/trunk/test/Simplify/identical_3phi.ll Thu May 11 10:07:38 2017
@@ -0,0 +1,61 @@
+; RUN: opt %loadPolly -polly-import-jscop -polly-import-jscop-dir=%S -polly-import-jscop-postfix=transformed -polly-simplify -analyze < %s | FileCheck -match-full-lines %s
+;
+; Remove identical writes
+; (two stores in the same statement that write the same value to the same
+; destination)
+;
+; for (int j = 0; j < n; j += 1) {
+; body:
+;   val = 21.0 + 21.0;
+;   A[1] = val;
+;   A[1] = val;
+;   A[1] = val;
+;
+; user:
+;   A[0] = A[1];
+; }
+;
+define void @identical_3phi(i32 %n, double* noalias nonnull %A) {
+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 %body, label %exit
+
+    body:
+      %val = fadd double 21.0, 21.0
+      br label %user
+
+    user:
+      %phi1 = phi double [%val, %body]
+      %phi2 = phi double [%val, %body]
+      %phi3 = phi double [%val, %body]
+      %add1 = fadd double %phi1, %phi2
+      %add2 = fadd double %add1, %phi3
+      store double %add2, double* %A
+      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:     Identical writes removed: 2
+; CHECK: }
+
+; CHECK:      Stmt_body
+; CHECK-NEXT:         MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:             [n] -> { Stmt_body[i0] -> MemRef_phi1__phi[] };
+; CHECK-NEXT:        new: [n] -> { Stmt_body[i0] -> MemRef_A[1] };
+; CHECK-NEXT: Stmt_user

Added: polly/trunk/test/Simplify/identical_3phi___%for---%return.jscop
URL: http://llvm.org/viewvc/llvm-project/polly/trunk/test/Simplify/identical_3phi___%25for---%25return.jscop?rev=302805&view=auto
==============================================================================
--- polly/trunk/test/Simplify/identical_3phi___%for---%return.jscop (added)
+++ polly/trunk/test/Simplify/identical_3phi___%for---%return.jscop Thu May 11 10:07:38 2017
@@ -0,0 +1,55 @@
+{
+   "arrays" : [
+      {
+         "name" : "MemRef_A",
+         "sizes" : [ "*" ],
+         "type" : "double"
+      }
+   ],
+   "context" : "[n] -> {  : -2147483648 <= n <= 2147483647 }",
+   "name" : "%for---%return",
+   "statements" : [
+      {
+         "accesses" : [
+            {
+               "kind" : "write",
+               "relation" : "[n] -> { Stmt_body[i0] -> MemRef_phi1__phi[] }"
+            },
+            {
+               "kind" : "write",
+               "relation" : "[n] -> { Stmt_body[i0] -> MemRef_phi2__phi[] }"
+            },
+            {
+               "kind" : "write",
+               "relation" : "[n] -> { Stmt_body[i0] -> MemRef_phi3__phi[] }"
+            }
+         ],
+         "domain" : "[n] -> { Stmt_body[i0] : 0 <= i0 < n }",
+         "name" : "Stmt_body",
+         "schedule" : "[n] -> { Stmt_body[i0] -> [i0, 0] }"
+      },
+      {
+         "accesses" : [
+            {
+               "kind" : "read",
+               "relation" : "[n] -> { Stmt_user[i0] -> MemRef_phi1__phi[] }"
+            },
+            {
+               "kind" : "read",
+               "relation" : "[n] -> { Stmt_user[i0] -> MemRef_phi2__phi[] }"
+            },
+            {
+               "kind" : "read",
+               "relation" : "[n] -> { Stmt_user[i0] -> MemRef_phi3__phi[] }"
+            },
+            {
+               "kind" : "write",
+               "relation" : "[n] -> { Stmt_user[i0] -> MemRef_A[0] }"
+            }
+         ],
+         "domain" : "[n] -> { Stmt_user[i0] : 0 <= i0 < n }",
+         "name" : "Stmt_user",
+         "schedule" : "[n] -> { Stmt_user[i0] -> [i0, 1] }"
+      }
+   ]
+}

Added: polly/trunk/test/Simplify/identical_3phi___%for---%return.jscop.transformed
URL: http://llvm.org/viewvc/llvm-project/polly/trunk/test/Simplify/identical_3phi___%25for---%25return.jscop.transformed?rev=302805&view=auto
==============================================================================
--- polly/trunk/test/Simplify/identical_3phi___%for---%return.jscop.transformed (added)
+++ polly/trunk/test/Simplify/identical_3phi___%for---%return.jscop.transformed Thu May 11 10:07:38 2017
@@ -0,0 +1,55 @@
+{
+   "arrays" : [
+      {
+         "name" : "MemRef_A",
+         "sizes" : [ "*" ],
+         "type" : "double"
+      }
+   ],
+   "context" : "[n] -> {  : -2147483648 <= n <= 2147483647 }",
+   "name" : "%for---%return",
+   "statements" : [
+      {
+         "accesses" : [
+            {
+               "kind" : "write",
+               "relation" : "[n] -> { Stmt_body[i0] -> MemRef_A[1] }"
+            },
+            {
+               "kind" : "write",
+               "relation" : "[n] -> { Stmt_body[i0] -> MemRef_A[1] }"
+            },
+            {
+               "kind" : "write",
+               "relation" : "[n] -> { Stmt_body[i0] -> MemRef_A[1] }"
+            }
+         ],
+         "domain" : "[n] -> { Stmt_body[i0] : 0 <= i0 < n }",
+         "name" : "Stmt_body",
+         "schedule" : "[n] -> { Stmt_body[i0] -> [i0, 0] }"
+      },
+      {
+         "accesses" : [
+            {
+               "kind" : "read",
+               "relation" : "[n] -> { Stmt_user[i0] -> MemRef_A[1] }"
+            },
+            {
+               "kind" : "read",
+               "relation" : "[n] -> { Stmt_user[i0] -> MemRef_A[1] }"
+            },
+            {
+               "kind" : "read",
+               "relation" : "[n] -> { Stmt_user[i0] -> MemRef_A[1] }"
+            },
+            {
+               "kind" : "write",
+               "relation" : "[n] -> { Stmt_user[i0] -> MemRef_A[0] }"
+            }
+         ],
+         "domain" : "[n] -> { Stmt_user[i0] : 0 <= i0 < n }",
+         "name" : "Stmt_user",
+         "schedule" : "[n] -> { Stmt_user[i0] -> [i0, 1] }"
+      }
+   ]
+}

Added: polly/trunk/test/Simplify/identical___%for---%return.jscop
URL: http://llvm.org/viewvc/llvm-project/polly/trunk/test/Simplify/identical___%25for---%25return.jscop?rev=302805&view=auto
==============================================================================
--- polly/trunk/test/Simplify/identical___%for---%return.jscop (added)
+++ polly/trunk/test/Simplify/identical___%for---%return.jscop Thu May 11 10:07:38 2017
@@ -0,0 +1,47 @@
+{
+   "arrays" : [
+      {
+         "name" : "MemRef_A",
+         "sizes" : [ "*" ],
+         "type" : "double"
+      }
+   ],
+   "context" : "[n] -> {  : -2147483648 <= n <= 2147483647 }",
+   "name" : "%for---%return",
+   "statements" : [
+      {
+         "accesses" : [
+            {
+               "kind" : "write",
+               "relation" : "[n] -> { Stmt_body[i0] -> MemRef_phi__phi[] }"
+            },
+            {
+               "kind" : "write",
+               "relation" : "[n] -> { Stmt_body[i0] -> MemRef_val[] }"
+            }
+         ],
+         "domain" : "[n] -> { Stmt_body[i0] : 0 <= i0 < n }",
+         "name" : "Stmt_body",
+         "schedule" : "[n] -> { Stmt_body[i0] -> [i0, 0] }"
+      },
+      {
+         "accesses" : [
+            {
+               "kind" : "read",
+               "relation" : "[n] -> { Stmt_user[i0] -> MemRef_phi__phi[] }"
+            },
+            {
+               "kind" : "read",
+               "relation" : "[n] -> { Stmt_user[i0] -> MemRef_val[] }"
+            },
+            {
+               "kind" : "write",
+               "relation" : "[n] -> { Stmt_user[i0] -> MemRef_A[0] }"
+            }
+         ],
+         "domain" : "[n] -> { Stmt_user[i0] : 0 <= i0 < n }",
+         "name" : "Stmt_user",
+         "schedule" : "[n] -> { Stmt_user[i0] -> [i0, 1] }"
+      }
+   ]
+}

Added: polly/trunk/test/Simplify/identical___%for---%return.jscop.transformed
URL: http://llvm.org/viewvc/llvm-project/polly/trunk/test/Simplify/identical___%25for---%25return.jscop.transformed?rev=302805&view=auto
==============================================================================
--- polly/trunk/test/Simplify/identical___%for---%return.jscop.transformed (added)
+++ polly/trunk/test/Simplify/identical___%for---%return.jscop.transformed Thu May 11 10:07:38 2017
@@ -0,0 +1,47 @@
+{
+   "arrays" : [
+      {
+         "name" : "MemRef_A",
+         "sizes" : [ "*" ],
+         "type" : "double"
+      }
+   ],
+   "context" : "[n] -> {  : -2147483648 <= n <= 2147483647 }",
+   "name" : "%for---%return",
+   "statements" : [
+      {
+         "accesses" : [
+            {
+               "kind" : "write",
+               "relation" : "[n] -> { Stmt_body[i0] -> MemRef_A[1] }"
+            },
+            {
+               "kind" : "write",
+               "relation" : "[n] -> { Stmt_body[i0] -> MemRef_A[1] }"
+            }
+         ],
+         "domain" : "[n] -> { Stmt_body[i0] : 0 <= i0 < n }",
+         "name" : "Stmt_body",
+         "schedule" : "[n] -> { Stmt_body[i0] -> [i0, 0] }"
+      },
+      {
+         "accesses" : [
+            {
+               "kind" : "read",
+               "relation" : "[n] -> { Stmt_user[i0] -> MemRef_A[1] }"
+            },
+            {
+               "kind" : "read",
+               "relation" : "[n] -> { Stmt_user[i0] -> MemRef_A[1] }"
+            },
+            {
+               "kind" : "write",
+               "relation" : "[n] -> { Stmt_user[i0] -> MemRef_A[0] }"
+            }
+         ],
+         "domain" : "[n] -> { Stmt_user[i0] : 0 <= i0 < n }",
+         "name" : "Stmt_user",
+         "schedule" : "[n] -> { Stmt_user[i0] -> [i0, 1] }"
+      }
+   ]
+}




More information about the llvm-commits mailing list