38#include "llvm/ADT/Statistic.h"
39#include "llvm/IR/Function.h"
40#include "llvm/Support/Debug.h"
41#include "llvm/Support/raw_ostream.h"
56#define DEBUG_TYPE "polly-ast"
65 cl::desc(
"Generate thread parallel code (isl codegen only)"),
69 cl::desc(
"Print memory access functions"),
73 "polly-parallel-force",
75 "Force generation of thread parallel code ignoring any cost model"),
79 cl::desc(
"Use context"), cl::Hidden,
83 cl::desc(
"Detect parallelism"), cl::Hidden,
86STATISTIC(ScopsProcessed,
"Number of SCoPs processed");
87STATISTIC(ScopsBeneficial,
"Number of beneficial SCoPs");
88STATISTIC(BeneficialAffineLoops,
"Number of beneficial affine loops");
89STATISTIC(BeneficialBoxedLoops,
"Number of beneficial boxed loops");
92STATISTIC(NumParallel,
"Number of parallel for-loops");
93STATISTIC(NumInnermostParallel,
"Number of innermost parallel for-loops");
94STATISTIC(NumOutermostParallel,
"Number of outermost parallel for-loops");
95STATISTIC(NumReductionParallel,
"Number of reduction-parallel for-loops");
96STATISTIC(NumExecutedInParallel,
"Number of for-loops executed in parallel");
97STATISTIC(NumIfConditions,
"Number of if-conditions");
127 const std::string &
str,
142 if (!BrokenReductions || BrokenReductions->empty())
146 std::map<MemoryAccess::ReductionType, std::string> Clauses;
149 Clauses[MA->getReductionType()] +=
150 ", " + MA->getScopArrayInfo()->getName();
154 for (
const auto &ReductionClause : Clauses) {
155 str +=
" reduction (";
158 str +=
" : " + ReductionClause.second.substr(2) +
")";
170 const std::string BrokenReductionsStr =
172 const std::string KnownParallelStr =
"#pragma known-parallel";
173 const std::string DepDisPragmaStr =
"#pragma minimal dependence distance: ";
174 const std::string SimdPragmaStr =
"#pragma simd";
175 const std::string OmpPragmaStr =
"#pragma omp parallel for";
178 Printer =
printLine(Printer, DepDisPragmaStr, DD.
get());
181 Printer =
printLine(Printer, SimdPragmaStr + BrokenReductionsStr);
184 Printer =
printLine(Printer, OmpPragmaStr);
186 Printer =
printLine(Printer, KnownParallelStr + BrokenReductionsStr);
216 isl_pw_aff *MinimalDependenceDistanceIsl =
nullptr;
218 &MinimalDependenceDistanceIsl);
232 if (!MaRedPair.second)
257 BuildInfo->
Deps, Payload);
278 assert(Id &&
"Post order visit assumes annotated for nodes");
280 assert(Payload &&
"Post order visit assumes annotated for nodes");
316 BuildInfo->
InSIMD =
false;
357 if (BaseLeft && BaseLeft == BaseRight)
373 NonAliasGroup = MaxExpr.
le(MinExpr);
386 NonAliasGroup = Result;
390 NonAliasGroup = True;
392 return NonAliasGroup;
401 auto PosCond = Build.
expr_from(
S.getAssumedContext());
402 if (
S.hasTrivialInvalidContext()) {
406 auto NegCond = Build.
expr_from(
S.getInvalidContext());
418 auto &MinMaxReadWrite = MinMaxAccessPair.first;
419 auto &MinMaxReadOnly = MinMaxAccessPair.second;
420 auto RWAccEnd = MinMaxReadWrite.end();
422 for (
auto RWAccIt0 = MinMaxReadWrite.begin(); RWAccIt0 != RWAccEnd;
424 for (
auto RWAccIt1 = RWAccIt0 + 1; RWAccIt1 != RWAccEnd; ++RWAccIt1)
464 switch (isl_ast_node_get_type(Node)) {
465 case isl_ast_node_for:
467 if (IslAstInfo::isParallel(isl::manage_copy(Node)))
469 if (IslAstInfo::isInnermostParallel(isl::manage_copy(Node)))
470 NumInnermostParallel++;
471 if (IslAstInfo::isOutermostParallel(isl::manage_copy(Node)))
472 NumOutermostParallel++;
473 if (IslAstInfo::isReductionParallel(isl::manage_copy(Node)))
474 NumReductionParallel++;
475 if (IslAstInfo::isExecutedInParallel(isl::manage_copy(Node)))
476 NumExecutedInParallel++;
479 case isl_ast_node_if:
496 :
S(O.
S),
Ctx(O.
Ctx), RunCondition(std::move(O.RunCondition)),
497 Root(std::move(O.Root)) {}
502 auto ScheduleTree =
S.getScheduleTree();
508 auto ScopStats =
S.getStatistics();
510 BeneficialAffineLoops += ScopStats.NumAffineLoops;
511 BeneficialBoxedLoops += ScopStats.NumBoxedLoops;
513 auto Ctx =
S.getIslCtx();
527 if (PerformParallelTest) {
648 dbgs() <<
"Got dependence analysis for different SCoP/isl_ctx\n");
652 std::unique_ptr<IslAstInfo> Ast = std::make_unique<IslAstInfo>(
Scop, D);
704 P,
MemAcc->getLatestScopArrayInfo()->getName().c_str());
724 OS <<
":: isl ast :: " << F.getName() <<
" :: " <<
S.getNameStr() <<
"\n";
727 OS <<
":: isl ast generation and code generation was skipped!\n\n";
728 OS <<
":: This is either because no useful optimizations could be applied "
729 "(use -polly-process-unprofitable to enforce code generation) or "
730 "because earlier passes such as dependence analysis timed out (use "
731 "-polly-dependences-computeout=0 to set dependence analysis timeout "
737 char *RtCStr, *AstStr;
756 dbgs() <<
S.getContextStr() <<
"\n";
757 dbgs() << stringFromIslObj(
S.getScheduleTree(),
"null");
759 OS <<
"\nif (" << RtCStr <<
")\n\n";
760 OS << AstStr <<
"\n";
762 OS <<
" { /* original code */ }\n\n";
776 return PreservedAnalyses::all();
801 OS <<
"Printing analysis 'Polly - Generate an AST of the SCoP (isl)'"
802 <<
S.getName() <<
"' in function '" <<
S.getFunction().getName() <<
"':\n";
814 "Polly - Generate an AST of the SCoP (isl)",
false,
819 "Polly - Generate an AST from the SCoP (isl)",
false,
false)
825class IslAstInfoPrinterLegacyPass final :
public ScopPass {
829 IslAstInfoPrinterLegacyPass() : IslAstInfoPrinterLegacyPass(outs()) {}
830 explicit IslAstInfoPrinterLegacyPass(llvm::raw_ostream &OS)
833 bool runOnScop(
Scop &
S)
override {
836 OS <<
"Printing analysis '" << P.getPassName() <<
"' for region: '"
837 <<
S.getRegion().getNameStr() <<
"' in function '"
838 <<
S.getFunction().getName() <<
"':\n";
844 void getAnalysisUsage(AnalysisUsage &AU)
const override {
847 AU.setPreservesAll();
851 llvm::raw_ostream &OS;
854char IslAstInfoPrinterLegacyPass::ID = 0;
858 return new IslAstInfoPrinterLegacyPass(OS);
862 "Polly - Print the AST from a SCoP (isl)",
false,
false);
865 "Polly - Print the AST from a SCoP (isl)",
false,
false)
INITIALIZE_PASS_BEGIN(DependenceInfo, "polly-dependences", "Polly - Calculate dependences", false, false)
INITIALIZE_PASS_END(DependenceInfo, "polly-dependences", "Polly - Calculate dependences", false, false) namespace
INITIALIZE_PASS_DEPENDENCY(ScopInfoRegionPass)
polly dump Polly Dump Function
static cl::opt< bool > UseContext("polly-ast-use-context", cl::desc("Use context"), cl::Hidden, cl::init(true), cl::cat(PollyCategory))
static isl::ast_expr buildCondition(Scop &S, isl::ast_build Build, const Scop::MinMaxAccessTy *It0, const Scop::MinMaxAccessTy *It1)
static cl::opt< bool > DetectParallel("polly-ast-detect-parallel", cl::desc("Detect parallelism"), cl::Hidden, cl::cat(PollyCategory))
static isl_printer * printLine(__isl_take isl_printer *Printer, const std::string &str, __isl_keep isl_pw_aff *PWA=nullptr)
Print a string str in a single line using Printer.
static __isl_give isl_id * astBuildBeforeFor(__isl_keep isl_ast_build *Build, void *User)
static __isl_give isl_ast_node * astBuildAfterMark(__isl_take isl_ast_node *Node, __isl_keep isl_ast_build *Build, void *User)
IslAstInfo::IslAstUserPayload IslAstUserPayload
static void walkAstForStatistics(const isl::ast_node &Ast)
Collect statistics for the syntax tree rooted at Ast.
static cl::opt< bool > PollyParallelForce("polly-parallel-force", cl::desc("Force generation of thread parallel code ignoring any cost model"), cl::cat(PollyCategory))
static bool benefitsFromPolly(Scop &Scop, bool PerformParallelTest)
Simple cost analysis for a given SCoP.
static const std::string getBrokenReductionsStr(const isl::ast_node &Node)
Return all broken reductions as a string of clauses (OpenMP style).
static __isl_give isl_ast_node * astBuildAfterFor(__isl_take isl_ast_node *Node, __isl_keep isl_ast_build *Build, void *User)
STATISTIC(ScopsProcessed, "Number of SCoPs processed")
static __isl_give isl_ast_node * AtEachDomain(__isl_take isl_ast_node *Node, __isl_keep isl_ast_build *Build, void *User)
static bool astScheduleDimIsParallel(const isl::ast_build &Build, const Dependences *D, IslAstUserPayload *NodeInfo)
Check if the current scheduling dimension is parallel.
static isl_printer * cbPrintFor(__isl_take isl_printer *Printer, __isl_take isl_ast_print_options *Options, __isl_keep isl_ast_node *Node, void *)
Callback executed for each for node in the ast in order to print it.
static cl::opt< bool > PrintAccesses("polly-ast-print-accesses", cl::desc("Print memory access functions"), cl::cat(PollyCategory))
static isl_stat astBuildBeforeMark(__isl_keep isl_id *MarkId, __isl_keep isl_ast_build *Build, void *User)
static __isl_give isl_printer * cbPrintUser(__isl_take isl_printer *P, __isl_take isl_ast_print_options *O, __isl_keep isl_ast_node *Node, void *User)
static cl::opt< bool > PollyParallel("polly-parallel", cl::desc("Generate thread parallel code (isl codegen only)"), cl::cat(PollyCategory))
static void freeIslAstUserPayload(void *Ptr)
Free an IslAstUserPayload object pointed to by Ptr.
static std::unique_ptr< IslAstInfo > runIslAst(Scop &Scop, function_ref< const Dependences &(Dependences::AnalysisLevel)> GetDeps)
llvm::cl::OptionCategory PollyCategory
__isl_give isl_printer * isl_printer_print_pw_aff(__isl_take isl_printer *p, __isl_keep isl_pw_aff *pwaff)
__isl_give isl_ast_node * isl_ast_node_set_annotation(__isl_take isl_ast_node *node, __isl_take isl_id *annotation)
__isl_give isl_printer * isl_ast_node_print(__isl_keep isl_ast_node *node, __isl_take isl_printer *p, __isl_take isl_ast_print_options *options)
isl_stat isl_ast_node_foreach_descendant_top_down(__isl_keep isl_ast_node *node, isl_bool(*fn)(__isl_keep isl_ast_node *node, void *user), void *user)
__isl_give isl_ast_print_options * isl_ast_print_options_alloc(isl_ctx *ctx)
__isl_give isl_ast_expr * isl_ast_expr_or(__isl_take isl_ast_expr *expr1, __isl_take isl_ast_expr *expr2)
__isl_give isl_ast_print_options * isl_ast_print_options_set_print_user(__isl_take isl_ast_print_options *options, __isl_give isl_printer *(*print_user)(__isl_take isl_printer *p, __isl_take isl_ast_print_options *options, __isl_keep isl_ast_node *node, void *user), void *user)
__isl_give isl_printer * isl_ast_node_for_print(__isl_keep isl_ast_node *node, __isl_take isl_printer *p, __isl_take isl_ast_print_options *options)
__isl_give isl_ast_print_options * isl_ast_print_options_set_print_for(__isl_take isl_ast_print_options *options, __isl_give isl_printer *(*print_for)(__isl_take isl_printer *p, __isl_take isl_ast_print_options *options, __isl_keep isl_ast_node *node, void *user), void *user)
__isl_export __isl_give isl_id * isl_ast_node_mark_get_id(__isl_keep isl_ast_node *node)
__isl_give isl_id * isl_ast_node_get_annotation(__isl_keep isl_ast_node *node)
__isl_null isl_ast_print_options * isl_ast_print_options_free(__isl_take isl_ast_print_options *options)
__isl_give isl_ast_expr * isl_ast_expr_and(__isl_take isl_ast_expr *expr1, __isl_take isl_ast_expr *expr2)
__isl_give isl_printer * isl_printer_print_ast_expr(__isl_take isl_printer *p, __isl_keep isl_ast_expr *expr)
__isl_give isl_ast_build * isl_ast_build_set_before_each_mark(__isl_take isl_ast_build *build, isl_stat(*fn)(__isl_keep isl_id *mark, __isl_keep isl_ast_build *build, void *user), void *user)
isl_stat isl_options_set_ast_build_detect_min_max(isl_ctx *ctx, int val)
__isl_give isl_ast_build * isl_ast_build_set_before_each_for(__isl_take isl_ast_build *build, __isl_give isl_id *(*fn)(__isl_keep isl_ast_build *build, void *user), void *user)
__isl_export __isl_give isl_ast_build * isl_ast_build_from_context(__isl_take isl_set *set)
isl_stat isl_options_set_ast_build_atomic_upper_bound(isl_ctx *ctx, int val)
__isl_give isl_ast_build * isl_ast_build_set_after_each_mark(__isl_take isl_ast_build *build, __isl_give isl_ast_node *(*fn)(__isl_take isl_ast_node *node, __isl_keep isl_ast_build *build, void *user), void *user)
__isl_null isl_ast_build * isl_ast_build_free(__isl_take isl_ast_build *build)
__isl_overload __isl_give isl_ast_node * isl_ast_build_node_from_schedule(__isl_keep isl_ast_build *build, __isl_take isl_schedule *schedule)
__isl_export __isl_give isl_ast_build * isl_ast_build_set_at_each_domain(__isl_take isl_ast_build *build, __isl_give isl_ast_node *(*fn)(__isl_take isl_ast_node *node, __isl_keep isl_ast_build *build, void *user), void *user)
isl_ctx * isl_ast_build_get_ctx(__isl_keep isl_ast_build *build)
__isl_give isl_ast_build * isl_ast_build_set_after_each_for(__isl_take isl_ast_build *build, __isl_give isl_ast_node *(*fn)(__isl_take isl_ast_node *node, __isl_keep isl_ast_build *build, void *user), void *user)
isl::ast_expr expr_from(isl::pw_aff pa) const
isl::union_map get_schedule() const
isl::ast_expr access_from(isl::multi_pw_aff mpa) const
isl::ast_expr le(isl::ast_expr expr2) const
static isl::ast_expr from_val(isl::val v)
isl::ast_expr get_op_arg(int pos) const
__isl_give isl_ast_expr * release()
isl::ast_expr eq(isl::ast_expr expr2) const
__isl_keep isl_ast_expr * get() const
isl::ast_expr address_of() const
isl::ast_expr expr() const
isl::id get_annotation() const
__isl_keep isl_ast_node * get() const
__isl_keep isl_pw_aff * get() const
isl::id get_tuple_id(isl::dim type) const
isl::pw_multi_aff intersect_params(isl::set set) const
__isl_give isl_union_map * release()
__isl_keep isl_union_map * get() const
static isl::val int_from_ui(isl::ctx ctx, unsigned long u)
static isl::val zero(isl::ctx ctx)
The accumulated dependence information for a SCoP.
bool isParallel(__isl_keep isl_union_map *Schedule, __isl_take isl_union_map *Deps, __isl_give isl_pw_aff **MinDistancePtr=nullptr) const
Check if a partial schedule is parallel wrt to Deps.
bool hasValidDependences() const
Report if valid dependences are available.
const std::shared_ptr< isl_ctx > & getSharedIslCtx() const
isl::union_map getDependences(int Kinds) const
Get the dependences of type Kinds.
__isl_give isl_map * getReductionDependences(MemoryAccess *MA) const
Return the reduction dependences caused by MA.
void printScop(raw_ostream &OS, Scop &S) const override
Print a source code representation of the program.
void getAnalysisUsage(AnalysisUsage &AU) const override
Register all analyses and transformation required.
void releaseMemory() override
Release the internal memory.
bool runOnScop(Scop &S) override
Build the AST for the given SCoP S.
std::unique_ptr< IslAstInfo > Ast
static bool isOutermostParallel(const isl::ast_node &Node)
Is this loop an outermost parallel loop?
static MemoryAccessSet * getBrokenReductions(const isl::ast_node &Node)
Get the nodes broken reductions or a nullptr if not available.
static bool isParallel(const isl::ast_node &Node)
Is this loop a parallel loop?
static isl::pw_aff getMinimalDependenceDistance(const isl::ast_node &Node)
Get minimal dependence distance or nullptr if not available.
static bool isInnermostParallel(const isl::ast_node &Node)
Is this loop an innermost parallel loop?
isl::ast_node getAst()
Return a copy of the AST root node.
SmallPtrSet< MemoryAccess *, 4 > MemoryAccessSet
static bool isExecutedInParallel(const isl::ast_node &Node)
Will the loop be run as thread parallel?
isl::ast_expr getRunCondition()
Get the run condition.
static bool isInnermost(const isl::ast_node &Node)
Is this loop an innermost loop?
static IslAstUserPayload * getNodePayload(const isl::ast_node &Node)
static isl::union_map getSchedule(const isl::ast_node &Node)
Get the nodes schedule or a nullptr if not available.
void print(raw_ostream &O)
static isl::ast_build getBuild(const isl::ast_node &Node)
Get the nodes build context or a nullptr if not available.
static bool isReductionParallel(const isl::ast_node &Node)
Is this loop a reduction parallel loop?
static isl::ast_expr buildRunCondition(Scop &S, const isl::ast_build &Build)
Build run-time condition for scop.
isl::ast_expr getRunCondition()
Get the run-time conditions for the Scop.
IslAst(const IslAst &)=delete
std::shared_ptr< isl_ctx > Ctx
static IslAst create(Scop &Scop, const Dependences &D)
isl::ast_expr RunCondition
void init(const Dependences &D)
Represent memory accesses in statements.
const std::string getReductionOperatorStr() const
Return a string representation of the access's reduction type.
A class to store information about arrays in the SCoP.
static const ScopArrayInfo * getFromId(isl::id Id)
Access the ScopArrayInfo associated with an isl Id.
const ScopArrayInfo * getBasePtrOriginSAI() const
For indirect accesses return the origin SAI of the BP, else null.
The legacy pass manager's analysis pass to compute scop information for a region.
ScopPass - This class adapts the RegionPass interface to allow convenient creation of passes that ope...
void getAnalysisUsage(AnalysisUsage &AU) const override
getAnalysisUsage - Subclasses that override getAnalysisUsage must call this.
const char * getBaseName() const
const MinMaxVectorPairVectorTy & getAliasGroups() const
Return all alias groups for this SCoP.
std::pair< MinMaxVectorTy, MinMaxVectorTy > MinMaxVectorPairTy
Pair of minimal/maximal access vectors representing read write and read only accesses.
const std::shared_ptr< isl_ctx > & getSharedIslCtx() const
Directly return the shared_ptr of the context.
std::pair< isl::pw_multi_aff, isl::pw_multi_aff > MinMaxAccessTy
Type to represent a pair of minimal/maximal access to an array.
bool isOptimized() const
Check if the SCoP has been optimized by the scheduler.
__isl_export __isl_keep const char * isl_id_get_name(__isl_keep isl_id *id)
__isl_null isl_id * isl_id_free(__isl_take isl_id *id)
void * isl_id_get_user(__isl_keep isl_id *id)
__isl_give isl_id * isl_id_alloc(isl_ctx *ctx, __isl_keep const char *name, void *user)
__isl_give isl_id * isl_id_set_free_user(__isl_take isl_id *id, void(*free_user)(void *user))
enum isl_ast_node_type isl_ast_node_get_type(__isl_keep isl_ast_node *node)
aff manage_copy(__isl_keep isl_aff *ptr)
boolean manage(isl_bool val)
This file contains the declaration of the PolyhedralInfo class, which will provide an interface to ex...
VectorizerChoice PollyVectorizerChoice
llvm::Pass * createIslAstInfoPrinterLegacyPass(llvm::raw_ostream &OS)
bool PollyProcessUnprofitable
AnalysisManager< Scop, ScopStandardAnalysisResults & > ScopAnalysisManager
llvm::Pass * createIslAstInfoWrapperPassPass()
__isl_null isl_printer * isl_printer_free(__isl_take isl_printer *printer)
__isl_give isl_printer * isl_printer_flush(__isl_take isl_printer *p)
__isl_give char * isl_printer_get_str(__isl_keep isl_printer *printer)
__isl_give isl_printer * isl_printer_print_str(__isl_take isl_printer *p, const char *s)
__isl_give isl_printer * isl_printer_start_line(__isl_take isl_printer *p)
__isl_give isl_printer * isl_printer_indent(__isl_take isl_printer *p, int indent)
__isl_give isl_printer * isl_printer_to_str(isl_ctx *ctx)
__isl_give isl_printer * isl_printer_end_line(__isl_take isl_printer *p)
__isl_give isl_printer * isl_printer_set_output_format(__isl_take isl_printer *p, int output_format)
__isl_export __isl_give isl_set * isl_set_universe(__isl_take isl_space *space)
Temporary information used when building the ast.
AstBuildUserInfo()=default
Construct and initialize the helper struct for AST creation.
bool InParallelFor
Flag to indicate that we are inside a parallel for node.
isl_id * LastForNodeId
The last iterator id created for the current SCoP.
const Dependences * Deps
The dependence information used for the parallelism check.
bool InSIMD
Flag to indicate that we are inside an SIMD node.
IslAstInfo run(Scop &S, ScopAnalysisManager &SAM, ScopStandardAnalysisResults &SAR)
Payload information used to annotate an AST node.
bool IsInnermost
Flag to mark innermost loops.
bool IsOutermostParallel
Flag to mark outermost parallel loops.
bool IsParallel
Does the dependence analysis determine that there are no loop-carried dependencies?
MemoryAccessSet BrokenReductions
Set of accesses which break reduction dependences.
isl::pw_aff MinimalDependenceDistance
The minimal dependence distance for non parallel loops.
bool IsReductionParallel
Flag to mark parallel loops which break reductions.
bool IsInnermostParallel
Flag to mark innermost parallel loops.
isl::ast_build Build
The build environment at the time this node was constructed.
PreservedAnalyses run(Scop &S, ScopAnalysisManager &SAM, ScopStandardAnalysisResults &, SPMUpdater &U)