blob: bab4fce864a80bcb2716a9dc6276e68275bcaf62 [file] [log] [blame]
//===- 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 {
using llvm::SmallPtrSet;
struct Dependences;
class IslAst {
public:
IslAst(const IslAst &) = delete;
IslAst &operator=(const IslAst &) = delete;
IslAst(IslAst &&);
IslAst &operator=(IslAst &&) = delete;
static IslAst create(Scop &Scop, const Dependences &D);
/// Print a source code representation of the program.
void pprint(raw_ostream &OS);
isl::ast_node getAst();
const std::shared_ptr<isl_ctx> getSharedIslCtx() const { return Ctx; }
/// Get the run-time conditions for the Scop.
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, const isl::ast_build &Build);
private:
Scop &S;
std::shared_ptr<isl_ctx> Ctx;
isl::ast_expr RunCondition;
isl::ast_node Root;
IslAst(Scop &Scop);
void init(const Dependences &D);
};
class IslAstInfo {
public:
using MemoryAccessSet = SmallPtrSet<MemoryAccess *, 4>;
/// Payload information used to annotate an AST node.
struct IslAstUserPayload {
/// Construct and initialize the payload.
IslAstUserPayload() = default;
/// 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;
/// 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::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::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(const isl::ast_node &Node);
/// Is this loop an innermost loop?
static bool isInnermost(const isl::ast_node &Node);
/// Is this loop a parallel loop?
static bool isParallel(const isl::ast_node &Node);
/// Is this loop an outermost parallel loop?
static bool isOutermostParallel(const isl::ast_node &Node);
/// Is this loop an innermost parallel loop?
static bool isInnermostParallel(const isl::ast_node &Node);
/// Is this loop a reduction parallel loop?
static bool isReductionParallel(const isl::ast_node &Node);
/// Will the loop be run as thread parallel?
static bool isExecutedInParallel(const isl::ast_node &Node);
/// Get the nodes schedule or a nullptr if not available.
static isl::union_map getSchedule(const isl::ast_node &Node);
/// Get minimal dependence distance or nullptr if not available.
static isl::pw_aff getMinimalDependenceDistance(const isl::ast_node &Node);
/// Get the nodes broken reductions or a nullptr if not available.
static MemoryAccessSet *getBrokenReductions(const isl::ast_node &Node);
/// Get the nodes build context or a nullptr if not available.
static isl::ast_build getBuild(const isl::ast_node &Node);
///}
};
struct IslAstAnalysis : public AnalysisInfoMixin<IslAstAnalysis> {
static AnalysisKey Key;
using Result = IslAstInfo;
IslAstInfo run(Scop &S, ScopAnalysisManager &SAM,
ScopStandardAnalysisResults &SAR);
};
class IslAstInfoWrapperPass : public ScopPass {
std::unique_ptr<IslAstInfo> 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> {
IslAstPrinterPass(raw_ostream &OS) : OS(OS) {}
PreservedAnalyses run(Scop &S, ScopAnalysisManager &SAM,
ScopStandardAnalysisResults &, SPMUpdater &U);
raw_ostream &OS;
};
} // namespace polly
#endif // POLLY_ISLAST_H