2011-04-29 14:27:02 +08:00
|
|
|
//===----- ScopDetection.cpp - Detect Scops --------------------*- C++ -*-===//
|
|
|
|
//
|
|
|
|
// The LLVM Compiler Infrastructure
|
|
|
|
//
|
|
|
|
// This file is distributed under the University of Illinois Open Source
|
|
|
|
// License. See LICENSE.TXT for details.
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
//
|
|
|
|
// Detect the maximal Scops of a function.
|
|
|
|
//
|
|
|
|
// A static control part (Scop) is a subgraph of the control flow graph (CFG)
|
|
|
|
// that only has statically known control flow and can therefore be described
|
|
|
|
// within the polyhedral model.
|
|
|
|
//
|
|
|
|
// Every Scop fullfills these restrictions:
|
|
|
|
//
|
|
|
|
// * It is a single entry single exit region
|
|
|
|
//
|
|
|
|
// * Only affine linear bounds in the loops
|
|
|
|
//
|
|
|
|
// Every natural loop in a Scop must have a number of loop iterations that can
|
|
|
|
// be described as an affine linear function in surrounding loop iterators or
|
|
|
|
// parameters. (A parameter is a scalar that does not change its value during
|
|
|
|
// execution of the Scop).
|
|
|
|
//
|
|
|
|
// * Only comparisons of affine linear expressions in conditions
|
|
|
|
//
|
|
|
|
// * All loops and conditions perfectly nested
|
|
|
|
//
|
|
|
|
// The control flow needs to be structured such that it could be written using
|
|
|
|
// just 'for' and 'if' statements, without the need for any 'goto', 'break' or
|
|
|
|
// 'continue'.
|
|
|
|
//
|
|
|
|
// * Side effect free functions call
|
|
|
|
//
|
|
|
|
// Only function calls and intrinsics that do not have side effects are allowed
|
|
|
|
// (readnone).
|
|
|
|
//
|
|
|
|
// The Scop detection finds the largest Scops by checking if the largest
|
|
|
|
// region is a Scop. If this is not the case, its canonical subregions are
|
|
|
|
// checked until a region is a Scop. It is now tried to extend this Scop by
|
|
|
|
// creating a larger non canonical region.
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2013-03-21 02:03:18 +08:00
|
|
|
#include "polly/CodeGen/BlockGenerators.h"
|
2011-04-29 14:27:02 +08:00
|
|
|
#include "polly/LinkAllPasses.h"
|
2013-05-07 15:31:10 +08:00
|
|
|
#include "polly/Options.h"
|
2014-04-02 19:54:01 +08:00
|
|
|
#include "polly/ScopDetectionDiagnostic.h"
|
2013-03-21 02:03:18 +08:00
|
|
|
#include "polly/ScopDetection.h"
|
2011-11-07 20:58:54 +08:00
|
|
|
#include "polly/Support/SCEVValidator.h"
|
2013-05-07 16:11:54 +08:00
|
|
|
#include "polly/Support/ScopHelper.h"
|
2014-09-18 19:17:17 +08:00
|
|
|
#include "polly/CodeGen/CodeGeneration.h"
|
2011-04-29 14:27:02 +08:00
|
|
|
#include "llvm/ADT/Statistic.h"
|
|
|
|
#include "llvm/Analysis/AliasAnalysis.h"
|
2011-11-10 06:35:00 +08:00
|
|
|
#include "llvm/Analysis/LoopInfo.h"
|
2014-07-20 02:40:17 +08:00
|
|
|
#include "llvm/Analysis/PostDominators.h"
|
2011-04-29 14:27:02 +08:00
|
|
|
#include "llvm/Analysis/RegionIterator.h"
|
2011-11-10 06:35:00 +08:00
|
|
|
#include "llvm/Analysis/ScalarEvolution.h"
|
2011-11-10 20:44:50 +08:00
|
|
|
#include "llvm/Analysis/ScalarEvolutionExpressions.h"
|
2014-03-06 08:47:27 +08:00
|
|
|
#include "llvm/IR/DebugInfo.h"
|
2013-12-18 18:49:53 +08:00
|
|
|
#include "llvm/IR/DiagnosticInfo.h"
|
|
|
|
#include "llvm/IR/DiagnosticPrinter.h"
|
2014-03-06 08:47:27 +08:00
|
|
|
#include "llvm/IR/LLVMContext.h"
|
2011-04-29 14:27:02 +08:00
|
|
|
#include "llvm/Support/Debug.h"
|
2011-11-08 23:41:28 +08:00
|
|
|
#include <set>
|
|
|
|
|
2011-04-29 14:27:02 +08:00
|
|
|
using namespace llvm;
|
|
|
|
using namespace polly;
|
|
|
|
|
2014-04-22 11:30:19 +08:00
|
|
|
#define DEBUG_TYPE "polly-detect"
|
|
|
|
|
2013-05-31 01:47:32 +08:00
|
|
|
static cl::opt<bool>
|
2014-07-09 18:50:10 +08:00
|
|
|
DetectScopsWithoutLoops("polly-detect-scops-in-functions-without-loops",
|
|
|
|
cl::desc("Detect scops in functions without loops"),
|
|
|
|
cl::Hidden, cl::init(false), cl::ZeroOrMore,
|
|
|
|
cl::cat(PollyCategory));
|
2013-05-31 01:47:32 +08:00
|
|
|
|
2013-06-04 00:35:37 +08:00
|
|
|
static cl::opt<bool>
|
2014-07-09 18:50:10 +08:00
|
|
|
DetectRegionsWithoutLoops("polly-detect-scops-in-regions-without-loops",
|
|
|
|
cl::desc("Detect scops in regions without loops"),
|
|
|
|
cl::Hidden, cl::init(false), cl::ZeroOrMore,
|
|
|
|
cl::cat(PollyCategory));
|
|
|
|
|
|
|
|
static cl::opt<std::string> OnlyFunction(
|
|
|
|
"polly-only-func",
|
|
|
|
cl::desc("Only run on functions that contain a certain string"),
|
|
|
|
cl::value_desc("string"), cl::ValueRequired, cl::init(""),
|
|
|
|
cl::cat(PollyCategory));
|
|
|
|
|
|
|
|
static cl::opt<std::string> OnlyRegion(
|
|
|
|
"polly-only-region",
|
|
|
|
cl::desc("Only run on certain regions (The provided identifier must "
|
|
|
|
"appear in the name of the region's entry block"),
|
|
|
|
cl::value_desc("identifier"), cl::ValueRequired, cl::init(""),
|
|
|
|
cl::cat(PollyCategory));
|
2014-01-27 22:24:53 +08:00
|
|
|
|
2011-11-10 20:47:26 +08:00
|
|
|
static cl::opt<bool>
|
2014-07-09 18:50:10 +08:00
|
|
|
IgnoreAliasing("polly-ignore-aliasing",
|
|
|
|
cl::desc("Ignore possible aliasing of the array bases"),
|
|
|
|
cl::Hidden, cl::init(false), cl::ZeroOrMore,
|
|
|
|
cl::cat(PollyCategory));
|
2011-10-23 19:17:06 +08:00
|
|
|
|
2014-09-18 19:17:17 +08:00
|
|
|
bool polly::PollyUseRuntimeAliasChecks;
|
|
|
|
static cl::opt<bool, true> XPollyUseRuntimeAliasChecks(
|
|
|
|
"polly-use-runtime-alias-checks",
|
|
|
|
cl::desc("Use runtime alias checks to resolve possible aliasing."),
|
|
|
|
cl::location(PollyUseRuntimeAliasChecks), cl::Hidden, cl::ZeroOrMore,
|
|
|
|
cl::init(true), cl::cat(PollyCategory));
|
|
|
|
|
2013-05-07 15:31:10 +08:00
|
|
|
static cl::opt<bool>
|
2014-07-09 18:50:10 +08:00
|
|
|
ReportLevel("polly-report",
|
|
|
|
cl::desc("Print information about the activities of Polly"),
|
|
|
|
cl::init(false), cl::ZeroOrMore, cl::cat(PollyCategory));
|
2012-11-02 00:45:20 +08:00
|
|
|
|
2011-12-20 18:43:14 +08:00
|
|
|
static cl::opt<bool>
|
2014-07-09 18:50:10 +08:00
|
|
|
AllowNonAffine("polly-allow-nonaffine",
|
|
|
|
cl::desc("Allow non affine access functions in arrays"),
|
|
|
|
cl::Hidden, cl::init(false), cl::ZeroOrMore,
|
|
|
|
cl::cat(PollyCategory));
|
2011-12-20 18:43:14 +08:00
|
|
|
|
2013-07-25 11:02:29 +08:00
|
|
|
static cl::opt<bool, true>
|
2014-07-09 18:50:10 +08:00
|
|
|
TrackFailures("polly-detect-track-failures",
|
|
|
|
cl::desc("Track failure strings in detecting scop regions"),
|
|
|
|
cl::location(PollyTrackFailures), cl::Hidden, cl::ZeroOrMore,
|
2014-08-17 18:09:03 +08:00
|
|
|
cl::init(true), cl::cat(PollyCategory));
|
2013-07-25 11:02:29 +08:00
|
|
|
|
2014-05-24 17:25:10 +08:00
|
|
|
static cl::opt<bool> KeepGoing("polly-detect-keep-going",
|
|
|
|
cl::desc("Do not fail on the first error."),
|
|
|
|
cl::Hidden, cl::ZeroOrMore, cl::init(false),
|
|
|
|
cl::cat(PollyCategory));
|
|
|
|
|
2014-04-09 05:20:44 +08:00
|
|
|
static cl::opt<bool, true>
|
2014-07-09 18:50:10 +08:00
|
|
|
PollyDelinearizeX("polly-delinearize",
|
|
|
|
cl::desc("Delinearize array access functions"),
|
|
|
|
cl::location(PollyDelinearize), cl::Hidden,
|
|
|
|
cl::ZeroOrMore, cl::init(false), cl::cat(PollyCategory));
|
2014-04-09 05:20:44 +08:00
|
|
|
|
2014-02-19 02:49:49 +08:00
|
|
|
static cl::opt<bool>
|
2014-07-09 18:50:10 +08:00
|
|
|
VerifyScops("polly-detect-verify",
|
|
|
|
cl::desc("Verify the detected SCoPs after each transformation"),
|
|
|
|
cl::Hidden, cl::init(false), cl::ZeroOrMore,
|
|
|
|
cl::cat(PollyCategory));
|
2014-02-19 02:49:49 +08:00
|
|
|
|
2013-07-25 11:02:29 +08:00
|
|
|
bool polly::PollyTrackFailures = false;
|
2014-04-09 05:20:44 +08:00
|
|
|
bool polly::PollyDelinearize = false;
|
2014-07-16 05:06:48 +08:00
|
|
|
StringRef polly::PollySkipFnAttr = "polly.skip.fn";
|
2013-07-25 11:02:29 +08:00
|
|
|
|
2011-04-29 14:27:02 +08:00
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// Statistics.
|
|
|
|
|
|
|
|
STATISTIC(ValidRegion, "Number of regions that a valid part of Scop");
|
|
|
|
|
2013-12-18 18:49:53 +08:00
|
|
|
class DiagnosticScopFound : public DiagnosticInfo {
|
|
|
|
private:
|
|
|
|
static int PluginDiagnosticKind;
|
|
|
|
|
|
|
|
Function &F;
|
|
|
|
std::string FileName;
|
|
|
|
unsigned EntryLine, ExitLine;
|
|
|
|
|
|
|
|
public:
|
2013-12-18 19:14:36 +08:00
|
|
|
DiagnosticScopFound(Function &F, std::string FileName, unsigned EntryLine,
|
|
|
|
unsigned ExitLine)
|
2013-12-18 18:49:53 +08:00
|
|
|
: DiagnosticInfo(PluginDiagnosticKind, DS_Note), F(F), FileName(FileName),
|
2013-12-18 19:14:36 +08:00
|
|
|
EntryLine(EntryLine), ExitLine(ExitLine) {}
|
2013-12-18 18:49:53 +08:00
|
|
|
|
|
|
|
virtual void print(DiagnosticPrinter &DP) const;
|
|
|
|
|
|
|
|
static bool classof(const DiagnosticInfo *DI) {
|
|
|
|
return DI->getKind() == PluginDiagnosticKind;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
int DiagnosticScopFound::PluginDiagnosticKind = 10;
|
|
|
|
|
|
|
|
void DiagnosticScopFound::print(DiagnosticPrinter &DP) const {
|
2013-12-18 19:14:36 +08:00
|
|
|
DP << "Polly detected an optimizable loop region (scop) in function '" << F
|
|
|
|
<< "'\n";
|
2013-12-18 18:49:53 +08:00
|
|
|
|
|
|
|
if (FileName.empty()) {
|
|
|
|
DP << "Scop location is unknown. Compile with debug info "
|
|
|
|
"(-g) to get more precise information. ";
|
2013-12-18 19:14:36 +08:00
|
|
|
return;
|
2013-12-18 18:49:53 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
DP << FileName << ":" << EntryLine << ": Start of scop\n";
|
|
|
|
DP << FileName << ":" << ExitLine << ": End of scop";
|
|
|
|
}
|
|
|
|
|
2011-04-29 14:27:02 +08:00
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// ScopDetection.
|
2014-04-02 19:54:01 +08:00
|
|
|
|
2014-09-18 19:17:17 +08:00
|
|
|
ScopDetection::ScopDetection() : FunctionPass(ID) {
|
|
|
|
if (!PollyUseRuntimeAliasChecks)
|
|
|
|
return;
|
|
|
|
|
2014-09-30 01:06:29 +08:00
|
|
|
// Disable runtime alias checks if we ignore aliasing all together.
|
|
|
|
if (IgnoreAliasing) {
|
|
|
|
PollyUseRuntimeAliasChecks = false;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2014-09-18 19:17:17 +08:00
|
|
|
if (AllowNonAffine) {
|
|
|
|
DEBUG(errs() << "WARNING: We disable runtime alias checks as non affine "
|
|
|
|
"accesses are enabled.\n");
|
|
|
|
PollyUseRuntimeAliasChecks = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef CLOOG_FOUND
|
|
|
|
if (PollyCodeGenChoice == CODEGEN_CLOOG) {
|
|
|
|
DEBUG(errs() << "WARNING: We disable runtime alias checks as the cloog "
|
|
|
|
"code generation cannot emit them.\n");
|
|
|
|
PollyUseRuntimeAliasChecks = false;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2014-04-02 19:54:01 +08:00
|
|
|
template <class RR, typename... Args>
|
|
|
|
inline bool ScopDetection::invalid(DetectionContext &Context, bool Assert,
|
|
|
|
Args &&... Arguments) const {
|
|
|
|
|
|
|
|
if (!Context.Verifying) {
|
2014-05-24 17:25:01 +08:00
|
|
|
RejectLog &Log = Context.Log;
|
|
|
|
std::shared_ptr<RR> RejectReason = std::make_shared<RR>(Arguments...);
|
2014-04-02 19:54:01 +08:00
|
|
|
|
2014-05-24 17:25:06 +08:00
|
|
|
if (PollyTrackFailures)
|
2014-05-24 17:25:01 +08:00
|
|
|
Log.report(RejectReason);
|
|
|
|
|
|
|
|
DEBUG(dbgs() << RejectReason->getMessage());
|
2014-04-02 19:54:01 +08:00
|
|
|
DEBUG(dbgs() << "\n");
|
|
|
|
} else {
|
|
|
|
assert(!Assert && "Verification of detected scop failed");
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2014-02-19 02:49:49 +08:00
|
|
|
bool ScopDetection::isMaxRegionInScop(const Region &R, bool Verify) const {
|
|
|
|
if (!ValidRegions.count(&R))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
if (Verify)
|
|
|
|
return isValidRegion(const_cast<Region &>(R));
|
|
|
|
|
|
|
|
return true;
|
2011-04-29 14:27:02 +08:00
|
|
|
}
|
|
|
|
|
2011-10-08 08:30:55 +08:00
|
|
|
std::string ScopDetection::regionIsInvalidBecause(const Region *R) const {
|
2014-05-24 17:25:06 +08:00
|
|
|
if (!RejectLogs.count(R))
|
2011-10-08 08:30:55 +08:00
|
|
|
return "";
|
|
|
|
|
2014-05-24 17:25:06 +08:00
|
|
|
// Get the first error we found. Even in keep-going mode, this is the first
|
|
|
|
// reason that caused the candidate to be rejected.
|
|
|
|
RejectLog Errors = RejectLogs.at(R);
|
2014-06-12 15:25:08 +08:00
|
|
|
|
|
|
|
// This can happen when we marked a region invalid, but didn't track
|
|
|
|
// an error for it.
|
|
|
|
if (Errors.size() == 0)
|
|
|
|
return "";
|
|
|
|
|
|
|
|
RejectReasonPtr RR = *Errors.begin();
|
|
|
|
return RR->getMessage();
|
2011-10-08 08:30:55 +08:00
|
|
|
}
|
|
|
|
|
2013-05-07 15:30:56 +08:00
|
|
|
bool ScopDetection::isValidCFG(BasicBlock &BB,
|
|
|
|
DetectionContext &Context) const {
|
2011-04-29 14:27:02 +08:00
|
|
|
Region &RefRegion = Context.CurRegion;
|
|
|
|
TerminatorInst *TI = BB.getTerminator();
|
|
|
|
|
|
|
|
// Return instructions are only valid if the region is the top level region.
|
|
|
|
if (isa<ReturnInst>(TI) && !RefRegion.getExit() && TI->getNumOperands() == 0)
|
|
|
|
return true;
|
|
|
|
|
|
|
|
BranchInst *Br = dyn_cast<BranchInst>(TI);
|
|
|
|
|
2014-04-02 19:54:01 +08:00
|
|
|
if (!Br)
|
|
|
|
return invalid<ReportNonBranchTerminator>(Context, /*Assert=*/true, &BB);
|
2011-04-29 14:27:02 +08:00
|
|
|
|
2013-01-15 06:40:23 +08:00
|
|
|
if (Br->isUnconditional())
|
|
|
|
return true;
|
2011-04-29 14:27:02 +08:00
|
|
|
|
|
|
|
Value *Condition = Br->getCondition();
|
|
|
|
|
|
|
|
// UndefValue is not allowed as condition.
|
2014-04-02 19:54:01 +08:00
|
|
|
if (isa<UndefValue>(Condition))
|
2014-06-26 18:06:40 +08:00
|
|
|
return invalid<ReportUndefCond>(Context, /*Assert=*/true, Br, &BB);
|
2011-04-29 14:27:02 +08:00
|
|
|
|
|
|
|
// Only Constant and ICmpInst are allowed as condition.
|
2014-04-02 19:54:01 +08:00
|
|
|
if (!(isa<Constant>(Condition) || isa<ICmpInst>(Condition)))
|
2014-06-26 18:06:40 +08:00
|
|
|
return invalid<ReportInvalidCond>(Context, /*Assert=*/true, Br, &BB);
|
2011-04-29 14:27:02 +08:00
|
|
|
|
|
|
|
// Allow perfectly nested conditions.
|
|
|
|
assert(Br->getNumSuccessors() == 2 && "Unexpected number of successors");
|
|
|
|
|
|
|
|
if (ICmpInst *ICmp = dyn_cast<ICmpInst>(Condition)) {
|
|
|
|
// Unsigned comparisons are not allowed. They trigger overflow problems
|
|
|
|
// in the code generation.
|
|
|
|
//
|
|
|
|
// TODO: This is not sufficient and just hides bugs. However it does pretty
|
|
|
|
// well.
|
2012-12-30 07:47:38 +08:00
|
|
|
if (ICmp->isUnsigned())
|
2011-04-29 14:27:02 +08:00
|
|
|
return false;
|
|
|
|
|
|
|
|
// Are both operands of the ICmp affine?
|
2013-01-15 06:40:23 +08:00
|
|
|
if (isa<UndefValue>(ICmp->getOperand(0)) ||
|
2014-04-02 19:54:01 +08:00
|
|
|
isa<UndefValue>(ICmp->getOperand(1)))
|
2014-06-26 18:06:40 +08:00
|
|
|
return invalid<ReportUndefOperand>(Context, /*Assert=*/true, &BB, ICmp);
|
2011-04-29 14:27:02 +08:00
|
|
|
|
scop detection: properly instantiate SCEVs to the place where they are used
Fix inspired from c2d4a0627e95c34a819b9d4ffb4db62daa78dade.
Given the following code
for (i = 0; i < 10; i++) {
;
}
S: A[i] = 0
When translate the data reference A[i] in statement S using scev, we need to
retrieve the scev of 'i' at the location of 'S'. If we do not do this the
scev that we obtain will be expressed as {0,+,1}_for and will reference loop
iterators that do not surround 'S'. What we really want is the scev to be
instantiated to the value of 'i' after the loop. This value is {10}.
This used to crash in:
int loopDimension = getLoopDepth(Expr->getLoop());
isl_aff *LAff = isl_aff_set_coefficient_si(
isl_aff_zero_on_domain(LocalSpace), isl_dim_in, loopDimension, 1);
(gdb) p Expr->dump()
{8,+,8}<nw><%do.body>
(gdb) p getLoopDepth(Expr->getLoop())
$5 = 0
isl_space *Space = isl_space_set_alloc(Ctx, 0, NbLoopSpaces);
isl_local_space *LocalSpace = isl_local_space_from_space(Space);
As we are trying to create a memory access in a stmt that is outside all loops,
LocalSpace has 0 dimensions:
(gdb) p NbLoopSpaces
$12 = 0
(gdb) p Statement.BB->dump()
if.then: ; preds = %do.end
%0 = load float* %add.ptr, align 4
store float %0, float* %q.1.reg2mem, align 4
br label %if.end.single_exit
and so the scev for %add.ptr should be taken at the place where it is used,
i.e., it should be the value on the last iteration of the do.body loop, and not
"{8,+,8}<nw><%do.body>".
llvm-svn: 179148
2013-04-10 12:05:18 +08:00
|
|
|
Loop *L = LI->getLoopFor(ICmp->getParent());
|
|
|
|
const SCEV *LHS = SE->getSCEVAtScope(ICmp->getOperand(0), L);
|
|
|
|
const SCEV *RHS = SE->getSCEVAtScope(ICmp->getOperand(1), L);
|
2011-04-29 14:27:02 +08:00
|
|
|
|
2011-11-10 20:45:11 +08:00
|
|
|
if (!isAffineExpr(&Context.CurRegion, LHS, *SE) ||
|
2014-04-02 19:54:01 +08:00
|
|
|
!isAffineExpr(&Context.CurRegion, RHS, *SE))
|
|
|
|
return invalid<ReportNonAffBranch>(Context, /*Assert=*/true, &BB, LHS,
|
2014-06-26 18:06:40 +08:00
|
|
|
RHS, ICmp);
|
2011-04-29 14:27:02 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// Allow loop exit conditions.
|
|
|
|
Loop *L = LI->getLoopFor(&BB);
|
|
|
|
if (L && L->getExitingBlock() == &BB)
|
|
|
|
return true;
|
|
|
|
|
|
|
|
// Allow perfectly nested conditions.
|
|
|
|
Region *R = RI->getRegionFor(&BB);
|
2014-04-02 19:54:01 +08:00
|
|
|
if (R->getEntry() != &BB)
|
|
|
|
return invalid<ReportCondition>(Context, /*Assert=*/true, &BB);
|
2011-04-29 14:27:02 +08:00
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool ScopDetection::isValidCallInst(CallInst &CI) {
|
|
|
|
if (CI.mayHaveSideEffects() || CI.doesNotReturn())
|
|
|
|
return false;
|
|
|
|
|
|
|
|
if (CI.doesNotAccessMemory())
|
|
|
|
return true;
|
|
|
|
|
|
|
|
Function *CalledFunction = CI.getCalledFunction();
|
|
|
|
|
|
|
|
// Indirect calls are not supported.
|
|
|
|
if (CalledFunction == 0)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
// TODO: Intrinsics.
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2014-01-28 20:58:58 +08:00
|
|
|
bool ScopDetection::isInvariant(const Value &Val, const Region &Reg) const {
|
|
|
|
// A reference to function argument or constant value is invariant.
|
|
|
|
if (isa<Argument>(Val) || isa<Constant>(Val))
|
|
|
|
return true;
|
|
|
|
|
|
|
|
const Instruction *I = dyn_cast<Instruction>(&Val);
|
|
|
|
if (!I)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
if (!Reg.contains(I))
|
|
|
|
return true;
|
|
|
|
|
|
|
|
if (I->mayHaveSideEffects())
|
|
|
|
return false;
|
|
|
|
|
|
|
|
// When Val is a Phi node, it is likely not invariant. We do not check whether
|
|
|
|
// Phi nodes are actually invariant, we assume that Phi nodes are usually not
|
|
|
|
// invariant. Recursively checking the operators of Phi nodes would lead to
|
|
|
|
// infinite recursion.
|
|
|
|
if (isa<PHINode>(*I))
|
|
|
|
return false;
|
|
|
|
|
2014-04-03 04:18:19 +08:00
|
|
|
for (const Use &Operand : I->operands())
|
2014-03-03 21:13:55 +08:00
|
|
|
if (!isInvariant(*Operand, Reg))
|
2014-01-28 20:58:58 +08:00
|
|
|
return false;
|
|
|
|
|
|
|
|
// When the instruction is a load instruction, check that no write to memory
|
|
|
|
// in the region aliases with the load.
|
|
|
|
if (const LoadInst *LI = dyn_cast<LoadInst>(I)) {
|
|
|
|
AliasAnalysis::Location Loc = AA->getLocation(LI);
|
|
|
|
const Region::const_block_iterator BE = Reg.block_end();
|
|
|
|
// Check if any basic block in the region can modify the location pointed to
|
|
|
|
// by 'Loc'. If so, 'Val' is (likely) not invariant in the region.
|
2014-04-03 04:18:19 +08:00
|
|
|
for (const BasicBlock *BB : Reg.blocks())
|
2014-03-03 21:13:55 +08:00
|
|
|
if (AA->canBasicBlockModify(*BB, Loc))
|
2014-01-28 20:58:58 +08:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
record delinearization result and reuse it in polyhedral translation
Without this patch, the testcase would fail on the delinearization of the second
array:
; void foo(long n, long m, long o, double A[n][m][o]) {
; for (long i = 0; i < n; i++)
; for (long j = 0; j < m; j++)
; for (long k = 0; k < o; k++) {
; A[i+3][j-4][k+7] = 1.0;
; A[i][0][k] = 2.0;
; }
; }
; CHECK: [n, m, o] -> { Stmt_for_body6[i0, i1, i2] -> MemRef_A[3 + i0, -4 + i1, 7 + i2] };
; CHECK: [n, m, o] -> { Stmt_for_body6[i0, i1, i2] -> MemRef_A[i0, 0, i2] };
Here is the output of FileCheck on the testcase without this patch:
; CHECK: [n, m, o] -> { Stmt_for_body6[i0, i1, i2] -> MemRef_A[i0, 0, i2] };
^
<stdin>:26:2: note: possible intended match here
[n, m, o] -> { Stmt_for_body6[i0, i1, i2] -> MemRef_A[o0] };
^
It is possible to find a good delinearization for A[i][0][k] only in the context
of the delinearization of both array accesses.
There are two ways to delinearize together all array subscripts touching the
same base address: either duplicate the code from scop detection to first gather
all array references and then run the delinearization; or as implemented in this
patch, use the same delinearization info that we computed during scop detection.
llvm-svn: 210117
2014-06-04 02:16:31 +08:00
|
|
|
MapInsnToMemAcc InsnToMemAcc;
|
|
|
|
|
2014-05-13 04:24:26 +08:00
|
|
|
bool ScopDetection::hasAffineMemoryAccesses(DetectionContext &Context) const {
|
2014-09-13 22:47:55 +08:00
|
|
|
for (const SCEVUnknown *BasePointer : Context.NonAffineAccesses) {
|
2014-05-10 06:45:15 +08:00
|
|
|
Value *BaseValue = BasePointer->getValue();
|
record delinearization result and reuse it in polyhedral translation
Without this patch, the testcase would fail on the delinearization of the second
array:
; void foo(long n, long m, long o, double A[n][m][o]) {
; for (long i = 0; i < n; i++)
; for (long j = 0; j < m; j++)
; for (long k = 0; k < o; k++) {
; A[i+3][j-4][k+7] = 1.0;
; A[i][0][k] = 2.0;
; }
; }
; CHECK: [n, m, o] -> { Stmt_for_body6[i0, i1, i2] -> MemRef_A[3 + i0, -4 + i1, 7 + i2] };
; CHECK: [n, m, o] -> { Stmt_for_body6[i0, i1, i2] -> MemRef_A[i0, 0, i2] };
Here is the output of FileCheck on the testcase without this patch:
; CHECK: [n, m, o] -> { Stmt_for_body6[i0, i1, i2] -> MemRef_A[i0, 0, i2] };
^
<stdin>:26:2: note: possible intended match here
[n, m, o] -> { Stmt_for_body6[i0, i1, i2] -> MemRef_A[o0] };
^
It is possible to find a good delinearization for A[i][0][k] only in the context
of the delinearization of both array accesses.
There are two ways to delinearize together all array subscripts touching the
same base address: either duplicate the code from scop detection to first gather
all array references and then run the delinearization; or as implemented in this
patch, use the same delinearization info that we computed during scop detection.
llvm-svn: 210117
2014-06-04 02:16:31 +08:00
|
|
|
ArrayShape *Shape = new ArrayShape(BasePointer);
|
2014-09-13 22:47:55 +08:00
|
|
|
bool BasePtrHasNonAffine = false;
|
2014-05-10 06:45:15 +08:00
|
|
|
|
|
|
|
// First step: collect parametric terms in all array references.
|
|
|
|
SmallVector<const SCEV *, 4> Terms;
|
2014-09-13 22:47:55 +08:00
|
|
|
for (const auto &Pair : Context.Accesses[BasePointer]) {
|
|
|
|
const SCEVAddRecExpr *AccessFunction =
|
|
|
|
dyn_cast<SCEVAddRecExpr>(Pair.second);
|
2014-05-10 06:45:15 +08:00
|
|
|
|
2014-09-13 22:47:55 +08:00
|
|
|
if (AccessFunction)
|
|
|
|
AccessFunction->collectParametricTerms(*SE, Terms);
|
|
|
|
}
|
2014-05-13 03:02:02 +08:00
|
|
|
|
2014-05-10 06:45:15 +08:00
|
|
|
// Second step: find array shape.
|
record delinearization result and reuse it in polyhedral translation
Without this patch, the testcase would fail on the delinearization of the second
array:
; void foo(long n, long m, long o, double A[n][m][o]) {
; for (long i = 0; i < n; i++)
; for (long j = 0; j < m; j++)
; for (long k = 0; k < o; k++) {
; A[i+3][j-4][k+7] = 1.0;
; A[i][0][k] = 2.0;
; }
; }
; CHECK: [n, m, o] -> { Stmt_for_body6[i0, i1, i2] -> MemRef_A[3 + i0, -4 + i1, 7 + i2] };
; CHECK: [n, m, o] -> { Stmt_for_body6[i0, i1, i2] -> MemRef_A[i0, 0, i2] };
Here is the output of FileCheck on the testcase without this patch:
; CHECK: [n, m, o] -> { Stmt_for_body6[i0, i1, i2] -> MemRef_A[i0, 0, i2] };
^
<stdin>:26:2: note: possible intended match here
[n, m, o] -> { Stmt_for_body6[i0, i1, i2] -> MemRef_A[o0] };
^
It is possible to find a good delinearization for A[i][0][k] only in the context
of the delinearization of both array accesses.
There are two ways to delinearize together all array subscripts touching the
same base address: either duplicate the code from scop detection to first gather
all array references and then run the delinearization; or as implemented in this
patch, use the same delinearization info that we computed during scop detection.
llvm-svn: 210117
2014-06-04 02:16:31 +08:00
|
|
|
SE->findArrayDimensions(Terms, Shape->DelinearizedSizes,
|
|
|
|
Context.ElementSize[BasePointer]);
|
2014-05-10 06:45:15 +08:00
|
|
|
|
2014-09-13 22:47:55 +08:00
|
|
|
// No array shape derived.
|
|
|
|
if (Shape->DelinearizedSizes.empty()) {
|
|
|
|
if (AllowNonAffine)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
for (const auto &Pair : Context.Accesses[BasePointer]) {
|
|
|
|
const Instruction *Insn = Pair.first;
|
|
|
|
const SCEV *AF = Pair.second;
|
|
|
|
|
|
|
|
if (!isAffineExpr(&Context.CurRegion, AF, *SE, BaseValue)) {
|
|
|
|
invalid<ReportNonAffineAccess>(Context, /*Assert=*/true, AF, Insn,
|
|
|
|
BaseValue);
|
|
|
|
if (!KeepGoing)
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
continue;
|
|
|
|
}
|
record delinearization result and reuse it in polyhedral translation
Without this patch, the testcase would fail on the delinearization of the second
array:
; void foo(long n, long m, long o, double A[n][m][o]) {
; for (long i = 0; i < n; i++)
; for (long j = 0; j < m; j++)
; for (long k = 0; k < o; k++) {
; A[i+3][j-4][k+7] = 1.0;
; A[i][0][k] = 2.0;
; }
; }
; CHECK: [n, m, o] -> { Stmt_for_body6[i0, i1, i2] -> MemRef_A[3 + i0, -4 + i1, 7 + i2] };
; CHECK: [n, m, o] -> { Stmt_for_body6[i0, i1, i2] -> MemRef_A[i0, 0, i2] };
Here is the output of FileCheck on the testcase without this patch:
; CHECK: [n, m, o] -> { Stmt_for_body6[i0, i1, i2] -> MemRef_A[i0, 0, i2] };
^
<stdin>:26:2: note: possible intended match here
[n, m, o] -> { Stmt_for_body6[i0, i1, i2] -> MemRef_A[o0] };
^
It is possible to find a good delinearization for A[i][0][k] only in the context
of the delinearization of both array accesses.
There are two ways to delinearize together all array subscripts touching the
same base address: either duplicate the code from scop detection to first gather
all array references and then run the delinearization; or as implemented in this
patch, use the same delinearization info that we computed during scop detection.
llvm-svn: 210117
2014-06-04 02:16:31 +08:00
|
|
|
|
2014-09-13 22:47:55 +08:00
|
|
|
// Third step: compute the access functions for each subscript.
|
|
|
|
//
|
|
|
|
// We first store the resulting memory accesses in TempMemoryAccesses. Only
|
|
|
|
// if the access functions for all memory accesses have been successfully
|
|
|
|
// delinearized we continue. Otherwise, we either report a failure or, if
|
|
|
|
// non-affine accesses are allowed, we drop the information. In case the
|
|
|
|
// information is dropped the memory accesses need to be overapproximated
|
|
|
|
// when translated to a polyhedral representation.
|
|
|
|
MapInsnToMemAcc TempMemoryAccesses;
|
|
|
|
for (const auto &Pair : Context.Accesses[BasePointer]) {
|
|
|
|
const Instruction *Insn = Pair.first;
|
|
|
|
const SCEVAddRecExpr *AF = dyn_cast<SCEVAddRecExpr>(Pair.second);
|
|
|
|
bool IsNonAffine = false;
|
record delinearization result and reuse it in polyhedral translation
Without this patch, the testcase would fail on the delinearization of the second
array:
; void foo(long n, long m, long o, double A[n][m][o]) {
; for (long i = 0; i < n; i++)
; for (long j = 0; j < m; j++)
; for (long k = 0; k < o; k++) {
; A[i+3][j-4][k+7] = 1.0;
; A[i][0][k] = 2.0;
; }
; }
; CHECK: [n, m, o] -> { Stmt_for_body6[i0, i1, i2] -> MemRef_A[3 + i0, -4 + i1, 7 + i2] };
; CHECK: [n, m, o] -> { Stmt_for_body6[i0, i1, i2] -> MemRef_A[i0, 0, i2] };
Here is the output of FileCheck on the testcase without this patch:
; CHECK: [n, m, o] -> { Stmt_for_body6[i0, i1, i2] -> MemRef_A[i0, 0, i2] };
^
<stdin>:26:2: note: possible intended match here
[n, m, o] -> { Stmt_for_body6[i0, i1, i2] -> MemRef_A[o0] };
^
It is possible to find a good delinearization for A[i][0][k] only in the context
of the delinearization of both array accesses.
There are two ways to delinearize together all array subscripts touching the
same base address: either duplicate the code from scop detection to first gather
all array references and then run the delinearization; or as implemented in this
patch, use the same delinearization info that we computed during scop detection.
llvm-svn: 210117
2014-06-04 02:16:31 +08:00
|
|
|
MemAcc *Acc = new MemAcc(Insn, Shape);
|
2014-09-13 22:47:55 +08:00
|
|
|
TempMemoryAccesses.insert({Insn, Acc});
|
|
|
|
|
|
|
|
if (!AF) {
|
|
|
|
if (isAffineExpr(&Context.CurRegion, Pair.second, *SE, BaseValue))
|
|
|
|
Acc->DelinearizedSubscripts.push_back(Pair.second);
|
|
|
|
else
|
|
|
|
IsNonAffine = true;
|
|
|
|
} else {
|
|
|
|
AF->computeAccessFunctions(*SE, Acc->DelinearizedSubscripts,
|
|
|
|
Shape->DelinearizedSizes);
|
|
|
|
if (Acc->DelinearizedSubscripts.size() == 0)
|
|
|
|
IsNonAffine = true;
|
|
|
|
for (const SCEV *S : Acc->DelinearizedSubscripts)
|
|
|
|
if (!isAffineExpr(&Context.CurRegion, S, *SE, BaseValue))
|
|
|
|
IsNonAffine = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
// (Possibly) report non affine access
|
|
|
|
if (IsNonAffine) {
|
|
|
|
BasePtrHasNonAffine = true;
|
|
|
|
if (!AllowNonAffine)
|
|
|
|
invalid<ReportNonAffineAccess>(Context, /*Assert=*/true, AF, Insn,
|
|
|
|
BaseValue);
|
|
|
|
if (!KeepGoing && !AllowNonAffine)
|
|
|
|
return false;
|
|
|
|
}
|
2014-05-10 06:45:15 +08:00
|
|
|
}
|
2014-09-13 22:47:55 +08:00
|
|
|
|
|
|
|
if (!BasePtrHasNonAffine)
|
|
|
|
InsnToMemAcc.insert(TempMemoryAccesses.begin(), TempMemoryAccesses.end());
|
2014-05-10 06:45:15 +08:00
|
|
|
}
|
2014-05-13 03:02:02 +08:00
|
|
|
return true;
|
2014-05-10 06:45:15 +08:00
|
|
|
}
|
|
|
|
|
2011-04-29 14:27:02 +08:00
|
|
|
bool ScopDetection::isValidMemoryAccess(Instruction &Inst,
|
|
|
|
DetectionContext &Context) const {
|
2011-11-10 20:45:03 +08:00
|
|
|
Value *Ptr = getPointerOperand(Inst);
|
scop detection: properly instantiate SCEVs to the place where they are used
Fix inspired from c2d4a0627e95c34a819b9d4ffb4db62daa78dade.
Given the following code
for (i = 0; i < 10; i++) {
;
}
S: A[i] = 0
When translate the data reference A[i] in statement S using scev, we need to
retrieve the scev of 'i' at the location of 'S'. If we do not do this the
scev that we obtain will be expressed as {0,+,1}_for and will reference loop
iterators that do not surround 'S'. What we really want is the scev to be
instantiated to the value of 'i' after the loop. This value is {10}.
This used to crash in:
int loopDimension = getLoopDepth(Expr->getLoop());
isl_aff *LAff = isl_aff_set_coefficient_si(
isl_aff_zero_on_domain(LocalSpace), isl_dim_in, loopDimension, 1);
(gdb) p Expr->dump()
{8,+,8}<nw><%do.body>
(gdb) p getLoopDepth(Expr->getLoop())
$5 = 0
isl_space *Space = isl_space_set_alloc(Ctx, 0, NbLoopSpaces);
isl_local_space *LocalSpace = isl_local_space_from_space(Space);
As we are trying to create a memory access in a stmt that is outside all loops,
LocalSpace has 0 dimensions:
(gdb) p NbLoopSpaces
$12 = 0
(gdb) p Statement.BB->dump()
if.then: ; preds = %do.end
%0 = load float* %add.ptr, align 4
store float %0, float* %q.1.reg2mem, align 4
br label %if.end.single_exit
and so the scev for %add.ptr should be taken at the place where it is used,
i.e., it should be the value on the last iteration of the do.body loop, and not
"{8,+,8}<nw><%do.body>".
llvm-svn: 179148
2013-04-10 12:05:18 +08:00
|
|
|
Loop *L = LI->getLoopFor(Inst.getParent());
|
|
|
|
const SCEV *AccessFunction = SE->getSCEVAtScope(Ptr, L);
|
2011-11-10 20:44:50 +08:00
|
|
|
const SCEVUnknown *BasePointer;
|
2011-11-10 20:45:03 +08:00
|
|
|
Value *BaseValue;
|
2011-04-29 14:27:02 +08:00
|
|
|
|
2011-11-10 20:44:50 +08:00
|
|
|
BasePointer = dyn_cast<SCEVUnknown>(SE->getPointerBase(AccessFunction));
|
|
|
|
|
2014-04-02 19:54:01 +08:00
|
|
|
if (!BasePointer)
|
2014-06-26 18:06:40 +08:00
|
|
|
return invalid<ReportNoBasePtr>(Context, /*Assert=*/true, &Inst);
|
2011-11-10 20:44:50 +08:00
|
|
|
|
|
|
|
BaseValue = BasePointer->getValue();
|
|
|
|
|
2014-04-02 19:54:01 +08:00
|
|
|
if (isa<UndefValue>(BaseValue))
|
2014-06-26 18:06:40 +08:00
|
|
|
return invalid<ReportUndefBasePtr>(Context, /*Assert=*/true, &Inst);
|
2011-11-10 20:44:50 +08:00
|
|
|
|
2014-01-28 20:58:58 +08:00
|
|
|
// Check that the base address of the access is invariant in the current
|
|
|
|
// region.
|
2014-04-02 19:54:01 +08:00
|
|
|
if (!isInvariant(*BaseValue, Context.CurRegion))
|
2014-01-28 21:43:24 +08:00
|
|
|
// Verification of this property is difficult as the independent blocks
|
|
|
|
// pass may introduce aliasing that we did not have when running the
|
|
|
|
// scop detection.
|
2014-06-26 18:06:40 +08:00
|
|
|
return invalid<ReportVariantBasePtr>(Context, /*Assert=*/false, BaseValue,
|
|
|
|
&Inst);
|
2014-01-28 20:58:58 +08:00
|
|
|
|
2011-11-10 20:44:50 +08:00
|
|
|
AccessFunction = SE->getMinusSCEV(AccessFunction, BasePointer);
|
2014-04-09 05:20:44 +08:00
|
|
|
|
2014-09-13 22:47:40 +08:00
|
|
|
const SCEV *Size = SE->getElementSize(&Inst);
|
|
|
|
if (Context.ElementSize.count(BasePointer)) {
|
|
|
|
if (Context.ElementSize[BasePointer] != Size)
|
|
|
|
return invalid<ReportDifferentArrayElementSize>(Context, /*Assert=*/true,
|
|
|
|
&Inst, BaseValue);
|
|
|
|
} else {
|
|
|
|
Context.ElementSize[BasePointer] = Size;
|
|
|
|
}
|
|
|
|
|
2014-09-13 22:47:55 +08:00
|
|
|
if (PollyDelinearize) {
|
|
|
|
Context.Accesses[BasePointer].push_back({&Inst, AccessFunction});
|
2014-05-10 06:45:15 +08:00
|
|
|
|
2014-09-13 22:47:55 +08:00
|
|
|
if (!isAffineExpr(&Context.CurRegion, AccessFunction, *SE, BaseValue))
|
|
|
|
Context.NonAffineAccesses.insert(BasePointer);
|
|
|
|
} else if (!AllowNonAffine) {
|
|
|
|
if (!isAffineExpr(&Context.CurRegion, AccessFunction, *SE, BaseValue))
|
2014-04-11 00:08:11 +08:00
|
|
|
return invalid<ReportNonAffineAccess>(Context, /*Assert=*/true,
|
2014-08-17 18:09:11 +08:00
|
|
|
AccessFunction, &Inst, BaseValue);
|
2014-04-09 05:20:44 +08:00
|
|
|
}
|
2011-04-29 14:27:02 +08:00
|
|
|
|
|
|
|
// FIXME: Alias Analysis thinks IntToPtrInst aliases with alloca instructions
|
|
|
|
// created by IndependentBlocks Pass.
|
2014-06-26 18:06:40 +08:00
|
|
|
if (IntToPtrInst *Inst = dyn_cast<IntToPtrInst>(BaseValue))
|
|
|
|
return invalid<ReportIntToPtr>(Context, /*Assert=*/true, Inst);
|
2011-04-29 14:27:02 +08:00
|
|
|
|
2014-09-25 05:04:29 +08:00
|
|
|
if (IgnoreAliasing)
|
2013-07-04 06:50:36 +08:00
|
|
|
return true;
|
|
|
|
|
|
|
|
// Check if the base pointer of the memory access does alias with
|
|
|
|
// any other pointer. This cannot be handled at the moment.
|
2014-10-05 19:58:57 +08:00
|
|
|
AAMDNodes AATags;
|
|
|
|
Inst.getAAMetadata(AATags);
|
|
|
|
AliasSet &AS = Context.AST.getAliasSetForPointer(
|
|
|
|
BaseValue, AliasAnalysis::UnknownSize, AATags);
|
2013-07-04 06:50:36 +08:00
|
|
|
|
|
|
|
// INVALID triggers an assertion in verifying mode, if it detects that a
|
|
|
|
// SCoP was detected by SCoP detection and that this SCoP was invalidated by
|
|
|
|
// a pass that stated it would preserve the SCoPs. We disable this check as
|
|
|
|
// the independent blocks pass may create memory references which seem to
|
|
|
|
// alias, if -basicaa is not available. They actually do not, but as we can
|
|
|
|
// not proof this without -basicaa we would fail. We disable this check to
|
|
|
|
// not cause irrelevant verification failures.
|
2014-09-25 05:04:29 +08:00
|
|
|
if (!AS.isMustAlias()) {
|
|
|
|
if (PollyUseRuntimeAliasChecks) {
|
|
|
|
bool CanBuildRunTimeCheck = true;
|
|
|
|
// The run-time alias check places code that involves the base pointer at
|
|
|
|
// the beginning of the SCoP. This breaks if the base pointer is defined
|
|
|
|
// inside the scop. Hence, we can only create a run-time check if we are
|
|
|
|
// sure the base pointer is not an instruction defined inside the scop.
|
|
|
|
for (const auto &Ptr : AS) {
|
|
|
|
Instruction *Inst = dyn_cast<Instruction>(Ptr.getValue());
|
|
|
|
if (Inst && Context.CurRegion.contains(Inst)) {
|
|
|
|
CanBuildRunTimeCheck = false;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (CanBuildRunTimeCheck)
|
|
|
|
return true;
|
|
|
|
}
|
2014-06-26 18:19:57 +08:00
|
|
|
return invalid<ReportAlias>(Context, /*Assert=*/false, &Inst, AS);
|
2014-09-25 05:04:29 +08:00
|
|
|
}
|
2011-04-29 14:27:02 +08:00
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool ScopDetection::isValidInstruction(Instruction &Inst,
|
|
|
|
DetectionContext &Context) const {
|
|
|
|
if (PHINode *PN = dyn_cast<PHINode>(&Inst))
|
2013-03-21 02:03:18 +08:00
|
|
|
if (!canSynthesize(PN, LI, SE, &Context.CurRegion)) {
|
2014-04-02 19:54:01 +08:00
|
|
|
if (SCEVCodegen)
|
|
|
|
return invalid<ReportPhiNodeRefInRegion>(Context, /*Assert=*/true,
|
|
|
|
&Inst);
|
|
|
|
else
|
|
|
|
return invalid<ReportNonCanonicalPhiNode>(Context, /*Assert=*/true,
|
|
|
|
&Inst);
|
2013-03-21 02:03:18 +08:00
|
|
|
}
|
2011-04-29 14:27:02 +08:00
|
|
|
|
|
|
|
// We only check the call instruction but not invoke instruction.
|
|
|
|
if (CallInst *CI = dyn_cast<CallInst>(&Inst)) {
|
|
|
|
if (isValidCallInst(*CI))
|
|
|
|
return true;
|
|
|
|
|
2014-04-02 19:54:01 +08:00
|
|
|
return invalid<ReportFuncCall>(Context, /*Assert=*/true, &Inst);
|
2011-04-29 14:27:02 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
if (!Inst.mayWriteToMemory() && !Inst.mayReadFromMemory()) {
|
2013-07-22 11:50:33 +08:00
|
|
|
if (!isa<AllocaInst>(Inst))
|
|
|
|
return true;
|
2011-04-29 14:27:02 +08:00
|
|
|
|
2014-04-02 19:54:01 +08:00
|
|
|
return invalid<ReportAlloca>(Context, /*Assert=*/true, &Inst);
|
2011-04-29 14:27:02 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// Check the access function.
|
|
|
|
if (isa<LoadInst>(Inst) || isa<StoreInst>(Inst))
|
|
|
|
return isValidMemoryAccess(Inst, Context);
|
|
|
|
|
|
|
|
// We do not know this instruction, therefore we assume it is invalid.
|
2014-04-02 19:54:01 +08:00
|
|
|
return invalid<ReportUnknownInst>(Context, /*Assert=*/true, &Inst);
|
2011-04-29 14:27:02 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
bool ScopDetection::isValidLoop(Loop *L, DetectionContext &Context) const {
|
2013-03-22 00:14:50 +08:00
|
|
|
if (!SCEVCodegen) {
|
|
|
|
// If code generation is not in scev based mode, we need to ensure that
|
|
|
|
// each loop has a canonical induction variable.
|
|
|
|
PHINode *IndVar = L->getCanonicalInductionVariable();
|
2014-04-02 19:54:01 +08:00
|
|
|
if (!IndVar)
|
|
|
|
return invalid<ReportLoopHeader>(Context, /*Assert=*/true, L);
|
2013-03-22 00:14:50 +08:00
|
|
|
}
|
2011-04-29 14:27:02 +08:00
|
|
|
|
|
|
|
// Is the loop count affine?
|
|
|
|
const SCEV *LoopCount = SE->getBackedgeTakenCount(L);
|
2014-04-02 19:54:01 +08:00
|
|
|
if (!isAffineExpr(&Context.CurRegion, LoopCount, *SE))
|
|
|
|
return invalid<ReportLoopBound>(Context, /*Assert=*/true, L, LoopCount);
|
2011-04-29 14:27:02 +08:00
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
Region *ScopDetection::expandRegion(Region &R) {
|
2012-04-07 23:14:28 +08:00
|
|
|
// Initial no valid region was found (greater than R)
|
2014-04-16 15:33:47 +08:00
|
|
|
Region *LastValidRegion = nullptr;
|
2012-12-30 07:47:38 +08:00
|
|
|
Region *ExpandedRegion = R.getExpandedRegion();
|
2011-04-29 14:27:02 +08:00
|
|
|
|
|
|
|
DEBUG(dbgs() << "\tExpanding " << R.getNameStr() << "\n");
|
|
|
|
|
2012-04-07 23:14:28 +08:00
|
|
|
while (ExpandedRegion) {
|
|
|
|
DetectionContext Context(*ExpandedRegion, *AA, false /* verifying */);
|
|
|
|
DEBUG(dbgs() << "\t\tTrying " << ExpandedRegion->getNameStr() << "\n");
|
2014-06-27 14:21:14 +08:00
|
|
|
// Only expand when we did not collect errors.
|
2011-04-29 14:27:02 +08:00
|
|
|
|
2012-04-07 23:14:28 +08:00
|
|
|
// Check the exit first (cheap)
|
2014-06-27 14:21:14 +08:00
|
|
|
if (isValidExit(Context) && !Context.Log.hasErrors()) {
|
2012-04-07 23:14:28 +08:00
|
|
|
// If the exit is valid check all blocks
|
|
|
|
// - if true, a valid region was found => store it + keep expanding
|
|
|
|
// - if false, .tbd. => stop (should this really end the loop?)
|
2014-06-27 14:21:14 +08:00
|
|
|
if (!allBlocksValid(Context) || Context.Log.hasErrors())
|
|
|
|
break;
|
|
|
|
|
|
|
|
if (Context.Log.hasErrors())
|
2012-04-07 23:14:28 +08:00
|
|
|
break;
|
2011-04-29 14:27:02 +08:00
|
|
|
|
2012-04-07 23:14:28 +08:00
|
|
|
// Delete unnecessary regions (allocated by getExpandedRegion)
|
|
|
|
if (LastValidRegion)
|
|
|
|
delete LastValidRegion;
|
2011-04-29 14:27:02 +08:00
|
|
|
|
2013-04-10 14:55:45 +08:00
|
|
|
// Store this region, because it is the greatest valid (encountered so
|
|
|
|
// far).
|
2012-04-07 23:14:28 +08:00
|
|
|
LastValidRegion = ExpandedRegion;
|
2011-04-29 14:27:02 +08:00
|
|
|
|
2012-04-07 23:14:28 +08:00
|
|
|
// Create and test the next greater region (if any)
|
|
|
|
ExpandedRegion = ExpandedRegion->getExpandedRegion();
|
2011-04-29 14:27:02 +08:00
|
|
|
|
2012-04-07 23:14:28 +08:00
|
|
|
} else {
|
|
|
|
// Create and test the next greater region (if any)
|
|
|
|
Region *TmpRegion = ExpandedRegion->getExpandedRegion();
|
2011-04-29 14:27:02 +08:00
|
|
|
|
2012-04-07 23:14:28 +08:00
|
|
|
// Delete unnecessary regions (allocated by getExpandedRegion)
|
|
|
|
delete ExpandedRegion;
|
|
|
|
|
|
|
|
ExpandedRegion = TmpRegion;
|
|
|
|
}
|
|
|
|
}
|
2011-04-29 14:27:02 +08:00
|
|
|
|
2013-11-17 03:34:11 +08:00
|
|
|
DEBUG({
|
|
|
|
if (LastValidRegion)
|
|
|
|
dbgs() << "\tto " << LastValidRegion->getNameStr() << "\n";
|
|
|
|
else
|
|
|
|
dbgs() << "\tExpanding " << R.getNameStr() << " failed\n";
|
|
|
|
});
|
2011-04-29 14:27:02 +08:00
|
|
|
|
2012-04-07 23:14:28 +08:00
|
|
|
return LastValidRegion;
|
2011-04-29 14:27:02 +08:00
|
|
|
}
|
2013-06-04 00:35:37 +08:00
|
|
|
static bool regionWithoutLoops(Region &R, LoopInfo *LI) {
|
2014-04-03 04:18:19 +08:00
|
|
|
for (const BasicBlock *BB : R.blocks())
|
2014-03-03 21:13:55 +08:00
|
|
|
if (R.contains(LI->getLoopFor(BB)))
|
2013-06-04 00:35:37 +08:00
|
|
|
return false;
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
2011-04-29 14:27:02 +08:00
|
|
|
|
2014-01-30 03:05:30 +08:00
|
|
|
// Remove all direct and indirect children of region R from the region set Regs,
|
|
|
|
// but do not recurse further if the first child has been found.
|
|
|
|
//
|
|
|
|
// Return the number of regions erased from Regs.
|
2014-10-23 04:39:07 +08:00
|
|
|
static unsigned eraseAllChildren(ScopDetection::RegionSet &Regs,
|
2014-04-16 02:45:27 +08:00
|
|
|
const Region &R) {
|
2014-01-30 03:05:30 +08:00
|
|
|
unsigned Count = 0;
|
2014-04-16 02:45:27 +08:00
|
|
|
for (auto &SubRegion : R) {
|
2014-10-23 04:39:07 +08:00
|
|
|
if (Regs.count(SubRegion.get())) {
|
2014-01-30 03:05:30 +08:00
|
|
|
++Count;
|
2014-10-23 04:39:07 +08:00
|
|
|
Regs.remove(SubRegion.get());
|
2014-01-30 03:05:30 +08:00
|
|
|
} else {
|
2014-04-16 02:45:27 +08:00
|
|
|
Count += eraseAllChildren(Regs, *SubRegion);
|
2014-01-30 03:05:30 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return Count;
|
|
|
|
}
|
|
|
|
|
2011-04-29 14:27:02 +08:00
|
|
|
void ScopDetection::findScops(Region &R) {
|
2013-06-04 00:35:37 +08:00
|
|
|
if (!DetectRegionsWithoutLoops && regionWithoutLoops(R, LI))
|
|
|
|
return;
|
|
|
|
|
2014-05-24 17:25:10 +08:00
|
|
|
bool IsValidRegion = isValidRegion(R);
|
|
|
|
bool HasErrors = RejectLogs.count(&R) > 0;
|
|
|
|
|
|
|
|
if (IsValidRegion && !HasErrors) {
|
2011-04-29 14:27:02 +08:00
|
|
|
++ValidRegion;
|
|
|
|
ValidRegions.insert(&R);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2014-04-16 02:45:27 +08:00
|
|
|
for (auto &SubRegion : R)
|
2014-03-02 20:02:46 +08:00
|
|
|
findScops(*SubRegion);
|
2011-04-29 14:27:02 +08:00
|
|
|
|
|
|
|
// Try to expand regions.
|
|
|
|
//
|
|
|
|
// As the region tree normally only contains canonical regions, non canonical
|
|
|
|
// regions that form a Scop are not found. Therefore, those non canonical
|
|
|
|
// regions are checked by expanding the canonical ones.
|
|
|
|
|
2013-02-05 19:56:05 +08:00
|
|
|
std::vector<Region *> ToExpand;
|
2011-04-29 14:27:02 +08:00
|
|
|
|
2014-04-16 02:45:27 +08:00
|
|
|
for (auto &SubRegion : R)
|
|
|
|
ToExpand.push_back(SubRegion.get());
|
2011-04-29 14:27:02 +08:00
|
|
|
|
2014-04-03 04:18:19 +08:00
|
|
|
for (Region *CurrentRegion : ToExpand) {
|
2014-06-27 14:21:14 +08:00
|
|
|
// Skip regions that had errors.
|
|
|
|
bool HadErrors = RejectLogs.hasErrors(CurrentRegion);
|
|
|
|
if (HadErrors)
|
|
|
|
continue;
|
|
|
|
|
2011-04-29 14:27:02 +08:00
|
|
|
// Skip invalid regions. Regions may become invalid, if they are element of
|
|
|
|
// an already expanded region.
|
2014-10-23 04:39:07 +08:00
|
|
|
if (!ValidRegions.count(CurrentRegion))
|
2011-04-29 14:27:02 +08:00
|
|
|
continue;
|
|
|
|
|
|
|
|
Region *ExpandedR = expandRegion(*CurrentRegion);
|
|
|
|
|
|
|
|
if (!ExpandedR)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
R.addSubRegion(ExpandedR, true);
|
|
|
|
ValidRegions.insert(ExpandedR);
|
2014-10-23 04:39:07 +08:00
|
|
|
ValidRegions.remove(CurrentRegion);
|
2011-04-29 14:27:02 +08:00
|
|
|
|
2014-01-30 03:05:30 +08:00
|
|
|
// Erase all (direct and indirect) children of ExpandedR from the valid
|
|
|
|
// regions and update the number of valid regions.
|
2014-04-16 02:45:27 +08:00
|
|
|
ValidRegion -= eraseAllChildren(ValidRegions, *ExpandedR);
|
2011-04-29 14:27:02 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool ScopDetection::allBlocksValid(DetectionContext &Context) const {
|
|
|
|
Region &R = Context.CurRegion;
|
|
|
|
|
2014-04-03 04:18:19 +08:00
|
|
|
for (const BasicBlock *BB : R.blocks()) {
|
2014-03-03 21:13:55 +08:00
|
|
|
Loop *L = LI->getLoopFor(BB);
|
2014-05-24 17:25:10 +08:00
|
|
|
if (L && L->getHeader() == BB && (!isValidLoop(L, Context) && !KeepGoing))
|
2013-06-12 06:20:32 +08:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2014-04-03 04:18:19 +08:00
|
|
|
for (BasicBlock *BB : R.blocks())
|
2014-05-24 17:25:10 +08:00
|
|
|
if (!isValidCFG(*BB, Context) && !KeepGoing)
|
2013-06-12 06:20:27 +08:00
|
|
|
return false;
|
|
|
|
|
2014-04-03 04:18:19 +08:00
|
|
|
for (BasicBlock *BB : R.blocks())
|
2014-03-03 21:13:55 +08:00
|
|
|
for (BasicBlock::iterator I = BB->begin(), E = --BB->end(); I != E; ++I)
|
2014-05-24 17:25:10 +08:00
|
|
|
if (!isValidInstruction(*I, Context) && !KeepGoing)
|
2013-06-15 04:20:43 +08:00
|
|
|
return false;
|
2011-04-29 14:27:02 +08:00
|
|
|
|
2014-05-13 03:02:02 +08:00
|
|
|
if (!hasAffineMemoryAccesses(Context))
|
2014-05-10 06:45:15 +08:00
|
|
|
return false;
|
|
|
|
|
2011-04-29 14:27:02 +08:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool ScopDetection::isValidExit(DetectionContext &Context) const {
|
|
|
|
Region &R = Context.CurRegion;
|
|
|
|
|
|
|
|
// PHI nodes are not allowed in the exit basic block.
|
|
|
|
if (BasicBlock *Exit = R.getExit()) {
|
|
|
|
BasicBlock::iterator I = Exit->begin();
|
2014-04-02 19:54:01 +08:00
|
|
|
if (I != Exit->end() && isa<PHINode>(*I))
|
2014-06-26 18:06:40 +08:00
|
|
|
return invalid<ReportPHIinExit>(Context, /*Assert=*/true, I);
|
2011-04-29 14:27:02 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2014-02-19 02:49:46 +08:00
|
|
|
bool ScopDetection::isValidRegion(Region &R) const {
|
|
|
|
DetectionContext Context(R, *AA, false /*verifying*/);
|
2014-05-24 17:25:01 +08:00
|
|
|
|
|
|
|
bool RegionIsValid = isValidRegion(Context);
|
2014-05-24 17:25:10 +08:00
|
|
|
bool HasErrors = !RegionIsValid || Context.Log.size() > 0;
|
|
|
|
|
2014-06-26 21:36:52 +08:00
|
|
|
if (PollyTrackFailures && HasErrors)
|
|
|
|
RejectLogs.insert(std::make_pair(&R, Context.Log));
|
2014-05-24 17:25:01 +08:00
|
|
|
|
|
|
|
return RegionIsValid;
|
2014-02-19 02:49:46 +08:00
|
|
|
}
|
|
|
|
|
2011-04-29 14:27:02 +08:00
|
|
|
bool ScopDetection::isValidRegion(DetectionContext &Context) const {
|
|
|
|
Region &R = Context.CurRegion;
|
|
|
|
|
|
|
|
DEBUG(dbgs() << "Checking region: " << R.getNameStr() << "\n\t");
|
|
|
|
|
2013-04-02 14:41:48 +08:00
|
|
|
if (R.isTopLevelRegion()) {
|
2014-10-23 07:00:03 +08:00
|
|
|
DEBUG(dbgs() << "Top level region is invalid\n");
|
2011-04-29 14:27:02 +08:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2014-01-27 22:24:53 +08:00
|
|
|
if (!R.getEntry()->getName().count(OnlyRegion)) {
|
|
|
|
DEBUG({
|
|
|
|
dbgs() << "Region entry does not match -polly-region-only";
|
|
|
|
dbgs() << "\n";
|
|
|
|
});
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2013-05-07 15:30:56 +08:00
|
|
|
if (!R.getEnteringBlock()) {
|
2013-06-12 06:20:40 +08:00
|
|
|
BasicBlock *entry = R.getEntry();
|
|
|
|
Loop *L = LI->getLoopFor(entry);
|
|
|
|
|
|
|
|
if (L) {
|
2014-04-02 19:54:01 +08:00
|
|
|
if (!L->isLoopSimplifyForm())
|
|
|
|
return invalid<ReportSimpleLoop>(Context, /*Assert=*/true);
|
2013-06-12 06:20:40 +08:00
|
|
|
|
|
|
|
for (pred_iterator PI = pred_begin(entry), PE = pred_end(entry); PI != PE;
|
|
|
|
++PI) {
|
|
|
|
// Region entering edges come from the same loop but outside the region
|
|
|
|
// are not allowed.
|
2014-04-02 19:54:01 +08:00
|
|
|
if (L->contains(*PI) && !R.contains(*PI))
|
2014-06-26 18:06:40 +08:00
|
|
|
return invalid<ReportIndEdge>(Context, /*Assert=*/true, *PI);
|
2013-06-12 06:20:40 +08:00
|
|
|
}
|
|
|
|
}
|
2013-04-16 16:04:42 +08:00
|
|
|
}
|
|
|
|
|
2012-04-11 02:12:19 +08:00
|
|
|
// SCoP cannot contain the entry block of the function, because we need
|
2011-04-29 14:27:02 +08:00
|
|
|
// to insert alloca instruction there when translate scalar to array.
|
2014-04-02 19:54:01 +08:00
|
|
|
if (R.getEntry() == &(R.getEntry()->getParent()->getEntryBlock()))
|
2014-06-26 18:06:40 +08:00
|
|
|
return invalid<ReportEntry>(Context, /*Assert=*/true, R.getEntry());
|
2011-04-29 14:27:02 +08:00
|
|
|
|
2012-04-07 20:29:17 +08:00
|
|
|
if (!isValidExit(Context))
|
2011-04-29 14:27:02 +08:00
|
|
|
return false;
|
|
|
|
|
2012-04-07 20:29:17 +08:00
|
|
|
if (!allBlocksValid(Context))
|
2011-04-29 14:27:02 +08:00
|
|
|
return false;
|
|
|
|
|
|
|
|
DEBUG(dbgs() << "OK\n");
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2014-07-16 05:06:48 +08:00
|
|
|
void ScopDetection::markFunctionAsInvalid(Function *F) const {
|
|
|
|
F->addFnAttr(PollySkipFnAttr);
|
|
|
|
}
|
|
|
|
|
2011-04-29 14:27:02 +08:00
|
|
|
bool ScopDetection::isValidFunction(llvm::Function &F) {
|
2014-07-16 05:06:48 +08:00
|
|
|
return !F.hasFnAttribute(PollySkipFnAttr);
|
2011-04-29 14:27:02 +08:00
|
|
|
}
|
|
|
|
|
2013-03-05 03:49:51 +08:00
|
|
|
void ScopDetection::printLocations(llvm::Function &F) {
|
2014-04-03 04:18:19 +08:00
|
|
|
for (const Region *R : *this) {
|
2012-11-02 00:45:20 +08:00
|
|
|
unsigned LineEntry, LineExit;
|
|
|
|
std::string FileName;
|
|
|
|
|
2014-03-02 20:02:46 +08:00
|
|
|
getDebugLocation(R, LineEntry, LineExit, FileName);
|
2013-12-18 18:49:53 +08:00
|
|
|
DiagnosticScopFound Diagnostic(F, FileName, LineEntry, LineExit);
|
|
|
|
F.getContext().diagnose(Diagnostic);
|
2012-11-02 00:45:20 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-06-26 18:06:40 +08:00
|
|
|
void
|
|
|
|
ScopDetection::emitMissedRemarksForValidRegions(const Function &F,
|
|
|
|
const RegionSet &ValidRegions) {
|
|
|
|
for (const Region *R : ValidRegions) {
|
|
|
|
const Region *Parent = R->getParent();
|
|
|
|
if (Parent && !Parent->isTopLevelRegion() && RejectLogs.count(Parent))
|
|
|
|
emitRejectionRemarks(F, RejectLogs.at(Parent));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void ScopDetection::emitMissedRemarksForLeaves(const Function &F,
|
|
|
|
const Region *R) {
|
|
|
|
for (const std::unique_ptr<Region> &Child : *R) {
|
|
|
|
bool IsValid = ValidRegions.count(Child.get());
|
|
|
|
if (IsValid)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
bool IsLeaf = Child->begin() == Child->end();
|
|
|
|
if (!IsLeaf)
|
|
|
|
emitMissedRemarksForLeaves(F, Child.get());
|
|
|
|
else {
|
|
|
|
if (RejectLogs.count(Child.get())) {
|
|
|
|
emitRejectionRemarks(F, RejectLogs.at(Child.get()));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-04-29 14:27:02 +08:00
|
|
|
bool ScopDetection::runOnFunction(llvm::Function &F) {
|
2013-05-31 01:47:32 +08:00
|
|
|
LI = &getAnalysis<LoopInfo>();
|
2014-07-20 02:40:17 +08:00
|
|
|
RI = &getAnalysis<RegionInfoPass>().getRegionInfo();
|
2013-05-31 01:47:32 +08:00
|
|
|
if (!DetectScopsWithoutLoops && LI->empty())
|
|
|
|
return false;
|
|
|
|
|
2011-04-29 14:27:02 +08:00
|
|
|
AA = &getAnalysis<AliasAnalysis>();
|
|
|
|
SE = &getAnalysis<ScalarEvolution>();
|
|
|
|
Region *TopRegion = RI->getTopLevelRegion();
|
|
|
|
|
2011-10-23 19:17:06 +08:00
|
|
|
releaseMemory();
|
|
|
|
|
2014-05-07 19:23:32 +08:00
|
|
|
if (OnlyFunction != "" && !F.getName().count(OnlyFunction))
|
2011-10-23 19:17:06 +08:00
|
|
|
return false;
|
|
|
|
|
2012-12-30 07:47:38 +08:00
|
|
|
if (!isValidFunction(F))
|
2011-04-29 14:27:02 +08:00
|
|
|
return false;
|
|
|
|
|
|
|
|
findScops(*TopRegion);
|
2012-11-02 00:45:20 +08:00
|
|
|
|
2014-06-26 18:06:40 +08:00
|
|
|
// Only makes sense when we tracked errors.
|
|
|
|
if (PollyTrackFailures) {
|
|
|
|
emitMissedRemarksForValidRegions(F, ValidRegions);
|
|
|
|
emitMissedRemarksForLeaves(F, TopRegion);
|
|
|
|
}
|
|
|
|
|
|
|
|
for (const Region *R : ValidRegions)
|
|
|
|
emitValidRemarks(F, R);
|
|
|
|
|
2014-10-16 07:24:28 +08:00
|
|
|
if (ReportLevel)
|
2013-03-05 03:49:51 +08:00
|
|
|
printLocations(F);
|
2012-11-02 00:45:20 +08:00
|
|
|
|
2011-04-29 14:27:02 +08:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
void polly::ScopDetection::verifyRegion(const Region &R) const {
|
|
|
|
assert(isMaxRegionInScop(R) && "Expect R is a valid region.");
|
2013-02-05 19:56:05 +08:00
|
|
|
DetectionContext Context(const_cast<Region &>(R), *AA, true /*verifying*/);
|
2011-04-29 14:27:02 +08:00
|
|
|
isValidRegion(Context);
|
|
|
|
}
|
|
|
|
|
|
|
|
void polly::ScopDetection::verifyAnalysis() const {
|
2014-02-19 02:49:49 +08:00
|
|
|
if (!VerifyScops)
|
|
|
|
return;
|
|
|
|
|
2014-04-03 04:18:19 +08:00
|
|
|
for (const Region *R : ValidRegions)
|
2014-03-02 20:02:46 +08:00
|
|
|
verifyRegion(*R);
|
2011-04-29 14:27:02 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void ScopDetection::getAnalysisUsage(AnalysisUsage &AU) const {
|
2014-01-14 06:29:56 +08:00
|
|
|
AU.addRequired<DominatorTreeWrapperPass>();
|
2011-04-29 14:27:02 +08:00
|
|
|
AU.addRequired<PostDominatorTree>();
|
|
|
|
AU.addRequired<LoopInfo>();
|
|
|
|
AU.addRequired<ScalarEvolution>();
|
|
|
|
// We also need AA and RegionInfo when we are verifying analysis.
|
|
|
|
AU.addRequiredTransitive<AliasAnalysis>();
|
2014-07-20 02:40:17 +08:00
|
|
|
AU.addRequiredTransitive<RegionInfoPass>();
|
2011-04-29 14:27:02 +08:00
|
|
|
AU.setPreservesAll();
|
|
|
|
}
|
|
|
|
|
2013-03-23 09:05:07 +08:00
|
|
|
void ScopDetection::print(raw_ostream &OS, const Module *) const {
|
2014-04-03 04:18:19 +08:00
|
|
|
for (const Region *R : ValidRegions)
|
2014-03-02 20:02:46 +08:00
|
|
|
OS << "Valid Region for Scop: " << R->getNameStr() << '\n';
|
2011-04-29 14:27:02 +08:00
|
|
|
|
|
|
|
OS << "\n";
|
|
|
|
}
|
|
|
|
|
|
|
|
void ScopDetection::releaseMemory() {
|
|
|
|
ValidRegions.clear();
|
2014-05-24 17:25:01 +08:00
|
|
|
RejectLogs.clear();
|
|
|
|
|
2011-05-06 10:38:20 +08:00
|
|
|
// Do not clear the invalid function set.
|
2011-04-29 14:27:02 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
char ScopDetection::ID = 0;
|
|
|
|
|
2013-03-23 09:05:07 +08:00
|
|
|
Pass *polly::createScopDetectionPass() { return new ScopDetection(); }
|
|
|
|
|
2011-10-08 08:30:40 +08:00
|
|
|
INITIALIZE_PASS_BEGIN(ScopDetection, "polly-detect",
|
|
|
|
"Polly - Detect static control parts (SCoPs)", false,
|
2013-03-23 09:05:07 +08:00
|
|
|
false);
|
|
|
|
INITIALIZE_AG_DEPENDENCY(AliasAnalysis);
|
2014-01-14 06:29:56 +08:00
|
|
|
INITIALIZE_PASS_DEPENDENCY(DominatorTreeWrapperPass);
|
2013-03-23 09:05:07 +08:00
|
|
|
INITIALIZE_PASS_DEPENDENCY(LoopInfo);
|
|
|
|
INITIALIZE_PASS_DEPENDENCY(PostDominatorTree);
|
2014-07-20 02:40:17 +08:00
|
|
|
INITIALIZE_PASS_DEPENDENCY(RegionInfoPass);
|
2013-03-23 09:05:07 +08:00
|
|
|
INITIALIZE_PASS_DEPENDENCY(ScalarEvolution);
|
2011-10-08 08:30:40 +08:00
|
|
|
INITIALIZE_PASS_END(ScopDetection, "polly-detect",
|
|
|
|
"Polly - Detect static control parts (SCoPs)", false, false)
|