Remove dependence on canonical induction variable

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
This commit is contained in:
Tobias Grosser 2013-03-20 18:03:18 +00:00
parent 62f1fea4c5
commit ecfe21b792
13 changed files with 81 additions and 60 deletions

View File

@ -26,16 +26,36 @@
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.

View File

@ -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.

View 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))

View 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)) {

View File

@ -1017,6 +1017,7 @@ public:
AU.addRequired<ScopDetection>();
AU.addRequired<ScopInfo>();
AU.addRequired<DataLayout>();
AU.addRequired<LoopInfo>();
AU.addPreserved<CloogInfo>();
AU.addPreserved<Dependences>();

View File

@ -1045,6 +1045,7 @@ public:
AU.addRequired<ScalarEvolution>();
AU.addRequired<ScopDetection>();
AU.addRequired<ScopInfo>();
AU.addRequired<LoopInfo>();
AU.addPreserved<Dependences>();

View 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.

View 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)))

View 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;

View 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;

View 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;

View 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"

View 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