Program Listing for File AutoTuningInterface.h#
↰ Return to documentation for file (src/midend/programTransformation/loopProcessing/driver/AutoTuningInterface.h)
#ifndef TUNING_H
#define TUNING_H
#include <map>
#include <string>
#include <list>
#include <AstInterface.h>
#include <LoopTree.h>
#include <LoopTreeTransform.h>
class POETProgram;
class XformVar;
class CodeVar;
class LocalVar;
class POETCode;
class LoopTreeNode;
class LoopBlocking;
class ParallelizeLoop;
class ArrayAbstractionInterface;
class CopyArrayConfig;
/*QY: map loop tree nodes and AST nodes to tracing variables in POET */
class LoopTreeCodeGenInfo;
class HandleMap : public LoopTreeObserver, public AstObserver
{
public: typedef std::map<const void*, LocalVar*> AstMapType;
private:
int loopindex, bodyindex;
std::vector<LocalVar*> topHandles;
std::map<const LoopTreeNode*,LocalVar*> loopMap;
std::map<LocalVar*,LocalVar*> bodyMap;
AstMapType astMap;
LocalVar* NewLoopHandle();
LocalVar* NewBodyHandle();
virtual void UpdateCodeGen(const LoopTreeCodeGenInfo& info);
virtual void UpdateDeleteNode(const LoopTreeNode* n);
virtual void ObserveCopyAst(AstInterfaceImpl& fa, const AstNodePtr& orig, const AstNodePtr& n);
public:
~HandleMap();
HandleMap() :loopindex(0),bodyindex(0) {}
/*QY: return the number of loop handles created*/
int NumOfLoops() { return loopindex; }
int NumOfBodies() { return bodyindex; }
std::string to_string() const;
/*QY:return a POET trace handle for the given AST or loop tree node*/
LocalVar* GetLoopHandle(AstInterface& fa, const AstNodePtr& loop);
LocalVar* GetLoopHandle(LoopTreeNode* loop);
LocalVar* GetBodyHandle(LoopTreeNode* loop, LocalVar* loopHandle);
/*QY:sort all the loop nest handles with AST root; return the top handles*/
const std::vector<LocalVar*>& GetTopTraceHandles() { return topHandles; }
void GenTraceHandles(POETProgram& poet, AstInterface& fa);
void GenTraceHandles(POETProgram& poet, LoopTreeNode* r);
LocalVar* HasBodyHandle(LocalVar* loopHandle)
{ std::map<LocalVar*,LocalVar*>::const_iterator p =
bodyMap.find(loopHandle);
if (p == bodyMap.end()) return 0;
return (*p).second;
}
/*QY: return trace handle for extra-top and decl of transformations*/
static LocalVar* GetTraceTarget();
static LocalVar* GetTraceTop(const std::string& handleName);
static LocalVar* GetTraceDecl(LocalVar* top);
static LocalVar* GetTracePrivate(LocalVar* top);
static LocalVar* FindTracePrivate(LocalVar* top);
static LocalVar* GetTraceInclude();
static LocalVar* FindTraceInclude();
static LocalVar* GetTraceCleanup(LocalVar* top);
static LocalVar* FindTraceCleanup(LocalVar* top);
static LocalVar* DeclareTraceInclude(POETProgram& poet, int& lineNo);
/*QY: generate commands to start tracing; return the top trace handle */
static LocalVar* GenTraceCommand(POETProgram& poet,
const std::vector<LocalVar*>& handles, LocalVar* target, int& lineNo);
};
class AutoTuningInterface;
/*QY: specification of program transformations to be implemented in POET*/
class OptSpec {
protected:
POETCode* target;
std::string targetName;
OptSpec(POETCode* _target, const std::string& _name)
: target(_target), targetName(_name) {}
protected:
struct LoopInfo { LocalVar* handle; std::string ivarname;
LoopInfo(LocalVar* _handle=0, const std::string& name="")
: handle(_handle),ivarname(name) {}
};
public:
typedef enum {PARLOOP, BLOCK, UNROLL, COPY_ARRAY, BLOCK_COPY_ARRAY, FINITE_DIFF,OPT_ENUM_SIZE} OptEnum;
typedef enum {OPT_NONE=0,OPT_PAR_LEVEL = 1,OPT_CACHE_LEVEL = 2, OPT_PAR_CACHE_LEVEL=3, OPT_REG_LEVEL = 4, OPT_CACHE_REG_LEVEL=6, OPT_PROC_LEVEL=8, OPT_POST_PAR_LEVEL=16, OPT_CLEANUP_LEVEL=32, OPT_CACHE_CLEANUP_LEVEL=34, OPT_CACHE_REG_CLEANUP_LEVEL=38, OPT_CACHE_PROC_CLEANUP_LEVEL=42, OPT_ALL=63, OPT_LEVEL_MAX=32} OptLevel;
typedef std::vector<OptSpec*>::const_iterator OptIterator;
POETCode* get_target() const { return target; }
std::string get_targetName() const { return targetName; }
virtual ~OptSpec() {}
virtual OptEnum get_enum() const = 0;
virtual OptLevel get_opt_level() const = 0;
virtual std::string get_opt_prefix(OptLevel optLevel) = 0;
virtual std::string to_string(OptLevel level) = 0;
/*QY: return xform declaration; modify lineNo;
append traceMod with variables that need to be kept track of; */
virtual void insert_xformDecl(POETProgram& poet, LocalVar* top, POETCode*& traceMod, int& lineNo) {}
/*QY: return xform evaluation; modify lineNo with new line number */
virtual POETCode* gen_xformEval(POETProgram& poet, LocalVar* top,
POETCode* traceMod, OptLevel optLevel, int& lineNo) = 0;
/*QY: insert parameter decl; modify lineNo with new line number;
return constrains on parameter values */
virtual POETCode* insert_paramDecl(AutoTuningInterface& tune,
POETProgram& poet, OptLevel optLevel, int& lineNo) { return NULL; }
friend class AutoTuningInterface;
protected:
};
/*QY: used for specifying non-perfect loops in loop blocking */
struct FuseLoopInfo
{
typedef std::pair<LoopTreeNode*,int> Entry;
std::vector<Entry> loops; /*QY: the loops being fused*/
LoopTreeNode *pivotLoop; /*QY: the pivot loop*/
FuseLoopInfo(LoopTreeNode* _pivot=0) : pivotLoop(_pivot) {}
static POETCode* toPOET(HandleMap& handleMap, const FuseLoopInfo& info);
};
class BlockSpec;
/*QY: interface for POET-code generation*/
class AutoTuningInterface
{
HandleMap handleMap;
std::vector<OptSpec*> optvec;
std::string inputName;
POETProgram* poet;
int lineNo;
LocalVar* target;
static ArrayAbstractionInterface* arrayInfo;
static POETCode* arrayAccess;
void BuildPOETProgram();
void Gen_POET_opt();
public:
AutoTuningInterface(const std::string& _fname)
: inputName(_fname), poet(0), lineNo(-1), target(0) {}
~AutoTuningInterface() ;
void set_astInterface(AstInterface& fa);
static void set_arrayInfo( ArrayAbstractionInterface& arrayInfo);
static POETCode* CreateArrayRef(POETProgram& poet, POETCode* arr, POETCode* subscript, int dim);
static POETCode* Access2Subscript(POETProgram& poet, POETCode* ref, int dim);
static POETCode* Access2Array(POETProgram& poet, POETCode* ref, int dim);
LocalVar* get_target() { return target; }
/*QY: whether loop has been blocked; if yes, at which level*/
BlockSpec* LoopBlocked(LocalVar* loop, unsigned* index=0);
void UnrollLoop(AstInterface& fa, const AstNodePtr& loop, int unrollsize);
void BlockLoops(LoopTreeNode* outerLoop, LoopTreeNode* innerLoop, LoopBlocking* config, const std::vector<FuseLoopInfo>* nonperfect= 0);
void ParallelizeLoop(LoopTreeNode* outerLoop, int bsize);
void CopyArray( CopyArrayConfig& config, LoopTreeNode* repl);
bool ApplyOpt(LoopTreeNode* root);
bool ApplyOpt(AstInterface& fa);
void GenOutput();
void gen_specification();
};
/*QY: loop unrolling optimization*/
class UnrollSpec : public OptSpec
{
#if 0 // [Robb Matzke 2021-03-17]: unused
/*QY: relevant POET invocation names
(need to be consistent with POET/lib/opt.pi*/
LocalVar* paramVar;
#endif
public:
UnrollSpec(LocalVar* handle, int unrollSize);
virtual OptEnum get_enum() const { return UNROLL; }
virtual OptLevel get_opt_level() const { return OPT_PROC_LEVEL; }
virtual std::string get_opt_prefix(OptLevel optLevel) { return "unroll"; }
virtual std::string to_string(OptLevel level);
/*QY: insert parameter decl; modify lineNo with new line number;
return constrains on parameter values */
virtual POETCode*
insert_paramDecl(AutoTuningInterface& tune,
POETProgram& poet, OptLevel optlevel, int& lineno);
virtual POETCode* gen_xformEval(POETProgram& poet, LocalVar* top,
POETCode* traceMod, OptLevel optLevel, int& lineNo);
/*QY: return a unique name that save relevant info. for a loop unroll optimization*/
static LocalVar* get_unrollSizeVar(const std::string& handleName);
};
class ParLoopSpec : public OptSpec
{
#if 0 // [Robb Matzke 2021-03-17]: unused
POETCode* privateVars;
POETCode* ivarName, *bvarName;
LocalVar* parVar, *parblockVar;
#endif
public:
ParLoopSpec(LocalVar* outerHandle, LoopTreeNode* loop, int bsize);
virtual OptEnum get_enum() const { return PARLOOP; }
virtual OptLevel get_opt_level() const { return OPT_PAR_LEVEL; }
virtual std::string get_opt_prefix(OptLevel optLevel) { return "par"; }
virtual std::string to_string(OptLevel level);
/*QY: insert parameter decl;
modify lineNo with new line number;
return constrains on parameter values */
virtual POETCode* insert_paramDecl(AutoTuningInterface& tune,
POETProgram& poet, OptLevel optlevel, int& lineno);
virtual void insert_xformDecl(POETProgram& poet, LocalVar* top, POETCode*& traceMod, int& lineNo);
virtual POETCode* gen_xformEval(POETProgram& poet, LocalVar* top,
POETCode* traceMod, OptLevel optLevel, int& lineNo);
};
/*QY: loop blocking optimization*/
class BlockSpec : public OptSpec
{
std::vector<LoopInfo> loopVec; /*QY: the loops to block */
#if 0 // [Robb Matzke 2021-03-17]: unused
POETCode* nonperfect; /*QY: the non-perfect loops*/
LocalVar* blockPar, *ujPar;
HandleMap& handleMap;
#endif
unsigned loopnum;
/*QY: compute the blocking dimension configuration */
POETCode* compute_blockDim(LocalVar* paramVar);
public:
BlockSpec(HandleMap& handleMap, LocalVar* outerHandle, LoopTreeNode* innerLoop, LoopBlocking* config, const std::vector<FuseLoopInfo>* nonperfect=0);
virtual OptEnum get_enum() const { return BLOCK; }
virtual OptLevel get_opt_level() const { return OPT_CACHE_REG_CLEANUP_LEVEL; }
virtual std::string get_opt_prefix(OptLevel optLevel)
{
switch (optLevel) {
case OPT_CACHE_LEVEL: return "block";
case OPT_REG_LEVEL: return "unrolljam";
case OPT_CLEANUP_LEVEL: return "cleanup";
default: return "";
}
}
virtual std::string to_string(OptLevel level);
unsigned get_loopnum() const { return loopnum; }
const LoopInfo& get_loop(int i) const { return loopVec[i]; }
/*QY: insert parameter decl;
modify lineNo with new line number;
return constrains on parameter values */
virtual POETCode* insert_paramDecl(AutoTuningInterface& tune,
POETProgram& poet, OptLevel optlevel, int& lineno);
/*QY: return xform declaration; modify lineNo;
append traceMod with variables that need to be kept track of; */
virtual void insert_xformDecl(POETProgram& poet, LocalVar* top, POETCode*& traceMod, int& lineNo);
virtual POETCode* gen_xformEval(POETProgram& poet, LocalVar* top,
POETCode* traceMod, OptLevel optLevel, int& lineNo);
/*QY: return unique names that save relevant info. for a blocking opt*/
static LocalVar* get_blockSizeVar(const std::string& handleName);
static LocalVar* get_unrollJamSizeVar(const std::string& handleName);
static LocalVar* get_blockDimVar(const std::string& handleName);
static LocalVar* get_blockTileVar(const std::string& handleName);
static LocalVar* get_blockSplitVar(const std::string& handleName);
static POETCode* get_blockSize(const std::string& handleName, int level);
static POETCode* get_ujSize(const std::string& handleName, int level);
};
/*QY: array copy */
class CopyArraySpec : public OptSpec
{
std::vector<SymbolicVal> subscriptVec;
void compute_copySubscript(LocalVar* dimVar=0);
protected:
/*QY: relevant POET invocation names
(need to be consistent with POET/lib/opt.pi*/
static int index;
SelectArray sel; /*QY: which array elements to copy*/
CopyArrayOpt opt; /*QY: alloc/init/save/free configurations */
std::vector<LoopInfo> loopVec; /*QY: the surrounding loops*/
std::vector<int> placeVec; /* QY: placement of loop dim*/
POETCode* permute; /* permutation of array dimension*/
std::string cur_id;
int get_loopLevel(const SelectArray::ArrayDim& cur);
/* QY: return the subscript pattern for the array references.
beforeCopy: before or after the copy optimization is done */
POETCode* compute_copySubscript(POETProgram& poet, bool afterCopy);
/* QY: return a list of copy dimensions */
POETCode* compute_copyDim(POETProgram& poet, bool scalar);
/* QY: compute internal info for copy; need to be done in constructor*/
void compute_config();
POETCode* gen_copyInvoke(POETProgram& poet, POETCode* cphandle,
LocalVar* top, POETCode* cpblock, bool scalar,
POETCode* traceMod, int& lineNo);
/*QY: insert parameter decl;
modify lineNo with new line number;
return constrains on parameter values */
virtual POETCode* insert_paramDecl(AutoTuningInterface& tune,
POETProgram& poet, OptLevel optLevel, int& lineNo);
CopyArraySpec(POETCode* input, const std::string& name,
CopyArrayConfig& config)
:OptSpec(input,name),sel(config.get_arr()),opt(config.get_opt()),permute(0)
{}
public:
CopyArraySpec(HandleMap& handleMap,POETCode* input,const std::string& name, CopyArrayConfig& config, LoopTreeNode* root);
virtual OptEnum get_enum() const { return COPY_ARRAY; }
virtual OptLevel get_opt_level() const { return OPT_REG_LEVEL; }
/*QY: insert xform declaration; append traceMod with variables that need to be kept track of;
return the new line number */
virtual void insert_xformDecl(POETProgram& poet, LocalVar* top,
POETCode*& traceMod, int& lineNo);
virtual POETCode* gen_xformEval(POETProgram& poet, LocalVar* top,
POETCode* traceMod, OptLevel optLevel, int& lineNo);
static bool do_scalarRepl(OptLevel optLevel)
{
switch (optLevel) {
case OPT_CACHE_LEVEL: return false;
case OPT_REG_LEVEL: return true;
default: ROSE_ABORT();
}
}
std::string get_opt_prefix(OptLevel optLevel)
{
switch (optLevel) {
case OPT_CACHE_LEVEL: return "copy"+cur_id;
case OPT_REG_LEVEL: return "scalar"+cur_id;
default: ROSE_ABORT();
}
}
virtual std::string to_string(OptLevel level);
/* QY: global variable for tracing array dimension and ref exp */
LocalVar* get_dimVar(POETProgram& poet, const std::string& arrname);
LocalVar* get_arrVar(POETProgram& poet, const std::string& arrname);
/*copy buffer name*/
std::string get_bufName(const std::string& arrname, bool scalar)
{ return (scalar)? arrname+"_"+cur_id+"_scalar" : arrname+"_buf"; }
/* QY: copy induction variable name */
std::string get_cpIvarName(const std::string& arrname, int sel_index)
{
assert( sel_index >= 0);
std::string copyIvar = targetName + "_" + cur_id+"_"+arrname + "_cp";
copyIvar.push_back('0' + sel_index);
return copyIvar;
}
/*QY: declaring copy induction variables*/
POETCode* gen_cpIvarDecl(POETProgram& poet, LocalVar* top,
const std::string& arrname, int dim, bool cpblock);
/*QY: the copy invocation*/
POETCode*
gen_copyInvoke(POETProgram& poet, POETCode* handle,LocalVar* top,
const std::string& arrname, POETCode* arrelemType, CopyArrayOpt opt,
POETCode* cpDim, POETCode* cpblock, bool scalar, POETCode* traceMod);
};
/*QY: array copy associated with blocking */
class BlockCopyArraySpec : public CopyArraySpec
{
/*QY: relevant POET invocation names
(need to be consistent with POET/lib/opt.pi*/
POETCode* AfterCopy_dimSize(POETProgram& poet);
POETCode* compute_copyBlock(POETProgram& poet);
/*QY: return handle for scalar repl*/
LocalVar* scalarRepl_handle(POETProgram& poet);
static std::string get_fdName(const std::string& arrname)
{ return arrname+"_fd"; } /*finite difference var name*/
/*QY:compute strenghth reduction dimension configuration
: return outermost loop level to start reduction */
int compute_fdConfig(POETProgram& poet, POETCode* handle, bool scalar,
std::vector<POETCode*>& expDimVec_cp, /*QY: to go with copying */
std::vector<POETCode*>& expDimVec_nocp);/*QY: to go without copying*/
public:
BlockCopyArraySpec(LocalVar* handle, CopyArrayConfig& config,
BlockSpec& _block);
virtual OptEnum get_enum() const { return BLOCK_COPY_ARRAY; }
virtual OptLevel get_opt_level() const { return OPT_CACHE_REG_LEVEL; }
virtual POETCode* gen_xformEval(POETProgram& poet, LocalVar* top,
POETCode* traceMod, OptLevel optLevel, int& lineNo);
};
#endif