[polly] r249099 - Make the SCoP generation resistent wrt. error blocks

Johannes Doerfert via llvm-commits llvm-commits at lists.llvm.org
Thu Oct 1 16:48:18 PDT 2015


Author: jdoerfert
Date: Thu Oct  1 18:48:18 2015
New Revision: 249099

URL: http://llvm.org/viewvc/llvm-project?rev=249099&view=rev
Log:
Make the SCoP generation resistent wrt. error blocks

  When error blocks are not terminated by an unreachable they have successors
  that might only be reachable via error blocks. Additionally, branches in
  error blocks are not checked during SCoP detection, thus we might not be able
  to handle them. With this patch we do not try to model error block exit
  conditions. Anything that is only reachable via error blocks is ignored too,
  as it will not be executed in the optimized version of the SCoP anyway.

Added:
    polly/trunk/test/ScopInfo/user-defined-error-causes-dead-blocks.ll
Modified:
    polly/trunk/include/polly/ScopInfo.h
    polly/trunk/lib/Analysis/ScopInfo.cpp

Modified: polly/trunk/include/polly/ScopInfo.h
URL: http://llvm.org/viewvc/llvm-project/polly/trunk/include/polly/ScopInfo.h?rev=249099&r1=249098&r2=249099&view=diff
==============================================================================
--- polly/trunk/include/polly/ScopInfo.h (original)
+++ polly/trunk/include/polly/ScopInfo.h Thu Oct  1 18:48:18 2015
@@ -1192,15 +1192,15 @@ private:
   void buildDomains(Region *R, LoopInfo &LI, ScopDetection &SD,
                     DominatorTree &DT);
 
-  /// @brief Check if a basic block is trivial.
+  /// @brief Check if a region part should be represented in the SCoP or not.
   ///
-  /// A trivial basic block does not contain any useful calculation. Therefore,
-  /// it does not need to be represented as a polyhedral statement.
+  /// If @p RN does not contain any useful calculation or is only reachable
+  /// via error blocks we do not model it in the polyhedral representation.
   ///
-  /// @param BB The basic block to check
+  /// @param RN The region part to check.
   ///
-  /// @return True if the basic block is trivial, otherwise false.
-  bool isTrivialBB(BasicBlock *BB);
+  /// @return True if the part should be ignored, otherwise false.
+  bool isIgnored(RegionNode *RN);
 
   /// @brief Add parameter constraints to @p C that imply a non-empty domain.
   __isl_give isl_set *addNonEmptyDomainConstraints(__isl_take isl_set *C) const;

Modified: polly/trunk/lib/Analysis/ScopInfo.cpp
URL: http://llvm.org/viewvc/llvm-project/polly/trunk/lib/Analysis/ScopInfo.cpp?rev=249099&r1=249098&r2=249099&view=diff
==============================================================================
--- polly/trunk/lib/Analysis/ScopInfo.cpp (original)
+++ polly/trunk/lib/Analysis/ScopInfo.cpp Thu Oct  1 18:48:18 2015
@@ -1693,6 +1693,15 @@ static inline unsigned getNumBlocksInReg
   return NumBlocks;
 }
 
+static bool containsErrorBlock(RegionNode *RN) {
+  if (!RN->isSubRegion())
+    return isErrorBlock(*RN->getNodeAs<BasicBlock>());
+  for (BasicBlock *BB : RN->getNodeAs<Region>()->blocks())
+    if (isErrorBlock(*BB))
+      return true;
+  return false;
+}
+
 ///}
 
 static inline __isl_give isl_set *addDomainDimId(__isl_take isl_set *Domain,
@@ -1765,22 +1774,29 @@ void Scop::buildDomainsWithBranchConstra
       }
     }
 
+    // Error blocks are assumed not to be executed. Therefor they are not
+    // checked properly in the ScopDetection. Any attempt to generate control
+    // conditions from them might result in a crash. However, this is only true
+    // for the first step of the domain generation (this function) where we
+    // push the control conditions of a block to the successors. In the second
+    // step (propagateDomainConstraints) we only receive domain constraints from
+    // the predecessors and can therefor look at the domain of a error block.
+    // That allows us to generate the assumptions needed for them not to be
+    // executed at runtime.
+    if (containsErrorBlock(RN))
+      continue;
+
     BasicBlock *BB = getRegionNodeBasicBlock(RN);
     TerminatorInst *TI = BB->getTerminator();
 
-    // Unreachable instructions do not have successors so we can skip them.
-    if (isa<UnreachableInst>(TI)) {
-      // Assume unreachables only in error blocks.
-      assert(isErrorBlock(*BB));
+    isl_set *Domain = DomainMap.lookup(BB);
+    if (!Domain) {
+      DEBUG(dbgs() << "\tSkip: " << BB->getName()
+                   << ", it is only reachable from error blocks.\n");
       continue;
     }
 
-    isl_set *Domain = DomainMap[BB];
     DEBUG(dbgs() << "\tVisit: " << BB->getName() << " : " << Domain << "\n");
-    assert(Domain && "Due to reverse post order traversal of the region all "
-                     "predecessor of the current region node should have been "
-                     "visited and a domain for this region node should have "
-                     "been set.");
 
     Loop *BBLoop = getRegionNodeLoop(RN, LI);
     int BBLoopDepth = getRelativeLoopDepth(BBLoop);
@@ -1873,15 +1889,6 @@ getDomainForBlock(BasicBlock *BB, DenseM
   return getDomainForBlock(R->getEntry(), DomainMap, RI);
 }
 
-static bool containsErrorBlock(RegionNode *RN) {
-  if (!RN->isSubRegion())
-    return isErrorBlock(*RN->getNodeAs<BasicBlock>());
-  for (BasicBlock *BB : RN->getNodeAs<Region>()->blocks())
-    if (isErrorBlock(*BB))
-      return true;
-  return false;
-}
-
 void Scop::propagateDomainConstraints(Region *R, LoopInfo &LI,
                                       ScopDetection &SD, DominatorTree &DT) {
   // Iterate over the region R and propagate the domain constrains from the
@@ -1909,16 +1916,26 @@ void Scop::propagateDomainConstraints(Re
       }
     }
 
+    // Get the domain for the current block and check if it was initialized or
+    // not. The only way it was not is if this block is only reachable via error
+    // blocks, thus will not be executed under the assumptions we make. Such
+    // blocks have to be skipped as their predecessors might not have domains
+    // either. It would not benefit us to compute the domain anyway, only the
+    // domains of the error blocks that are reachable from non-error blocks
+    // are needed to generate assumptions.
     BasicBlock *BB = getRegionNodeBasicBlock(RN);
+    isl_set *&Domain = DomainMap[BB];
+    if (!Domain) {
+      DEBUG(dbgs() << "\tSkip: " << BB->getName()
+                   << ", it is only reachable from error blocks.\n");
+      DomainMap.erase(BB);
+      continue;
+    }
+    DEBUG(dbgs() << "\tVisit: " << BB->getName() << " : " << Domain << "\n");
+
     Loop *BBLoop = getRegionNodeLoop(RN, LI);
     int BBLoopDepth = getRelativeLoopDepth(BBLoop);
 
-    isl_set *&Domain = DomainMap[BB];
-    assert(Domain && "Due to reverse post order traversal of the region all "
-                     "predecessor of the current region node should have been "
-                     "visited and a domain for this region node should have "
-                     "been set.");
-
     isl_set *PredDom = isl_set_empty(isl_set_get_space(Domain));
     for (auto *PredBB : predecessors(BB)) {
 
@@ -2019,8 +2036,12 @@ void Scop::addLoopBoundsToHeaderDomain(L
   L->getLoopLatches(LatchBlocks);
 
   for (BasicBlock *LatchBB : LatchBlocks) {
-    assert(DomainMap.count(LatchBB));
-    isl_set *LatchBBDom = DomainMap[LatchBB];
+
+    // If the latch is only reachable via error statements we skip it.
+    isl_set *LatchBBDom = DomainMap.lookup(LatchBB);
+    if (!LatchBBDom)
+      continue;
+
     isl_set *BackedgeCondition = nullptr;
 
     TerminatorInst *TI = LatchBB->getTerminator();
@@ -2752,11 +2773,28 @@ bool Scop::restrictDomains(__isl_take is
 
 ScalarEvolution *Scop::getSE() const { return SE; }
 
-bool Scop::isTrivialBB(BasicBlock *BB) {
-  if (getAccessFunctions(BB) && !isErrorBlock(*BB))
-    return false;
+bool Scop::isIgnored(RegionNode *RN) {
+  BasicBlock *BB = getRegionNodeBasicBlock(RN);
 
-  return true;
+  // Check if there are accesses contained.
+  bool ContainsAccesses = false;
+  if (!RN->isSubRegion())
+    ContainsAccesses = getAccessFunctions(BB);
+  else
+    for (BasicBlock *RBB : RN->getNodeAs<Region>()->blocks())
+      ContainsAccesses |= (getAccessFunctions(RBB) != nullptr);
+  if (!ContainsAccesses)
+    return true;
+
+  // Check for reachability via non-error blocks.
+  if (!DomainMap.count(BB))
+    return true;
+
+  // Check if error blocks are contained.
+  if (containsErrorBlock(RN))
+    return true;
+
+  return false;
 }
 
 struct MapToDimensionDataTy {
@@ -2863,14 +2901,13 @@ void Scop::buildSchedule(
     auto &LSchedulePair = LoopSchedules[L];
     LSchedulePair.second += getNumBlocksInRegionNode(RN);
 
-    BasicBlock *BB = getRegionNodeBasicBlock(RN);
-    if (RN->isSubRegion() || !isTrivialBB(BB)) {
+    if (!isIgnored(RN)) {
 
       ScopStmt *Stmt;
       if (RN->isSubRegion())
         Stmt = addScopStmt(nullptr, RN->getNodeAs<Region>());
       else
-        Stmt = addScopStmt(BB, nullptr);
+        Stmt = addScopStmt(RN->getNodeAs<BasicBlock>(), nullptr);
 
       auto *UDomain = isl_union_set_from_set(Stmt->getDomain());
       auto *StmtSchedule = isl_schedule_from_domain(UDomain);

Added: polly/trunk/test/ScopInfo/user-defined-error-causes-dead-blocks.ll
URL: http://llvm.org/viewvc/llvm-project/polly/trunk/test/ScopInfo/user-defined-error-causes-dead-blocks.ll?rev=249099&view=auto
==============================================================================
--- polly/trunk/test/ScopInfo/user-defined-error-causes-dead-blocks.ll (added)
+++ polly/trunk/test/ScopInfo/user-defined-error-causes-dead-blocks.ll Thu Oct  1 18:48:18 2015
@@ -0,0 +1,139 @@
+; RUN: opt %loadPolly -polly-scops -polly-detect-unprofitable -polly-error-functions=timer_start,timer_stop -analyze < %s | FileCheck %s
+;
+; Error blocks are skipped during SCoP detection. Hence, we have to skip
+; them during SCoP too as they might contain accesses or branches we cannot
+; handle. Additionally, some blocks might be only reachable via error blocks.
+; Such blocks should not be considered to be valid and therefor ignored.
+;
+;    void timer_start(void);
+;    void timer_stop(void);
+;    void kernel(int *A, int *B, int timeit, int N) {
+;
+;      if (timeit) {
+;        timer_start();
+;        // split BB
+;        A[0] = 0;                 // Do not create a statement for this block
+;      }
+;
+;      for (int i = 0; i < N; i++)
+;        A[i] += B[i];
+;
+;      if (timeit) {
+;        timer_stop();
+;        if (invalid float branch) // Do not crash on the float branch
+;          timer_start();
+;      }
+;
+;      for (int i = 0; i < N; i++)
+;        A[i] += B[i];
+;
+;      if (timeit)
+;        timer_stop();
+;    }
+;
+;  The assumed context is empty because all statements are executed only
+;  if timeit != 0. This is due to the fact that they are not "reached"
+;  by the error blocks that are executed for timeit == 0.
+;
+; CHECK:    Region: %entry.split---%if.end.20
+; CHECK:    Assumed Context:
+; CHECK-NEXT:    [timeit, N] -> { : }
+; CHECK:    Statements {
+; CHECK-NOT:  Stmt_if_then_split
+; CHECK:      Stmt_for_body
+; CHECK-NOT:  Stmt_if_then_split
+; CHECK:      Stmt_for_body_9
+; CHECK-NOT:  Stmt_if_then_split
+; CHECK:    }
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @kernel(i32* %A, i32* %B, i32 %timeit, i32 %N) {
+entry:
+  br label %entry.split
+
+entry.split:
+  %tobool = icmp eq i32 %timeit, 0
+  br i1 %tobool, label %for.cond.pre, label %if.then
+
+if.then:                                          ; preds = %entry
+  call void @timer_start()
+  br label %if.then.split
+
+; Dead block if we assume if.then not to be executed because of the call
+if.then.split:                                           ; preds = %if.then
+  %A0 = getelementptr inbounds i32, i32* %A, i64 0
+  store i32 0, i32* %A0, align 4
+  br label %for.cond.pre
+
+for.cond.pre:
+  %tmp = sext i32 %N to i64
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc, %if.end
+  %indvars.iv1 = phi i64 [ %indvars.iv.next2, %for.inc ], [ 0, %for.cond.pre ]
+  %cmp = icmp slt i64 %indvars.iv1, %tmp
+  br i1 %cmp, label %for.body, label %for.end
+
+for.body:                                         ; preds = %for.cond
+  %arrayidx = getelementptr inbounds i32, i32* %B, i64 %indvars.iv1
+  %tmp3 = load i32, i32* %arrayidx, align 4
+  %arrayidx2 = getelementptr inbounds i32, i32* %A, i64 %indvars.iv1
+  %tmp4 = load i32, i32* %arrayidx2, align 4
+  %add = add nsw i32 %tmp4, %tmp3
+  store i32 %add, i32* %arrayidx2, align 4
+  br label %for.inc
+
+for.inc:                                          ; preds = %for.body
+  %indvars.iv.next2 = add nuw nsw i64 %indvars.iv1, 1
+  br label %for.cond
+
+for.end:                                          ; preds = %for.cond
+  %tobool3 = icmp eq i32 %timeit, 0
+  br i1 %tobool3, label %if.end.5, label %if.then.4
+
+if.then.4:                                        ; preds = %for.end
+  call void @timer_stop()
+  %na = fcmp one float 4.0, 5.0
+  br i1 %na, label %if.end.5, label %if.then.4.rem
+
+if.then.4.rem:                                        ; preds = %for.end
+  call void @timer_start()
+  br label %if.end.5
+
+if.end.5:                                         ; preds = %for.end, %if.then.4
+  %tmp5 = sext i32 %N to i64
+  br label %for.cond.7
+
+for.cond.7:                                       ; preds = %for.inc.15, %if.end.5
+  %indvars.iv = phi i64 [ %indvars.iv.next, %for.inc.15 ], [ 0, %if.end.5 ]
+  %cmp8 = icmp slt i64 %indvars.iv, %tmp5
+  br i1 %cmp8, label %for.body.9, label %for.end.17
+
+for.body.9:                                       ; preds = %for.cond.7
+  %arrayidx11 = getelementptr inbounds i32, i32* %B, i64 %indvars.iv
+  %tmp6 = load i32, i32* %arrayidx11, align 4
+  %arrayidx13 = getelementptr inbounds i32, i32* %A, i64 %indvars.iv
+  %tmp7 = load i32, i32* %arrayidx13, align 4
+  %add14 = add nsw i32 %tmp7, %tmp6
+  store i32 %add14, i32* %arrayidx13, align 4
+  br label %for.inc.15
+
+for.inc.15:                                       ; preds = %for.body.9
+  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
+  br label %for.cond.7
+
+for.end.17:                                       ; preds = %for.cond.7
+  %tobool18 = icmp eq i32 %timeit, 0
+  br i1 %tobool18, label %if.end.20, label %if.then.19
+
+if.then.19:                                       ; preds = %for.end.17
+  call void @timer_stop()
+  br label %if.end.20
+
+if.end.20:                                        ; preds = %for.end.17, %if.then.19
+  ret void
+}
+
+declare void @timer_start()
+declare void @timer_stop()




More information about the llvm-commits mailing list