//===- IslAst.h - Interface to the isl code generator -----------*- C++ -*-===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // // The isl code generator interface takes a Scop and generates a isl_ast. This // ist_ast can either be returned directly or it can be pretty printed to // stdout. // // A typical isl_ast output looks like this: // // for (c2 = max(0, ceild(n + m, 2); c2 <= min(511, floord(5 * n, 3)); c2++) { // bb2(c2); // } // //===----------------------------------------------------------------------===// #ifndef POLLY_ISLAST_H #define POLLY_ISLAST_H #include "polly/ScopPass.h" #include "llvm/ADT/SmallPtrSet.h" #include "llvm/IR/PassManager.h" #include "isl/ctx.h" namespace polly { struct Dependences; class IslAst { public: IslAst(const IslAst &) = delete; IslAst &operator=(const IslAst &) = delete; IslAst(IslAst &&); IslAst &operator=(IslAst &&) = delete; ~IslAst(); static IslAst create(Scop &Scop, const Dependences &D); /// Print a source code representation of the program. void pprint(raw_ostream &OS); __isl_give isl_ast_node *getAst(); const std::shared_ptr getSharedIslCtx() const { return Ctx; } /// Get the run-time conditions for the Scop. __isl_give isl_ast_expr *getRunCondition(); /// Build run-time condition for scop. /// /// @param S The scop to build the condition for. /// @param Build The isl_build object to use to build the condition. /// /// @returns An ast expression that describes the necessary run-time check. static isl_ast_expr *buildRunCondition(Scop &S, __isl_keep isl_ast_build *Build); private: Scop &S; isl_ast_node *Root = nullptr; isl_ast_expr *RunCondition = nullptr; std::shared_ptr Ctx; IslAst(Scop &Scop); void init(const Dependences &D); }; class IslAstInfo { public: using MemoryAccessSet = SmallPtrSet; /// Payload information used to annotate an AST node. struct IslAstUserPayload { /// Construct and initialize the payload. IslAstUserPayload() = default; /// Cleanup all isl structs on destruction. ~IslAstUserPayload(); /// Does the dependence analysis determine that there are no loop-carried /// dependencies? bool IsParallel = false; /// Flag to mark innermost loops. bool IsInnermost = false; /// Flag to mark innermost parallel loops. bool IsInnermostParallel = false; /// Flag to mark outermost parallel loops. bool IsOutermostParallel = false; /// Flag to mark parallel loops which break reductions. bool IsReductionParallel = false; /// The minimal dependence distance for non parallel loops. isl::pw_aff MinimalDependenceDistance; /// The build environment at the time this node was constructed. isl_ast_build *Build = nullptr; /// Set of accesses which break reduction dependences. MemoryAccessSet BrokenReductions; }; private: Scop &S; IslAst Ast; public: IslAstInfo(Scop &S, const Dependences &D) : S(S), Ast(IslAst::create(S, D)) {} /// Return the isl AST computed by this IslAstInfo. IslAst &getIslAst() { return Ast; } /// Return a copy of the AST root node. __isl_give isl_ast_node *getAst(); /// Get the run condition. /// /// Only if the run condition evaluates at run-time to a non-zero value, the /// assumptions that have been taken hold. If the run condition evaluates to /// zero/false some assumptions do not hold and the original code needs to /// be executed. __isl_give isl_ast_expr *getRunCondition(); void print(raw_ostream &O); /// @name Extract information attached to an isl ast (for) node. /// ///{ /// Get the complete payload attached to @p Node. static IslAstUserPayload *getNodePayload(__isl_keep isl_ast_node *Node); /// Is this loop an innermost loop? static bool isInnermost(__isl_keep isl_ast_node *Node); /// Is this loop a parallel loop? static bool isParallel(__isl_keep isl_ast_node *Node); /// Is this loop an outermost parallel loop? static bool isOutermostParallel(__isl_keep isl_ast_node *Node); /// Is this loop an innermost parallel loop? static bool isInnermostParallel(__isl_keep isl_ast_node *Node); /// Is this loop a reduction parallel loop? static bool isReductionParallel(__isl_keep isl_ast_node *Node); /// Will the loop be run as thread parallel? static bool isExecutedInParallel(__isl_keep isl_ast_node *Node); /// Get the nodes schedule or a nullptr if not available. static __isl_give isl_union_map *getSchedule(__isl_keep isl_ast_node *Node); /// Get minimal dependence distance or nullptr if not available. static __isl_give isl_pw_aff * getMinimalDependenceDistance(__isl_keep isl_ast_node *Node); /// Get the nodes broken reductions or a nullptr if not available. static MemoryAccessSet *getBrokenReductions(__isl_keep isl_ast_node *Node); /// Get the nodes build context or a nullptr if not available. static __isl_give isl_ast_build *getBuild(__isl_keep isl_ast_node *Node); ///} }; struct IslAstAnalysis : public AnalysisInfoMixin { static AnalysisKey Key; using Result = IslAstInfo; IslAstInfo run(Scop &S, ScopAnalysisManager &SAM, ScopStandardAnalysisResults &SAR); }; class IslAstInfoWrapperPass : public ScopPass { std::unique_ptr Ast; public: static char ID; IslAstInfoWrapperPass() : ScopPass(ID) {} IslAstInfo &getAI() { return *Ast; } const IslAstInfo &getAI() const { return *Ast; } /// Build the AST for the given SCoP @p S. bool runOnScop(Scop &S) override; /// Register all analyses and transformation required. void getAnalysisUsage(AnalysisUsage &AU) const override; /// Release the internal memory. void releaseMemory() override; /// Print a source code representation of the program. void printScop(raw_ostream &OS, Scop &S) const override; }; struct IslAstPrinterPass : public PassInfoMixin { IslAstPrinterPass(raw_ostream &OS) : OS(OS) {} PreservedAnalyses run(Scop &S, ScopAnalysisManager &SAM, ScopStandardAnalysisResults &, SPMUpdater &U); raw_ostream &OS; }; } // namespace polly #endif // POLLY_ISLAST_H