[polly] r247310 - Runtime error check elimination

Johannes Doerfert via llvm-commits llvm-commits at lists.llvm.org
Thu Sep 10 10:51:28 PDT 2015


Author: jdoerfert
Date: Thu Sep 10 12:51:27 2015
New Revision: 247310

URL: http://llvm.org/viewvc/llvm-project?rev=247310&view=rev
Log:
Runtime error check elimination

  Hoist runtime checks in the loop nest if they guard an "error" like event.
  Such events are recognized as blocks with an unreachable terminator or a call
  to the ubsan function that deals with out of bound accesses. Other "error"
  events can be added easily.

  We will ignore these blocks when we detect/model/optmize and code generate SCoPs
  but we will make sure that they would not have been executed using the assumption
  framework.

Added:
    polly/trunk/test/ScopInfo/BoundChecks/two-loops.ll
Modified:
    polly/trunk/include/polly/Support/ScopHelper.h
    polly/trunk/lib/Analysis/ScopDetection.cpp
    polly/trunk/lib/Analysis/ScopInfo.cpp
    polly/trunk/lib/Support/ScopHelper.cpp
    polly/trunk/test/ScopInfo/BoundChecks/single-loop.ll

Modified: polly/trunk/include/polly/Support/ScopHelper.h
URL: http://llvm.org/viewvc/llvm-project/polly/trunk/include/polly/Support/ScopHelper.h?rev=247310&r1=247309&r2=247310&view=diff
==============================================================================
--- polly/trunk/include/polly/Support/ScopHelper.h (original)
+++ polly/trunk/include/polly/Support/ScopHelper.h Thu Sep 10 12:51:27 2015
@@ -99,5 +99,19 @@ llvm::Value *expandCodeFor(Scop &S, llvm
                            const llvm::DataLayout &DL, const char *Name,
                            const llvm::SCEV *E, llvm::Type *Ty,
                            llvm::Instruction *IP);
+
+/// @brief Check if the block is a error block.
+///
+/// A error block is currently any block that fullfills at least one of
+/// the following conditions:
+///
+///  - It is terminated by an unreachable instruction
+///  - It contains a call to a function named:
+///     + __ubsan_handle_out_of_bounds
+///
+/// @param BB The block to check.
+///
+/// @return True if the block is a error block, false otherwise.
+bool isErrorBlock(llvm::BasicBlock &BB);
 }
 #endif

Modified: polly/trunk/lib/Analysis/ScopDetection.cpp
URL: http://llvm.org/viewvc/llvm-project/polly/trunk/lib/Analysis/ScopDetection.cpp?rev=247310&r1=247309&r2=247310&view=diff
==============================================================================
--- polly/trunk/lib/Analysis/ScopDetection.cpp (original)
+++ polly/trunk/lib/Analysis/ScopDetection.cpp Thu Sep 10 12:51:27 2015
@@ -896,14 +896,17 @@ bool ScopDetection::allBlocksValid(Detec
       return false;
   }
 
-  for (BasicBlock *BB : CurRegion.blocks())
+  for (BasicBlock *BB : CurRegion.blocks()) {
+    // Do not check exception blocks as we will never include them in the SCoP.
+    if (isErrorBlock(*BB))
+      continue;
+
     if (!isValidCFG(*BB, Context) && !KeepGoing)
       return false;
-
-  for (BasicBlock *BB : CurRegion.blocks())
     for (BasicBlock::iterator I = BB->begin(), E = --BB->end(); I != E; ++I)
       if (!isValidInstruction(*I, Context) && !KeepGoing)
         return false;
+  }
 
   if (!hasAffineMemoryAccesses(Context))
     return false;

Modified: polly/trunk/lib/Analysis/ScopInfo.cpp
URL: http://llvm.org/viewvc/llvm-project/polly/trunk/lib/Analysis/ScopInfo.cpp?rev=247310&r1=247309&r2=247310&view=diff
==============================================================================
--- polly/trunk/lib/Analysis/ScopInfo.cpp (original)
+++ polly/trunk/lib/Analysis/ScopInfo.cpp Thu Sep 10 12:51:27 2015
@@ -1554,6 +1554,15 @@ void Scop::buildDomainsWithBranchConstra
     }
 
     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));
+      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 "
@@ -1569,7 +1578,7 @@ void Scop::buildDomainsWithBranchConstra
     // exit node, hence the single entry node domain is the condition set. For
     // basic blocks we use the helper function buildConditionSets.
     SmallVector<isl_set *, 2> ConditionSets;
-    BranchInst *BI = cast<BranchInst>(BB->getTerminator());
+    BranchInst *BI = cast<BranchInst>(TI);
     if (RN->isSubRegion())
       ConditionSets.push_back(isl_set_copy(Domain));
     else
@@ -1738,6 +1747,13 @@ void Scop::propagateDomainConstraints(Re
 
     // Under the union of all predecessor conditions we can reach this block.
     Domain = isl_set_intersect(Domain, PredDom);
+
+    // Add assumptions for error blocks.
+    if (isErrorBlock(*BB)) {
+      IsOptimized = true;
+      isl_set *DomPar = isl_set_params(isl_set_copy(Domain));
+      addAssumption(isl_set_complement(DomPar));
+    }
   }
 }
 
@@ -2435,7 +2451,7 @@ bool Scop::restrictDomains(__isl_take is
 ScalarEvolution *Scop::getSE() const { return SE; }
 
 bool Scop::isTrivialBB(BasicBlock *BB, TempScop &tempScop) {
-  if (tempScop.getAccessFunctions(BB))
+  if (tempScop.getAccessFunctions(BB) && !isErrorBlock(*BB))
     return false;
 
   return true;

Modified: polly/trunk/lib/Support/ScopHelper.cpp
URL: http://llvm.org/viewvc/llvm-project/polly/trunk/lib/Support/ScopHelper.cpp?rev=247310&r1=247309&r2=247310&view=diff
==============================================================================
--- polly/trunk/lib/Support/ScopHelper.cpp (original)
+++ polly/trunk/lib/Support/ScopHelper.cpp Thu Sep 10 12:51:27 2015
@@ -331,3 +331,17 @@ Value *polly::expandCodeFor(Scop &S, Sca
   ScopExpander Expander(S.getRegion(), SE, DL, Name);
   return Expander.expandCodeFor(E, Ty, IP);
 }
+
+bool polly::isErrorBlock(BasicBlock &BB) {
+
+  for (Instruction &Inst : BB)
+    if (CallInst *CI = dyn_cast<CallInst>(&Inst))
+      if (Function *F = CI->getCalledFunction())
+        if (F->getName().equals("__ubsan_handle_out_of_bounds"))
+          return true;
+
+  if (isa<UnreachableInst>(BB.getTerminator()))
+    return true;
+
+  return false;
+}

Modified: polly/trunk/test/ScopInfo/BoundChecks/single-loop.ll
URL: http://llvm.org/viewvc/llvm-project/polly/trunk/test/ScopInfo/BoundChecks/single-loop.ll?rev=247310&r1=247309&r2=247310&view=diff
==============================================================================
--- polly/trunk/test/ScopInfo/BoundChecks/single-loop.ll (original)
+++ polly/trunk/test/ScopInfo/BoundChecks/single-loop.ll Thu Sep 10 12:51:27 2015
@@ -1,5 +1,5 @@
-; RUN: opt %loadPolly -polly-scops -analyze < %s | FileCheck %s
-; XFAIL: *
+; RUN: opt %loadPolly -polly-detect-unprofitable -polly-scops -analyze < %s | FileCheck %s
+; RUN: opt %loadPolly -polly-detect-unprofitable -polly-ast -analyze < %s | FileCheck %s --check-prefix=AST
 ;
 ;    void exception() __attribute__((noreturn));
 ;
@@ -18,7 +18,18 @@
 ; We should detect this kernel as a SCoP and derive run-time conditions such
 ; that the bound-checked blocks are not part of the optimized SCoP.
 
-; CHECK: Assumed Context
+; CHECK: Assumed Context:
+; CHECK:  [n] -> {  : n <= 100 }
+
+; AST: if (n <= 100)
+; AST:     for (int c0 = 0; c0 <= min(99, n - 1); c0 += 1)
+; AST:       Stmt_if_end_4(c0);
+;
+; AST-NOT: for
+; AST-NOT: Stmt
+;
+; AST: else
+; AST:     {  /* original code */ }
 
 target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
 

Added: polly/trunk/test/ScopInfo/BoundChecks/two-loops.ll
URL: http://llvm.org/viewvc/llvm-project/polly/trunk/test/ScopInfo/BoundChecks/two-loops.ll?rev=247310&view=auto
==============================================================================
--- polly/trunk/test/ScopInfo/BoundChecks/two-loops.ll (added)
+++ polly/trunk/test/ScopInfo/BoundChecks/two-loops.ll Thu Sep 10 12:51:27 2015
@@ -0,0 +1,98 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -polly-scops -analyze < %s | FileCheck %s
+; RUN: opt %loadPolly -polly-detect-unprofitable -polly-ast -analyze < %s | FileCheck %s --check-prefix=AST
+;
+;    void exception() __attribute__((noreturn));
+;
+;    void foo(long n, float A[100]) {
+;      for (long j = 0; j < n; j++) {
+;        for (long i = j; i < n; i++) {
+;          if (i < 0)
+;            exception();
+;
+;          if (i >= 100)
+;            exception();
+;
+;          A[i] += i;
+;        }
+;      }
+;    }
+;
+; CHECK: Assumed Context:
+; CHECK:  [n] -> {  : n <= 100 }
+
+; AST: if (n <= 100)
+; AST:     for (int c0 = 0; c0 <= min(99, n - 1); c0 += 1)
+; AST:       for (int c1 = 0; c1 <= min(n - c0 - 1, -c0 + 99); c1 += 1)
+; AST:         Stmt_if_end_7(c0, c1);
+;
+; AST-NOT: for
+; AST-NOT: Stmt
+;
+; AST: else
+; AST:     {  /* original code */ }
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @foo(i64 %n, float* %A) #0 {
+entry:
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc.8, %entry
+  %j.0 = phi i64 [ 0, %entry ], [ %inc9, %for.inc.8 ]
+  %cmp = icmp slt i64 %j.0, %n
+  br i1 %cmp, label %for.body, label %for.end.10
+
+for.body:                                         ; preds = %for.cond
+  br label %for.cond.1
+
+for.cond.1:                                       ; preds = %for.inc, %for.body
+  %i.0 = phi i64 [ %j.0, %for.body ], [ %inc, %for.inc ]
+  %cmp2 = icmp slt i64 %i.0, %n
+  br i1 %cmp2, label %for.body.3, label %for.end
+
+for.body.3:                                       ; preds = %for.cond.1
+  br i1 false, label %if.then, label %if.end
+
+if.then:                                          ; preds = %for.body.3
+  call void (...) @exception() #2
+  unreachable
+
+if.end:                                           ; preds = %for.body.3
+  %cmp5 = icmp sgt i64 %i.0, 99
+  br i1 %cmp5, label %if.then.6, label %if.end.7
+
+if.then.6:                                        ; preds = %if.end
+  call void (...) @exception() #2
+  unreachable
+
+if.end.7:                                         ; preds = %if.end
+  %conv = sitofp i64 %i.0 to float
+  %arrayidx = getelementptr inbounds float, float* %A, i64 %i.0
+  %tmp = load float, float* %arrayidx, align 4
+  %add = fadd float %tmp, %conv
+  store float %add, float* %arrayidx, align 4
+  br label %for.inc
+
+for.inc:                                          ; preds = %if.end.7
+  %inc = add nuw nsw i64 %i.0, 1
+  br label %for.cond.1
+
+for.end:                                          ; preds = %for.cond.1
+  br label %for.inc.8
+
+for.inc.8:                                        ; preds = %for.end
+  %inc9 = add nuw nsw i64 %j.0, 1
+  br label %for.cond
+
+for.end.10:                                       ; preds = %for.cond
+  ret void
+}
+
+declare void @exception(...) #1
+
+attributes #0 = { nounwind uwtable "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+sse,+sse2" "unsafe-fp-math"="false" "use-soft-float"="false" }
+attributes #1 = { noreturn "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+sse,+sse2" "unsafe-fp-math"="false" "use-soft-float"="false" }
+attributes #2 = { noreturn nounwind }
+
+!llvm.ident = !{!0}
+
+!0 = !{!"clang version 3.8.0 (trunk 246853)"}




More information about the llvm-commits mailing list