Remove dependence on canonical induction variable
authorTobias Grosser <grosser@fim.uni-passau.de>
Wed, 20 Mar 2013 18:03:18 +0000 (18:03 +0000)
committerTobias Grosser <grosser@fim.uni-passau.de>
Wed, 20 Mar 2013 18:03:18 +0000 (18:03 +0000)
When using the scev based code generation, we now do not rely on the presence
of a canonical induction variable any more. This commit prepares the path to
(conditionally) disable the induction variable canonicalization pass.

llvm-svn: 177548

13 files changed:
polly/include/polly/CodeGen/BlockGenerators.h
polly/include/polly/Support/ScopHelper.h
polly/lib/Analysis/ScopDetection.cpp
polly/lib/CodeGen/BlockGenerators.cpp
polly/lib/CodeGen/CodeGeneration.cpp
polly/lib/CodeGen/IslCodeGeneration.cpp
polly/lib/IndependentBlocks.cpp
polly/lib/Support/ScopHelper.cpp
polly/test/IndependentBlocks/inter_bb_scalar_dep.ll
polly/test/IndependentBlocks/intra_and_inter_bb_scalar_dep.ll
polly/test/IndependentBlocks/intra_bb_scalar_dep.ll
polly/test/IndependentBlocks/scalar_to_array.ll
polly/test/ScopDetect/simple_loop_with_param.ll

index e2518f2..dfea649 100644 (file)
 
 namespace llvm {
   class Pass;
+  class Region;
   class ScalarEvolution;
 }
 
 namespace polly {
+extern bool SCEVCodegen;
+
 using namespace llvm;
 class ScopStmt;
 
 typedef DenseMap<const Value*, Value*> ValueMapT;
 typedef std::vector<ValueMapT> VectorValueMapT;
 
+/// @brief Check whether an instruction can be synthesized by the code
+///        generator.
+///
+/// Some instructions will be recalculated only from information that is code
+/// generated from the polyhedral representation. For such instructions we do
+/// not need to ensure that their operands are available during code generation.
+///
+/// @param I The instruction to check.
+/// @param LI The LoopInfo analysis.
+/// @param SE The scalar evolution database.
+/// @param R The region out of which SSA names are parameters.
+/// @return If the instruction I can be regenerated from its
+///         scalar evolution representation, return true,
+///         otherwise return false.
+bool canSynthesize(const llvm::Instruction *I, const llvm::LoopInfo *LI,
+                   llvm::ScalarEvolution *SE, const llvm::Region *R);
+
 /// @brief Generate a new basic block for a polyhedral statement.
 ///
 /// The only public function exposed is generate().
@@ -64,12 +84,6 @@ protected:
 
   BlockGenerator(IRBuilder<> &B, ScopStmt &Stmt, Pass *P);
 
-  /// @brief Check if an instruction can be 'SCEV-ignored'
-  ///
-  /// An instruction can be ignored if we can recreate it from its scalar
-  /// evolution expression.
-  bool isSCEVIgnore(const Instruction *Inst);
-
   /// @brief Get the new version of a Value.
   ///
   /// @param Old       The old Value.
index 5068c5c..4c23365 100755 (executable)
@@ -39,15 +39,6 @@ namespace polly {
 ///         return the loop, otherwise, return null.
 llvm::Loop *castToLoop(const llvm::Region &R, llvm::LoopInfo &LI);
 
-/// @brief Check if the instruction I is the induction variable of a loop.
-///
-/// @param I The instruction to check.
-/// @param LI The LoopInfo analysis.
-///
-/// @return Return true if I is the induction variable of a loop, false
-///         otherwise.
-bool isIndVar(const llvm::Instruction *I, const llvm::LoopInfo *LI);
-
 /// @brief Check if the PHINode has any incoming Invoke edge.
 ///
 /// @param PN The PHINode to check.
index 8c3f2fd..a35f03c 100644 (file)
@@ -44,9 +44,9 @@
 //
 //===----------------------------------------------------------------------===//
 
-#include "polly/ScopDetection.h"
-
+#include "polly/CodeGen/BlockGenerators.h"
 #include "polly/LinkAllPasses.h"
+#include "polly/ScopDetection.h"
 #include "polly/Support/ScopHelper.h"
 #include "polly/Support/SCEVValidator.h"
 
@@ -338,10 +338,14 @@ bool ScopDetection::hasScalarDependency(Instruction &Inst,
 
 bool ScopDetection::isValidInstruction(Instruction &Inst,
                                        DetectionContext &Context) const {
-  // Only canonical IVs are allowed.
   if (PHINode *PN = dyn_cast<PHINode>(&Inst))
-    if (!isIndVar(PN, LI))
-      INVALID(IndVar, "Non canonical PHI node: " << Inst);
+    if (!canSynthesize(PN, LI, SE, &Context.CurRegion)) {
+      if (SCEVCodegen)
+        INVALID(IndVar,
+                "SCEV of PHI node refers to SSA names in region: " << Inst);
+      else
+        INVALID(IndVar, "Non canonical PHI node: " << Inst);
+    }
 
   // Scalar dependencies are not allowed.
   if (hasScalarDependency(Inst, Context.CurRegion))
index 35b7535..063ec77 100644 (file)
@@ -18,6 +18,7 @@
 #include "polly/CodeGen/BlockGenerators.h"
 #include "polly/Support/GICHelper.h"
 #include "polly/Support/SCEVValidator.h"
+#include "polly/Support/ScopHelper.h"
 
 #include "llvm/Analysis/LoopInfo.h"
 #include "llvm/Analysis/ScalarEvolution.h"
@@ -36,9 +37,31 @@ Aligned("enable-polly-aligned", cl::desc("Assumed aligned memory accesses."),
         cl::Hidden, cl::value_desc("OpenMP code generation enabled if true"),
         cl::init(false), cl::ZeroOrMore);
 
-static cl::opt<bool>
-SCEVCodegen("polly-codegen-scev", cl::desc("Use SCEV based code generation."),
-            cl::Hidden, cl::init(false), cl::ZeroOrMore);
+static cl::opt<bool, true>
+SCEVCodegenF("polly-codegen-scev", cl::desc("Use SCEV based code generation."),
+             cl::Hidden, cl::location(SCEVCodegen), cl::init(false),
+             cl::ZeroOrMore);
+
+bool polly::SCEVCodegen;
+
+bool polly::canSynthesize(const Instruction *I, const llvm::LoopInfo *LI,
+                          ScalarEvolution *SE, const Region *R) {
+  if (SCEVCodegen) {
+    if (!I || !SE->isSCEVable(I->getType()))
+      return false;
+
+    if (const SCEV *Scev = SE->getSCEV(const_cast<Instruction *>(I)))
+      if (!isa<SCEVCouldNotCompute>(Scev))
+        if (!hasScalarDepsInsideRegion(Scev, R))
+          return true;
+
+    return false;
+  }
+
+  Loop *L = LI->getLoopFor(I->getParent());
+  return L && I == L->getCanonicalInductionVariable();
+}
+
 
 // Helper class to generate memory location.
 namespace {
@@ -146,16 +169,6 @@ BlockGenerator::BlockGenerator(IRBuilder<> &B, ScopStmt &Stmt, Pass *P)
     : Builder(B), Statement(Stmt), P(P), SE(P->getAnalysis<ScalarEvolution>()) {
 }
 
-bool BlockGenerator::isSCEVIgnore(const Instruction *Inst) {
-  if (SCEVCodegen && SE.isSCEVable(Inst->getType()))
-    if (const SCEV *Scev = SE.getSCEV(const_cast<Instruction *>(Inst)))
-      if (!isa<SCEVCouldNotCompute>(Scev))
-        return !hasScalarDepsInsideRegion(Scev,
-                                          &Statement.getParent()->getRegion());
-
-  return false;
-}
-
 Value *BlockGenerator::getNewValue(const Value *Old, ValueMapT &BBMap,
                                    ValueMapT &GlobalMap, LoopToScevMapT &LTS) {
   // We assume constants never change.
@@ -193,14 +206,11 @@ Value *BlockGenerator::getNewValue(const Value *Old, ValueMapT &BBMap,
         return Expanded;
       }
 
-  // 'Old' is within the original SCoP, but was not rewritten.
-  //
-  // Such values appear, if they only calculate information already available in
-  // the polyhedral description (e.g.  an induction variable increment). They
-  // can be safely ignored.
-  if (const Instruction *Inst = dyn_cast<Instruction>(Old))
-    if (Statement.getParent()->getRegion().contains(Inst->getParent()))
-      return NULL;
+  if (const Instruction *Inst = dyn_cast<Instruction>(Old)) {
+    (void) Inst;
+    assert(!Statement.getParent()->getRegion().contains(Inst->getParent()) &&
+           "unexpected scalar dependence in region");
+  }
 
   // Everything else is probably a scop-constant value defined as global,
   // function parameter or an instruction not within the scop.
@@ -330,7 +340,8 @@ void BlockGenerator::copyInstruction(const Instruction *Inst, ValueMapT &BBMap,
   if (Inst->isTerminator())
     return;
 
-  if (isSCEVIgnore(Inst))
+  if (canSynthesize(Inst, &P->getAnalysis<LoopInfo>(), &SE,
+                    &Statement.getParent()->getRegion()))
     return;
 
   if (const LoadInst *Load = dyn_cast<LoadInst>(Inst)) {
@@ -619,7 +630,8 @@ void VectorBlockGenerator::copyInstruction(const Instruction *Inst,
   if (Inst->isTerminator())
     return;
 
-  if (isSCEVIgnore(Inst))
+  if (canSynthesize(Inst, &P->getAnalysis<LoopInfo>(), &SE,
+                    &Statement.getParent()->getRegion()))
     return;
 
   if (const LoadInst *Load = dyn_cast<LoadInst>(Inst)) {
index f71e931..ffe6f38 100644 (file)
@@ -1017,6 +1017,7 @@ public:
     AU.addRequired<ScopDetection>();
     AU.addRequired<ScopInfo>();
     AU.addRequired<DataLayout>();
+    AU.addRequired<LoopInfo>();
 
     AU.addPreserved<CloogInfo>();
     AU.addPreserved<Dependences>();
index 83a5884..20738a9 100644 (file)
@@ -1045,6 +1045,7 @@ public:
     AU.addRequired<ScalarEvolution>();
     AU.addRequired<ScopDetection>();
     AU.addRequired<ScopInfo>();
+    AU.addRequired<LoopInfo>();
 
     AU.addPreserved<Dependences>();
 
index fe78ef3..f62fc50 100644 (file)
@@ -14,6 +14,7 @@
 #include "polly/LinkAllPasses.h"
 #include "polly/ScopDetection.h"
 #include "polly/Support/ScopHelper.h"
+#include "polly/CodeGen/BlockGenerators.h"
 #include "polly/CodeGen/Cloog.h"
 
 #include "llvm/Analysis/LoopInfo.h"
@@ -191,8 +192,7 @@ void IndependentBlocks::moveOperandTree(Instruction *Inst, const Region *R,
         continue;
       }
 
-      // No need to move induction variable.
-      if (isIndVar(Operand, LI)) {
+      if (canSynthesize(Operand, LI, SE, R)) {
         DEBUG(dbgs() << "is IV.\n");
         continue;
       }
@@ -245,7 +245,7 @@ bool IndependentBlocks::createIndependentBlocks(BasicBlock *BB,
                                                 const Region *R) {
   std::vector<Instruction*> WorkList;
   for (BasicBlock::iterator II = BB->begin(), IE = BB->end(); II != IE; ++II)
-    if (!isSafeToMove(II) && !isIndVar(II, LI))
+    if (!isSafeToMove(II) && !canSynthesize(II, LI, SE, R))
       WorkList.push_back(II);
 
   ReplacedMapType ReplacedMap;
@@ -307,7 +307,7 @@ bool IndependentBlocks::isEscapeOperand(const Value *Operand,
   if (OpInst == 0) return false;
 
   // Induction variables are valid operands.
-  if (isIndVar(OpInst, LI)) return false;
+  if (canSynthesize(OpInst, LI, SE, R)) return false;
 
   // A value from a different BB is used in the same region.
   return R->contains(OpInst) && (OpInst->getParent() != CurBB);
@@ -356,7 +356,7 @@ bool IndependentBlocks::translateScalarToArray(const Region *R) {
 
 bool IndependentBlocks::translateScalarToArray(Instruction *Inst,
                                                const Region *R) {
-  if (isIndVar(Inst, LI))
+  if (canSynthesize(Inst, LI, SE, R))
     return false;
 
   SmallVector<Instruction*, 4> LoadInside, LoadOutside;
@@ -369,7 +369,7 @@ bool IndependentBlocks::translateScalarToArray(Instruction *Inst,
       if (isEscapeUse(U, R))
         LoadOutside.push_back(U);
 
-      if (isIndVar(U, LI))
+      if (canSynthesize(U, LI, SE, R))
         continue;
 
       if (R->contains(UParent) && isEscapeOperand(Inst, UParent, R))
@@ -402,7 +402,7 @@ bool IndependentBlocks::translateScalarToArray(Instruction *Inst,
 
   while (!LoadInside.empty()) {
     Instruction *U = LoadInside.pop_back_val();
-    assert(!isa<PHINode>(U) && "Can not handle PHI node outside!");
+    assert(!isa<PHINode>(U) && "Can not handle PHI node inside!");
     SE->forgetValue(U);
     LoadInst *L = new LoadInst(Slot, Inst->getName()+".loadarray",
                                false, U);
@@ -435,7 +435,7 @@ bool IndependentBlocks::isIndependentBlock(const Region *R,
        II != IE; ++II) {
     Instruction *Inst = &*II;
 
-    if (isIndVar(Inst, LI))
+    if (canSynthesize(Inst, LI, SE, R))
       continue;
 
     // A value inside the Scop is referenced outside.
index 180f579..904492a 100644 (file)
@@ -66,15 +66,6 @@ Value *polly::getPointerOperand(Instruction &Inst) {
   return 0;
 }
 
-//===----------------------------------------------------------------------===//
-// Helper functions
-
-bool polly::isIndVar(const Instruction *I, const LoopInfo *LI) {
-  Loop *L = LI->getLoopFor(I->getParent());
-
-  return L && I == L->getCanonicalInductionVariable();
-}
-
 bool polly::hasInvokeEdge(const PHINode *PN) {
   for (unsigned i = 0, e = PN->getNumIncomingValues(); i < e; ++i)
     if (InvokeInst *II = dyn_cast<InvokeInst>(PN->getIncomingValue(i)))
index dd595f1..4860e87 100644 (file)
@@ -1,4 +1,5 @@
 ; RUN: opt %loadPolly -basicaa -polly-independent -S < %s | FileCheck %s
+; RUN: opt %loadPolly -basicaa -polly-independent -polly-codegen-scev -S < %s | FileCheck %s
 
 ; void f(long A[], int N, int *init_ptr) {
 ;   long i, j;
index 40704f7..279a392 100644 (file)
@@ -1,4 +1,5 @@
 ; RUN: opt %loadPolly -basicaa -polly-independent -S < %s | FileCheck %s
+; RUN: opt %loadPolly -basicaa -polly-independent -polly-codegen-scev -S < %s | FileCheck %s
 
 ; void f(long A[], int N, int *init_ptr) {
 ;   long i, j;
index 62dfbd6..c9d8e6e 100644 (file)
@@ -1,4 +1,5 @@
 ; RUN: opt %loadPolly -basicaa -polly-independent -S < %s | FileCheck %s
+; RUN: opt %loadPolly -basicaa -polly-independent -polly-codegen-scev -S < %s | FileCheck %s
 
 ; void f(long A[], int N, int *init_ptr) {
 ;   long i, j;
index 4de46a9..55851bf 100644 (file)
@@ -1,4 +1,6 @@
 ; RUN: opt %loadPolly -basicaa -polly-independent < %s -S | FileCheck %s
+; RUN: opt %loadPolly -basicaa -polly-independent -polly-codegen-scev < %s -S | FileCheck %s
+
 target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64"
 target triple = "x86_64-unknown-linux-gnu"
 
index 73e3401..d117213 100644 (file)
@@ -1,4 +1,5 @@
 ; RUN: opt %loadPolly -basicaa -polly-detect -analyze < %s | FileCheck %s
+; RUN: opt %loadPolly -basicaa -polly-detect -analyze -polly-codegen-scev < %s | FileCheck -check-prefix=CHECK-SCEV %s
 
 ; void f(long A[], long N, long *init_ptr) {
 ;   long i, j;
@@ -49,3 +50,4 @@ return:
 }
 
 ; CHECK-NOT: Valid Region for Scop
+; CHECK-SCEV: Valid Region for Scop: for.j => for.i.end