forked from OSchip/llvm-project
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:
parent
62f1fea4c5
commit
ecfe21b792
|
@ -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.
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -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 <S) {
|
||||
// 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)) {
|
||||
|
|
|
@ -1017,6 +1017,7 @@ public:
|
|||
AU.addRequired<ScopDetection>();
|
||||
AU.addRequired<ScopInfo>();
|
||||
AU.addRequired<DataLayout>();
|
||||
AU.addRequired<LoopInfo>();
|
||||
|
||||
AU.addPreserved<CloogInfo>();
|
||||
AU.addPreserved<Dependences>();
|
||||
|
|
|
@ -1045,6 +1045,7 @@ public:
|
|||
AU.addRequired<ScalarEvolution>();
|
||||
AU.addRequired<ScopDetection>();
|
||||
AU.addRequired<ScopInfo>();
|
||||
AU.addRequired<LoopInfo>();
|
||||
|
||||
AU.addPreserved<Dependences>();
|
||||
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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)))
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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"
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue