Imported Upstream version 6.10.0.49

Former-commit-id: 1d6753294b2993e1fbf92de9366bb9544db4189b
This commit is contained in:
Xamarin Public Jenkins (auto-signing)
2020-01-16 16:38:04 +00:00
parent d94e79959b
commit 468663ddbb
48518 changed files with 2789335 additions and 61176 deletions

View File

@@ -0,0 +1,27 @@
//===--- Canonicalization.h - Set of canonicalization passes ----*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#ifndef POLLY_CANONICALIZATION_H
#define POLLY_CANONICALIZATION_H
#include "llvm/IR/LegacyPassManager.h"
namespace polly {
/// Schedule a set of canonicalization passes to prepare for Polly.
///
/// The set of optimization passes was partially taken/copied from the
/// set of default optimization passes in LLVM. It is used to bring the code
/// into a canonical form that simplifies the analysis and optimization passes
/// of Polly. The set of optimization passes scheduled here is probably not yet
/// optimal. TODO: Optimize the set of canonicalization passes.
void registerCanonicalicationPasses(llvm::legacy::PassManagerBase &PM);
} // namespace polly
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,50 @@
//===- polly/CodeGeneration.h - The Polly code generator --------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#ifndef POLLY_CODEGENERATION_H
#define POLLY_CODEGENERATION_H
#include "IRBuilder.h"
#include "polly/Config/config.h"
#include "polly/ScopPass.h"
#include "llvm/IR/PassManager.h"
namespace llvm {
class BasicBlock;
} // namespace llvm
namespace polly {
class Scop;
enum VectorizerChoice {
VECTORIZER_NONE,
VECTORIZER_STRIPMINE,
VECTORIZER_POLLY,
};
extern VectorizerChoice PollyVectorizerChoice;
/// Mark a basic block unreachable.
///
/// Marks the basic block @p Block unreachable by equipping it with an
/// UnreachableInst.
void markBlockUnreachable(BasicBlock &Block, PollyIRBuilder &Builder);
struct CodeGenerationPass : public PassInfoMixin<CodeGenerationPass> {
PreservedAnalyses run(Scop &S, ScopAnalysisManager &SAM,
ScopStandardAnalysisResults &AR, SPMUpdater &U);
};
extern bool PerfMonitoring;
} // namespace polly
#endif // POLLY_CODEGENERATION_H

View File

@@ -0,0 +1,17 @@
#ifndef POLLY_CODEGENCLEANUP_H
#define POLLY_CODEGENCLEANUP_H
namespace llvm {
class FunctionPass;
class PassRegistry;
} // namespace llvm
namespace polly {
llvm::FunctionPass *createCodegenCleanupPass();
} // namespace polly
namespace llvm {
void initializeCodegenCleanupPass(llvm::PassRegistry &);
} // namespace llvm
#endif

View File

@@ -0,0 +1,169 @@
//===- Codegen/IRBuilder.h - The IR builder used by Polly -*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// The Polly IRBuilder file contains Polly specific extensions for the IRBuilder
// that are used e.g. to emit the llvm.loop.parallel metadata.
//
//===----------------------------------------------------------------------===//
#ifndef POLLY_CODEGEN_IRBUILDER_H
#define POLLY_CODEGEN_IRBUILDER_H
#include "llvm/ADT/MapVector.h"
#include "llvm/Analysis/LoopInfo.h"
#include "llvm/Analysis/ScalarEvolution.h"
#include "llvm/IR/IRBuilder.h"
#include "llvm/IR/ValueMap.h"
namespace llvm {
class ScalarEvolution;
} // namespace llvm
namespace polly {
class Scop;
/// Helper class to annotate newly generated SCoPs with metadata.
///
/// The annotations are twofold:
/// 1) Loops are stored in a stack-like structure in the order they are
/// constructed and the LoopID metadata node is added to the backedge.
/// Contained memory instructions and loop headers are annotated according
/// to all parallel surrounding loops.
/// 2) The new SCoP is assumed alias free (either due to the result of
/// AliasAnalysis queries or runtime alias checks). We annotate therefore
/// all memory instruction with alias scopes to indicate that fact to
/// later optimizations.
/// These alias scopes live in a new alias domain only used in this SCoP.
/// Each base pointer has its own alias scope and is annotated to not
/// alias with any access to different base pointers.
class ScopAnnotator {
public:
ScopAnnotator();
/// Build all alias scopes for the given SCoP.
void buildAliasScopes(Scop &S);
/// Add a new loop @p L which is parallel if @p IsParallel is true.
void pushLoop(llvm::Loop *L, bool IsParallel);
/// Remove the last added loop.
void popLoop(bool isParallel);
/// Annotate the new instruction @p I for all parallel loops.
void annotate(llvm::Instruction *I);
/// Annotate the loop latch @p B wrt. @p L.
void annotateLoopLatch(llvm::BranchInst *B, llvm::Loop *L, bool IsParallel,
bool IsLoopVectorizerDisabled) const;
/// Add alternative alias based pointers
///
/// When annotating instructions with alias scope metadata, the right metadata
/// is identified through the base pointer of the memory access. In some cases
/// (e.g. OpenMP code generation), the base pointer of the memory accesses is
/// not the original base pointer, but was changed when passing the original
/// base pointer over a function boundary. This function allows to provide a
/// map that maps from these new base pointers to the original base pointers
/// to allow the ScopAnnotator to still find the right alias scop annotations.
///
/// @param NewMap A map from new base pointers to original base pointers.
void addAlternativeAliasBases(
llvm::DenseMap<llvm::AssertingVH<llvm::Value>,
llvm::AssertingVH<llvm::Value>> &NewMap) {
AlternativeAliasBases.insert(NewMap.begin(), NewMap.end());
}
/// Delete the set of alternative alias bases
void resetAlternativeAliasBases() { AlternativeAliasBases.clear(); }
/// Add inter iteration alias-free base pointer @p BasePtr.
void addInterIterationAliasFreeBasePtr(llvm::Value *BasePtr);
private:
/// Annotate with the second level alias metadata
///
/// Annotate the instruction @p I with the second level alias metadata
/// to distinguish the individual non-aliasing accesses that have inter
/// iteration alias-free base pointers.
///
/// @param I The instruction to be annotated.
/// @param BasePtr The base pointer of @p I.
void annotateSecondLevel(llvm::Instruction *I, llvm::Value *BasePtr);
/// The ScalarEvolution analysis we use to find base pointers.
llvm::ScalarEvolution *SE;
/// All loops currently under construction.
llvm::SmallVector<llvm::Loop *, 8> ActiveLoops;
/// Metadata pointing to parallel loops currently under construction.
llvm::SmallVector<llvm::MDNode *, 8> ParallelLoops;
/// The alias scope domain for the current SCoP.
llvm::MDNode *AliasScopeDomain;
/// A map from base pointers to its alias scope.
llvm::MapVector<llvm::AssertingVH<llvm::Value>, llvm::MDNode *> AliasScopeMap;
/// A map from base pointers to an alias scope list of other pointers.
llvm::DenseMap<llvm::AssertingVH<llvm::Value>, llvm::MDNode *>
OtherAliasScopeListMap;
/// A map from pointers to second level alias scopes.
llvm::DenseMap<const llvm::SCEV *, llvm::MDNode *> SecondLevelAliasScopeMap;
/// A map from pointers to second level alias scope list of other pointers.
llvm::DenseMap<const llvm::SCEV *, llvm::MDNode *>
SecondLevelOtherAliasScopeListMap;
/// Inter iteration alias-free base pointers.
llvm::SmallPtrSet<llvm::Value *, 4> InterIterationAliasFreeBasePtrs;
llvm::DenseMap<llvm::AssertingVH<llvm::Value>, llvm::AssertingVH<llvm::Value>>
AlternativeAliasBases;
};
/// Add Polly specifics when running IRBuilder.
///
/// This is used to add additional items such as e.g. the llvm.loop.parallel
/// metadata.
class IRInserter : protected llvm::IRBuilderDefaultInserter {
public:
IRInserter() = default;
IRInserter(class ScopAnnotator &A) : Annotator(&A) {}
protected:
void InsertHelper(llvm::Instruction *I, const llvm::Twine &Name,
llvm::BasicBlock *BB,
llvm::BasicBlock::iterator InsertPt) const {
llvm::IRBuilderDefaultInserter::InsertHelper(I, Name, BB, InsertPt);
if (Annotator)
Annotator->annotate(I);
}
private:
class ScopAnnotator *Annotator = nullptr;
};
// TODO: We should not name instructions in NDEBUG builds.
//
// We currently always name instructions, as the polly test suite currently
// matches for certain names.
typedef llvm::IRBuilder<llvm::ConstantFolder, IRInserter> PollyIRBuilder;
/// Return an IR builder pointed before the @p BB terminator.
static inline PollyIRBuilder createPollyIRBuilder(llvm::BasicBlock *BB,
ScopAnnotator &LA) {
PollyIRBuilder Builder(BB->getContext(), llvm::ConstantFolder(),
polly::IRInserter(LA));
Builder.SetInsertPoint(BB->getTerminator());
return Builder;
}
} // namespace polly
#endif

View File

@@ -0,0 +1,236 @@
//===- IslAst.h - Interface to the isl code generator -----------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// 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/Config/config.h"
#include "polly/ScopPass.h"
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/IR/PassManager.h"
#include "isl/ast.h"
#include "isl/ctx.h"
#include <memory>
namespace llvm {
class PassRegistry;
class raw_ostream;
void initializeIslAstInfoWrapperPassPass(PassRegistry &);
} // namespace llvm
struct isl_ast_build;
struct isl_ast_expr;
struct isl_ast_node;
struct isl_pw_aff;
struct isl_pw_multi_aff;
struct isl_union_map;
namespace polly {
struct Dependences;
class MemoryAccess;
class Scop;
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<isl_ctx> 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<isl_ctx> Ctx;
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;
/// Cleanup all isl structs on destruction.
~IslAstUserPayload();
/// 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 = nullptr;
/// 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<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

View File

@@ -0,0 +1,278 @@
//===-IslExprBuilder.h - Helper to generate code for isl AST expressions --===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
//===----------------------------------------------------------------------===//
#ifndef POLLY_ISL_EXPR_BUILDER_H
#define POLLY_ISL_EXPR_BUILDER_H
#include "polly/CodeGen/IRBuilder.h"
#include "polly/Support/ScopHelper.h"
#include "llvm/ADT/MapVector.h"
#include "isl/ast.h"
#include "isl/isl-noexceptions.h"
namespace llvm {
class DataLayout;
class ScalarEvolution;
} // namespace llvm
struct isl_id;
namespace llvm {
// Provide PointerLikeTypeTraits for isl_id.
template <> struct PointerLikeTypeTraits<isl_id *> {
public:
static inline const void *getAsVoidPointer(isl_id *P) { return (void *)P; }
static inline const Region *getFromVoidPointer(void *P) {
return (Region *)P;
}
enum { NumLowBitsAvailable = 0 };
};
} // namespace llvm
namespace polly {
class ScopArrayInfo;
/// LLVM-IR generator for isl_ast_expr[essions]
///
/// This generator generates LLVM-IR that performs the computation described by
/// an isl_ast_expr[ession].
///
/// Example:
///
/// An isl_ast_expr[ession] can look like this:
///
/// (N + M) + 10
///
/// The IslExprBuilder could create the following LLVM-IR:
///
/// %tmp1 = add nsw i64 %N
/// %tmp2 = add nsw i64 %tmp1, %M
/// %tmp3 = add nsw i64 %tmp2, 10
///
/// The implementation of this class is mostly a mapping from isl_ast_expr
/// constructs to the corresponding LLVM-IR constructs.
///
/// The following decisions may need some explanation:
///
/// 1) Which data-type to choose
///
/// isl_ast_expr[essions] are untyped expressions that assume arbitrary
/// precision integer computations. LLVM-IR instead has fixed size integers.
/// When lowering to LLVM-IR we need to chose both the size of the data type and
/// the sign of the operations we use.
///
/// At the moment, we hardcode i64 bit signed computations. Our experience has
/// shown that 64 bit are generally large enough for the loop bounds that appear
/// in the wild. Signed computations are needed, as loop bounds may become
/// negative.
///
/// It is possible to track overflows that occurred in the generated IR. See the
/// description of @see OverflowState for more information.
///
/// FIXME: Hardcoding sizes can cause issues:
///
/// - On embedded systems and especially for high-level-synthesis 64 bit
/// computations are very costly.
///
/// The right approach is to compute the minimal necessary bitwidth and
/// signedness for each subexpression during in the isl AST generation and
/// to use this information in our IslAstGenerator. Preliminary patches are
/// available, but have not been committed yet.
///
class IslExprBuilder {
public:
/// A map from isl_ids to llvm::Values.
typedef llvm::MapVector<isl_id *, llvm::AssertingVH<llvm::Value>> IDToValueTy;
typedef llvm::MapVector<isl_id *, const ScopArrayInfo *> IDToScopArrayInfoTy;
/// A map from isl_ids to ScopArrayInfo objects.
///
/// This map is used to obtain ScopArrayInfo objects for isl_ids which do not
/// carry a ScopArrayInfo object in their user pointer. This is useful if the
/// construction of ScopArrayInfo objects happens only after references (e.g.
/// in an AST) to an isl_id are generated and the user pointer of the isl_id
/// can not be changed any more.
///
/// This is useful for external users who just use the IslExprBuilder for
/// code generation.
IDToScopArrayInfoTy *IDToSAI = nullptr;
/// Set the isl_id to ScopArrayInfo map.
///
/// @param NewIDToSAI The new isl_id to ScopArrayInfo map to use.
void setIDToSAI(IDToScopArrayInfoTy *NewIDToSAI) { IDToSAI = NewIDToSAI; }
/// Construct an IslExprBuilder.
///
/// @param Builder The IRBuilder used to construct the
/// isl_ast_expr[ession]. The insert location of this
/// IRBuilder defines WHERE the corresponding LLVM-IR
/// is generated.
/// @param IDToValue The isl_ast_expr[ession] may reference parameters or
/// variables (identified by an isl_id). The IDTOValue map
/// specifies the LLVM-IR Values that correspond to these
/// parameters and variables.
/// @param GlobalMap A mapping from llvm::Values used in the original scop
/// region to a new set of llvm::Values.
/// @param DL DataLayout for the current Module.
/// @param SE ScalarEvolution analysis for the current function.
/// @param DT DominatorTree analysis for the current function.
/// @param LI LoopInfo analysis for the current function.
/// @param StartBlock The first basic block after the RTC.
IslExprBuilder(Scop &S, PollyIRBuilder &Builder, IDToValueTy &IDToValue,
ValueMapT &GlobalMap, const llvm::DataLayout &DL,
llvm::ScalarEvolution &SE, llvm::DominatorTree &DT,
llvm::LoopInfo &LI, llvm::BasicBlock *StartBlock);
/// Create LLVM-IR for an isl_ast_expr[ession].
///
/// @param Expr The ast expression for which we generate LLVM-IR.
///
/// @return The llvm::Value* containing the result of the computation.
llvm::Value *create(__isl_take isl_ast_expr *Expr);
/// Return the largest of two types.
///
/// @param T1 The first type.
/// @param T2 The second type.
///
/// @return The largest of the two types.
llvm::Type *getWidestType(llvm::Type *T1, llvm::Type *T2);
/// Return the type with which this expression should be computed.
///
/// The type needs to be large enough to hold all possible input and all
/// possible output values.
///
/// @param Expr The expression for which to find the type.
/// @return The type with which the expression should be computed.
llvm::IntegerType *getType(__isl_keep isl_ast_expr *Expr);
/// Change if runtime overflows are tracked or not.
///
/// @param Enable Flag to enable/disable the tracking.
///
/// Note that this will reset the tracking state and that tracking is only
/// allowed if the last tracked expression dominates the current insert point.
void setTrackOverflow(bool Enable);
/// Return the current overflow status or nullptr if it is not tracked.
///
/// @return A nullptr if tracking is disabled or otherwise an i1 that has the
/// value of "0" if and only if no overflow happened since tracking
/// was enabled.
llvm::Value *getOverflowState() const;
/// Create LLVM-IR that computes the memory location of an access expression.
///
/// For a given isl_ast_expr[ession] of type isl_ast_op_access this function
/// creates IR that computes the address the access expression refers to.
///
/// @param Expr The ast expression of type isl_ast_op_access
/// for which we generate LLVM-IR.
///
/// @return The llvm::Value* containing the result of the computation.
llvm::Value *createAccessAddress(__isl_take isl_ast_expr *Expr);
/// Check if an @p Expr contains integer constants larger than 64 bit.
///
/// @param Expr The expression to check.
///
/// @return True if the ast expression is larger than 64 bit.
bool hasLargeInts(isl::ast_expr Expr);
private:
Scop &S;
/// Flag that will be set if an overflow occurred at runtime.
///
/// Note that this flag is by default a nullptr and if it is a nullptr
/// we will not record overflows but simply perform the computations.
/// The intended usage is as follows:
/// - If overflows in [an] expression[s] should be tracked, call
/// the setTrackOverflow(true) function.
/// - Use create(...) for all expressions that should be checked.
/// - Call getOverflowState() to get the value representing the current
/// state of the overflow flag.
/// - To stop tracking call setTrackOverflow(false).
llvm::Value *OverflowState;
PollyIRBuilder &Builder;
IDToValueTy &IDToValue;
ValueMapT &GlobalMap;
const llvm::DataLayout &DL;
llvm::ScalarEvolution &SE;
llvm::DominatorTree &DT;
llvm::LoopInfo &LI;
llvm::BasicBlock *StartBlock;
llvm::Value *createOp(__isl_take isl_ast_expr *Expr);
llvm::Value *createOpUnary(__isl_take isl_ast_expr *Expr);
llvm::Value *createOpAccess(__isl_take isl_ast_expr *Expr);
llvm::Value *createOpBin(__isl_take isl_ast_expr *Expr);
llvm::Value *createOpNAry(__isl_take isl_ast_expr *Expr);
llvm::Value *createOpSelect(__isl_take isl_ast_expr *Expr);
llvm::Value *createOpICmp(__isl_take isl_ast_expr *Expr);
llvm::Value *createOpBoolean(__isl_take isl_ast_expr *Expr);
llvm::Value *createOpBooleanConditional(__isl_take isl_ast_expr *Expr);
llvm::Value *createId(__isl_take isl_ast_expr *Expr);
llvm::Value *createInt(__isl_take isl_ast_expr *Expr);
llvm::Value *createOpAddressOf(__isl_take isl_ast_expr *Expr);
/// Create a binary operation @p Opc and track overflows if requested.
///
/// @param OpC The binary operation that should be performed [Add/Sub/Mul].
/// @param LHS The left operand.
/// @param RHS The right operand.
/// @param Name The (base) name of the new IR operations.
///
/// @return A value that represents the result of the binary operation.
llvm::Value *createBinOp(llvm::BinaryOperator::BinaryOps Opc,
llvm::Value *LHS, llvm::Value *RHS,
const llvm::Twine &Name);
/// Create an addition and track overflows if requested.
///
/// @param LHS The left operand.
/// @param RHS The right operand.
/// @param Name The (base) name of the new IR operations.
///
/// @return A value that represents the result of the addition.
llvm::Value *createAdd(llvm::Value *LHS, llvm::Value *RHS,
const llvm::Twine &Name = "");
/// Create a subtraction and track overflows if requested.
///
/// @param LHS The left operand.
/// @param RHS The right operand.
/// @param Name The (base) name of the new IR operations.
///
/// @return A value that represents the result of the subtraction.
llvm::Value *createSub(llvm::Value *LHS, llvm::Value *RHS,
const llvm::Twine &Name = "");
/// Create a multiplication and track overflows if requested.
///
/// @param LHS The left operand.
/// @param RHS The right operand.
/// @param Name The (base) name of the new IR operations.
///
/// @return A value that represents the result of the multiplication.
llvm::Value *createMul(llvm::Value *LHS, llvm::Value *RHS,
const llvm::Twine &Name = "");
};
} // namespace polly
#endif

View File

@@ -0,0 +1,464 @@
//=- IslNodeBuilder.cpp - Translate an isl AST into a LLVM-IR AST -*- C++ -*-=//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file contains the IslNodeBuilder, a class to translate an isl AST into
// a LLVM-IR AST.
//
//===----------------------------------------------------------------------===//
#ifndef POLLY_ISLNODEBUILDER_H
#define POLLY_ISLNODEBUILDER_H
#include "polly/CodeGen/BlockGenerators.h"
#include "polly/CodeGen/IslExprBuilder.h"
#include "polly/ScopDetectionDiagnostic.h"
#include "polly/Support/ScopHelper.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/SetVector.h"
#include "llvm/ADT/SmallSet.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/Analysis/ScalarEvolutionExpressions.h"
#include "llvm/IR/InstrTypes.h"
#include "isl/ctx.h"
#include "isl/isl-noexceptions.h"
#include <utility>
#include <vector>
using namespace llvm;
using namespace polly;
namespace llvm {
class BasicBlock;
class DataLayout;
class DominatorTree;
class Function;
class Instruction;
class Loop;
class LoopInfo;
class ScalarEvolution;
class SCEV;
class Type;
class Value;
} // namespace llvm
namespace polly {
struct InvariantEquivClassTy;
class MemoryAccess;
class Scop;
class ScopStmt;
} // namespace polly
struct isl_ast_node;
struct isl_ast_build;
struct isl_union_map;
struct SubtreeReferences {
LoopInfo &LI;
ScalarEvolution &SE;
Scop &S;
ValueMapT &GlobalMap;
SetVector<Value *> &Values;
SetVector<const SCEV *> &SCEVs;
BlockGenerator &BlockGen;
// In case an (optional) parameter space location is provided, parameter space
// information is collected as well.
isl::space *ParamSpace;
};
/// Extract the out-of-scop values and SCEVs referenced from a ScopStmt.
///
/// This includes the SCEVUnknowns referenced by the SCEVs used in the
/// statement and the base pointers of the memory accesses. For scalar
/// statements we force the generation of alloca memory locations and list
/// these locations in the set of out-of-scop values as well.
///
/// We also collect an isl::space that includes all parameter dimensions
/// used in the statement's memory accesses, in case the ParamSpace pointer
/// is non-null.
///
/// @param Stmt The statement for which to extract the information.
/// @param UserPtr A void pointer that can be casted to a
/// SubtreeReferences structure.
/// @param CreateScalarRefs Should the result include allocas of scalar
/// references?
isl_stat addReferencesFromStmt(const ScopStmt *Stmt, void *UserPtr,
bool CreateScalarRefs = true);
class IslNodeBuilder {
public:
IslNodeBuilder(PollyIRBuilder &Builder, ScopAnnotator &Annotator,
const DataLayout &DL, LoopInfo &LI, ScalarEvolution &SE,
DominatorTree &DT, Scop &S, BasicBlock *StartBlock)
: S(S), Builder(Builder), Annotator(Annotator),
ExprBuilder(S, Builder, IDToValue, ValueMap, DL, SE, DT, LI,
StartBlock),
BlockGen(Builder, LI, SE, DT, ScalarMap, EscapeMap, ValueMap,
&ExprBuilder, StartBlock),
RegionGen(BlockGen), DL(DL), LI(LI), SE(SE), DT(DT),
StartBlock(StartBlock) {}
virtual ~IslNodeBuilder() = default;
void addParameters(__isl_take isl_set *Context);
/// Create Values which hold the sizes of the outermost dimension of all
/// Fortran arrays in the current scop.
///
/// @returns False, if a problem occurred and a Fortran array was not
/// materialized. True otherwise.
bool materializeFortranArrayOutermostDimension();
/// Generate code that evaluates @p Condition at run-time.
///
/// This function is typically called to generate the LLVM-IR for the
/// run-time condition of the scop, that verifies that all the optimistic
/// assumptions we have taken during scop modeling and transformation
/// hold at run-time.
///
/// @param Condition The condition to evaluate
///
/// @result An llvm::Value that is true if the condition holds and false
/// otherwise.
Value *createRTC(isl_ast_expr *Condition);
void create(__isl_take isl_ast_node *Node);
/// Allocate memory for all new arrays created by Polly.
void allocateNewArrays(BBPair StartExitBlocks);
/// Preload all memory loads that are invariant.
bool preloadInvariantLoads();
/// Finalize code generation.
///
/// @see BlockGenerator::finalizeSCoP(Scop &S)
virtual void finalize() { BlockGen.finalizeSCoP(S); }
IslExprBuilder &getExprBuilder() { return ExprBuilder; }
/// Get the associated block generator.
///
/// @return A reference to the associated block generator.
BlockGenerator &getBlockGenerator() { return BlockGen; }
/// Return the parallel subfunctions that have been created.
const ArrayRef<Function *> getParallelSubfunctions() const {
return ParallelSubfunctions;
}
protected:
Scop &S;
PollyIRBuilder &Builder;
ScopAnnotator &Annotator;
IslExprBuilder ExprBuilder;
/// Maps used by the block and region generator to demote scalars.
///
///@{
/// See BlockGenerator::ScalarMap.
BlockGenerator::AllocaMapTy ScalarMap;
/// See BlockGenerator::EscapeMap.
BlockGenerator::EscapeUsersAllocaMapTy EscapeMap;
///@}
/// The generator used to copy a basic block.
BlockGenerator BlockGen;
/// The generator used to copy a non-affine region.
RegionGenerator RegionGen;
const DataLayout &DL;
LoopInfo &LI;
ScalarEvolution &SE;
DominatorTree &DT;
BasicBlock *StartBlock;
/// The current iteration of out-of-scop loops
///
/// This map provides for a given loop a llvm::Value that contains the current
/// loop iteration.
LoopToScevMapT OutsideLoopIterations;
// This maps an isl_id* to the Value* it has in the generated program. For now
// on, the only isl_ids that are stored here are the newly calculated loop
// ivs.
IslExprBuilder::IDToValueTy IDToValue;
/// A collection of all parallel subfunctions that have been created.
SmallVector<Function *, 8> ParallelSubfunctions;
/// Generate code for a given SCEV*
///
/// This function generates code for a given SCEV expression. It generated
/// code is emitted at the end of the basic block our Builder currently
/// points to and the resulting value is returned.
///
/// @param Expr The expression to code generate.
Value *generateSCEV(const SCEV *Expr);
/// A set of Value -> Value remappings to apply when generating new code.
///
/// When generating new code for a ScopStmt this map is used to map certain
/// llvm::Values to new llvm::Values.
ValueMapT ValueMap;
/// Materialize code for @p Id if it was not done before.
///
/// @returns False, iff a problem occurred and the value was not materialized.
bool materializeValue(__isl_take isl_id *Id);
/// Materialize parameters of @p Set.
///
/// @returns False, iff a problem occurred and the value was not materialized.
bool materializeParameters(__isl_take isl_set *Set);
/// Materialize all parameters in the current scop.
///
/// @returns False, iff a problem occurred and the value was not materialized.
bool materializeParameters();
// Extract the upper bound of this loop
//
// The isl code generation can generate arbitrary expressions to check if the
// upper bound of a loop is reached, but it provides an option to enforce
// 'atomic' upper bounds. An 'atomic upper bound is always of the form
// iv <= expr, where expr is an (arbitrary) expression not containing iv.
//
// This function extracts 'atomic' upper bounds. Polly, in general, requires
// atomic upper bounds for the following reasons:
//
// 1. An atomic upper bound is loop invariant
//
// It must not be calculated at each loop iteration and can often even be
// hoisted out further by the loop invariant code motion.
//
// 2. OpenMP needs a loop invariant upper bound to calculate the number
// of loop iterations.
//
// 3. With the existing code, upper bounds have been easier to implement.
__isl_give isl_ast_expr *getUpperBound(__isl_keep isl_ast_node *For,
CmpInst::Predicate &Predicate);
/// Return non-negative number of iterations in case of the following form
/// of a loop and -1 otherwise.
///
/// for (i = 0; i <= NumIter; i++) {
/// loop body;
/// }
///
/// NumIter is a non-negative integer value. Condition can have
/// isl_ast_op_lt type.
int getNumberOfIterations(__isl_keep isl_ast_node *For);
/// Compute the values and loops referenced in this subtree.
///
/// This function looks at all ScopStmts scheduled below the provided For node
/// and finds the llvm::Value[s] and llvm::Loops[s] which are referenced but
/// not locally defined.
///
/// Values that can be synthesized or that are available as globals are
/// considered locally defined.
///
/// Loops that contain the scop or that are part of the scop are considered
/// locally defined. Loops that are before the scop, but do not contain the
/// scop itself are considered not locally defined.
///
/// @param For The node defining the subtree.
/// @param Values A vector that will be filled with the Values referenced in
/// this subtree.
/// @param Loops A vector that will be filled with the Loops referenced in
/// this subtree.
void getReferencesInSubtree(__isl_keep isl_ast_node *For,
SetVector<Value *> &Values,
SetVector<const Loop *> &Loops);
/// Change the llvm::Value(s) used for code generation.
///
/// When generating code certain values (e.g., references to induction
/// variables or array base pointers) in the original code may be replaced by
/// new values. This function allows to (partially) update the set of values
/// used. A typical use case for this function is the case when we continue
/// code generation in a subfunction/kernel function and need to explicitly
/// pass down certain values.
///
/// @param NewValues A map that maps certain llvm::Values to new llvm::Values.
void updateValues(ValueMapT &NewValues);
/// Return the most up-to-date version of the llvm::Value for code generation.
/// @param Original The Value to check for an up to date version.
/// @returns A remapped `Value` from ValueMap, or `Original` if no mapping
/// exists.
/// @see IslNodeBuilder::updateValues
/// @see IslNodeBuilder::ValueMap
Value *getLatestValue(Value *Original) const;
/// Generate code for a marker now.
///
/// For mark nodes with an unknown name, we just forward the code generation
/// to its child. This is currently the only behavior implemented, as there is
/// currently not special handling for marker nodes implemented.
///
/// @param Mark The node we generate code for.
virtual void createMark(__isl_take isl_ast_node *Marker);
virtual void createFor(__isl_take isl_ast_node *For);
/// Set to remember materialized invariant loads.
///
/// An invariant load is identified by its pointer (the SCEV) and its type.
SmallSet<std::pair<const SCEV *, Type *>, 16> PreloadedPtrs;
/// Preload the memory access at @p AccessRange with @p Build.
///
/// @returns The preloaded value casted to type @p Ty
Value *preloadUnconditionally(__isl_take isl_set *AccessRange,
isl_ast_build *Build, Instruction *AccInst);
/// Preload the memory load access @p MA.
///
/// If @p MA is not always executed it will be conditionally loaded and
/// merged with undef from the same type. Hence, if @p MA is executed only
/// under condition C then the preload code will look like this:
///
/// MA_preload = undef;
/// if (C)
/// MA_preload = load MA;
/// use MA_preload
Value *preloadInvariantLoad(const MemoryAccess &MA,
__isl_take isl_set *Domain);
/// Preload the invariant access equivalence class @p IAClass
///
/// This function will preload the representing load from @p IAClass and
/// map all members of @p IAClass to that preloaded value, potentially casted
/// to the required type.
///
/// @returns False, iff a problem occurred and the load was not preloaded.
bool preloadInvariantEquivClass(InvariantEquivClassTy &IAClass);
void createForVector(__isl_take isl_ast_node *For, int VectorWidth);
void createForSequential(__isl_take isl_ast_node *For, bool MarkParallel);
/// Create LLVM-IR that executes a for node thread parallel.
///
/// @param For The FOR isl_ast_node for which code is generated.
void createForParallel(__isl_take isl_ast_node *For);
/// Create new access functions for modified memory accesses.
///
/// In case the access function of one of the memory references in the Stmt
/// has been modified, we generate a new isl_ast_expr that reflects the
/// newly modified access function and return a map that maps from the
/// individual memory references in the statement (identified by their id)
/// to these newly generated ast expressions.
///
/// @param Stmt The statement for which to (possibly) generate new access
/// functions.
/// @param Node The ast node corresponding to the statement for us to extract
/// the local schedule from.
/// @return A new hash table that contains remappings from memory ids to new
/// access expressions.
__isl_give isl_id_to_ast_expr *
createNewAccesses(ScopStmt *Stmt, __isl_keep isl_ast_node *Node);
/// Generate LLVM-IR that computes the values of the original induction
/// variables in function of the newly generated loop induction variables.
///
/// Example:
///
/// // Original
/// for i
/// for j
/// S(i)
///
/// Schedule: [i,j] -> [i+j, j]
///
/// // New
/// for c0
/// for c1
/// S(c0 - c1, c1)
///
/// Assuming the original code consists of two loops which are
/// transformed according to a schedule [i,j] -> [c0=i+j,c1=j]. The resulting
/// ast models the original statement as a call expression where each argument
/// is an expression that computes the old induction variables from the new
/// ones, ordered such that the first argument computes the value of induction
/// variable that was outermost in the original code.
///
/// @param Expr The call expression that represents the statement.
/// @param Stmt The statement that is called.
/// @param LTS The loop to SCEV map in which the mapping from the original
/// loop to a SCEV representing the new loop iv is added. This
/// mapping does not require an explicit induction variable.
/// Instead, we think in terms of an implicit induction variable
/// that counts the number of times a loop is executed. For each
/// original loop this count, expressed in function of the new
/// induction variables, is added to the LTS map.
void createSubstitutions(__isl_take isl_ast_expr *Expr, ScopStmt *Stmt,
LoopToScevMapT &LTS);
void createSubstitutionsVector(__isl_take isl_ast_expr *Expr, ScopStmt *Stmt,
std::vector<LoopToScevMapT> &VLTS,
std::vector<Value *> &IVS,
__isl_take isl_id *IteratorID);
virtual void createIf(__isl_take isl_ast_node *If);
void createUserVector(__isl_take isl_ast_node *User,
std::vector<Value *> &IVS,
__isl_take isl_id *IteratorID,
__isl_take isl_union_map *Schedule);
virtual void createUser(__isl_take isl_ast_node *User);
virtual void createBlock(__isl_take isl_ast_node *Block);
/// Get the schedule for a given AST node.
///
/// This information is used to reason about parallelism of loops or the
/// locality of memory accesses under a given schedule.
///
/// @param Node The node we want to obtain the schedule for.
/// @return Return an isl_union_map that maps from the statements executed
/// below this ast node to the scheduling vectors used to enumerate
/// them.
///
virtual __isl_give isl_union_map *
getScheduleForAstNode(__isl_take isl_ast_node *Node);
private:
/// Create code for a copy statement.
///
/// A copy statement is expected to have one read memory access and one write
/// memory access (in this very order). Data is loaded from the location
/// described by the read memory access and written to the location described
/// by the write memory access. @p NewAccesses contains for each access
/// the isl ast expression that describes the location accessed.
///
/// @param Stmt The copy statement that contains the accesses.
/// @param NewAccesses The hash table that contains remappings from memory
/// ids to new access expressions.
void generateCopyStmt(ScopStmt *Stmt,
__isl_keep isl_id_to_ast_expr *NewAccesses);
/// Materialize a canonical loop induction variable for `L`, which is a loop
/// that is *not* present in the Scop.
///
/// Note that this is materialized at the point where the `Builder` is
/// currently pointing.
/// We also populate the `OutsideLoopIterations` map with `L`s SCEV to keep
/// track of the induction variable.
/// See [Code generation of induction variables of loops outside Scops]
Value *materializeNonScopLoopInductionVariable(const Loop *L);
};
#endif // POLLY_ISLNODEBUILDER_H

View File

@@ -0,0 +1,220 @@
//===- LoopGenerators.h - IR helper to create loops -------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file contains functions to create scalar and OpenMP parallel loops
// as LLVM-IR.
//
//===----------------------------------------------------------------------===//
#ifndef POLLY_LOOP_GENERATORS_H
#define POLLY_LOOP_GENERATORS_H
#include "polly/CodeGen/IRBuilder.h"
#include "polly/Support/ScopHelper.h"
#include "llvm/ADT/SetVector.h"
#include "llvm/IR/ValueMap.h"
namespace llvm {
class Value;
class Pass;
class BasicBlock;
} // namespace llvm
namespace polly {
using namespace llvm;
/// Create a scalar do/for-style loop.
///
/// @param LowerBound The starting value of the induction variable.
/// @param UpperBound The upper bound of the induction variable.
/// @param Stride The value by which the induction variable
/// is incremented.
///
/// @param Builder The builder used to create the loop.
/// @param P A pointer to the pass that uses this function.
/// It is used to update analysis information.
/// @param LI The loop info for the current function
/// @param DT The dominator tree we need to update
/// @param ExitBlock The block the loop will exit to.
/// @param Predicate The predicate used to generate the upper loop
/// bound.
/// @param Annotator This function can (optionally) take
/// a ScopAnnotator which
/// annotates loops and alias information in the SCoP.
/// @param Parallel If this loop should be marked parallel in
/// the Annotator.
/// @param UseGuard Create a guard in front of the header to check if
/// the loop is executed at least once, otherwise just
/// assume it.
/// @param LoopVectDisabled If the Loop vectorizer should be disabled for this
/// loop.
///
/// @return Value* The newly created induction variable for this loop.
Value *createLoop(Value *LowerBound, Value *UpperBound, Value *Stride,
PollyIRBuilder &Builder, LoopInfo &LI, DominatorTree &DT,
BasicBlock *&ExitBlock, ICmpInst::Predicate Predicate,
ScopAnnotator *Annotator = NULL, bool Parallel = false,
bool UseGuard = true, bool LoopVectDisabled = false);
/// The ParallelLoopGenerator allows to create parallelized loops
///
/// To parallelize a loop, we perform the following steps:
/// o Generate a subfunction which will hold the loop body.
/// o Create a struct to hold all outer values needed in the loop body.
/// o Create calls to a runtime library to achieve the actual parallelism.
/// These calls will spawn and join threads, define how the work (here the
/// iterations) are distributed between them and make sure each has access
/// to the struct holding all needed values.
///
/// At the moment we support only one parallel runtime, OpenMP.
///
/// If we parallelize the outer loop of the following loop nest,
///
/// S0;
/// for (int i = 0; i < N; i++)
/// for (int j = 0; j < M; j++)
/// S1(i, j);
/// S2;
///
/// we will generate the following code (with different runtime function names):
///
/// S0;
/// auto *values = storeValuesIntoStruct();
/// // Execute subfunction with multiple threads
/// spawn_threads(subfunction, values);
/// join_threads();
/// S2;
///
/// // This function is executed in parallel by different threads
/// void subfunction(values) {
/// while (auto *WorkItem = getWorkItem()) {
/// int LB = WorkItem.begin();
/// int UB = WorkItem.end();
/// for (int i = LB; i < UB; i++)
/// for (int j = 0; j < M; j++)
/// S1(i, j);
/// }
/// cleanup_thread();
/// }
class ParallelLoopGenerator {
public:
/// Create a parallel loop generator for the current function.
ParallelLoopGenerator(PollyIRBuilder &Builder, LoopInfo &LI,
DominatorTree &DT, const DataLayout &DL)
: Builder(Builder), LI(LI), DT(DT),
LongType(
Type::getIntNTy(Builder.getContext(), DL.getPointerSizeInBits())),
M(Builder.GetInsertBlock()->getParent()->getParent()) {}
/// Create a parallel loop.
///
/// This function is the main function to automatically generate a parallel
/// loop with all its components.
///
/// @param LB The lower bound for the loop we parallelize.
/// @param UB The upper bound for the loop we parallelize.
/// @param Stride The stride of the loop we parallelize.
/// @param Values A set of LLVM-IR Values that should be available in
/// the new loop body.
/// @param VMap A map to allow outside access to the new versions of
/// the values in @p Values.
/// @param LoopBody A pointer to an iterator that is set to point to the
/// body of the created loop. It should be used to insert
/// instructions that form the actual loop body.
///
/// @return The newly created induction variable for this loop.
Value *createParallelLoop(Value *LB, Value *UB, Value *Stride,
SetVector<Value *> &Values, ValueMapT &VMap,
BasicBlock::iterator *LoopBody);
private:
/// The IR builder we use to create instructions.
PollyIRBuilder &Builder;
/// The loop info of the current function we need to update.
LoopInfo &LI;
/// The dominance tree of the current function we need to update.
DominatorTree &DT;
/// The type of a "long" on this hardware used for backend calls.
Type *LongType;
/// The current module
Module *M;
public:
/// The functions below can be used if one does not want to generate a
/// specific OpenMP parallel loop, but generate individual parts of it
/// (e.g., the subfunction definition).
/// Create a runtime library call to spawn the worker threads.
///
/// @param SubFn The subfunction which holds the loop body.
/// @param SubFnParam The parameter for the subfunction (basically the struct
/// filled with the outside values).
/// @param LB The lower bound for the loop we parallelize.
/// @param UB The upper bound for the loop we parallelize.
/// @param Stride The stride of the loop we parallelize.
void createCallSpawnThreads(Value *SubFn, Value *SubFnParam, Value *LB,
Value *UB, Value *Stride);
/// Create a runtime library call to join the worker threads.
void createCallJoinThreads();
/// Create a runtime library call to get the next work item.
///
/// @param LBPtr A pointer value to store the work item begin in.
/// @param UBPtr A pointer value to store the work item end in.
///
/// @returns A true value if the work item is not empty.
Value *createCallGetWorkItem(Value *LBPtr, Value *UBPtr);
/// Create a runtime library call to allow cleanup of the thread.
///
/// @note This function is called right before the thread will exit the
/// subfunction and only if the runtime system depends on it.
void createCallCleanupThread();
/// Create a struct for all @p Values and store them in there.
///
/// @param Values The values which should be stored in the struct.
///
/// @return The created struct.
AllocaInst *storeValuesIntoStruct(SetVector<Value *> &Values);
/// Extract all values from the @p Struct and construct the mapping.
///
/// @param Values The values which were stored in the struct.
/// @param Struct The struct holding all the values in @p Values.
/// @param VMap A map to associate every element of @p Values with the
/// new llvm value loaded from the @p Struct.
void extractValuesFromStruct(SetVector<Value *> Values, Type *Ty,
Value *Struct, ValueMapT &VMap);
/// Create the definition of the parallel subfunction.
Function *createSubFnDefinition();
/// Create the parallel subfunction.
///
/// @param Stride The induction variable increment.
/// @param Struct A struct holding all values in @p Values.
/// @param Values A set of LLVM-IR Values that should be available in
/// the new loop body.
/// @param VMap A map to allow outside access to the new versions of
/// the values in @p Values.
/// @param SubFn The newly created subfunction is returned here.
///
/// @return The newly created induction variable.
Value *createSubFn(Value *Stride, AllocaInst *Struct,
SetVector<Value *> UsedValues, ValueMapT &VMap,
Function **SubFn);
};
} // end namespace polly
#endif

View File

@@ -0,0 +1,28 @@
//===--- polly/PPCGCodeGeneration.h - Polly Accelerator Code Generation. --===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// Take a scop created by ScopInfo and map it to GPU code using the ppcg
// GPU mapping strategy.
//
//===----------------------------------------------------------------------===//
#ifndef POLLY_PPCGCODEGENERATION_H
#define POLLY_PPCGCODEGENERATION_H
/// The GPU Architecture to target.
enum GPUArch { NVPTX64, SPIR32, SPIR64 };
/// The GPU Runtime implementation to use.
enum GPURuntime { CUDA, OpenCL };
namespace polly {
extern bool PollyManagedMemory;
}
#endif // POLLY_PPCGCODEGENERATION_H

View File

@@ -0,0 +1,155 @@
//===--- PerfMonitor.h --- Monitor time spent in scops --------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#ifndef PERF_MONITOR_H
#define PERF_MONITOR_H
#include "polly/CodeGen/IRBuilder.h"
namespace llvm {
class Function;
class Module;
class Value;
class Instruction;
} // namespace llvm
namespace polly {
class PerfMonitor {
public:
/// Create a new performance monitor.
///
/// @param S The scop for which to generate fine-grained performance
/// monitoring information.
/// @param M The module for which to generate the performance monitor.
PerfMonitor(const Scop &S, llvm::Module *M);
/// Initialize the performance monitor.
///
/// Ensure that all global variables, functions, and callbacks needed to
/// manage the performance monitor are initialized and registered.
void initialize();
/// Mark the beginning of a timing region.
///
/// @param InsertBefore The instruction before which the timing region starts.
void insertRegionStart(llvm::Instruction *InsertBefore);
/// Mark the end of a timing region.
///
/// @param InsertBefore The instruction before which the timing region starts.
void insertRegionEnd(llvm::Instruction *InsertBefore);
private:
llvm::Module *M;
PollyIRBuilder Builder;
// The scop to profile against.
const Scop &S;
/// Indicates if performance profiling is supported on this architecture.
bool Supported;
/// The cycle counter at the beginning of the program execution.
llvm::Value *CyclesTotalStartPtr;
/// The total number of cycles spent in the current scop S.
llvm::Value *CyclesInCurrentScopPtr;
/// The total number of times the current scop S is executed.
llvm::Value *TripCountForCurrentScopPtr;
/// The total number of cycles spent within scops.
llvm::Value *CyclesInScopsPtr;
/// The value of the cycle counter at the beginning of the last scop.
llvm::Value *CyclesInScopStartPtr;
/// A memory location which serves as argument of the RDTSCP function.
///
/// The value written to this location is currently not used.
llvm::Value *RDTSCPWriteLocation;
/// A global variable, that keeps track if the performance monitor
/// initialization has already been run.
llvm::Value *AlreadyInitializedPtr;
llvm::Function *insertInitFunction(llvm::Function *FinalReporting);
/// Add Function @p to list of global constructors
///
/// If no global constructors are available in this current module, insert
/// a new list of global constructors containing @p Fn as only global
/// constructor. Otherwise, append @p Fn to the list of global constructors.
///
/// All functions listed as global constructors are executed before the
/// main() function is called.
///
/// @param Fn Function to add to global constructors
void addToGlobalConstructors(llvm::Function *Fn);
/// Add global variables to module.
///
/// Insert a set of global variables that are used to track performance,
/// into the module (or obtain references to them if they already exist).
void addGlobalVariables();
/// Add per-scop tracking to module.
///
/// Insert the global variable which is used to track the number of cycles
/// this scop runs.
void addScopCounter();
/// Get a reference to the intrinsic "i64 @llvm.x86.rdtscp(i8*)".
///
/// The rdtscp function returns the current value of the processor's
/// time-stamp counter as well as the current CPU identifier. On modern x86
/// systems, the returned value is independent of the dynamic clock frequency
/// and consistent across multiple cores. It can consequently be used to get
/// accurate and low-overhead timing information. Even though the counter is
/// wrapping, it can be reliably used even for measuring longer time
/// intervals, as on a 1 GHz processor the counter only wraps every 545 years.
///
/// The RDTSCP instruction is "pseudo" serializing:
///
/// "“The RDTSCP instruction waits until all previous instructions have been
/// executed before reading the counter. However, subsequent instructions may
/// begin execution before the read operation is performed.”
///
/// To ensure that no later instructions are scheduled before the RDTSCP
/// instruction it is often recommended to schedule a cpuid call after the
/// RDTSCP instruction. We do not do this yet, trading some imprecision in
/// our timing for a reduced overhead in our timing.
///
/// @returns A reference to the declaration of @llvm.x86.rdtscp.
llvm::Function *getRDTSCP();
/// Get a reference to "int atexit(void (*function)(void))" function.
///
/// This function allows to register function pointers that must be executed
/// when the program is terminated.
///
/// @returns A reference to @atexit().
llvm::Function *getAtExit();
/// Create function "__polly_perf_final_reporting".
///
/// This function finalizes the performance measurements and prints the
/// results to stdout. It is expected to be registered with 'atexit()'.
llvm::Function *insertFinalReporting();
/// Append Scop reporting data to "__polly_perf_final_reporting".
///
/// This function appends the current scop (S)'s information to the final
/// printing function.
void AppendScopReporting();
};
} // namespace polly
#endif

View File

@@ -0,0 +1,154 @@
//===--- RuntimeDebugBuilder.h --- Helper to insert prints into LLVM-IR ---===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
//===----------------------------------------------------------------------===//
#ifndef RUNTIME_DEBUG_BUILDER_H
#define RUNTIME_DEBUG_BUILDER_H
#include "polly/CodeGen/IRBuilder.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/StringRef.h"
#include <vector>
namespace llvm {
class Value;
class Function;
} // namespace llvm
namespace polly {
/// Insert function calls that print certain LLVM values at run time.
///
/// This class inserts libc function calls to print certain LLVM values at
/// run time.
struct RuntimeDebugBuilder {
/// Print a set of LLVM-IR Values or StringRefs via printf
///
/// This function emits a call to printf that will print the given arguments.
/// It is useful for debugging CPU programs. All arguments given in this list
/// will be automatically concatenated and the resulting string will be
/// printed atomically. We also support ArrayRef arguments, which can be used
/// to provide of id values.
///
/// @param Builder The builder used to emit the printer calls.
/// @param Args The list of values to print.
template <typename... Args>
static void createCPUPrinter(PollyIRBuilder &Builder, Args... args) {
std::vector<llvm::Value *> Vector;
createPrinter(Builder, /* CPU */ false, Vector, args...);
}
/// Print a set of LLVM-IR Values or StringRefs on an NVIDIA GPU.
///
/// This function emits a call to vprintf that will print the given
/// arguments from within a kernel thread. It is useful for debugging
/// CUDA program kernels. All arguments given in this list will be
/// automatically concatenated and the resulting string will be printed
/// atomically. We also support ArrayRef arguments, which can be used to
/// provide for example a list of thread-id values.
///
/// @param Builder The builder used to emit the printer calls.
/// @param Args The list of values to print.
template <typename... Args>
static void createGPUPrinter(PollyIRBuilder &Builder, Args... args) {
std::vector<llvm::Value *> Vector;
createPrinter(Builder, /* GPU */ true, Vector, args...);
}
private:
/// Handle Values.
template <typename... Args>
static void createPrinter(PollyIRBuilder &Builder, bool UseGPU,
std::vector<llvm::Value *> &Values,
llvm::Value *Value, Args... args) {
Values.push_back(Value);
createPrinter(Builder, UseGPU, Values, args...);
}
/// Handle StringRefs.
template <typename... Args>
static void createPrinter(PollyIRBuilder &Builder, bool UseGPU,
std::vector<llvm::Value *> &Values,
llvm::StringRef String, Args... args) {
Values.push_back(Builder.CreateGlobalStringPtr(String, "", 4));
createPrinter(Builder, UseGPU, Values, args...);
}
/// Handle ArrayRefs.
template <typename... Args>
static void createPrinter(PollyIRBuilder &Builder, bool UseGPU,
std::vector<llvm::Value *> &Values,
llvm::ArrayRef<llvm::Value *> Array, Args... args) {
if (Array.size() >= 2)
createPrinter(Builder, Values, Array[0], " ",
llvm::ArrayRef<llvm::Value *>(&Array[1], Array.size() - 1),
args...);
else if (Array.size() == 1)
createPrinter(Builder, UseGPU, Values, Array[0], args...);
else
createPrinter(Builder, UseGPU, Values, args...);
}
/// Print a list of Values.
static void createPrinter(PollyIRBuilder &Builder, bool UseGPU,
llvm::ArrayRef<llvm::Value *> Values);
/// Print a list of Values on a GPU.
static void createGPUPrinterT(PollyIRBuilder &Builder,
llvm::ArrayRef<llvm::Value *> Values);
/// Print a list of Values on a CPU.
static void createCPUPrinterT(PollyIRBuilder &Builder,
llvm::ArrayRef<llvm::Value *> Values);
/// Get a reference to the 'printf' function.
///
/// If the current module does not yet contain a reference to printf, we
/// insert a reference to it. Otherwise the existing reference is returned.
static llvm::Function *getPrintF(PollyIRBuilder &Builder);
/// Call printf
///
/// @param Builder The builder used to insert the code.
/// @param Format The format string.
/// @param Values The set of values to print.
static void createPrintF(PollyIRBuilder &Builder, std::string Format,
llvm::ArrayRef<llvm::Value *> Values);
/// Get (and possibly insert) a vprintf declaration into the module.
static llvm::Function *getVPrintF(PollyIRBuilder &Builder);
/// Call fflush
///
/// @parma Builder The builder used to insert the code.
static void createFlush(PollyIRBuilder &Builder);
/// Get (and possibly insert) a NVIDIA address space cast call.
static llvm::Function *getAddressSpaceCast(PollyIRBuilder &Builder,
unsigned Src, unsigned Dst,
unsigned SrcBits = 8,
unsigned DstBits = 8);
/// Get identifiers that describe the currently executed GPU thread.
///
/// The result will be a vector that if passed to the GPU printer will result
/// into a string (initialized to values corresponding to the printing
/// thread):
///
/// "> block-id: bidx bid1y bidz | thread-id: tidx tidy tidz "
static std::vector<llvm::Value *>
getGPUThreadIdentifiers(PollyIRBuilder &Builder);
};
} // namespace polly
extern bool PollyDebugPrinting;
#endif

View File

@@ -0,0 +1,74 @@
//===- Utils.h - Utility functions for code generation ----------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file contains utility functions for the code generation.
//===----------------------------------------------------------------------===//
#ifndef POLLY_CODEGEN_UTILS_H
#define POLLY_CODEGEN_UTILS_H
#include <utility>
namespace llvm {
class Pass;
class Value;
class BasicBlock;
class DominatorTree;
class RegionInfo;
class LoopInfo;
class BranchInst;
} // namespace llvm
namespace polly {
class Scop;
using BBPair = std::pair<llvm::BasicBlock *, llvm::BasicBlock *>;
/// Execute a Scop conditionally wrt @p RTC.
///
/// In the CFG the optimized code of the Scop is generated next to the
/// original code. Both the new and the original version of the code remain
/// in the CFG. A branch statement decides which version is executed based on
/// the runtime value of @p RTC.
///
/// Before transformation:
///
/// bb0
/// |
/// orig_scop
/// |
/// bb1
///
/// After transformation:
/// bb0
/// |
/// polly.splitBlock
/// / \.
/// | startBlock
/// | |
/// orig_scop new_scop
/// \ /
/// \ /
/// bb1 (joinBlock)
///
/// @param S The Scop to execute conditionally.
/// @param P A reference to the pass calling this function.
/// @param RTC The runtime condition checked before executing the new SCoP.
///
/// @return An std::pair:
/// - The first element is a BBPair of (StartBlock, EndBlock).
/// - The second element is the BranchInst which conditionally
/// branches to the SCoP based on the RTC.
///
std::pair<BBPair, llvm::BranchInst *>
executeScopConditionally(Scop &S, llvm::Value *RTC, llvm::DominatorTree &DT,
llvm::RegionInfo &RI, llvm::LoopInfo &LI);
} // namespace polly
#endif

View File

@@ -0,0 +1,26 @@
//===- polly/ScopPreparation.h - Code preparation pass ----------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// Prepare the Function for polyhedral codegeneration.
//
//===----------------------------------------------------------------------===//
#ifndef POLLY_CODEPREPARATION_H
#define POLLY_CODEPREPARATION_H
#include "llvm/IR/PassManager.h"
namespace polly {
struct CodePreparationPass : public llvm::PassInfoMixin<CodePreparationPass> {
llvm::PreservedAnalyses run(llvm::Function &F,
llvm::FunctionAnalysisManager &FAM);
};
} // namespace polly
#endif /* POLLY_CODEPREPARATION_H */

View File

@@ -0,0 +1,19 @@
//===- polly/Config.h ------------ Configuration of Polly -------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// Configuration of Polly.
//
//===----------------------------------------------------------------------===//
#ifndef POLLY_CONFIG_H
#define POLLY_CONFIG_H
#cmakedefine CUDA_FOUND
#cmakedefine GPU_CODEGEN
#endif

View File

@@ -0,0 +1,48 @@
//===------ DeLICM.h --------------------------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// Undo the effect of Loop Invariant Code Motion (LICM) and
// GVN Partial Redundancy Elimination (PRE) on SCoP-level.
//
// Namely, remove register/scalar dependencies by mapping them back to array
// elements.
//
//===----------------------------------------------------------------------===//
#ifndef POLLY_DELICM_H
#define POLLY_DELICM_H
#include "polly/Support/GICHelper.h"
namespace llvm {
class PassRegistry;
class Pass;
} // namespace llvm
namespace polly {
/// Create a new DeLICM pass instance.
llvm::Pass *createDeLICMPass();
/// Determine whether two lifetimes are conflicting.
///
/// Used by unittesting.
bool isConflicting(isl::union_set ExistingOccupied,
isl::union_set ExistingUnused, isl::union_map ExistingKnown,
isl::union_map ExistingWrites,
isl::union_set ProposedOccupied,
isl::union_set ProposedUnused, isl::union_map ProposedKnown,
isl::union_map ProposedWrites,
llvm::raw_ostream *OS = nullptr, unsigned Indent = 0);
} // namespace polly
namespace llvm {
void initializeDeLICMPass(llvm::PassRegistry &);
} // namespace llvm
#endif /* POLLY_DELICM_H */

View File

@@ -0,0 +1,322 @@
//===--- polly/DependenceInfo.h - Polyhedral dependency analysis *- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// Calculate the data dependency relations for a Scop using ISL.
//
// The integer set library (ISL) from Sven has an integrated dependency analysis
// to calculate data dependences. This pass takes advantage of this and
// calculates those dependences of a Scop.
//
// The dependences in this pass are exact in terms that for a specific read
// statement instance only the last write statement instance is returned. In
// case of may-writes, a set of possible write instances is returned. This
// analysis will never produce redundant dependences.
//
//===----------------------------------------------------------------------===//
#ifndef POLLY_DEPENDENCE_INFO_H
#define POLLY_DEPENDENCE_INFO_H
#include "polly/ScopPass.h"
#include "isl/ctx.h"
struct isl_pw_aff;
struct isl_union_map;
struct isl_union_set;
struct isl_map;
struct isl_set;
struct clast_for;
using namespace llvm;
namespace polly {
class Scop;
class ScopStmt;
class MemoryAccess;
/// The accumulated dependence information for a SCoP.
///
/// The Dependences struct holds all dependence information we collect and
/// compute for one SCoP. It also offers an interface that allows users to
/// query only specific parts.
struct Dependences {
// Granularities of the current dependence analysis
enum AnalysisLevel {
AL_Statement = 0,
// Distinguish accessed memory references in the same statement
AL_Reference,
// Distinguish memory access instances in the same statement
AL_Access,
NumAnalysisLevels
};
/// Map type for reduction dependences.
using ReductionDependencesMapTy = DenseMap<MemoryAccess *, isl_map *>;
/// Map type to associate statements with schedules.
using StatementToIslMapTy = DenseMap<ScopStmt *, isl_map *>;
/// The type of the dependences.
///
/// Reduction dependences are separated from RAW/WAW/WAR dependences because
/// we can ignore them during the scheduling. That's because the order
/// in which the reduction statements are executed does not matter. However,
/// if they are executed in parallel we need to take additional measures
/// (e.g, privatization) to ensure a correct result. The (reverse) transitive
/// closure of the reduction dependences are used to check for parallel
/// executed reduction statements during code generation. These dependences
/// connect all instances of a reduction with each other, they are therefore
/// cyclic and possibly "reversed".
enum Type {
// Write after read
TYPE_WAR = 1 << 0,
// Read after write
TYPE_RAW = 1 << 1,
// Write after write
TYPE_WAW = 1 << 2,
// Reduction dependences
TYPE_RED = 1 << 3,
// Transitive closure of the reduction dependences (& the reverse)
TYPE_TC_RED = 1 << 4,
};
const std::shared_ptr<isl_ctx> &getSharedIslCtx() const { return IslCtx; }
/// Get the dependences of type @p Kinds.
///
/// @param Kinds This integer defines the different kinds of dependences
/// that will be returned. To return more than one kind, the
/// different kinds are 'ored' together.
__isl_give isl_union_map *getDependences(int Kinds) const;
/// Report if valid dependences are available.
bool hasValidDependences() const;
/// Return the reduction dependences caused by @p MA.
///
/// @return The reduction dependences caused by @p MA or nullptr if none.
__isl_give isl_map *getReductionDependences(MemoryAccess *MA) const;
/// Return all reduction dependences.
const ReductionDependencesMapTy &getReductionDependences() const {
return ReductionDependences;
}
/// Check if a partial schedule is parallel wrt to @p Deps.
///
/// @param Schedule The subset of the schedule space that we want to
/// check.
/// @param Deps The dependences @p Schedule needs to respect.
/// @param MinDistancePtr If not nullptr, the minimal dependence distance will
/// be returned at the address of that pointer
///
/// @return Returns true, if executing parallel the outermost dimension of
/// @p Schedule is valid according to the dependences @p Deps.
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 new schedule is valid.
///
/// @param S The current SCoP.
/// @param NewSchedules The new schedules
///
/// @return True if the new schedule is valid, false if it reverses
/// dependences.
bool isValidSchedule(Scop &S, StatementToIslMapTy *NewSchedules) const;
/// Print the stored dependence information.
void print(llvm::raw_ostream &OS) const;
/// Dump the dependence information stored to the dbgs stream.
void dump() const;
/// Return the granularity of this dependence analysis.
AnalysisLevel getDependenceLevel() { return Level; }
/// Allow the DependenceInfo access to private members and methods.
///
/// To restrict access to the internal state, only the DependenceInfo class
/// is able to call or modify a Dependences struct.
friend struct DependenceAnalysis;
friend struct DependenceInfoPrinterPass;
friend class DependenceInfo;
friend class DependenceInfoWrapperPass;
/// Destructor that will free internal objects.
~Dependences() { releaseMemory(); }
private:
/// Create an empty dependences struct.
explicit Dependences(const std::shared_ptr<isl_ctx> &IslCtx,
AnalysisLevel Level)
: RAW(nullptr), WAR(nullptr), WAW(nullptr), RED(nullptr), TC_RED(nullptr),
IslCtx(IslCtx), Level(Level) {}
/// Calculate and add at the privatization dependences.
void addPrivatizationDependences();
/// Calculate the dependences for a certain SCoP @p S.
void calculateDependences(Scop &S);
/// Set the reduction dependences for @p MA to @p Deps.
void setReductionDependences(MemoryAccess *MA, __isl_take isl_map *Deps);
/// Free the objects associated with this Dependences struct.
///
/// The Dependences struct will again be "empty" afterwards.
void releaseMemory();
/// The different basic kinds of dependences we calculate.
isl_union_map *RAW;
isl_union_map *WAR;
isl_union_map *WAW;
/// The special reduction dependences.
isl_union_map *RED;
/// The (reverse) transitive closure of reduction dependences.
isl_union_map *TC_RED;
/// Mapping from memory accesses to their reduction dependences.
ReductionDependencesMapTy ReductionDependences;
/// Isl context from the SCoP.
std::shared_ptr<isl_ctx> IslCtx;
/// Granularity of this dependence analysis.
const AnalysisLevel Level;
};
struct DependenceAnalysis : public AnalysisInfoMixin<DependenceAnalysis> {
static AnalysisKey Key;
struct Result {
Scop &S;
std::unique_ptr<Dependences> D[Dependences::NumAnalysisLevels];
/// Return the dependence information for the current SCoP.
///
/// @param Level The granularity of dependence analysis result.
///
/// @return The dependence analysis result
///
const Dependences &getDependences(Dependences::AnalysisLevel Level);
/// Recompute dependences from schedule and memory accesses.
const Dependences &recomputeDependences(Dependences::AnalysisLevel Level);
};
Result run(Scop &S, ScopAnalysisManager &SAM,
ScopStandardAnalysisResults &SAR);
};
struct DependenceInfoPrinterPass
: public PassInfoMixin<DependenceInfoPrinterPass> {
DependenceInfoPrinterPass(raw_ostream &OS) : OS(OS) {}
PreservedAnalyses run(Scop &S, ScopAnalysisManager &,
ScopStandardAnalysisResults &, SPMUpdater &);
raw_ostream &OS;
};
class DependenceInfo : public ScopPass {
public:
static char ID;
/// Construct a new DependenceInfo pass.
DependenceInfo() : ScopPass(ID) {}
/// Return the dependence information for the current SCoP.
///
/// @param Level The granularity of dependence analysis result.
///
/// @return The dependence analysis result
///
const Dependences &getDependences(Dependences::AnalysisLevel Level);
/// Recompute dependences from schedule and memory accesses.
const Dependences &recomputeDependences(Dependences::AnalysisLevel Level);
/// Compute the dependence information for the SCoP @p S.
bool runOnScop(Scop &S) override;
/// Print the dependences for the given SCoP to @p OS.
void printScop(raw_ostream &OS, Scop &) const override;
/// Release the internal memory.
void releaseMemory() override {
for (auto &d : D)
d.reset();
}
/// Register all analyses and transformation required.
void getAnalysisUsage(AnalysisUsage &AU) const override;
private:
Scop *S;
/// Dependences struct for the current SCoP.
std::unique_ptr<Dependences> D[Dependences::NumAnalysisLevels];
};
/// Construct a new DependenceInfoWrapper pass.
class DependenceInfoWrapperPass : public FunctionPass {
public:
static char ID;
/// Construct a new DependenceInfoWrapper pass.
DependenceInfoWrapperPass() : FunctionPass(ID) {}
/// Return the dependence information for the given SCoP.
///
/// @param S SCoP object.
/// @param Level The granularity of dependence analysis result.
///
/// @return The dependence analysis result
///
const Dependences &getDependences(Scop *S, Dependences::AnalysisLevel Level);
/// Recompute dependences from schedule and memory accesses.
const Dependences &recomputeDependences(Scop *S,
Dependences::AnalysisLevel Level);
/// Compute the dependence information on-the-fly for the function.
bool runOnFunction(Function &F) override;
/// Print the dependences for the current function to @p OS.
void print(raw_ostream &OS, const Module *M = nullptr) const override;
/// Release the internal memory.
void releaseMemory() override { ScopToDepsMap.clear(); }
/// Register all analyses and transformation required.
void getAnalysisUsage(AnalysisUsage &AU) const override;
private:
using ScopToDepsMapTy = DenseMap<Scop *, std::unique_ptr<Dependences>>;
/// Scop to Dependence map for the current function.
ScopToDepsMapTy ScopToDepsMap;
};
} // namespace polly
namespace llvm {
class PassRegistry;
void initializeDependenceInfoPass(llvm::PassRegistry &);
void initializeDependenceInfoWrapperPassPass(llvm::PassRegistry &);
} // namespace llvm
#endif

View File

@@ -0,0 +1,38 @@
//===------ FlattenAlgo.h --------------------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// Main algorithm of the FlattenSchedulePass. This is a separate file to avoid
// the unittest for this requiring linking against LLVM.
//
//===----------------------------------------------------------------------===//
#ifndef POLLY_FLATTENALGO_H
#define POLLY_FLATTENALGO_H
#include "polly/Support/GICHelper.h"
namespace polly {
/// Recursively flatten a schedule.
///
/// Reduce the number of scatter dimensions as much as possible without changing
/// the relative order of instances in a schedule. Ideally, this results in a
/// single scatter dimension, but it may not always be possible to combine
/// dimensions, eg. if a dimension is unbounded. In worst case, the original
/// schedule is returned.
///
/// Schedules with fewer dimensions may be easier to understand for humans, but
/// it should make no difference to the computer.
///
/// @param Schedule The input schedule.
///
/// @return The flattened schedule.
isl::union_map flattenSchedule(isl::union_map Schedule);
} // namespace polly
#endif /* POLLY_FLATTENALGO_H */

View File

@@ -0,0 +1,32 @@
//===------ FlattenSchedule.h ----------------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// Try to reduce the number of scatter dimension. Useful to make isl_union_map
// schedules more understandable. This is only intended for debugging and
// unittests, not for optimizations themselves.
//
//===----------------------------------------------------------------------===//
#ifndef POLLY_FLATTENSCHEDULE_H
#define POLLY_FLATTENSCHEDULE_H
namespace llvm {
class PassRegistry;
class Pass;
} // namespace llvm
namespace polly {
llvm::Pass *createFlattenSchedulePass();
} // namespace polly
namespace llvm {
void initializeFlattenSchedulePass(llvm::PassRegistry &);
} // namespace llvm
#endif /* POLLY_FLATTENSCHEDULE_H */

View File

@@ -0,0 +1,33 @@
//===- ForwardOpTree.h ------------------------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// Move instructions between statements.
//
//===----------------------------------------------------------------------===//
#ifndef POLLY_FORWARDOPTREE_H
#define POLLY_FORWARDOPTREE_H
namespace llvm {
class PassRegistry;
void initializeForwardOpTreePass(PassRegistry &);
} // namespace llvm
namespace polly {
class ScopPass;
ScopPass *createForwardOpTreePass();
} // namespace polly
#endif // POLLY_FORWARDOPTREE_H

Some files were not shown because too many files have changed in this diff Show More