2017-08-26 05:35:27 +08:00
|
|
|
//===- ScopDetection.cpp - Detect Scops -----------------------------------===//
|
2011-04-29 14:27:02 +08:00
|
|
|
//
|
|
|
|
// 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.
|
|
|
|
//
|
2017-06-08 20:06:15 +08:00
|
|
|
// Every Scop fulfills these restrictions:
|
2011-04-29 14:27:02 +08:00
|
|
|
//
|
|
|
|
// * 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
|
|
|
|
//
|
2016-02-22 03:13:19 +08:00
|
|
|
// Function calls and intrinsics that do not have side effects (readnone)
|
|
|
|
// or memory intrinsics (memset, memcpy, memmove) are allowed.
|
2011-04-29 14:27:02 +08:00
|
|
|
//
|
|
|
|
// 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.
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2015-12-21 20:38:56 +08:00
|
|
|
#include "polly/ScopDetection.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"
|
2015-05-09 17:13:42 +08:00
|
|
|
#include "polly/ScopDetectionDiagnostic.h"
|
2011-11-07 20:58:54 +08:00
|
|
|
#include "polly/Support/SCEVValidator.h"
|
2017-08-26 05:35:27 +08:00
|
|
|
#include "polly/Support/ScopHelper.h"
|
2015-05-03 13:21:36 +08:00
|
|
|
#include "polly/Support/ScopLocation.h"
|
2017-08-26 05:35:27 +08:00
|
|
|
#include "llvm/ADT/DenseMap.h"
|
|
|
|
#include "llvm/ADT/SetVector.h"
|
|
|
|
#include "llvm/ADT/SmallPtrSet.h"
|
|
|
|
#include "llvm/ADT/SmallVector.h"
|
2011-04-29 14:27:02 +08:00
|
|
|
#include "llvm/ADT/Statistic.h"
|
2017-08-26 05:35:27 +08:00
|
|
|
#include "llvm/ADT/StringRef.h"
|
2011-04-29 14:27:02 +08:00
|
|
|
#include "llvm/Analysis/AliasAnalysis.h"
|
2017-03-09 19:36:00 +08:00
|
|
|
#include "llvm/Analysis/Loads.h"
|
2011-11-10 06:35:00 +08:00
|
|
|
#include "llvm/Analysis/LoopInfo.h"
|
2017-08-26 05:35:27 +08:00
|
|
|
#include "llvm/Analysis/MemoryLocation.h"
|
|
|
|
#include "llvm/Analysis/OptimizationDiagnosticInfo.h"
|
|
|
|
#include "llvm/Analysis/RegionInfo.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"
|
2017-08-26 05:35:27 +08:00
|
|
|
#include "llvm/IR/BasicBlock.h"
|
|
|
|
#include "llvm/IR/Constants.h"
|
|
|
|
#include "llvm/IR/DebugLoc.h"
|
|
|
|
#include "llvm/IR/DerivedTypes.h"
|
2013-12-18 18:49:53 +08:00
|
|
|
#include "llvm/IR/DiagnosticInfo.h"
|
|
|
|
#include "llvm/IR/DiagnosticPrinter.h"
|
2017-08-26 05:35:27 +08:00
|
|
|
#include "llvm/IR/Dominators.h"
|
|
|
|
#include "llvm/IR/Function.h"
|
|
|
|
#include "llvm/IR/InstrTypes.h"
|
|
|
|
#include "llvm/IR/Instruction.h"
|
|
|
|
#include "llvm/IR/Instructions.h"
|
2015-05-09 17:13:42 +08:00
|
|
|
#include "llvm/IR/IntrinsicInst.h"
|
2017-08-26 05:35:27 +08:00
|
|
|
#include "llvm/IR/Intrinsics.h"
|
2014-03-06 08:47:27 +08:00
|
|
|
#include "llvm/IR/LLVMContext.h"
|
2017-08-26 05:35:27 +08:00
|
|
|
#include "llvm/IR/Metadata.h"
|
|
|
|
#include "llvm/IR/Module.h"
|
|
|
|
#include "llvm/IR/PassManager.h"
|
|
|
|
#include "llvm/IR/Type.h"
|
|
|
|
#include "llvm/IR/Value.h"
|
|
|
|
#include "llvm/Pass.h"
|
|
|
|
#include "llvm/Support/Casting.h"
|
|
|
|
#include "llvm/Support/CommandLine.h"
|
2011-04-29 14:27:02 +08:00
|
|
|
#include "llvm/Support/Debug.h"
|
2017-08-26 05:35:27 +08:00
|
|
|
#include "llvm/Support/ErrorHandling.h"
|
2017-07-24 20:40:52 +08:00
|
|
|
#include "llvm/Support/Regex.h"
|
2017-08-26 05:35:27 +08:00
|
|
|
#include "llvm/Support/raw_ostream.h"
|
|
|
|
#include <algorithm>
|
|
|
|
#include <cassert>
|
|
|
|
#include <memory>
|
2016-01-22 17:44:37 +08:00
|
|
|
#include <stack>
|
2017-08-26 05:35:27 +08:00
|
|
|
#include <string>
|
|
|
|
#include <utility>
|
|
|
|
#include <vector>
|
2011-11-08 23:41:28 +08:00
|
|
|
|
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"
|
|
|
|
|
2015-12-22 05:00:43 +08:00
|
|
|
// This option is set to a very high value, as analyzing such loops increases
|
|
|
|
// compile time on several cases. For experiments that enable this option,
|
|
|
|
// a value of around 40 has been working to avoid run-time regressions with
|
|
|
|
// Polly while still exposing interesting optimization opportunities.
|
|
|
|
static cl::opt<int> ProfitabilityMinPerLoopInstructions(
|
|
|
|
"polly-detect-profitability-min-per-loop-insts",
|
|
|
|
cl::desc("The minimal number of per-loop instructions before a single loop "
|
|
|
|
"region is considered profitable"),
|
|
|
|
cl::Hidden, cl::ValueRequired, cl::init(100000000), cl::cat(PollyCategory));
|
|
|
|
|
2015-10-07 00:10:29 +08:00
|
|
|
bool polly::PollyProcessUnprofitable;
|
2017-08-26 05:35:27 +08:00
|
|
|
|
2015-10-07 00:10:29 +08:00
|
|
|
static cl::opt<bool, true> XPollyProcessUnprofitable(
|
|
|
|
"polly-process-unprofitable",
|
|
|
|
cl::desc(
|
|
|
|
"Process scops that are unlikely to benefit from Polly optimizations."),
|
|
|
|
cl::location(PollyProcessUnprofitable), cl::init(false), cl::ZeroOrMore,
|
|
|
|
cl::cat(PollyCategory));
|
2015-02-19 13:31:07 +08:00
|
|
|
|
2017-06-09 16:23:40 +08:00
|
|
|
static cl::list<std::string> OnlyFunctions(
|
2014-07-09 18:50:10 +08:00
|
|
|
"polly-only-func",
|
2017-07-24 20:40:52 +08:00
|
|
|
cl::desc("Only run on functions that match a regex. "
|
|
|
|
"Multiple regexes can be comma separated. "
|
|
|
|
"Scop detection will run on all functions that match "
|
|
|
|
"ANY of the regexes provided."),
|
2017-06-09 16:23:40 +08:00
|
|
|
cl::ZeroOrMore, cl::CommaSeparated, cl::cat(PollyCategory));
|
2014-07-09 18:50:10 +08:00
|
|
|
|
2017-07-28 19:47:24 +08:00
|
|
|
static cl::list<std::string> IgnoredFunctions(
|
|
|
|
"polly-ignore-func",
|
|
|
|
cl::desc("Ignore functions that match a regex. "
|
|
|
|
"Multiple regexes can be comma separated. "
|
|
|
|
"Scop detection will ignore all functions that match "
|
|
|
|
"ANY of the regexes provided."),
|
|
|
|
cl::ZeroOrMore, cl::CommaSeparated, cl::cat(PollyCategory));
|
|
|
|
|
2017-08-18 05:57:23 +08:00
|
|
|
bool polly::PollyAllowFullFunction;
|
2017-08-26 05:35:27 +08:00
|
|
|
|
2017-08-18 05:57:23 +08:00
|
|
|
static cl::opt<bool, true>
|
|
|
|
XAllowFullFunction("polly-detect-full-functions",
|
|
|
|
cl::desc("Allow the detection of full functions"),
|
|
|
|
cl::location(polly::PollyAllowFullFunction),
|
|
|
|
cl::init(false), cl::cat(PollyCategory));
|
2017-05-19 20:13:02 +08:00
|
|
|
|
2014-07-09 18:50:10 +08:00
|
|
|
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
|
|
|
|
2016-12-03 01:55:41 +08:00
|
|
|
bool polly::PollyAllowUnsignedOperations;
|
2017-08-26 05:35:27 +08:00
|
|
|
|
2016-12-03 01:55:41 +08:00
|
|
|
static cl::opt<bool, true> XPollyAllowUnsignedOperations(
|
|
|
|
"polly-allow-unsigned-operations",
|
|
|
|
cl::desc("Allow unsigned operations such as comparisons or zero-extends."),
|
|
|
|
cl::location(PollyAllowUnsignedOperations), cl::Hidden, cl::ZeroOrMore,
|
|
|
|
cl::init(true), cl::cat(PollyCategory));
|
|
|
|
|
2014-09-18 19:17:17 +08:00
|
|
|
bool polly::PollyUseRuntimeAliasChecks;
|
2017-08-26 05:35:27 +08:00
|
|
|
|
2014-09-18 19:17:17 +08:00
|
|
|
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
|
|
|
|
2016-02-07 16:48:57 +08:00
|
|
|
static cl::opt<bool> AllowDifferentTypes(
|
|
|
|
"polly-allow-differing-element-types",
|
|
|
|
cl::desc("Allow different element types for array accesses"), cl::Hidden,
|
2016-02-16 22:37:24 +08:00
|
|
|
cl::init(true), cl::ZeroOrMore, cl::cat(PollyCategory));
|
2016-02-07 16:48:57 +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
|
|
|
|
2016-03-23 14:40:15 +08:00
|
|
|
static cl::opt<bool>
|
|
|
|
AllowModrefCall("polly-allow-modref-calls",
|
|
|
|
cl::desc("Allow functions with known modref behavior"),
|
|
|
|
cl::Hidden, cl::init(false), cl::ZeroOrMore,
|
|
|
|
cl::cat(PollyCategory));
|
|
|
|
|
2015-02-24 19:45:21 +08:00
|
|
|
static cl::opt<bool> AllowNonAffineSubRegions(
|
|
|
|
"polly-allow-nonaffine-branches",
|
|
|
|
cl::desc("Allow non affine conditions for branches"), cl::Hidden,
|
2015-02-26 19:09:24 +08:00
|
|
|
cl::init(true), cl::ZeroOrMore, cl::cat(PollyCategory));
|
2015-02-24 19:45:21 +08:00
|
|
|
|
2015-04-13 06:52:20 +08:00
|
|
|
static cl::opt<bool>
|
|
|
|
AllowNonAffineSubLoops("polly-allow-nonaffine-loops",
|
|
|
|
cl::desc("Allow non affine conditions for loops"),
|
|
|
|
cl::Hidden, cl::init(false), cl::ZeroOrMore,
|
|
|
|
cl::cat(PollyCategory));
|
|
|
|
|
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,
|
2015-03-08 23:21:18 +08:00
|
|
|
cl::ZeroOrMore, cl::init(true), 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
|
|
|
|
2016-02-27 00:43:35 +08:00
|
|
|
bool polly::PollyInvariantLoadHoisting;
|
2017-08-26 05:35:27 +08:00
|
|
|
|
2016-02-27 00:43:35 +08:00
|
|
|
static cl::opt<bool, true> XPollyInvariantLoadHoisting(
|
|
|
|
"polly-invariant-load-hoisting", cl::desc("Hoist invariant loads."),
|
|
|
|
cl::location(PollyInvariantLoadHoisting), cl::Hidden, cl::ZeroOrMore,
|
2016-08-16 00:43:36 +08:00
|
|
|
cl::init(false), cl::cat(PollyCategory));
|
2016-02-27 00:43:35 +08:00
|
|
|
|
2016-09-02 14:33:33 +08:00
|
|
|
/// The minimal trip count under which loops are considered unprofitable.
|
2015-09-22 03:10:11 +08:00
|
|
|
static const unsigned MIN_LOOP_TRIP_COUNT = 8;
|
|
|
|
|
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.
|
|
|
|
|
2016-11-26 15:37:46 +08:00
|
|
|
STATISTIC(NumScopRegions, "Number of scops");
|
|
|
|
STATISTIC(NumLoopsInScop, "Number of loops in scops");
|
|
|
|
STATISTIC(NumScopsDepthOne, "Number of scops with maximal loop depth 1");
|
|
|
|
STATISTIC(NumScopsDepthTwo, "Number of scops with maximal loop depth 2");
|
|
|
|
STATISTIC(NumScopsDepthThree, "Number of scops with maximal loop depth 3");
|
|
|
|
STATISTIC(NumScopsDepthFour, "Number of scops with maximal loop depth 4");
|
|
|
|
STATISTIC(NumScopsDepthFive, "Number of scops with maximal loop depth 5");
|
|
|
|
STATISTIC(NumScopsDepthLarger,
|
|
|
|
"Number of scops with maximal loop depth 6 and larger");
|
|
|
|
STATISTIC(NumProfScopRegions, "Number of scops (profitable scops only)");
|
|
|
|
STATISTIC(NumLoopsInProfScop,
|
|
|
|
"Number of loops in scops (profitable scops only)");
|
|
|
|
STATISTIC(NumLoopsOverall, "Number of total loops");
|
|
|
|
STATISTIC(NumProfScopsDepthOne,
|
|
|
|
"Number of scops with maximal loop depth 1 (profitable scops only)");
|
|
|
|
STATISTIC(NumProfScopsDepthTwo,
|
|
|
|
"Number of scops with maximal loop depth 2 (profitable scops only)");
|
|
|
|
STATISTIC(NumProfScopsDepthThree,
|
|
|
|
"Number of scops with maximal loop depth 3 (profitable scops only)");
|
|
|
|
STATISTIC(NumProfScopsDepthFour,
|
|
|
|
"Number of scops with maximal loop depth 4 (profitable scops only)");
|
|
|
|
STATISTIC(NumProfScopsDepthFive,
|
|
|
|
"Number of scops with maximal loop depth 5 (profitable scops only)");
|
2017-01-16 22:08:10 +08:00
|
|
|
STATISTIC(NumProfScopsDepthLarger,
|
|
|
|
"Number of scops with maximal loop depth 6 and larger "
|
|
|
|
"(profitable scops only)");
|
2017-02-12 18:52:57 +08:00
|
|
|
STATISTIC(MaxNumLoopsInScop, "Maximal number of loops in scops");
|
|
|
|
STATISTIC(MaxNumLoopsInProfScop,
|
|
|
|
"Maximal number of loops in scops (profitable scops only)");
|
2011-04-29 14:27:02 +08:00
|
|
|
|
2017-05-12 22:37:29 +08:00
|
|
|
static void updateLoopCountStatistic(ScopDetection::LoopStats Stats,
|
|
|
|
bool OnlyProfitable);
|
|
|
|
|
2017-08-26 05:35:27 +08:00
|
|
|
namespace {
|
|
|
|
|
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
|
|
|
|
2017-08-26 05:35:27 +08:00
|
|
|
void print(DiagnosticPrinter &DP) const override;
|
2013-12-18 18:49:53 +08:00
|
|
|
|
|
|
|
static bool classof(const DiagnosticInfo *DI) {
|
|
|
|
return DI->getKind() == PluginDiagnosticKind;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2017-08-26 05:35:27 +08:00
|
|
|
} // namespace
|
|
|
|
|
2016-04-01 15:15:19 +08:00
|
|
|
int DiagnosticScopFound::PluginDiagnosticKind =
|
|
|
|
getNextAvailablePluginDiagnosticKind();
|
2013-12-18 18:49:53 +08:00
|
|
|
|
|
|
|
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";
|
|
|
|
}
|
|
|
|
|
2017-07-28 19:47:24 +08:00
|
|
|
/// Check if a string matches any regex in a list of regexes.
|
|
|
|
/// @param Str the input string to match against.
|
|
|
|
/// @param RegexList a list of strings that are regular expressions.
|
|
|
|
static bool doesStringMatchAnyRegex(StringRef Str,
|
|
|
|
const cl::list<std::string> &RegexList) {
|
|
|
|
for (auto RegexStr : RegexList) {
|
2017-07-24 20:40:52 +08:00
|
|
|
Regex R(RegexStr);
|
|
|
|
|
|
|
|
std::string Err;
|
|
|
|
if (!R.isValid(Err))
|
2017-07-28 19:47:24 +08:00
|
|
|
report_fatal_error("invalid regex given as input to polly: " + Err, true);
|
2017-07-24 20:40:52 +08:00
|
|
|
|
2017-07-28 19:47:24 +08:00
|
|
|
if (R.match(Str))
|
2017-06-09 16:23:40 +08:00
|
|
|
return true;
|
2017-07-24 20:40:52 +08:00
|
|
|
}
|
2017-06-09 16:23:40 +08:00
|
|
|
return false;
|
|
|
|
}
|
2011-04-29 14:27:02 +08:00
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// ScopDetection.
|
2014-04-02 19:54:01 +08:00
|
|
|
|
2017-05-12 22:37:29 +08:00
|
|
|
ScopDetection::ScopDetection(Function &F, const DominatorTree &DT,
|
|
|
|
ScalarEvolution &SE, LoopInfo &LI, RegionInfo &RI,
|
2017-07-18 07:58:33 +08:00
|
|
|
AliasAnalysis &AA, OptimizationRemarkEmitter &ORE)
|
|
|
|
: DT(DT), SE(SE), LI(LI), RI(RI), AA(AA), ORE(ORE) {
|
2017-05-12 22:37:29 +08:00
|
|
|
if (!PollyProcessUnprofitable && LI.empty())
|
|
|
|
return;
|
|
|
|
|
|
|
|
Region *TopRegion = RI.getTopLevelRegion();
|
|
|
|
|
2017-08-26 05:35:27 +08:00
|
|
|
if (!OnlyFunctions.empty() &&
|
2017-07-28 19:47:24 +08:00
|
|
|
!doesStringMatchAnyRegex(F.getName(), OnlyFunctions))
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (doesStringMatchAnyRegex(F.getName(), IgnoredFunctions))
|
2017-05-12 22:37:29 +08:00
|
|
|
return;
|
|
|
|
|
|
|
|
if (!isValidFunction(F))
|
|
|
|
return;
|
|
|
|
|
|
|
|
findScops(*TopRegion);
|
|
|
|
|
|
|
|
NumScopRegions += ValidRegions.size();
|
|
|
|
|
|
|
|
// Prune non-profitable regions.
|
|
|
|
for (auto &DIt : DetectionContextMap) {
|
|
|
|
auto &DC = DIt.getSecond();
|
|
|
|
if (DC.Log.hasErrors())
|
|
|
|
continue;
|
|
|
|
if (!ValidRegions.count(&DC.CurRegion))
|
|
|
|
continue;
|
|
|
|
LoopStats Stats = countBeneficialLoops(&DC.CurRegion, SE, LI, 0);
|
|
|
|
updateLoopCountStatistic(Stats, false /* OnlyProfitable */);
|
|
|
|
if (isProfitableRegion(DC)) {
|
|
|
|
updateLoopCountStatistic(Stats, true /* OnlyProfitable */);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
ValidRegions.remove(&DC.CurRegion);
|
|
|
|
}
|
|
|
|
|
|
|
|
NumProfScopRegions += ValidRegions.size();
|
|
|
|
NumLoopsOverall += countBeneficialLoops(TopRegion, SE, LI, 0).NumLoops;
|
|
|
|
|
|
|
|
// Only makes sense when we tracked errors.
|
|
|
|
if (PollyTrackFailures)
|
|
|
|
emitMissedRemarks(F);
|
|
|
|
|
|
|
|
if (ReportLevel)
|
|
|
|
printLocations(F);
|
|
|
|
|
|
|
|
assert(ValidRegions.size() <= DetectionContextMap.size() &&
|
|
|
|
"Cached more results than valid regions");
|
2014-09-18 19:17:17 +08:00
|
|
|
}
|
|
|
|
|
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;
|
|
|
|
|
2015-02-20 02:11:50 +08:00
|
|
|
if (Verify) {
|
2016-05-13 02:50:01 +08:00
|
|
|
DetectionContextMap.erase(getBBPairForRegion(&R));
|
|
|
|
const auto &It = DetectionContextMap.insert(std::make_pair(
|
|
|
|
getBBPairForRegion(&R),
|
2017-05-12 22:37:29 +08:00
|
|
|
DetectionContext(const_cast<Region &>(R), AA, false /*verifying*/)));
|
2015-10-25 18:55:35 +08:00
|
|
|
DetectionContext &Context = It.first->second;
|
2015-02-20 02:11:50 +08:00
|
|
|
return isValidRegion(Context);
|
|
|
|
}
|
2014-02-19 02:49:49 +08:00
|
|
|
|
|
|
|
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
|
|
|
// Get the first error we found. Even in keep-going mode, this is the first
|
|
|
|
// reason that caused the candidate to be rejected.
|
2016-05-13 02:50:01 +08:00
|
|
|
auto *Log = lookupRejectionLog(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.
|
2016-05-13 02:50:01 +08:00
|
|
|
if (!Log || !Log->hasErrors())
|
2014-06-12 15:25:08 +08:00
|
|
|
return "";
|
|
|
|
|
2016-05-13 02:50:01 +08:00
|
|
|
RejectReasonPtr RR = *Log->begin();
|
2014-06-12 15:25:08 +08:00
|
|
|
return RR->getMessage();
|
2011-10-08 08:30:55 +08:00
|
|
|
}
|
|
|
|
|
2015-04-13 06:52:20 +08:00
|
|
|
bool ScopDetection::addOverApproximatedRegion(Region *AR,
|
|
|
|
DetectionContext &Context) const {
|
|
|
|
// If we already know about Ar we can exit.
|
|
|
|
if (!Context.NonAffineSubRegionSet.insert(AR))
|
|
|
|
return true;
|
|
|
|
|
|
|
|
// All loops in the region have to be overapproximated too if there
|
|
|
|
// are accesses that depend on the iteration count.
|
2016-06-28 03:00:49 +08:00
|
|
|
|
2015-04-13 06:52:20 +08:00
|
|
|
for (BasicBlock *BB : AR->blocks()) {
|
2017-05-12 22:37:29 +08:00
|
|
|
Loop *L = LI.getLoopFor(BB);
|
2016-09-21 01:05:22 +08:00
|
|
|
if (AR->contains(L))
|
2015-04-13 06:52:20 +08:00
|
|
|
Context.BoxedLoopsSet.insert(L);
|
2015-02-24 19:45:21 +08:00
|
|
|
}
|
2015-04-13 06:52:20 +08:00
|
|
|
|
|
|
|
return (AllowNonAffineSubLoops || Context.BoxedLoopsSet.empty());
|
2015-02-24 19:45:21 +08:00
|
|
|
}
|
|
|
|
|
2015-10-08 04:17:36 +08:00
|
|
|
bool ScopDetection::onlyValidRequiredInvariantLoads(
|
|
|
|
InvariantLoadsSetTy &RequiredILS, DetectionContext &Context) const {
|
|
|
|
Region &CurRegion = Context.CurRegion;
|
2017-04-11 12:59:13 +08:00
|
|
|
const DataLayout &DL = CurRegion.getEntry()->getModule()->getDataLayout();
|
2015-10-08 04:17:36 +08:00
|
|
|
|
2016-02-27 00:43:35 +08:00
|
|
|
if (!PollyInvariantLoadHoisting && !RequiredILS.empty())
|
|
|
|
return false;
|
|
|
|
|
2017-03-02 20:15:37 +08:00
|
|
|
for (LoadInst *Load : RequiredILS) {
|
2017-05-04 18:16:20 +08:00
|
|
|
// If we already know a load has been accepted as required invariant, we
|
|
|
|
// already run the validation below once and consequently don't need to
|
|
|
|
// run it again. Hence, we return early. For certain test cases (e.g.,
|
|
|
|
// COSMO this avoids us spending 50% of scop-detection time in this
|
|
|
|
// very function (and its children).
|
|
|
|
if (Context.RequiredILS.count(Load))
|
|
|
|
continue;
|
|
|
|
|
2017-05-12 22:37:29 +08:00
|
|
|
if (!isHoistableLoad(Load, CurRegion, LI, SE, DT))
|
2015-10-08 04:17:36 +08:00
|
|
|
return false;
|
|
|
|
|
2017-03-09 19:36:00 +08:00
|
|
|
for (auto NonAffineRegion : Context.NonAffineSubRegionSet) {
|
|
|
|
if (isSafeToLoadUnconditionally(Load->getPointerOperand(),
|
|
|
|
Load->getAlignment(), DL))
|
|
|
|
continue;
|
|
|
|
|
2017-03-02 20:15:37 +08:00
|
|
|
if (NonAffineRegion->contains(Load) &&
|
|
|
|
Load->getParent() != NonAffineRegion->getEntry())
|
|
|
|
return false;
|
2017-03-09 19:36:00 +08:00
|
|
|
}
|
2017-03-02 20:15:37 +08:00
|
|
|
}
|
|
|
|
|
2015-10-08 04:17:36 +08:00
|
|
|
Context.RequiredILS.insert(RequiredILS.begin(), RequiredILS.end());
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2016-12-03 01:49:52 +08:00
|
|
|
bool ScopDetection::involvesMultiplePtrs(const SCEV *S0, const SCEV *S1,
|
|
|
|
Loop *Scope) const {
|
|
|
|
SetVector<Value *> Values;
|
2017-05-12 22:37:29 +08:00
|
|
|
findValues(S0, SE, Values);
|
2016-12-03 01:49:52 +08:00
|
|
|
if (S1)
|
2017-05-12 22:37:29 +08:00
|
|
|
findValues(S1, SE, Values);
|
2016-12-03 01:49:52 +08:00
|
|
|
|
|
|
|
SmallPtrSet<Value *, 8> PtrVals;
|
|
|
|
for (auto *V : Values) {
|
|
|
|
if (auto *P2I = dyn_cast<PtrToIntInst>(V))
|
|
|
|
V = P2I->getOperand(0);
|
|
|
|
|
|
|
|
if (!V->getType()->isPointerTy())
|
|
|
|
continue;
|
|
|
|
|
2017-05-12 22:37:29 +08:00
|
|
|
auto *PtrSCEV = SE.getSCEVAtScope(V, Scope);
|
2016-12-03 01:49:52 +08:00
|
|
|
if (isa<SCEVConstant>(PtrSCEV))
|
|
|
|
continue;
|
|
|
|
|
2017-05-12 22:37:29 +08:00
|
|
|
auto *BasePtr = dyn_cast<SCEVUnknown>(SE.getPointerBase(PtrSCEV));
|
2016-12-03 01:49:52 +08:00
|
|
|
if (!BasePtr)
|
|
|
|
return true;
|
|
|
|
|
|
|
|
auto *BasePtrVal = BasePtr->getValue();
|
|
|
|
if (PtrVals.insert(BasePtrVal).second) {
|
|
|
|
for (auto *PtrVal : PtrVals)
|
2017-05-12 22:37:29 +08:00
|
|
|
if (PtrVal != BasePtrVal && !AA.isNoAlias(PtrVal, BasePtrVal))
|
2016-12-03 01:49:52 +08:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2016-03-04 06:10:47 +08:00
|
|
|
bool ScopDetection::isAffine(const SCEV *S, Loop *Scope,
|
2016-04-25 21:32:36 +08:00
|
|
|
DetectionContext &Context) const {
|
2015-10-08 04:17:36 +08:00
|
|
|
InvariantLoadsSetTy AccessILS;
|
2017-05-12 22:37:29 +08:00
|
|
|
if (!isAffineExpr(&Context.CurRegion, Scope, S, SE, &AccessILS))
|
2015-10-08 04:17:36 +08:00
|
|
|
return false;
|
|
|
|
|
|
|
|
if (!onlyValidRequiredInvariantLoads(AccessILS, Context))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2015-09-28 17:33:22 +08:00
|
|
|
bool ScopDetection::isValidSwitch(BasicBlock &BB, SwitchInst *SI,
|
2015-10-04 22:54:27 +08:00
|
|
|
Value *Condition, bool IsLoopBranch,
|
2015-09-28 17:33:22 +08:00
|
|
|
DetectionContext &Context) const {
|
2017-05-12 22:37:29 +08:00
|
|
|
Loop *L = LI.getLoopFor(&BB);
|
|
|
|
const SCEV *ConditionSCEV = SE.getSCEVAtScope(Condition, L);
|
2011-04-29 14:27:02 +08:00
|
|
|
|
2016-11-10 13:20:29 +08:00
|
|
|
if (IsLoopBranch && L->isLoopLatch(&BB))
|
|
|
|
return false;
|
|
|
|
|
2016-12-03 01:49:52 +08:00
|
|
|
// Check for invalid usage of different pointers in one expression.
|
|
|
|
if (involvesMultiplePtrs(ConditionSCEV, nullptr, L))
|
|
|
|
return false;
|
|
|
|
|
2016-03-04 06:10:47 +08:00
|
|
|
if (isAffine(ConditionSCEV, L, Context))
|
2015-10-04 22:54:27 +08:00
|
|
|
return true;
|
2011-04-29 14:27:02 +08:00
|
|
|
|
2016-11-10 13:20:29 +08:00
|
|
|
if (AllowNonAffineSubRegions &&
|
2017-05-12 22:37:29 +08:00
|
|
|
addOverApproximatedRegion(RI.getRegionFor(&BB), Context))
|
2015-10-04 22:54:27 +08:00
|
|
|
return true;
|
|
|
|
|
|
|
|
return invalid<ReportNonAffBranch>(Context, /*Assert=*/true, &BB,
|
|
|
|
ConditionSCEV, ConditionSCEV, SI);
|
2015-09-28 17:33:22 +08:00
|
|
|
}
|
2011-04-29 14:27:02 +08:00
|
|
|
|
2015-09-28 17:33:22 +08:00
|
|
|
bool ScopDetection::isValidBranch(BasicBlock &BB, BranchInst *BI,
|
2015-10-04 22:54:27 +08:00
|
|
|
Value *Condition, bool IsLoopBranch,
|
2015-09-28 17:33:22 +08:00
|
|
|
DetectionContext &Context) const {
|
2016-11-10 13:20:29 +08:00
|
|
|
// Constant integer conditions are always affine.
|
|
|
|
if (isa<ConstantInt>(Condition))
|
|
|
|
return true;
|
|
|
|
|
2015-10-11 21:21:03 +08:00
|
|
|
if (BinaryOperator *BinOp = dyn_cast<BinaryOperator>(Condition)) {
|
|
|
|
auto Opcode = BinOp->getOpcode();
|
|
|
|
if (Opcode == Instruction::And || Opcode == Instruction::Or) {
|
|
|
|
Value *Op0 = BinOp->getOperand(0);
|
|
|
|
Value *Op1 = BinOp->getOperand(1);
|
|
|
|
return isValidBranch(BB, BI, Op0, IsLoopBranch, Context) &&
|
|
|
|
isValidBranch(BB, BI, Op1, IsLoopBranch, Context);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-09-28 17:33:22 +08:00
|
|
|
// Non constant conditions of branches need to be ICmpInst.
|
|
|
|
if (!isa<ICmpInst>(Condition)) {
|
2015-10-04 22:54:27 +08:00
|
|
|
if (!IsLoopBranch && AllowNonAffineSubRegions &&
|
2017-05-12 22:37:29 +08:00
|
|
|
addOverApproximatedRegion(RI.getRegionFor(&BB), Context))
|
2015-10-04 22:54:27 +08:00
|
|
|
return true;
|
|
|
|
return invalid<ReportInvalidCond>(Context, /*Assert=*/true, BI, &BB);
|
2015-02-24 19:45:21 +08:00
|
|
|
}
|
2011-04-29 14:27:02 +08:00
|
|
|
|
2015-10-04 22:54:27 +08:00
|
|
|
ICmpInst *ICmp = cast<ICmpInst>(Condition);
|
|
|
|
|
|
|
|
// Are both operands of the ICmp affine?
|
|
|
|
if (isa<UndefValue>(ICmp->getOperand(0)) ||
|
|
|
|
isa<UndefValue>(ICmp->getOperand(1)))
|
|
|
|
return invalid<ReportUndefOperand>(Context, /*Assert=*/true, &BB, ICmp);
|
|
|
|
|
2017-05-12 22:37:29 +08:00
|
|
|
Loop *L = LI.getLoopFor(&BB);
|
|
|
|
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
|
|
|
|
2016-12-03 01:55:41 +08:00
|
|
|
// If unsigned operations are not allowed try to approximate the region.
|
|
|
|
if (ICmp->isUnsigned() && !PollyAllowUnsignedOperations)
|
|
|
|
return !IsLoopBranch && AllowNonAffineSubRegions &&
|
2017-05-12 22:37:29 +08:00
|
|
|
addOverApproximatedRegion(RI.getRegionFor(&BB), Context);
|
2016-12-03 01:55:41 +08:00
|
|
|
|
2016-12-03 01:49:52 +08:00
|
|
|
// Check for invalid usage of different pointers in one expression.
|
|
|
|
if (ICmp->isEquality() && involvesMultiplePtrs(LHS, nullptr, L) &&
|
|
|
|
involvesMultiplePtrs(RHS, nullptr, L))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
// Check for invalid usage of different pointers in a relational comparison.
|
|
|
|
if (ICmp->isRelational() && involvesMultiplePtrs(LHS, RHS, L))
|
|
|
|
return false;
|
|
|
|
|
2016-03-04 06:10:47 +08:00
|
|
|
if (isAffine(LHS, L, Context) && isAffine(RHS, L, Context))
|
2015-10-04 22:54:27 +08:00
|
|
|
return true;
|
2011-04-29 14:27:02 +08:00
|
|
|
|
2015-10-04 22:54:27 +08:00
|
|
|
if (!IsLoopBranch && AllowNonAffineSubRegions &&
|
2017-05-12 22:37:29 +08:00
|
|
|
addOverApproximatedRegion(RI.getRegionFor(&BB), Context))
|
2015-10-04 22:54:27 +08:00
|
|
|
return true;
|
|
|
|
|
|
|
|
if (IsLoopBranch)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
return invalid<ReportNonAffBranch>(Context, /*Assert=*/true, &BB, LHS, RHS,
|
|
|
|
ICmp);
|
2011-04-29 14:27:02 +08:00
|
|
|
}
|
|
|
|
|
2015-10-04 22:54:27 +08:00
|
|
|
bool ScopDetection::isValidCFG(BasicBlock &BB, bool IsLoopBranch,
|
2015-11-11 16:42:20 +08:00
|
|
|
bool AllowUnreachable,
|
2015-09-28 17:33:22 +08:00
|
|
|
DetectionContext &Context) const {
|
|
|
|
Region &CurRegion = Context.CurRegion;
|
|
|
|
|
|
|
|
TerminatorInst *TI = BB.getTerminator();
|
|
|
|
|
2015-11-11 16:42:20 +08:00
|
|
|
if (AllowUnreachable && isa<UnreachableInst>(TI))
|
|
|
|
return true;
|
|
|
|
|
2015-09-28 17:33:22 +08:00
|
|
|
// Return instructions are only valid if the region is the top level region.
|
2017-05-25 02:39:39 +08:00
|
|
|
if (isa<ReturnInst>(TI) && CurRegion.isTopLevelRegion())
|
2015-09-28 17:33:22 +08:00
|
|
|
return true;
|
|
|
|
|
|
|
|
Value *Condition = getConditionFromTerminator(TI);
|
|
|
|
|
|
|
|
if (!Condition)
|
|
|
|
return invalid<ReportInvalidTerminator>(Context, /*Assert=*/true, &BB);
|
|
|
|
|
|
|
|
// UndefValue is not allowed as condition.
|
|
|
|
if (isa<UndefValue>(Condition))
|
|
|
|
return invalid<ReportUndefCond>(Context, /*Assert=*/true, TI, &BB);
|
|
|
|
|
|
|
|
if (BranchInst *BI = dyn_cast<BranchInst>(TI))
|
2015-10-04 22:54:27 +08:00
|
|
|
return isValidBranch(BB, BI, Condition, IsLoopBranch, Context);
|
2015-09-28 17:33:22 +08:00
|
|
|
|
|
|
|
SwitchInst *SI = dyn_cast<SwitchInst>(TI);
|
|
|
|
assert(SI && "Terminator was neither branch nor switch");
|
|
|
|
|
2015-10-04 22:54:27 +08:00
|
|
|
return isValidSwitch(BB, SI, Condition, IsLoopBranch, Context);
|
2015-09-28 17:33:22 +08:00
|
|
|
}
|
|
|
|
|
2016-02-22 03:13:19 +08:00
|
|
|
bool ScopDetection::isValidCallInst(CallInst &CI,
|
|
|
|
DetectionContext &Context) const {
|
2015-01-26 02:07:30 +08:00
|
|
|
if (CI.doesNotReturn())
|
2011-04-29 14:27:02 +08:00
|
|
|
return false;
|
|
|
|
|
|
|
|
if (CI.doesNotAccessMemory())
|
|
|
|
return true;
|
|
|
|
|
2016-02-22 03:13:19 +08:00
|
|
|
if (auto *II = dyn_cast<IntrinsicInst>(&CI))
|
2016-02-25 22:08:48 +08:00
|
|
|
if (isValidIntrinsicInst(*II, Context))
|
|
|
|
return true;
|
2016-02-22 03:13:19 +08:00
|
|
|
|
2011-04-29 14:27:02 +08:00
|
|
|
Function *CalledFunction = CI.getCalledFunction();
|
|
|
|
|
|
|
|
// Indirect calls are not supported.
|
2016-06-23 00:22:00 +08:00
|
|
|
if (CalledFunction == nullptr)
|
2011-04-29 14:27:02 +08:00
|
|
|
return false;
|
|
|
|
|
2016-03-23 14:40:15 +08:00
|
|
|
if (AllowModrefCall) {
|
2017-05-12 22:37:29 +08:00
|
|
|
switch (AA.getModRefBehavior(CalledFunction)) {
|
2016-11-21 17:04:45 +08:00
|
|
|
case FMRB_UnknownModRefBehavior:
|
2016-03-23 14:40:15 +08:00
|
|
|
return false;
|
2016-11-21 17:04:45 +08:00
|
|
|
case FMRB_DoesNotAccessMemory:
|
|
|
|
case FMRB_OnlyReadsMemory:
|
2016-02-25 22:08:48 +08:00
|
|
|
// Implicitly disable delinearization since we have an unknown
|
|
|
|
// accesses with an unknown access function.
|
|
|
|
Context.HasUnknownAccess = true;
|
2016-03-23 14:40:15 +08:00
|
|
|
Context.AST.add(&CI);
|
|
|
|
return true;
|
2016-11-21 17:04:45 +08:00
|
|
|
case FMRB_OnlyReadsArgumentPointees:
|
|
|
|
case FMRB_OnlyAccessesArgumentPointees:
|
2016-03-23 14:40:15 +08:00
|
|
|
for (const auto &Arg : CI.arg_operands()) {
|
|
|
|
if (!Arg->getType()->isPointerTy())
|
|
|
|
continue;
|
|
|
|
|
|
|
|
// Bail if a pointer argument has a base address not known to
|
|
|
|
// ScalarEvolution. Note that a zero pointer is acceptable.
|
2017-05-12 22:37:29 +08:00
|
|
|
auto *ArgSCEV = SE.getSCEVAtScope(Arg, LI.getLoopFor(CI.getParent()));
|
2016-03-23 14:40:15 +08:00
|
|
|
if (ArgSCEV->isZero())
|
|
|
|
continue;
|
|
|
|
|
2017-05-12 22:37:29 +08:00
|
|
|
auto *BP = dyn_cast<SCEVUnknown>(SE.getPointerBase(ArgSCEV));
|
2016-03-23 14:40:15 +08:00
|
|
|
if (!BP)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
// Implicitly disable delinearization since we have an unknown
|
|
|
|
// accesses with an unknown access function.
|
|
|
|
Context.HasUnknownAccess = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
Context.AST.add(&CI);
|
|
|
|
return true;
|
2016-07-12 02:27:52 +08:00
|
|
|
case FMRB_DoesNotReadMemory:
|
2016-11-14 03:27:24 +08:00
|
|
|
case FMRB_OnlyAccessesInaccessibleMem:
|
|
|
|
case FMRB_OnlyAccessesInaccessibleOrArgMem:
|
2016-07-12 02:27:52 +08:00
|
|
|
return false;
|
2016-02-25 22:08:48 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-02-22 03:13:19 +08:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool ScopDetection::isValidIntrinsicInst(IntrinsicInst &II,
|
|
|
|
DetectionContext &Context) const {
|
|
|
|
if (isIgnoredIntrinsic(&II))
|
|
|
|
return true;
|
|
|
|
|
|
|
|
// The closest loop surrounding the call instruction.
|
2017-05-12 22:37:29 +08:00
|
|
|
Loop *L = LI.getLoopFor(II.getParent());
|
2016-02-22 03:13:19 +08:00
|
|
|
|
|
|
|
// The access function and base pointer for memory intrinsics.
|
|
|
|
const SCEV *AF;
|
|
|
|
const SCEVUnknown *BP;
|
|
|
|
|
|
|
|
switch (II.getIntrinsicID()) {
|
|
|
|
// Memory intrinsics that can be represented are supported.
|
2017-08-26 05:35:27 +08:00
|
|
|
case Intrinsic::memmove:
|
|
|
|
case Intrinsic::memcpy:
|
2017-05-12 22:37:29 +08:00
|
|
|
AF = SE.getSCEVAtScope(cast<MemTransferInst>(II).getSource(), L);
|
2016-03-24 21:50:04 +08:00
|
|
|
if (!AF->isZero()) {
|
2017-05-12 22:37:29 +08:00
|
|
|
BP = dyn_cast<SCEVUnknown>(SE.getPointerBase(AF));
|
2016-03-24 21:50:04 +08:00
|
|
|
// Bail if the source pointer is not valid.
|
|
|
|
if (!isValidAccess(&II, AF, BP, Context))
|
|
|
|
return false;
|
|
|
|
}
|
2016-02-22 03:13:19 +08:00
|
|
|
// Fall through
|
2017-08-26 05:35:27 +08:00
|
|
|
case Intrinsic::memset:
|
2017-05-12 22:37:29 +08:00
|
|
|
AF = SE.getSCEVAtScope(cast<MemIntrinsic>(II).getDest(), L);
|
2016-03-24 21:50:04 +08:00
|
|
|
if (!AF->isZero()) {
|
2017-05-12 22:37:29 +08:00
|
|
|
BP = dyn_cast<SCEVUnknown>(SE.getPointerBase(AF));
|
2016-03-24 21:50:04 +08:00
|
|
|
// Bail if the destination pointer is not valid.
|
|
|
|
if (!isValidAccess(&II, AF, BP, Context))
|
|
|
|
return false;
|
|
|
|
}
|
2016-02-22 03:13:19 +08:00
|
|
|
|
|
|
|
// Bail if the length is not affine.
|
2017-05-12 22:37:29 +08:00
|
|
|
if (!isAffine(SE.getSCEVAtScope(cast<MemIntrinsic>(II).getLength(), L), L,
|
2016-02-22 03:13:19 +08:00
|
|
|
Context))
|
|
|
|
return false;
|
|
|
|
|
2015-08-31 00:57:15 +08:00
|
|
|
return true;
|
2016-02-22 03:13:19 +08:00
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
2015-01-26 02:07:30 +08:00
|
|
|
|
2011-04-29 14:27:02 +08:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2017-03-08 04:28:43 +08:00
|
|
|
bool ScopDetection::isInvariant(Value &Val, const Region &Reg,
|
|
|
|
DetectionContext &Ctx) const {
|
2014-01-28 20:58:58 +08:00
|
|
|
// A reference to function argument or constant value is invariant.
|
|
|
|
if (isa<Argument>(Val) || isa<Constant>(Val))
|
|
|
|
return true;
|
|
|
|
|
2017-03-08 04:28:43 +08:00
|
|
|
Instruction *I = dyn_cast<Instruction>(&Val);
|
2014-01-28 20:58:58 +08:00
|
|
|
if (!I)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
if (!Reg.contains(I))
|
|
|
|
return true;
|
|
|
|
|
2017-03-08 04:28:43 +08:00
|
|
|
// Loads within the SCoP may read arbitrary values, need to hoist them. If it
|
|
|
|
// is not hoistable, it will be rejected later, but here we assume it is and
|
|
|
|
// that makes the value invariant.
|
|
|
|
if (auto LI = dyn_cast<LoadInst>(I)) {
|
|
|
|
Ctx.RequiredILS.insert(LI);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
[ScopDetection] Only allow SCoP-wide available base pointers.
Simplify ScopDetection::isInvariant(). Essentially deny everything that
is defined within the SCoP and is not load-hoisted.
The previous understanding of "invariant" has a few holes:
- Expressions without side-effects with only invariant arguments, but
are defined withing the SCoP's region with the exception of selects
and PHIs. These should be part of the index expression derived by
ScalarEvolution and not of the base pointer.
- Function calls with that are !mayHaveSideEffects() (typically
functions with "readnone nounwind" attributes). An example is given
below.
@C = external global i32
declare float* @getNextBasePtr(float*) readnone nounwind
...
%ptr = call float* @getNextBasePtr(float* %A, float %B)
The call might return:
* %A, so %ptr aliases with it in the SCoP
* %B, so %ptr aliases with it in the SCoP
* @C, so %ptr aliases with it in the SCoP
* a new pointer everytime it is called, such as malloc()
* a pointer into the allocated block of one of the aforementioned
* any of the above, at random at each call
Hence and contrast to a comment in the base_pointer.ll regression
test, %ptr is not necessarily the same all the time. It might also
alias with anything and no AliasAnalysis can tell otherwise if the
definition is external. It is hence not suitable in the role of a
base pointer.
The practical problem with base pointers defined in SCoP statements is
that it is not available globally in the SCoP. The statement instance
must be executed first before the base pointer can be used. This is no
problem if the base pointer is transferred as a scalar value between
statements. Uses of MemoryAccess::setNewAccessRelation may add a use of
the base pointer anywhere in the array. setNewAccessRelation is used by
JSONImporter, DeLICM and D28518. Indeed, BlockGenerator currently
assumes that base pointers are available globally and generates invalid
code for new access relation (referring to the base pointer of the
original code) if not, even if the base pointer would be available in
the statement.
This could be fixed with some added complexity and restrictions. The
ExprBuilder must lookup the local BBMap and code that call
setNewAccessRelation must check whether the base pointer is available
first.
The code would still be incorrect in the presence of aliasing. There
is the switch -polly-ignore-aliasing to explicitly allow this, but
it is hardly a justification for the additional complexity. It would
still be mostly useless because in most cases either getNextBasePtr()
has external linkage in which case the readnone nounwind attributes
cannot be derived in the translation unit itself, or is defined in the
same translation unit and gets inlined.
Reviewed By: grosser
Differential Revision: https://reviews.llvm.org/D30695
llvm-svn: 297281
2017-03-08 23:14:46 +08:00
|
|
|
return false;
|
2014-01-28 20:58:58 +08:00
|
|
|
}
|
|
|
|
|
2017-08-26 05:35:27 +08:00
|
|
|
namespace {
|
|
|
|
|
2016-09-02 14:33:33 +08:00
|
|
|
/// Remove smax of smax(0, size) expressions from a SCEV expression and
|
2015-11-25 01:06:38 +08:00
|
|
|
/// register the '...' components.
|
|
|
|
///
|
2017-06-08 20:06:15 +08:00
|
|
|
/// Array access expressions as they are generated by GFortran contain smax(0,
|
2015-11-25 01:06:38 +08:00
|
|
|
/// size) expressions that confuse the 'normal' delinearization algorithm.
|
|
|
|
/// However, if we extract such expressions before the normal delinearization
|
|
|
|
/// takes place they can actually help to identify array size expressions in
|
2017-06-08 20:06:15 +08:00
|
|
|
/// Fortran accesses. For the subsequently following delinearization the smax(0,
|
2015-11-25 01:06:38 +08:00
|
|
|
/// size) component can be replaced by just 'size'. This is correct as we will
|
|
|
|
/// always add and verify the assumption that for all subscript expressions
|
|
|
|
/// 'exp' the inequality 0 <= exp < size holds. Hence, we will also verify
|
|
|
|
/// that 0 <= size, which means smax(0, size) == size.
|
2016-10-29 14:19:34 +08:00
|
|
|
class SCEVRemoveMax : public SCEVRewriteVisitor<SCEVRemoveMax> {
|
2015-11-25 01:06:38 +08:00
|
|
|
public:
|
2017-08-26 05:35:27 +08:00
|
|
|
SCEVRemoveMax(ScalarEvolution &SE, std::vector<const SCEV *> *Terms)
|
|
|
|
: SCEVRewriteVisitor(SE), Terms(Terms) {}
|
|
|
|
|
2016-10-29 14:19:34 +08:00
|
|
|
static const SCEV *rewrite(const SCEV *Scev, ScalarEvolution &SE,
|
|
|
|
std::vector<const SCEV *> *Terms = nullptr) {
|
|
|
|
SCEVRemoveMax Rewriter(SE, Terms);
|
|
|
|
return Rewriter.visit(Scev);
|
2015-11-25 01:06:38 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
const SCEV *visitSMaxExpr(const SCEVSMaxExpr *Expr) {
|
2015-12-20 22:42:32 +08:00
|
|
|
if ((Expr->getNumOperands() == 2) && Expr->getOperand(0)->isZero()) {
|
2015-11-25 01:06:38 +08:00
|
|
|
auto Res = visit(Expr->getOperand(1));
|
|
|
|
if (Terms)
|
|
|
|
(*Terms).push_back(Res);
|
|
|
|
return Res;
|
|
|
|
}
|
|
|
|
|
|
|
|
return Expr;
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
std::vector<const SCEV *> *Terms;
|
|
|
|
};
|
|
|
|
|
2017-08-26 05:35:27 +08:00
|
|
|
} // namespace
|
|
|
|
|
2015-11-24 13:00:36 +08:00
|
|
|
SmallVector<const SCEV *, 4>
|
|
|
|
ScopDetection::getDelinearizationTerms(DetectionContext &Context,
|
|
|
|
const SCEVUnknown *BasePointer) const {
|
|
|
|
SmallVector<const SCEV *, 4> Terms;
|
|
|
|
for (const auto &Pair : Context.Accesses[BasePointer]) {
|
2015-11-25 01:06:38 +08:00
|
|
|
std::vector<const SCEV *> MaxTerms;
|
2017-05-12 22:37:29 +08:00
|
|
|
SCEVRemoveMax::rewrite(Pair.second, SE, &MaxTerms);
|
2017-08-26 05:35:27 +08:00
|
|
|
if (!MaxTerms.empty()) {
|
2015-11-25 01:06:38 +08:00
|
|
|
Terms.insert(Terms.begin(), MaxTerms.begin(), MaxTerms.end());
|
|
|
|
continue;
|
|
|
|
}
|
2015-11-24 13:00:36 +08:00
|
|
|
// In case the outermost expression is a plain add, we check if any of its
|
|
|
|
// terms has the form 4 * %inst * %param * %param ..., aka a term that
|
|
|
|
// contains a product between a parameter and an instruction that is
|
|
|
|
// inside the scop. Such instructions, if allowed at all, are instructions
|
|
|
|
// SCEV can not represent, but Polly is still looking through. As a
|
|
|
|
// result, these instructions can depend on induction variables and are
|
|
|
|
// most likely no array sizes. However, terms that are multiplied with
|
|
|
|
// them are likely candidates for array sizes.
|
|
|
|
if (auto *AF = dyn_cast<SCEVAddExpr>(Pair.second)) {
|
|
|
|
for (auto Op : AF->operands()) {
|
|
|
|
if (auto *AF2 = dyn_cast<SCEVAddRecExpr>(Op))
|
2017-05-12 22:37:29 +08:00
|
|
|
SE.collectParametricTerms(AF2, Terms);
|
2015-11-24 13:00:36 +08:00
|
|
|
if (auto *AF2 = dyn_cast<SCEVMulExpr>(Op)) {
|
|
|
|
SmallVector<const SCEV *, 0> Operands;
|
|
|
|
|
|
|
|
for (auto *MulOp : AF2->operands()) {
|
|
|
|
if (auto *Const = dyn_cast<SCEVConstant>(MulOp))
|
|
|
|
Operands.push_back(Const);
|
|
|
|
if (auto *Unknown = dyn_cast<SCEVUnknown>(MulOp)) {
|
|
|
|
if (auto *Inst = dyn_cast<Instruction>(Unknown->getValue())) {
|
|
|
|
if (!Context.CurRegion.contains(Inst))
|
2015-06-29 22:44:22 +08:00
|
|
|
Operands.push_back(MulOp);
|
2015-11-24 13:00:36 +08:00
|
|
|
|
|
|
|
} else {
|
|
|
|
Operands.push_back(MulOp);
|
2015-06-29 22:44:22 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2015-11-24 13:00:36 +08:00
|
|
|
if (Operands.size())
|
2017-05-12 22:37:29 +08:00
|
|
|
Terms.push_back(SE.getMulExpr(Operands));
|
2015-06-29 22:44:22 +08:00
|
|
|
}
|
|
|
|
}
|
2014-09-13 22:47:55 +08:00
|
|
|
}
|
2015-11-24 13:00:36 +08:00
|
|
|
if (Terms.empty())
|
2017-05-12 22:37:29 +08:00
|
|
|
SE.collectParametricTerms(Pair.second, Terms);
|
2015-11-24 13:00:36 +08:00
|
|
|
}
|
|
|
|
return Terms;
|
|
|
|
}
|
2014-05-13 03:02:02 +08:00
|
|
|
|
2015-11-24 13:00:36 +08:00
|
|
|
bool ScopDetection::hasValidArraySizes(DetectionContext &Context,
|
|
|
|
SmallVectorImpl<const SCEV *> &Sizes,
|
2016-03-02 05:44:06 +08:00
|
|
|
const SCEVUnknown *BasePointer,
|
|
|
|
Loop *Scope) const {
|
2017-05-27 23:18:53 +08:00
|
|
|
// If no sizes were found, all sizes are trivially valid. We allow this case
|
|
|
|
// to make it possible to pass known-affine accesses to the delinearization to
|
|
|
|
// try to recover some interesting multi-dimensional accesses, but to still
|
|
|
|
// allow the already known to be affine access in case the delinearization
|
|
|
|
// fails. In such situations, the delinearization will just return a Sizes
|
|
|
|
// array of size zero.
|
|
|
|
if (Sizes.size() == 0)
|
|
|
|
return true;
|
|
|
|
|
2015-11-24 13:00:36 +08:00
|
|
|
Value *BaseValue = BasePointer->getValue();
|
|
|
|
Region &CurRegion = Context.CurRegion;
|
|
|
|
for (const SCEV *DelinearizedSize : Sizes) {
|
2016-04-25 21:32:36 +08:00
|
|
|
if (!isAffine(DelinearizedSize, Scope, Context)) {
|
2015-11-24 13:00:36 +08:00
|
|
|
Sizes.clear();
|
|
|
|
break;
|
2015-10-25 16:40:38 +08:00
|
|
|
}
|
2015-11-24 13:00:36 +08:00
|
|
|
if (auto *Unknown = dyn_cast<SCEVUnknown>(DelinearizedSize)) {
|
|
|
|
auto *V = dyn_cast<Value>(Unknown->getValue());
|
|
|
|
if (auto *Load = dyn_cast<LoadInst>(V)) {
|
|
|
|
if (Context.CurRegion.contains(Load) &&
|
2017-05-12 22:37:29 +08:00
|
|
|
isHoistableLoad(Load, CurRegion, LI, SE, DT))
|
2015-11-24 13:00:36 +08:00
|
|
|
Context.RequiredILS.insert(Load);
|
2014-09-13 22:47:55 +08:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
2017-07-13 20:18:56 +08:00
|
|
|
if (hasScalarDepsInsideRegion(DelinearizedSize, &CurRegion, Scope, false,
|
|
|
|
Context.RequiredILS))
|
2015-12-21 17:09:39 +08:00
|
|
|
return invalid<ReportNonAffineAccess>(
|
2015-11-24 13:00:36 +08:00
|
|
|
Context, /*Assert=*/true, DelinearizedSize,
|
|
|
|
Context.Accesses[BasePointer].front().first, BaseValue);
|
|
|
|
}
|
|
|
|
|
|
|
|
// No array shape derived.
|
|
|
|
if (Sizes.empty()) {
|
|
|
|
if (AllowNonAffine)
|
|
|
|
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
|
|
|
|
2014-09-13 22:47:55 +08:00
|
|
|
for (const auto &Pair : Context.Accesses[BasePointer]) {
|
|
|
|
const Instruction *Insn = Pair.first;
|
2015-11-24 13:00:36 +08:00
|
|
|
const SCEV *AF = Pair.second;
|
2014-09-13 22:47:55 +08:00
|
|
|
|
2016-04-25 21:32:36 +08:00
|
|
|
if (!isAffine(AF, Scope, Context)) {
|
2015-11-24 13:00:36 +08:00
|
|
|
invalid<ReportNonAffineAccess>(Context, /*Assert=*/true, AF, Insn,
|
|
|
|
BaseValue);
|
|
|
|
if (!KeepGoing)
|
2014-09-13 22:47:55 +08:00
|
|
|
return false;
|
|
|
|
}
|
2014-05-10 06:45:15 +08:00
|
|
|
}
|
2015-11-24 13:00:36 +08:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
// 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.
|
|
|
|
bool ScopDetection::computeAccessFunctions(
|
|
|
|
DetectionContext &Context, const SCEVUnknown *BasePointer,
|
|
|
|
std::shared_ptr<ArrayShape> Shape) const {
|
|
|
|
Value *BaseValue = BasePointer->getValue();
|
|
|
|
bool BasePtrHasNonAffine = false;
|
|
|
|
MapInsnToMemAcc TempMemoryAccesses;
|
|
|
|
for (const auto &Pair : Context.Accesses[BasePointer]) {
|
|
|
|
const Instruction *Insn = Pair.first;
|
|
|
|
auto *AF = Pair.second;
|
2017-05-12 22:37:29 +08:00
|
|
|
AF = SCEVRemoveMax::rewrite(AF, SE);
|
2015-11-24 13:00:36 +08:00
|
|
|
bool IsNonAffine = false;
|
|
|
|
TempMemoryAccesses.insert(std::make_pair(Insn, MemAcc(Insn, Shape)));
|
|
|
|
MemAcc *Acc = &TempMemoryAccesses.find(Insn)->second;
|
2017-05-12 22:37:29 +08:00
|
|
|
auto *Scope = LI.getLoopFor(Insn->getParent());
|
2015-11-24 13:00:36 +08:00
|
|
|
|
|
|
|
if (!AF) {
|
2016-04-25 21:32:36 +08:00
|
|
|
if (isAffine(Pair.second, Scope, Context))
|
2015-11-24 13:00:36 +08:00
|
|
|
Acc->DelinearizedSubscripts.push_back(Pair.second);
|
|
|
|
else
|
|
|
|
IsNonAffine = true;
|
|
|
|
} else {
|
2017-05-27 23:18:53 +08:00
|
|
|
if (Shape->DelinearizedSizes.size() == 0) {
|
|
|
|
Acc->DelinearizedSubscripts.push_back(AF);
|
|
|
|
} else {
|
|
|
|
SE.computeAccessFunctions(AF, Acc->DelinearizedSubscripts,
|
|
|
|
Shape->DelinearizedSizes);
|
|
|
|
if (Acc->DelinearizedSubscripts.size() == 0)
|
|
|
|
IsNonAffine = true;
|
|
|
|
}
|
2015-11-24 13:00:36 +08:00
|
|
|
for (const SCEV *S : Acc->DelinearizedSubscripts)
|
2016-04-25 21:32:36 +08:00
|
|
|
if (!isAffine(S, Scope, Context))
|
2015-11-24 13:00:36 +08:00
|
|
|
IsNonAffine = true;
|
|
|
|
}
|
2014-09-13 22:47:55 +08:00
|
|
|
|
2015-11-24 13:00:36 +08:00
|
|
|
// (Possibly) report non affine access
|
|
|
|
if (IsNonAffine) {
|
|
|
|
BasePtrHasNonAffine = true;
|
|
|
|
if (!AllowNonAffine)
|
|
|
|
invalid<ReportNonAffineAccess>(Context, /*Assert=*/true, Pair.second,
|
|
|
|
Insn, BaseValue);
|
|
|
|
if (!KeepGoing && !AllowNonAffine)
|
|
|
|
return false;
|
|
|
|
}
|
2014-05-10 06:45:15 +08:00
|
|
|
}
|
2015-11-24 13:00:36 +08:00
|
|
|
|
|
|
|
if (!BasePtrHasNonAffine)
|
2016-02-15 08:20:58 +08:00
|
|
|
Context.InsnToMemAcc.insert(TempMemoryAccesses.begin(),
|
|
|
|
TempMemoryAccesses.end());
|
2015-11-24 13:00:36 +08:00
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2016-03-02 05:44:06 +08:00
|
|
|
bool ScopDetection::hasBaseAffineAccesses(DetectionContext &Context,
|
|
|
|
const SCEVUnknown *BasePointer,
|
|
|
|
Loop *Scope) const {
|
2015-11-24 13:00:36 +08:00
|
|
|
auto Shape = std::shared_ptr<ArrayShape>(new ArrayShape(BasePointer));
|
|
|
|
|
|
|
|
auto Terms = getDelinearizationTerms(Context, BasePointer);
|
|
|
|
|
2017-05-12 22:37:29 +08:00
|
|
|
SE.findArrayDimensions(Terms, Shape->DelinearizedSizes,
|
|
|
|
Context.ElementSize[BasePointer]);
|
2015-11-24 13:00:36 +08:00
|
|
|
|
2016-03-02 05:44:06 +08:00
|
|
|
if (!hasValidArraySizes(Context, Shape->DelinearizedSizes, BasePointer,
|
|
|
|
Scope))
|
2015-11-24 13:00:36 +08:00
|
|
|
return false;
|
|
|
|
|
|
|
|
return computeAccessFunctions(Context, BasePointer, Shape);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool ScopDetection::hasAffineMemoryAccesses(DetectionContext &Context) const {
|
2016-02-25 22:08:48 +08:00
|
|
|
// TODO: If we have an unknown access and other non-affine accesses we do
|
|
|
|
// not try to delinearize them for now.
|
|
|
|
if (Context.HasUnknownAccess && !Context.NonAffineAccesses.empty())
|
|
|
|
return AllowNonAffine;
|
|
|
|
|
2016-03-02 05:44:06 +08:00
|
|
|
for (auto &Pair : Context.NonAffineAccesses) {
|
|
|
|
auto *BasePointer = Pair.first;
|
|
|
|
auto *Scope = Pair.second;
|
|
|
|
if (!hasBaseAffineAccesses(Context, BasePointer, Scope)) {
|
2015-11-24 13:00:36 +08:00
|
|
|
if (KeepGoing)
|
|
|
|
continue;
|
|
|
|
else
|
|
|
|
return false;
|
|
|
|
}
|
2016-03-02 05:44:06 +08:00
|
|
|
}
|
2014-05-13 03:02:02 +08:00
|
|
|
return true;
|
2014-05-10 06:45:15 +08:00
|
|
|
}
|
|
|
|
|
2016-02-22 03:13:19 +08:00
|
|
|
bool ScopDetection::isValidAccess(Instruction *Inst, const SCEV *AF,
|
|
|
|
const SCEVUnknown *BP,
|
|
|
|
DetectionContext &Context) const {
|
2011-11-10 20:44:50 +08:00
|
|
|
|
2016-02-22 03:13:19 +08:00
|
|
|
if (!BP)
|
2016-01-28 01:09:17 +08:00
|
|
|
return invalid<ReportNoBasePtr>(Context, /*Assert=*/true, Inst);
|
2011-11-10 20:44:50 +08:00
|
|
|
|
2016-02-22 03:13:19 +08:00
|
|
|
auto *BV = BP->getValue();
|
|
|
|
if (isa<UndefValue>(BV))
|
2016-01-28 01:09:17 +08:00
|
|
|
return invalid<ReportUndefBasePtr>(Context, /*Assert=*/true, Inst);
|
2011-11-10 20:44:50 +08:00
|
|
|
|
2016-02-22 03:13:19 +08:00
|
|
|
// FIXME: Think about allowing IntToPtrInst
|
|
|
|
if (IntToPtrInst *Inst = dyn_cast<IntToPtrInst>(BV))
|
|
|
|
return invalid<ReportIntToPtr>(Context, /*Assert=*/true, Inst);
|
|
|
|
|
2014-01-28 20:58:58 +08:00
|
|
|
// Check that the base address of the access is invariant in the current
|
|
|
|
// region.
|
2017-03-08 04:28:43 +08:00
|
|
|
if (!isInvariant(*BV, Context.CurRegion, Context))
|
2016-02-22 03:13:19 +08:00
|
|
|
return invalid<ReportVariantBasePtr>(Context, /*Assert=*/true, BV, Inst);
|
2014-01-28 20:58:58 +08:00
|
|
|
|
2017-05-12 22:37:29 +08:00
|
|
|
AF = SE.getMinusSCEV(AF, BP);
|
2014-04-09 05:20:44 +08:00
|
|
|
|
2016-02-22 03:13:19 +08:00
|
|
|
const SCEV *Size;
|
|
|
|
if (!isa<MemIntrinsic>(Inst)) {
|
2017-05-12 22:37:29 +08:00
|
|
|
Size = SE.getElementSize(Inst);
|
2016-02-22 03:13:19 +08:00
|
|
|
} else {
|
|
|
|
auto *SizeTy =
|
2017-05-12 22:37:29 +08:00
|
|
|
SE.getEffectiveSCEVType(PointerType::getInt8PtrTy(SE.getContext()));
|
|
|
|
Size = SE.getConstant(SizeTy, 8);
|
2016-02-22 03:13:19 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
if (Context.ElementSize[BP]) {
|
|
|
|
if (!AllowDifferentTypes && Context.ElementSize[BP] != Size)
|
2016-02-07 16:48:57 +08:00
|
|
|
return invalid<ReportDifferentArrayElementSize>(Context, /*Assert=*/true,
|
2016-02-22 03:13:19 +08:00
|
|
|
Inst, BV);
|
2016-02-07 16:48:57 +08:00
|
|
|
|
2017-05-12 22:37:29 +08:00
|
|
|
Context.ElementSize[BP] = SE.getSMinExpr(Size, Context.ElementSize[BP]);
|
2016-02-07 16:48:57 +08:00
|
|
|
} else {
|
2016-02-22 03:13:19 +08:00
|
|
|
Context.ElementSize[BP] = Size;
|
2016-02-07 16:48:57 +08:00
|
|
|
}
|
2014-09-13 22:47:40 +08:00
|
|
|
|
2016-02-22 03:13:19 +08:00
|
|
|
bool IsVariantInNonAffineLoop = false;
|
2015-04-13 06:52:20 +08:00
|
|
|
SetVector<const Loop *> Loops;
|
2016-02-22 03:13:19 +08:00
|
|
|
findLoops(AF, Loops);
|
2015-04-13 06:52:20 +08:00
|
|
|
for (const Loop *L : Loops)
|
|
|
|
if (Context.BoxedLoopsSet.count(L))
|
2016-02-22 03:13:19 +08:00
|
|
|
IsVariantInNonAffineLoop = true;
|
|
|
|
|
2017-05-12 22:37:29 +08:00
|
|
|
auto *Scope = LI.getLoopFor(Inst->getParent());
|
2016-04-25 21:32:36 +08:00
|
|
|
bool IsAffine = !IsVariantInNonAffineLoop && isAffine(AF, Scope, Context);
|
2016-02-22 03:13:19 +08:00
|
|
|
// Do not try to delinearize memory intrinsics and force them to be affine.
|
|
|
|
if (isa<MemIntrinsic>(Inst) && !IsAffine) {
|
|
|
|
return invalid<ReportNonAffineAccess>(Context, /*Assert=*/true, AF, Inst,
|
|
|
|
BV);
|
|
|
|
} else if (PollyDelinearize && !IsVariantInNonAffineLoop) {
|
|
|
|
Context.Accesses[BP].push_back({Inst, AF});
|
|
|
|
|
2017-05-27 23:18:53 +08:00
|
|
|
if (!IsAffine || hasIVParams(AF))
|
2016-03-02 05:44:06 +08:00
|
|
|
Context.NonAffineAccesses.insert(
|
2017-05-12 22:37:29 +08:00
|
|
|
std::make_pair(BP, LI.getLoopFor(Inst->getParent())));
|
2016-02-22 03:13:19 +08:00
|
|
|
} else if (!AllowNonAffine && !IsAffine) {
|
|
|
|
return invalid<ReportNonAffineAccess>(Context, /*Assert=*/true, AF, Inst,
|
|
|
|
BV);
|
2014-04-09 05:20:44 +08:00
|
|
|
}
|
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;
|
2016-02-22 03:13:19 +08:00
|
|
|
Inst->getAAMetadata(AATags);
|
2014-10-05 19:58:57 +08:00
|
|
|
AliasSet &AS = Context.AST.getAliasSetForPointer(
|
2016-02-22 03:13:19 +08:00
|
|
|
BP->getValue(), MemoryLocation::UnknownSize, AATags);
|
2013-07-04 06:50:36 +08:00
|
|
|
|
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.
|
2015-10-08 04:17:36 +08:00
|
|
|
// However, we can ignore loads that will be hoisted.
|
2014-09-25 05:04:29 +08:00
|
|
|
for (const auto &Ptr : AS) {
|
|
|
|
Instruction *Inst = dyn_cast<Instruction>(Ptr.getValue());
|
2016-02-22 03:13:19 +08:00
|
|
|
if (Inst && Context.CurRegion.contains(Inst)) {
|
2015-10-08 04:17:36 +08:00
|
|
|
auto *Load = dyn_cast<LoadInst>(Inst);
|
2017-05-12 22:37:29 +08:00
|
|
|
if (Load && isHoistableLoad(Load, Context.CurRegion, LI, SE, DT)) {
|
2015-10-08 04:17:36 +08:00
|
|
|
Context.RequiredILS.insert(Load);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2014-09-25 05:04:29 +08:00
|
|
|
CanBuildRunTimeCheck = false;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (CanBuildRunTimeCheck)
|
|
|
|
return true;
|
|
|
|
}
|
2016-01-28 01:09:17 +08:00
|
|
|
return invalid<ReportAlias>(Context, /*Assert=*/true, Inst, AS);
|
2014-09-25 05:04:29 +08:00
|
|
|
}
|
2011-04-29 14:27:02 +08:00
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2016-02-22 03:13:19 +08:00
|
|
|
bool ScopDetection::isValidMemoryAccess(MemAccInst Inst,
|
|
|
|
DetectionContext &Context) const {
|
|
|
|
Value *Ptr = Inst.getPointerOperand();
|
2017-05-12 22:37:29 +08:00
|
|
|
Loop *L = LI.getLoopFor(Inst->getParent());
|
|
|
|
const SCEV *AccessFunction = SE.getSCEVAtScope(Ptr, L);
|
2016-02-22 03:13:19 +08:00
|
|
|
const SCEVUnknown *BasePointer;
|
|
|
|
|
2017-05-12 22:37:29 +08:00
|
|
|
BasePointer = dyn_cast<SCEVUnknown>(SE.getPointerBase(AccessFunction));
|
2016-02-22 03:13:19 +08:00
|
|
|
|
|
|
|
return isValidAccess(Inst, AccessFunction, BasePointer, Context);
|
|
|
|
}
|
|
|
|
|
2011-04-29 14:27:02 +08:00
|
|
|
bool ScopDetection::isValidInstruction(Instruction &Inst,
|
|
|
|
DetectionContext &Context) const {
|
2015-11-11 20:44:18 +08:00
|
|
|
for (auto &Op : Inst.operands()) {
|
|
|
|
auto *OpInst = dyn_cast<Instruction>(&Op);
|
|
|
|
|
|
|
|
if (!OpInst)
|
|
|
|
continue;
|
|
|
|
|
2017-05-12 22:37:29 +08:00
|
|
|
if (isErrorBlock(*OpInst->getParent(), Context.CurRegion, LI, DT))
|
2015-11-11 20:44:18 +08:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2016-04-10 05:55:58 +08:00
|
|
|
if (isa<LandingPadInst>(&Inst) || isa<ResumeInst>(&Inst))
|
|
|
|
return false;
|
|
|
|
|
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)) {
|
2016-02-22 03:13:19 +08:00
|
|
|
if (isValidCallInst(*CI, Context))
|
2011-04-29 14:27:02 +08:00
|
|
|
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
|
|
|
}
|
|
|
|
|
2016-11-21 17:07:30 +08:00
|
|
|
if (!Inst.mayReadOrWriteMemory()) {
|
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.
|
2016-01-28 01:09:17 +08:00
|
|
|
if (auto MemInst = MemAccInst::dyn_cast(Inst)) {
|
2016-02-27 09:49:58 +08:00
|
|
|
Context.hasStores |= isa<StoreInst>(MemInst);
|
|
|
|
Context.hasLoads |= isa<LoadInst>(MemInst);
|
2016-01-28 01:09:17 +08:00
|
|
|
if (!MemInst.isSimple())
|
|
|
|
return invalid<ReportNonSimpleMemoryAccess>(Context, /*Assert=*/true,
|
|
|
|
&Inst);
|
|
|
|
|
|
|
|
return isValidMemoryAccess(MemInst, Context);
|
2015-02-19 13:31:07 +08:00
|
|
|
}
|
2011-04-29 14:27:02 +08:00
|
|
|
|
|
|
|
// 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
|
|
|
}
|
|
|
|
|
2017-08-25 03:47:15 +08:00
|
|
|
/// Check whether @p L has exiting blocks.
|
|
|
|
///
|
|
|
|
/// @param L The loop of interest
|
|
|
|
///
|
|
|
|
/// @return True if the loop has exiting blocks, false otherwise.
|
|
|
|
static bool hasExitingBlocks(Loop *L) {
|
|
|
|
SmallVector<BasicBlock *, 4> ExitingBlocks;
|
|
|
|
L->getExitingBlocks(ExitingBlocks);
|
|
|
|
return !ExitingBlocks.empty();
|
|
|
|
}
|
|
|
|
|
2015-08-27 14:53:52 +08:00
|
|
|
bool ScopDetection::canUseISLTripCount(Loop *L,
|
|
|
|
DetectionContext &Context) const {
|
2015-10-04 22:53:18 +08:00
|
|
|
// Ensure the loop has valid exiting blocks as well as latches, otherwise we
|
|
|
|
// need to overapproximate it as a boxed loop.
|
|
|
|
SmallVector<BasicBlock *, 4> LoopControlBlocks;
|
2016-04-04 03:36:52 +08:00
|
|
|
L->getExitingBlocks(LoopControlBlocks);
|
2016-04-04 07:09:06 +08:00
|
|
|
L->getLoopLatches(LoopControlBlocks);
|
2015-10-04 22:53:18 +08:00
|
|
|
for (BasicBlock *ControlBB : LoopControlBlocks) {
|
2015-11-11 16:42:20 +08:00
|
|
|
if (!isValidCFG(*ControlBB, true, false, Context))
|
2015-08-27 14:53:52 +08:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// We can use ISL to compute the trip count of L.
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2011-04-29 14:27:02 +08:00
|
|
|
bool ScopDetection::isValidLoop(Loop *L, DetectionContext &Context) const {
|
2016-09-21 01:05:22 +08:00
|
|
|
// Loops that contain part but not all of the blocks of a region cannot be
|
|
|
|
// handled by the schedule generation. Such loop constructs can happen
|
|
|
|
// because a region can contain BBs that have no path to the exit block
|
2017-08-25 03:47:15 +08:00
|
|
|
// (Infinite loops, UnreachableInst), but such blocks are never part of a
|
|
|
|
// loop.
|
|
|
|
//
|
|
|
|
// _______________
|
|
|
|
// | Loop Header | <-----------.
|
|
|
|
// --------------- |
|
|
|
|
// | |
|
|
|
|
// _______________ ______________
|
|
|
|
// | RegionEntry |-----> | RegionExit |----->
|
|
|
|
// --------------- --------------
|
|
|
|
// |
|
|
|
|
// _______________
|
|
|
|
// | EndlessLoop | <--.
|
|
|
|
// --------------- |
|
|
|
|
// | |
|
|
|
|
// \------------/
|
|
|
|
//
|
|
|
|
// In the example above, the loop (LoopHeader,RegionEntry,RegionExit) is
|
|
|
|
// neither entirely contained in the region RegionEntry->RegionExit
|
|
|
|
// (containing RegionEntry,EndlessLoop) nor is the region entirely contained
|
|
|
|
// in the loop.
|
|
|
|
// The block EndlessLoop is contained in the region because Region::contains
|
|
|
|
// tests whether it is not dominated by RegionExit. This is probably to not
|
|
|
|
// having to query the PostdominatorTree. Instead of an endless loop, a dead
|
|
|
|
// end can also be formed by an UnreachableInst. This case is already caught
|
|
|
|
// by isErrorBlock(). We hence only have to reject endless loops here.
|
|
|
|
if (!hasExitingBlocks(L))
|
|
|
|
return invalid<ReportLoopHasNoExit>(Context, /*Assert=*/true, L);
|
2016-09-21 01:05:22 +08:00
|
|
|
|
2015-10-04 22:56:08 +08:00
|
|
|
if (canUseISLTripCount(L, Context))
|
2015-02-24 19:45:21 +08:00
|
|
|
return true;
|
2015-04-13 06:52:20 +08:00
|
|
|
|
2015-09-10 23:27:46 +08:00
|
|
|
if (AllowNonAffineSubLoops && AllowNonAffineSubRegions) {
|
2017-05-12 22:37:29 +08:00
|
|
|
Region *R = RI.getRegionFor(L->getHeader());
|
2015-10-04 22:54:27 +08:00
|
|
|
while (R != &Context.CurRegion && !R->contains(L))
|
|
|
|
R = R->getParent();
|
|
|
|
|
|
|
|
if (addOverApproximatedRegion(R, Context))
|
|
|
|
return true;
|
2015-04-13 06:52:20 +08:00
|
|
|
}
|
2011-04-29 14:27:02 +08:00
|
|
|
|
2017-05-12 22:37:29 +08:00
|
|
|
const SCEV *LoopCount = SE.getBackedgeTakenCount(L);
|
2015-02-24 19:45:21 +08:00
|
|
|
return invalid<ReportLoopBound>(Context, /*Assert=*/true, L, LoopCount);
|
2011-04-29 14:27:02 +08:00
|
|
|
}
|
|
|
|
|
2016-09-02 14:33:33 +08:00
|
|
|
/// Return the number of loops in @p L (incl. @p L) that have a trip
|
2016-11-26 15:37:46 +08:00
|
|
|
/// count that is not known to be less than @MinProfitableTrips.
|
|
|
|
ScopDetection::LoopStats
|
|
|
|
ScopDetection::countBeneficialSubLoops(Loop *L, ScalarEvolution &SE,
|
2017-02-17 16:12:36 +08:00
|
|
|
unsigned MinProfitableTrips) {
|
2015-09-20 22:56:54 +08:00
|
|
|
auto *TripCount = SE.getBackedgeTakenCount(L);
|
|
|
|
|
2016-11-26 15:37:46 +08:00
|
|
|
int NumLoops = 1;
|
|
|
|
int MaxLoopDepth = 1;
|
2017-08-23 21:29:59 +08:00
|
|
|
if (MinProfitableTrips > 0)
|
|
|
|
if (auto *TripCountC = dyn_cast<SCEVConstant>(TripCount))
|
|
|
|
if (TripCountC->getType()->getScalarSizeInBits() <= 64)
|
|
|
|
if (TripCountC->getValue()->getZExtValue() <= MinProfitableTrips)
|
|
|
|
NumLoops -= 1;
|
2015-09-20 22:56:54 +08:00
|
|
|
|
2016-11-26 15:37:46 +08:00
|
|
|
for (auto &SubLoop : *L) {
|
|
|
|
LoopStats Stats = countBeneficialSubLoops(SubLoop, SE, MinProfitableTrips);
|
|
|
|
NumLoops += Stats.NumLoops;
|
2017-02-17 16:08:54 +08:00
|
|
|
MaxLoopDepth = std::max(MaxLoopDepth, Stats.MaxDepth + 1);
|
2016-11-26 15:37:46 +08:00
|
|
|
}
|
2015-09-20 22:56:54 +08:00
|
|
|
|
2016-11-26 15:37:46 +08:00
|
|
|
return {NumLoops, MaxLoopDepth};
|
2015-09-20 22:56:54 +08:00
|
|
|
}
|
|
|
|
|
2016-11-26 15:37:46 +08:00
|
|
|
ScopDetection::LoopStats
|
2017-02-17 16:12:36 +08:00
|
|
|
ScopDetection::countBeneficialLoops(Region *R, ScalarEvolution &SE,
|
|
|
|
LoopInfo &LI, unsigned MinProfitableTrips) {
|
2015-10-04 22:56:08 +08:00
|
|
|
int LoopNum = 0;
|
2016-11-26 15:37:46 +08:00
|
|
|
int MaxLoopDepth = 0;
|
2015-08-28 00:55:18 +08:00
|
|
|
|
2017-02-17 16:12:36 +08:00
|
|
|
auto L = LI.getLoopFor(R->getEntry());
|
2017-08-28 05:39:25 +08:00
|
|
|
|
|
|
|
// If L is fully contained in R, move to first loop surrounding R. Otherwise,
|
|
|
|
// L is either nullptr or already surrounding R.
|
|
|
|
if (L && R->contains(L)) {
|
|
|
|
L = R->outermostLoopInRegion(L);
|
|
|
|
L = L->getParentLoop();
|
|
|
|
}
|
2015-08-28 00:55:18 +08:00
|
|
|
|
2015-08-31 20:08:11 +08:00
|
|
|
auto SubLoops =
|
2017-02-17 16:12:36 +08:00
|
|
|
L ? L->getSubLoopsVector() : std::vector<Loop *>(LI.begin(), LI.end());
|
2015-08-28 00:55:18 +08:00
|
|
|
|
2015-08-31 20:08:11 +08:00
|
|
|
for (auto &SubLoop : SubLoops)
|
2016-11-26 15:37:46 +08:00
|
|
|
if (R->contains(SubLoop)) {
|
|
|
|
LoopStats Stats =
|
2017-02-17 16:12:36 +08:00
|
|
|
countBeneficialSubLoops(SubLoop, SE, MinProfitableTrips);
|
2016-11-26 15:37:46 +08:00
|
|
|
LoopNum += Stats.NumLoops;
|
|
|
|
MaxLoopDepth = std::max(MaxLoopDepth, Stats.MaxDepth);
|
|
|
|
}
|
2015-08-31 20:08:11 +08:00
|
|
|
|
2016-11-26 15:37:46 +08:00
|
|
|
return {LoopNum, MaxLoopDepth};
|
2015-08-28 00:55:18 +08:00
|
|
|
}
|
|
|
|
|
2011-04-29 14:27:02 +08:00
|
|
|
Region *ScopDetection::expandRegion(Region &R) {
|
2012-04-07 23:14:28 +08:00
|
|
|
// Initial no valid region was found (greater than R)
|
2015-06-05 01:59:54 +08:00
|
|
|
std::unique_ptr<Region> LastValidRegion;
|
|
|
|
auto ExpandedRegion = std::unique_ptr<Region>(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) {
|
2015-10-08 04:46:06 +08:00
|
|
|
const auto &It = DetectionContextMap.insert(std::make_pair(
|
2016-05-13 02:50:01 +08:00
|
|
|
getBBPairForRegion(ExpandedRegion.get()),
|
2017-05-12 22:37:29 +08:00
|
|
|
DetectionContext(*ExpandedRegion, AA, false /*verifying*/)));
|
2015-10-08 04:46:06 +08:00
|
|
|
DetectionContext &Context = It.first->second;
|
2012-04-07 23:14:28 +08:00
|
|
|
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
|
|
|
|
2015-09-09 05:44:27 +08:00
|
|
|
if (!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?)
|
2015-10-01 18:59:14 +08:00
|
|
|
if (!allBlocksValid(Context) || Context.Log.hasErrors()) {
|
|
|
|
removeCachedResults(*ExpandedRegion);
|
2016-08-09 06:39:32 +08:00
|
|
|
DetectionContextMap.erase(It.first);
|
2014-06-27 14:21:14 +08:00
|
|
|
break;
|
2015-10-01 18:59:14 +08:00
|
|
|
}
|
2014-06-27 14:21:14 +08:00
|
|
|
|
2013-04-10 14:55:45 +08:00
|
|
|
// Store this region, because it is the greatest valid (encountered so
|
|
|
|
// far).
|
2016-08-09 06:39:32 +08:00
|
|
|
if (LastValidRegion) {
|
|
|
|
removeCachedResults(*LastValidRegion);
|
|
|
|
DetectionContextMap.erase(getBBPairForRegion(LastValidRegion.get()));
|
|
|
|
}
|
2015-06-05 01:59:54 +08:00
|
|
|
LastValidRegion = std::move(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)
|
2015-06-05 01:59:54 +08:00
|
|
|
ExpandedRegion =
|
|
|
|
std::unique_ptr<Region>(LastValidRegion->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)
|
2015-10-08 04:46:06 +08:00
|
|
|
removeCachedResults(*ExpandedRegion);
|
2016-08-09 06:39:32 +08:00
|
|
|
DetectionContextMap.erase(It.first);
|
2015-06-05 01:59:54 +08:00
|
|
|
ExpandedRegion =
|
|
|
|
std::unique_ptr<Region>(ExpandedRegion->getExpandedRegion());
|
2012-04-07 23:14:28 +08:00
|
|
|
}
|
|
|
|
}
|
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
|
|
|
|
2015-06-05 01:59:54 +08:00
|
|
|
return LastValidRegion.release();
|
2011-04-29 14:27:02 +08:00
|
|
|
}
|
2017-08-26 05:35:27 +08:00
|
|
|
|
2017-05-12 22:37:29 +08:00
|
|
|
static bool regionWithoutLoops(Region &R, LoopInfo &LI) {
|
2014-04-03 04:18:19 +08:00
|
|
|
for (const BasicBlock *BB : R.blocks())
|
2017-05-12 22:37:29 +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
|
|
|
|
2016-11-26 15:37:46 +08:00
|
|
|
void ScopDetection::removeCachedResultsRecursively(const Region &R) {
|
2014-04-16 02:45:27 +08:00
|
|
|
for (auto &SubRegion : R) {
|
2015-10-01 18:59:14 +08:00
|
|
|
if (ValidRegions.count(SubRegion.get())) {
|
|
|
|
removeCachedResults(*SubRegion.get());
|
|
|
|
} else
|
2016-11-26 15:37:46 +08:00
|
|
|
removeCachedResultsRecursively(*SubRegion);
|
2014-01-30 03:05:30 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-10-01 18:59:14 +08:00
|
|
|
void ScopDetection::removeCachedResults(const Region &R) {
|
|
|
|
ValidRegions.remove(&R);
|
|
|
|
}
|
|
|
|
|
2011-04-29 14:27:02 +08:00
|
|
|
void ScopDetection::findScops(Region &R) {
|
2016-05-13 02:50:01 +08:00
|
|
|
const auto &It = DetectionContextMap.insert(std::make_pair(
|
2017-05-12 22:37:29 +08:00
|
|
|
getBBPairForRegion(&R), DetectionContext(R, AA, false /*verifying*/)));
|
2015-10-08 04:46:06 +08:00
|
|
|
DetectionContext &Context = It.first->second;
|
2015-03-08 23:11:50 +08:00
|
|
|
|
|
|
|
bool RegionIsValid = false;
|
2016-03-01 00:54:18 +08:00
|
|
|
if (!PollyProcessUnprofitable && regionWithoutLoops(R, LI))
|
2015-03-08 23:11:50 +08:00
|
|
|
invalid<ReportUnprofitable>(Context, /*Assert=*/true, &R);
|
2016-03-01 00:54:18 +08:00
|
|
|
else
|
2015-03-08 23:11:50 +08:00
|
|
|
RegionIsValid = isValidRegion(Context);
|
|
|
|
|
2015-02-20 02:11:50 +08:00
|
|
|
bool HasErrors = !RegionIsValid || Context.Log.size() > 0;
|
2014-05-24 17:25:10 +08:00
|
|
|
|
2015-10-01 18:59:14 +08:00
|
|
|
if (HasErrors) {
|
|
|
|
removeCachedResults(R);
|
|
|
|
} else {
|
2011-04-29 14:27:02 +08:00
|
|
|
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) {
|
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;
|
|
|
|
|
2016-05-13 02:50:01 +08:00
|
|
|
// Skip regions that had errors.
|
|
|
|
bool HadErrors = lookupRejectionLog(CurrentRegion)->hasErrors();
|
|
|
|
if (HadErrors)
|
|
|
|
continue;
|
|
|
|
|
2011-04-29 14:27:02 +08:00
|
|
|
Region *ExpandedR = expandRegion(*CurrentRegion);
|
|
|
|
|
|
|
|
if (!ExpandedR)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
R.addSubRegion(ExpandedR, true);
|
|
|
|
ValidRegions.insert(ExpandedR);
|
2015-10-01 18:59:14 +08:00
|
|
|
removeCachedResults(*CurrentRegion);
|
2016-11-26 15:37:46 +08:00
|
|
|
removeCachedResultsRecursively(*ExpandedR);
|
2011-04-29 14:27:02 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool ScopDetection::allBlocksValid(DetectionContext &Context) const {
|
2015-02-23 22:18:28 +08:00
|
|
|
Region &CurRegion = Context.CurRegion;
|
2011-04-29 14:27:02 +08:00
|
|
|
|
2015-02-23 22:18:28 +08:00
|
|
|
for (const BasicBlock *BB : CurRegion.blocks()) {
|
2017-05-12 22:37:29 +08:00
|
|
|
Loop *L = LI.getLoopFor(BB);
|
2017-07-16 06:42:17 +08:00
|
|
|
if (L && L->getHeader() == BB) {
|
|
|
|
if (CurRegion.contains(L)) {
|
|
|
|
if (!isValidLoop(L, Context) && !KeepGoing)
|
|
|
|
return false;
|
|
|
|
} else {
|
|
|
|
SmallVector<BasicBlock *, 1> Latches;
|
|
|
|
L->getLoopLatches(Latches);
|
|
|
|
for (BasicBlock *Latch : Latches)
|
|
|
|
if (CurRegion.contains(Latch))
|
|
|
|
return invalid<ReportLoopOnlySomeLatches>(Context, /*Assert=*/true,
|
|
|
|
L);
|
|
|
|
}
|
|
|
|
}
|
2013-06-12 06:20:32 +08:00
|
|
|
}
|
|
|
|
|
2015-09-11 01:51:27 +08:00
|
|
|
for (BasicBlock *BB : CurRegion.blocks()) {
|
2017-05-12 22:37:29 +08:00
|
|
|
bool IsErrorBlock = isErrorBlock(*BB, CurRegion, LI, DT);
|
2015-09-11 01:51:27 +08:00
|
|
|
|
2015-11-11 16:42:20 +08:00
|
|
|
// Also check exception blocks (and possibly register them as non-affine
|
|
|
|
// regions). Even though exception blocks are not modeled, we use them
|
|
|
|
// to forward-propagate domain constraints during ScopInfo construction.
|
|
|
|
if (!isValidCFG(*BB, false, IsErrorBlock, Context) && !KeepGoing)
|
2013-06-12 06:20:27 +08:00
|
|
|
return false;
|
2015-11-11 16:42:20 +08:00
|
|
|
|
|
|
|
if (IsErrorBlock)
|
|
|
|
continue;
|
|
|
|
|
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;
|
2015-09-11 01:51:27 +08:00
|
|
|
}
|
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;
|
|
|
|
}
|
|
|
|
|
2015-12-22 05:00:43 +08:00
|
|
|
bool ScopDetection::hasSufficientCompute(DetectionContext &Context,
|
|
|
|
int NumLoops) const {
|
|
|
|
int InstCount = 0;
|
|
|
|
|
2016-09-08 22:08:05 +08:00
|
|
|
if (NumLoops == 0)
|
|
|
|
return false;
|
|
|
|
|
2015-12-22 05:00:43 +08:00
|
|
|
for (auto *BB : Context.CurRegion.blocks())
|
2017-05-12 22:37:29 +08:00
|
|
|
if (Context.CurRegion.contains(LI.getLoopFor(BB)))
|
2015-12-23 01:38:59 +08:00
|
|
|
InstCount += BB->size();
|
2015-12-22 05:00:43 +08:00
|
|
|
|
|
|
|
InstCount = InstCount / NumLoops;
|
|
|
|
|
|
|
|
return InstCount >= ProfitabilityMinPerLoopInstructions;
|
|
|
|
}
|
|
|
|
|
2016-05-10 22:42:30 +08:00
|
|
|
bool ScopDetection::hasPossiblyDistributableLoop(
|
|
|
|
DetectionContext &Context) const {
|
|
|
|
for (auto *BB : Context.CurRegion.blocks()) {
|
2017-05-12 22:37:29 +08:00
|
|
|
auto *L = LI.getLoopFor(BB);
|
2016-05-10 22:42:30 +08:00
|
|
|
if (!Context.CurRegion.contains(L))
|
|
|
|
continue;
|
|
|
|
if (Context.BoxedLoopsSet.count(L))
|
|
|
|
continue;
|
|
|
|
unsigned StmtsWithStoresInLoops = 0;
|
|
|
|
for (auto *LBB : L->blocks()) {
|
|
|
|
bool MemStore = false;
|
|
|
|
for (auto &I : *LBB)
|
|
|
|
MemStore |= isa<StoreInst>(&I);
|
|
|
|
StmtsWithStoresInLoops += MemStore;
|
|
|
|
}
|
|
|
|
return (StmtsWithStoresInLoops > 1);
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2015-12-21 20:14:48 +08:00
|
|
|
bool ScopDetection::isProfitableRegion(DetectionContext &Context) const {
|
|
|
|
Region &CurRegion = Context.CurRegion;
|
|
|
|
|
|
|
|
if (PollyProcessUnprofitable)
|
|
|
|
return true;
|
|
|
|
|
|
|
|
// We can probably not do a lot on scops that only write or only read
|
|
|
|
// data.
|
|
|
|
if (!Context.hasStores || !Context.hasLoads)
|
|
|
|
return invalid<ReportUnprofitable>(Context, /*Assert=*/true, &CurRegion);
|
|
|
|
|
2017-02-17 16:12:36 +08:00
|
|
|
int NumLoops =
|
2017-05-12 22:37:29 +08:00
|
|
|
countBeneficialLoops(&CurRegion, SE, LI, MIN_LOOP_TRIP_COUNT).NumLoops;
|
2015-12-21 20:14:48 +08:00
|
|
|
int NumAffineLoops = NumLoops - Context.BoxedLoopsSet.size();
|
|
|
|
|
2015-12-22 05:00:43 +08:00
|
|
|
// Scops with at least two loops may allow either loop fusion or tiling and
|
|
|
|
// are consequently interesting to look at.
|
|
|
|
if (NumAffineLoops >= 2)
|
|
|
|
return true;
|
|
|
|
|
2017-06-08 20:06:15 +08:00
|
|
|
// A loop with multiple non-trivial blocks might be amendable to distribution.
|
2016-05-10 22:42:30 +08:00
|
|
|
if (NumAffineLoops == 1 && hasPossiblyDistributableLoop(Context))
|
|
|
|
return true;
|
|
|
|
|
2015-12-22 05:00:43 +08:00
|
|
|
// Scops that contain a loop with a non-trivial amount of computation per
|
|
|
|
// loop-iteration are interesting as we may be able to parallelize such
|
|
|
|
// loops. Individual loops that have only a small amount of computation
|
|
|
|
// per-iteration are performance-wise very fragile as any change to the
|
|
|
|
// loop induction variables may affect performance. To not cause spurious
|
|
|
|
// performance regressions, we do not consider such loops.
|
|
|
|
if (NumAffineLoops == 1 && hasSufficientCompute(Context, NumLoops))
|
|
|
|
return true;
|
|
|
|
|
|
|
|
return invalid<ReportUnprofitable>(Context, /*Assert=*/true, &CurRegion);
|
2015-12-21 20:14:48 +08:00
|
|
|
}
|
|
|
|
|
2011-04-29 14:27:02 +08:00
|
|
|
bool ScopDetection::isValidRegion(DetectionContext &Context) const {
|
2015-02-23 22:18:28 +08:00
|
|
|
Region &CurRegion = Context.CurRegion;
|
2011-04-29 14:27:02 +08:00
|
|
|
|
2015-02-23 22:18:28 +08:00
|
|
|
DEBUG(dbgs() << "Checking region: " << CurRegion.getNameStr() << "\n\t");
|
2011-04-29 14:27:02 +08:00
|
|
|
|
2017-08-18 05:57:23 +08:00
|
|
|
if (!PollyAllowFullFunction && CurRegion.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;
|
|
|
|
}
|
|
|
|
|
2017-03-07 23:50:43 +08:00
|
|
|
DebugLoc DbgLoc;
|
2017-05-25 02:39:39 +08:00
|
|
|
if (CurRegion.getExit() &&
|
|
|
|
isa<UnreachableInst>(CurRegion.getExit()->getTerminator())) {
|
2017-03-07 23:50:43 +08:00
|
|
|
DEBUG(dbgs() << "Unreachable in exit\n");
|
|
|
|
return invalid<ReportUnreachableInExit>(Context, /*Assert=*/true,
|
|
|
|
CurRegion.getExit(), DbgLoc);
|
|
|
|
}
|
|
|
|
|
2015-02-23 22:18:28 +08:00
|
|
|
if (!CurRegion.getEntry()->getName().count(OnlyRegion)) {
|
2014-01-27 22:24:53 +08:00
|
|
|
DEBUG({
|
|
|
|
dbgs() << "Region entry does not match -polly-region-only";
|
|
|
|
dbgs() << "\n";
|
|
|
|
});
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
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.
|
2017-08-18 05:57:23 +08:00
|
|
|
if (!PollyAllowFullFunction &&
|
2017-05-19 20:13:02 +08:00
|
|
|
CurRegion.getEntry() ==
|
|
|
|
&(CurRegion.getEntry()->getParent()->getEntryBlock()))
|
2015-02-23 22:18:28 +08:00
|
|
|
return invalid<ReportEntry>(Context, /*Assert=*/true, CurRegion.getEntry());
|
2011-04-29 14:27:02 +08:00
|
|
|
|
2012-04-07 20:29:17 +08:00
|
|
|
if (!allBlocksValid(Context))
|
2011-04-29 14:27:02 +08:00
|
|
|
return false;
|
|
|
|
|
2016-01-22 17:44:37 +08:00
|
|
|
if (!isReducibleRegion(CurRegion, DbgLoc))
|
|
|
|
return invalid<ReportIrreducibleRegion>(Context, /*Assert=*/true,
|
|
|
|
&CurRegion, DbgLoc);
|
|
|
|
|
2011-04-29 14:27:02 +08:00
|
|
|
DEBUG(dbgs() << "OK\n");
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2016-08-03 20:00:07 +08:00
|
|
|
void ScopDetection::markFunctionAsInvalid(Function *F) {
|
2014-07-16 05:06:48 +08:00
|
|
|
F->addFnAttr(PollySkipFnAttr);
|
|
|
|
}
|
|
|
|
|
2017-08-26 05:35:27 +08:00
|
|
|
bool ScopDetection::isValidFunction(Function &F) {
|
2014-07-16 05:06:48 +08:00
|
|
|
return !F.hasFnAttribute(PollySkipFnAttr);
|
2011-04-29 14:27:02 +08:00
|
|
|
}
|
|
|
|
|
2017-08-26 05:35:27 +08:00
|
|
|
void ScopDetection::printLocations(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
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-05-13 02:50:01 +08:00
|
|
|
void ScopDetection::emitMissedRemarks(const Function &F) {
|
|
|
|
for (auto &DIt : DetectionContextMap) {
|
|
|
|
auto &DC = DIt.getSecond();
|
|
|
|
if (DC.Log.hasErrors())
|
2017-07-18 07:58:33 +08:00
|
|
|
emitRejectionRemarks(DIt.getFirst(), DC.Log, ORE);
|
2014-06-26 18:06:40 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-01-22 17:44:37 +08:00
|
|
|
bool ScopDetection::isReducibleRegion(Region &R, DebugLoc &DbgLoc) const {
|
2016-09-02 14:33:33 +08:00
|
|
|
/// Enum for coloring BBs in Region.
|
2016-06-11 17:00:37 +08:00
|
|
|
///
|
|
|
|
/// WHITE - Unvisited BB in DFS walk.
|
|
|
|
/// GREY - BBs which are currently on the DFS stack for processing.
|
|
|
|
/// BLACK - Visited and completely processed BB.
|
|
|
|
enum Color { WHITE, GREY, BLACK };
|
|
|
|
|
2016-01-22 17:44:37 +08:00
|
|
|
BasicBlock *REntry = R.getEntry();
|
|
|
|
BasicBlock *RExit = R.getExit();
|
|
|
|
// Map to match the color of a BasicBlock during the DFS walk.
|
|
|
|
DenseMap<const BasicBlock *, Color> BBColorMap;
|
|
|
|
// Stack keeping track of current BB and index of next child to be processed.
|
|
|
|
std::stack<std::pair<BasicBlock *, unsigned>> DFSStack;
|
|
|
|
|
|
|
|
unsigned AdjacentBlockIndex = 0;
|
|
|
|
BasicBlock *CurrBB, *SuccBB;
|
|
|
|
CurrBB = REntry;
|
|
|
|
|
|
|
|
// Initialize the map for all BB with WHITE color.
|
|
|
|
for (auto *BB : R.blocks())
|
2016-05-19 20:36:43 +08:00
|
|
|
BBColorMap[BB] = WHITE;
|
2016-01-22 17:44:37 +08:00
|
|
|
|
|
|
|
// Process the entry block of the Region.
|
2016-05-19 20:36:43 +08:00
|
|
|
BBColorMap[CurrBB] = GREY;
|
2016-01-22 17:44:37 +08:00
|
|
|
DFSStack.push(std::make_pair(CurrBB, 0));
|
|
|
|
|
|
|
|
while (!DFSStack.empty()) {
|
|
|
|
// Get next BB on stack to be processed.
|
|
|
|
CurrBB = DFSStack.top().first;
|
|
|
|
AdjacentBlockIndex = DFSStack.top().second;
|
|
|
|
DFSStack.pop();
|
|
|
|
|
|
|
|
// Loop to iterate over the successors of current BB.
|
|
|
|
const TerminatorInst *TInst = CurrBB->getTerminator();
|
|
|
|
unsigned NSucc = TInst->getNumSuccessors();
|
|
|
|
for (unsigned I = AdjacentBlockIndex; I < NSucc;
|
|
|
|
++I, ++AdjacentBlockIndex) {
|
|
|
|
SuccBB = TInst->getSuccessor(I);
|
|
|
|
|
|
|
|
// Checks for region exit block and self-loops in BB.
|
|
|
|
if (SuccBB == RExit || SuccBB == CurrBB)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
// WHITE indicates an unvisited BB in DFS walk.
|
2016-05-19 20:36:43 +08:00
|
|
|
if (BBColorMap[SuccBB] == WHITE) {
|
2016-01-22 17:44:37 +08:00
|
|
|
// Push the current BB and the index of the next child to be visited.
|
|
|
|
DFSStack.push(std::make_pair(CurrBB, I + 1));
|
|
|
|
// Push the next BB to be processed.
|
|
|
|
DFSStack.push(std::make_pair(SuccBB, 0));
|
|
|
|
// First time the BB is being processed.
|
2016-05-19 20:36:43 +08:00
|
|
|
BBColorMap[SuccBB] = GREY;
|
2016-01-22 17:44:37 +08:00
|
|
|
break;
|
2016-05-19 20:36:43 +08:00
|
|
|
} else if (BBColorMap[SuccBB] == GREY) {
|
2016-01-22 17:44:37 +08:00
|
|
|
// GREY indicates a loop in the control flow.
|
|
|
|
// If the destination dominates the source, it is a natural loop
|
|
|
|
// else, an irreducible control flow in the region is detected.
|
2017-05-12 22:37:29 +08:00
|
|
|
if (!DT.dominates(SuccBB, CurrBB)) {
|
2016-01-22 17:44:37 +08:00
|
|
|
// Get debug info of instruction which causes irregular control flow.
|
|
|
|
DbgLoc = TInst->getDebugLoc();
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// If all children of current BB have been processed,
|
|
|
|
// then mark that BB as fully processed.
|
|
|
|
if (AdjacentBlockIndex == NSucc)
|
2016-05-19 20:36:43 +08:00
|
|
|
BBColorMap[CurrBB] = BLACK;
|
2016-01-22 17:44:37 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2017-05-12 22:37:29 +08:00
|
|
|
static void updateLoopCountStatistic(ScopDetection::LoopStats Stats,
|
|
|
|
bool OnlyProfitable) {
|
2016-11-26 15:37:46 +08:00
|
|
|
if (!OnlyProfitable) {
|
|
|
|
NumLoopsInScop += Stats.NumLoops;
|
2017-02-12 18:52:57 +08:00
|
|
|
MaxNumLoopsInScop =
|
|
|
|
std::max(MaxNumLoopsInScop.getValue(), (unsigned)Stats.NumLoops);
|
2016-11-26 15:37:46 +08:00
|
|
|
if (Stats.MaxDepth == 1)
|
|
|
|
NumScopsDepthOne++;
|
|
|
|
else if (Stats.MaxDepth == 2)
|
|
|
|
NumScopsDepthTwo++;
|
|
|
|
else if (Stats.MaxDepth == 3)
|
|
|
|
NumScopsDepthThree++;
|
|
|
|
else if (Stats.MaxDepth == 4)
|
|
|
|
NumScopsDepthFour++;
|
|
|
|
else if (Stats.MaxDepth == 5)
|
|
|
|
NumScopsDepthFive++;
|
|
|
|
else
|
|
|
|
NumScopsDepthLarger++;
|
|
|
|
} else {
|
|
|
|
NumLoopsInProfScop += Stats.NumLoops;
|
2017-02-12 18:52:57 +08:00
|
|
|
MaxNumLoopsInProfScop =
|
|
|
|
std::max(MaxNumLoopsInProfScop.getValue(), (unsigned)Stats.NumLoops);
|
2016-11-26 15:37:46 +08:00
|
|
|
if (Stats.MaxDepth == 1)
|
|
|
|
NumProfScopsDepthOne++;
|
|
|
|
else if (Stats.MaxDepth == 2)
|
|
|
|
NumProfScopsDepthTwo++;
|
|
|
|
else if (Stats.MaxDepth == 3)
|
|
|
|
NumProfScopsDepthThree++;
|
|
|
|
else if (Stats.MaxDepth == 4)
|
|
|
|
NumProfScopsDepthFour++;
|
|
|
|
else if (Stats.MaxDepth == 5)
|
|
|
|
NumProfScopsDepthFive++;
|
|
|
|
else
|
|
|
|
NumProfScopsDepthLarger++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-05-23 17:07:08 +08:00
|
|
|
ScopDetection::DetectionContext *
|
2015-10-08 04:46:06 +08:00
|
|
|
ScopDetection::getDetectionContext(const Region *R) const {
|
2016-05-13 02:50:01 +08:00
|
|
|
auto DCMIt = DetectionContextMap.find(getBBPairForRegion(R));
|
2015-10-08 04:46:06 +08:00
|
|
|
if (DCMIt == DetectionContextMap.end())
|
|
|
|
return nullptr;
|
|
|
|
return &DCMIt->second;
|
2015-02-24 19:45:21 +08:00
|
|
|
}
|
|
|
|
|
2016-05-13 02:50:01 +08:00
|
|
|
const RejectLog *ScopDetection::lookupRejectionLog(const Region *R) const {
|
|
|
|
const DetectionContext *DC = getDetectionContext(R);
|
|
|
|
return DC ? &DC->Log : nullptr;
|
|
|
|
}
|
|
|
|
|
2017-08-26 05:35:27 +08:00
|
|
|
void ScopDetection::verifyRegion(const Region &R) const {
|
2011-04-29 14:27:02 +08:00
|
|
|
assert(isMaxRegionInScop(R) && "Expect R is a valid region.");
|
2015-04-13 06:52:20 +08:00
|
|
|
|
2017-05-12 22:37:29 +08:00
|
|
|
DetectionContext Context(const_cast<Region &>(R), AA, true /*verifying*/);
|
2011-04-29 14:27:02 +08:00
|
|
|
isValidRegion(Context);
|
|
|
|
}
|
|
|
|
|
2017-08-26 05:35:27 +08:00
|
|
|
void 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
|
|
|
}
|
|
|
|
|
2017-08-26 05:35:27 +08:00
|
|
|
bool ScopDetectionWrapperPass::runOnFunction(Function &F) {
|
2017-05-12 22:37:29 +08:00
|
|
|
auto &LI = getAnalysis<LoopInfoWrapperPass>().getLoopInfo();
|
|
|
|
auto &RI = getAnalysis<RegionInfoPass>().getRegionInfo();
|
|
|
|
auto &AA = getAnalysis<AAResultsWrapperPass>().getAAResults();
|
|
|
|
auto &SE = getAnalysis<ScalarEvolutionWrapperPass>().getSE();
|
|
|
|
auto &DT = getAnalysis<DominatorTreeWrapperPass>().getDomTree();
|
2017-07-18 07:58:33 +08:00
|
|
|
auto &ORE = getAnalysis<OptimizationRemarkEmitterWrapperPass>().getORE();
|
|
|
|
Result.reset(new ScopDetection(F, DT, SE, LI, RI, AA, ORE));
|
2017-05-12 22:37:29 +08:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
void ScopDetectionWrapperPass::getAnalysisUsage(AnalysisUsage &AU) const {
|
2015-01-17 22:16:56 +08:00
|
|
|
AU.addRequired<LoopInfoWrapperPass>();
|
2016-10-17 21:29:20 +08:00
|
|
|
AU.addRequiredTransitive<ScalarEvolutionWrapperPass>();
|
2015-10-08 04:32:43 +08:00
|
|
|
AU.addRequired<DominatorTreeWrapperPass>();
|
2017-07-18 07:58:33 +08:00
|
|
|
AU.addRequired<OptimizationRemarkEmitterWrapperPass>();
|
2011-04-29 14:27:02 +08:00
|
|
|
// We also need AA and RegionInfo when we are verifying analysis.
|
2015-09-10 06:13:56 +08:00
|
|
|
AU.addRequiredTransitive<AAResultsWrapperPass>();
|
2014-07-20 02:40:17 +08:00
|
|
|
AU.addRequiredTransitive<RegionInfoPass>();
|
2011-04-29 14:27:02 +08:00
|
|
|
AU.setPreservesAll();
|
|
|
|
}
|
|
|
|
|
2017-05-12 22:37:29 +08:00
|
|
|
void ScopDetectionWrapperPass::print(raw_ostream &OS, const Module *) const {
|
|
|
|
for (const Region *R : Result->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";
|
|
|
|
}
|
|
|
|
|
2017-05-12 22:37:29 +08:00
|
|
|
ScopDetectionWrapperPass::ScopDetectionWrapperPass() : FunctionPass(ID) {
|
|
|
|
// Disable runtime alias checks if we ignore aliasing all together.
|
|
|
|
if (IgnoreAliasing)
|
|
|
|
PollyUseRuntimeAliasChecks = false;
|
|
|
|
}
|
2017-08-26 05:35:27 +08:00
|
|
|
|
2017-08-02 19:08:01 +08:00
|
|
|
ScopAnalysis::ScopAnalysis() {
|
|
|
|
// Disable runtime alias checks if we ignore aliasing all together.
|
|
|
|
if (IgnoreAliasing)
|
|
|
|
PollyUseRuntimeAliasChecks = false;
|
|
|
|
}
|
2017-05-12 22:37:29 +08:00
|
|
|
|
|
|
|
void ScopDetectionWrapperPass::releaseMemory() { Result.reset(); }
|
|
|
|
|
|
|
|
char ScopDetectionWrapperPass::ID;
|
|
|
|
|
|
|
|
AnalysisKey ScopAnalysis::Key;
|
2014-05-24 17:25:01 +08:00
|
|
|
|
2017-05-12 22:37:29 +08:00
|
|
|
ScopDetection ScopAnalysis::run(Function &F, FunctionAnalysisManager &FAM) {
|
|
|
|
auto &LI = FAM.getResult<LoopAnalysis>(F);
|
|
|
|
auto &RI = FAM.getResult<RegionInfoAnalysis>(F);
|
|
|
|
auto &AA = FAM.getResult<AAManager>(F);
|
|
|
|
auto &SE = FAM.getResult<ScalarEvolutionAnalysis>(F);
|
|
|
|
auto &DT = FAM.getResult<DominatorTreeAnalysis>(F);
|
2017-07-18 07:58:33 +08:00
|
|
|
auto &ORE = FAM.getResult<OptimizationRemarkEmitterAnalysis>(F);
|
|
|
|
return {F, DT, SE, LI, RI, AA, ORE};
|
2011-04-29 14:27:02 +08:00
|
|
|
}
|
|
|
|
|
2017-05-12 22:37:29 +08:00
|
|
|
PreservedAnalyses ScopAnalysisPrinterPass::run(Function &F,
|
|
|
|
FunctionAnalysisManager &FAM) {
|
2017-08-26 05:35:27 +08:00
|
|
|
OS << "Detected Scops in Function " << F.getName() << "\n";
|
2017-05-12 22:37:29 +08:00
|
|
|
auto &SD = FAM.getResult<ScopAnalysis>(F);
|
|
|
|
for (const Region *R : SD.ValidRegions)
|
2017-08-26 05:35:27 +08:00
|
|
|
OS << "Valid Region for Scop: " << R->getNameStr() << '\n';
|
2011-04-29 14:27:02 +08:00
|
|
|
|
2017-08-26 05:35:27 +08:00
|
|
|
OS << "\n";
|
2017-05-12 22:37:29 +08:00
|
|
|
return PreservedAnalyses::all();
|
|
|
|
}
|
|
|
|
|
|
|
|
Pass *polly::createScopDetectionWrapperPassPass() {
|
|
|
|
return new ScopDetectionWrapperPass();
|
|
|
|
}
|
2013-03-23 09:05:07 +08:00
|
|
|
|
2017-05-12 22:37:29 +08:00
|
|
|
INITIALIZE_PASS_BEGIN(ScopDetectionWrapperPass, "polly-detect",
|
2011-10-08 08:30:40 +08:00
|
|
|
"Polly - Detect static control parts (SCoPs)", false,
|
2013-03-23 09:05:07 +08:00
|
|
|
false);
|
2015-09-10 06:13:56 +08:00
|
|
|
INITIALIZE_PASS_DEPENDENCY(AAResultsWrapperPass);
|
2015-01-17 22:16:56 +08:00
|
|
|
INITIALIZE_PASS_DEPENDENCY(LoopInfoWrapperPass);
|
2014-07-20 02:40:17 +08:00
|
|
|
INITIALIZE_PASS_DEPENDENCY(RegionInfoPass);
|
2015-10-08 04:32:43 +08:00
|
|
|
INITIALIZE_PASS_DEPENDENCY(DominatorTreeWrapperPass);
|
2015-08-17 18:57:08 +08:00
|
|
|
INITIALIZE_PASS_DEPENDENCY(ScalarEvolutionWrapperPass);
|
2017-07-18 07:58:33 +08:00
|
|
|
INITIALIZE_PASS_DEPENDENCY(OptimizationRemarkEmitterWrapperPass);
|
2017-05-12 22:37:29 +08:00
|
|
|
INITIALIZE_PASS_END(ScopDetectionWrapperPass, "polly-detect",
|
2011-10-08 08:30:40 +08:00
|
|
|
"Polly - Detect static control parts (SCoPs)", false, false)
|