diff options
| author | Tuowen Zhao <ztuowen@gmail.com> | 2016-10-03 14:39:24 -0600 | 
|---|---|---|
| committer | Tuowen Zhao <ztuowen@gmail.com> | 2016-10-03 14:39:24 -0600 | 
| commit | 342af96cd123860b3fbe0fe9b0669627cefca1cc (patch) | |
| tree | b691d3fb21d1c9907076176db6d40137d22d5b1a /include | |
| parent | d2176835fc6e497a6c3e19b4630745c3911bde2c (diff) | |
| download | chill-342af96cd123860b3fbe0fe9b0669627cefca1cc.tar.gz chill-342af96cd123860b3fbe0fe9b0669627cefca1cc.tar.bz2 chill-342af96cd123860b3fbe0fe9b0669627cefca1cc.zip  | |
doc
Diffstat (limited to 'include')
| -rw-r--r-- | include/dep.hh | 19 | ||||
| -rw-r--r-- | include/ir_code.hh | 124 | ||||
| -rw-r--r-- | include/irtools.hh | 57 | ||||
| -rw-r--r-- | include/loop.hh | 109 | 
4 files changed, 207 insertions, 102 deletions
diff --git a/include/dep.hh b/include/dep.hh index ffd2db5..035d382 100644 --- a/include/dep.hh +++ b/include/dep.hh @@ -6,6 +6,19 @@  #include "ir_code.hh"  #include "chill_error.hh" +/*! + * \file + * \brief Data dependence vector and graph. + * + * All dependence vectors are normalized, i.e., the first non-zero distance + * must be positve. Thus the correct dependence meaning can be given based on + * source/destination pair's read/write type. Suppose for a dependence vector + * 1, 0~5, -3), we want to permute the first and the second dimension, + * the result would be two dependence vectors (0, 1, -3) and (1~5, 1, -3). + * All operations on dependence vectors are non-destructive, i.e., new + * dependence vectors are returned. + */ +  enum DependenceType {    DEP_W2R, DEP_R2W, DEP_W2W, DEP_R2R, DEP_CONTROL, DEP_UNKNOWN  }; @@ -21,8 +34,8 @@ struct DependenceVector {    bool from_same_stmt; // Manu    bool is_reduction_cand; // Manu -  bool is_reduction; // used to identify a class of flow dependence -  // that can be broken +  bool is_reduction; //!< used to identify a class of flow dependencies that can be broken +    std::vector<omega::coef_t> lbounds;    std::vector<omega::coef_t> ubounds; @@ -54,7 +67,7 @@ struct DependenceVector {    bool has_been_carried_before(int dim) const; -  // the following functions will be cleaned up or removed later +  // TODO the following functions will be cleaned up or removed later    bool isZero() const;    bool isPositive() const; diff --git a/include/ir_code.hh b/include/ir_code.hh index 8de0f01..b56ce41 100644 --- a/include/ir_code.hh +++ b/include/ir_code.hh @@ -23,40 +23,48 @@  #define IR_CODE_HH  #include <ir_enums.hh> -  #include <chillAST/chillASTs.hh> -  #include <vector> - -// needed for omega::coef_t below -#include <basic/util.h>   // in omega ... why is this not in CG_output*.h? -  #include <code_gen/CG_outputRepr.h>  #include <code_gen/CG_outputBuilder.h> +/*! + * \file + * \brief CHiLL's compiler intermediate representation interface that extends Omega's builder interface to accomodate compiler analyses and extra code generation. + * + * Unlike CG_outputRepr, IR_Symbol,IR_Ref and IR_Control are place holders + * to the underlying code, thus deleting or duplicating them does not affect + * the actual code.  Similar to Omega builder's memory allocation strategy, + * all non-const pointer parameters of CG_outputRepr/IR_Symbol/IR_Ref/IR_Control + * are destroyed after the call. + */  class IR_Code; // forward declaration - -// Base abstract class for scalar and array symbols.  This is a place -// holder for related declaration in IR code. +/*! + * @brief Base abstract class for scalar and array symbols. + * + * This is a place holder for related declaration in IR code. + */  struct IR_Symbol {    const IR_Code *ir_; -  virtual ~IR_Symbol() {/* ir_ is not the responsibility of this object */} +  //! ir_ is not the responsibility of this object +  virtual ~IR_Symbol() { } -  virtual int n_dim() const = 0; // IR_Symbol +  virtual int n_dim() const = 0;    virtual std::string name() const = 0;    virtual bool operator==(const IR_Symbol &that) const = 0;    virtual bool operator!=(const IR_Symbol &that) const { return !(*this == that); } -  virtual IR_Symbol *clone() const = 0;  /* shallow copy */ +  //! shallow copy +  virtual IR_Symbol *clone() const = 0; -  virtual bool isScalar() const { return false; } // default -  virtual bool isArray() const { return false; } // default -  virtual bool isPointer() const { return false; } // default +  virtual bool isScalar() const { return false; } +  virtual bool isArray() const { return false; } +  virtual bool isPointer() const { return false; }    //IR_SYMBOL_TYPE symtype; // base type: int, float, double, struct, .... typedef'd something    //IR_SYMBOL_TYPE getDatatype() ;  @@ -87,7 +95,6 @@ struct IR_ArraySymbol : public IR_Symbol {    bool isArray() const { return true; }  }; -  struct IR_PointerSymbol : public IR_Symbol {    virtual ~IR_PointerSymbol() {} @@ -100,14 +107,18 @@ struct IR_PointerSymbol : public IR_Symbol {    bool isPointer() const { return true; }  }; -// Base abstract class for scalar and array references.  This is a -// place holder for related code in IR code. + +/*! + * @brief Base abstract class for scalar and array references. + * + * This is a place holder for related code in IR code. + */  struct IR_Ref {    const IR_Code *ir_; +  //! ir_ is not the responsibility of this object +  virtual ~IR_Ref() { } -  virtual ~IR_Ref() {/* ir_ is not the responsibility of this object */} - -  virtual int n_dim() const = 0; // IR_Ref +  virtual int n_dim() const = 0;    virtual bool is_write() const = 0;    virtual std::string name() const = 0; @@ -118,7 +129,8 @@ struct IR_Ref {    virtual omega::CG_outputRepr *convert() = 0; -  virtual IR_Ref *clone() const = 0;  /* shallow copy */ +  //! shallow copy +  virtual IR_Ref *clone() const = 0;    virtual void Dump() const {      fprintf(stderr, "some IR_*Ref needs to implement Dump()\n");      int *i = 0; @@ -236,15 +248,17 @@ struct IR_PointerArrayRef : public IR_Ref {  struct IR_Block; -// Base abstract class for code structures.  This is a place holder -// for the actual structure in the IR code.  However, in cases that -// original source code may be transformed during loop initialization -// such as converting a while loop to a for loop or reconstructing the -// loop from low level IR code, the helper loop class (NOT -// IMPLEMENTED) must contain the transformed code that needs to be -// freed when out of service. +//! Base abstract class for code structures. +/*! + * This is a place holder for the actual structure in the IR code. + * However, in cases that original source code may be transformed during + * loop initialization such as converting a while loop to a for loop or + * reconstructing the loop from low level IR code, the helper loop class (NOT + * IMPLEMENTED) must contain the transformed code that needs to be + * freed when out of service. + */  struct IR_Control { -  const IR_Code *ir_; // hate this +  const IR_Code *ir_;    virtual ~IR_Control() {/* ir_ is not the responsibility of this object */} @@ -306,16 +320,14 @@ struct IR_While : public IR_Control {  }; -// Abstract class for compiler IR.  // TODO made a lot of definition to pass instantiation for IR_clangCode +//! Abstract class for compiler IR.  class IR_Code {  protected: -  // the only data members in IR_Code are Omega classes -  omega::CG_outputBuilder *ocg_;    // Omega Code Gen +  omega::CG_outputBuilder *ocg_;    omega::CG_outputRepr *init_code_;    omega::CG_outputRepr *cleanup_code_; -  // OK, I lied    static int ir_pointer_counter;    static int ir_array_counter; @@ -338,8 +350,7 @@ public:      return ir_array_counter - 1;    } -  // if all flavors of ir_code use chillAST internally ...  -  chillAST_FunctionDecl *func_defn;     // the function we're modifying +  chillAST_FunctionDecl *func_defn;     //!< the function we're modifying    chillAST_FunctionDecl *GetChillFuncDefinition() { return func_defn; };    IR_Code() { @@ -355,8 +366,11 @@ public:    omega::CG_outputRepr *init_code() { return init_code_; } -  // memory_type is for differentiating the location of where the new memory is allocated. -  // this is useful for processors with heterogeneous memory hierarchy. +  /*! +   * \param memory_type is for differentiating the location of +   *    where the new memory is allocated. this is useful for +   *    processors with heterogeneous memory hierarchy. +   */    virtual IR_ScalarSymbol *CreateScalarSymbol(const IR_Symbol *sym, int memory_type) = 0;    virtual IR_ScalarSymbol *CreateScalarSymbol(IR_CONSTANT_TYPE type, int memory_type, std::string name = "") { @@ -441,11 +455,15 @@ public:      CHILL_ERROR("NOT IMPLEMENTED\n");      return NULL;    } - -  // Array references should be returned in their accessing order. -  // e.g. s1: A[i] = A[i-1] -  //      s2: B[C[i]] = D[i] + E[i] -  // return A[i-1], A[i], D[i], E[i], C[i], B[C[i]] in this order. +  /*! +  * Array references should be returned in their accessing order. +  * +  * ~~~ +  * e.g. s1: A[i] = A[i-1] +  *      s2: B[C[i]] = D[i] + E[i] +  * return A[i-1], A[i], D[i], E[i], C[i], B[C[i]] in this order. +  * ~~~ +  */    virtual std::vector<IR_ArrayRef *> FindArrayRef(const omega::CG_outputRepr *repr) const = 0;    virtual std::vector<IR_PointerArrayRef *> FindPointerArrayRef(const omega::CG_outputRepr *repr) const { @@ -461,13 +479,15 @@ public:      CHILL_ERROR("NOT IMPLEMENTED\n");      return false;    } - -  // If there is no sub structure interesting inside the block, return empty, -  // so we know when to stop looking inside. +  /*! +   * If there is no sub structure interesting inside the block, return empty, +   * so we know when to stop looking inside. +   */    virtual std::vector<IR_Control *> FindOneLevelControlStructure(const IR_Block *block) const = 0; - -  // All controls must be in the same block, at the same level and in -  // contiguous lexical order as appeared in parameter vector. +  /*! +   * All controls must be in the same block, at the same level and in +   * contiguous lexical order as appeared in parameter vector. +   */    virtual IR_Block *MergeNeighboringControlStructures(const std::vector<IR_Control *> &controls) const = 0;    virtual IR_Block *GetCode() const = 0; @@ -552,11 +572,7 @@ public:      return NULL;    } -  //void Dump() { ocg_->Dump(); };  -  //--------------------------------------------------------------------------- -  // CC Omega code builder interface here - -  //--------------------------------------------------------------------------- +  //! Codegen Omega code builder interface    omega::CG_outputBuilder *builder() const { return ocg_; }  }; diff --git a/include/irtools.hh b/include/irtools.hh index c4a78ed..66b3144 100644 --- a/include/irtools.hh +++ b/include/irtools.hh @@ -9,15 +9,23 @@  #define DEP_DEBUG 0 -// IR tree is used to initialize a loop. For a loop node, payload is -// its mapped iteration space dimension. For a simple block node, -// payload is its mapped statement number. Normal if-else is split -// into two nodes where the one with odd payload represents then-part and -// the one with even payload represents else-part. +/*! + * \file + * \brief Useful tools to analyze code in compiler IR format. + */ + +//! It is used to initialize a loop.  struct ir_tree_node {    IR_Control *content;    ir_tree_node *parent;    std::vector<ir_tree_node *> children; +  /*! +   * * For a loop node, payload is its mapped iteration space dimension. +   * * For a simple block node, payload is its mapped statement number. +   * * Normal if-else is splitted into two nodes +   *   * the one with odd payload represents then-part and +   *   * the one with even payload represents else-part. +   */    int payload;    ~ir_tree_node() { @@ -26,16 +34,49 @@ struct ir_tree_node {      delete content;    }  }; - +/*! + * @brief Build IR tree from the source code + * + * Block type node can only be leaf, i.e., there is no further stuctures inside a block allowed + * + * @param control + * @param parent + * @return + */  std::vector<ir_tree_node *> build_ir_tree(IR_Control *control,                                            ir_tree_node *parent = NULL); - +/*! + * @brief Extract statements from IR tree + * + * Statements returned are ordered in lexical order in the source code + * + * @param ir_tree + * @return + */  std::vector<ir_tree_node *> extract_ir_stmts(      const std::vector<ir_tree_node *> &ir_tree);  bool is_dependence_valid(ir_tree_node *src_node, ir_tree_node *dst_node,                           const DependenceVector &dv, bool before); - +/*! + * @brief test data dependeces between two statements + * + * The first statement in parameter must be lexically before the second statement in parameter. + * Returned dependences are all lexicographically positive + * + * @param ir + * @param repr1 + * @param IS1 + * @param repr2 + * @param IS2 + * @param freevar + * @param index + * @param i + * @param j + * @param uninterpreted_symbols + * @param uninterpreted_symbols_stringrepr + * @return + */  std::pair<std::vector<DependenceVector>, std::vector<DependenceVector> > test_data_dependences(      IR_Code *ir, const omega::CG_outputRepr *repr1,      const omega::Relation &IS1, const omega::CG_outputRepr *repr2, diff --git a/include/loop.hh b/include/loop.hh index 554b005..7c746f6 100644 --- a/include/loop.hh +++ b/include/loop.hh @@ -15,24 +15,44 @@  #include "stencil.hh" +/*! + * \file + * \brief Core loop transformation functionality. + * + * "level" (starting from 1) means loop level and it corresponds to "dim" + * (starting from 0) in transformed iteration space [c_1,l_1,c_2,l_2,...., + * c_n,l_n,c_(n+1)], e.g., l_2 is loop level 2 in generated code, dim 3 + * in transformed iteration space, and variable 4 in Omega relation. + * All c's are constant numbers only and they will not show up as actual loops. + * + * Formula: + * + * ~~~ + *   dim = 2*level - 1 + *   var = dim + 1 + * ~~~ + */  class IR_Code;  enum TilingMethodType { StridedTile, CountedTile };  enum LoopLevelType { LoopLevelOriginal, LoopLevelTile, LoopLevelUnknown }; - -// Describes properties of each loop level of a statement. "payload" -// for LoopLevelOriginal means iteration space dimension, for -// LoopLevelTile means tiled loop level.  Special value -1 for -// LoopLevelTile means purely derived loop. For dependence dimension -// payloads, the values must be in an increasing order. -// "parallel_level" will be used by code generation to support -// multi-level parallelization (default 0 means sequential loop under -// the current parallelization level). +//! Describes properties of each loop level of a statement.  struct LoopLevel {    LoopLevelType type; -  int payload;   +  /*! +   * For LoopLevelOriginal means iteration space dimension +   * For LoopLevelTile means tiled loop level. Special value -1 for +   * LoopLevelTile means purely derived loop. For dependence dimension +   * payloads, the values must be in an increasing order. +   */ +  int payload; +  /*! +   * Used by code generation to support +   * multi-level parallelization (default 0 means sequential loop under +   * the current parallelization level). +   */    int parallel_level;    bool segreducible;    std::string segment_descriptor; @@ -46,14 +66,15 @@ struct Statement {    std::vector<LoopLevel> loop_level;    ir_tree_node *ir_stmt_node;    bool has_inspector; -  int reduction; // Manu:: 0 == reduction not possible, 1 == reduction possible, 2 == reduction with some processing +  /*! +   * @brief Whether reduction is possible +   * +   * 0 == reduction not possible, 1 == reduction possible, 2 == reduction with some processing +   */ +  int reduction;    IR_OPERATION_TYPE reductionOp; // Manu    class stencilInfo *statementStencil; - -  //protonu--temporarily putting this back here -  //omega::Tuple<int> nonSplitLevels; -  //end--protonu.  }; @@ -118,7 +139,6 @@ public:    ~Loop();    omega::CG_outputRepr *getCode(int effort = 1) const; // TODO was 1 -  //chillAST_Node* getCode(int effort, std::set<int> stmts) const;    void stencilASEPadded(int stmt_num);  @@ -133,15 +153,12 @@ public:    void dump() const;    std::vector<std::set <int > > sort_by_same_loops(std::set<int > active, int level); -  // -  // legacy unimodular transformations for perfectly nested loops -  // e.g. M*(i,j)^T = (i',j')^T or M*(i,j,1)^T = (i',j')^T -  // +  //! legacy unimodular transformations for perfectly nested loops +  /*! +   * e.g. \f$M*(i,j)^T = (i',j')^T or M*(i,j,1)^T = (i',j')^T\f$ +   */    bool nonsingular(const std::vector<std::vector<int> > &M); -  // -  // high-level loop transformations -  //    void permute(const std::set<int> &active, const std::vector<int> &pi);    void permute(int stmt_num, int level, const std::vector<int> &pi);    void permute(const std::vector<int> &pi); @@ -150,14 +167,43 @@ public:    void tile(int stmt_num, int level, int tile_size, int outer_level = 1, TilingMethodType method = StridedTile, int alignment_offset = 0, int alignment_multiple = 1);    std::set<int> split(int stmt_num, int level, const omega::Relation &cond);    std::set<int> unroll(int stmt_num, int level, int unroll_amount, std::vector< std::vector<std::string> >idxNames= std::vector< std::vector<std::string> >(), int cleanup_split_level = 0); -   + +  //! Datacopy function by reffering arrays by numbers +  /*! +   * for example +   * ~~~ +   * A[i] = A[i-1] + B[i]; +   * ~~~ +   * parameter array_ref_num=[0,2] means to copy data touched by A[i-1] and A[i] +   * +   * @param array_ref_nums +   * @param level +   * @param allow_extra_read +   * @param fastest_changing_dimension +   * @param padding_stride +   * @param padding_alignment +   * @param memory_type +   * @return +   */    bool datacopy(const std::vector<std::pair<int, std::vector<int> > > &array_ref_nums, int level, bool allow_extra_read = false, int fastest_changing_dimension = -1, int padding_stride = 1, int padding_alignment = 4, int memory_type = 0); +  //! Datacopy function by reffering arrays by name +  /*! +   * parameter array_name=A means to copy data touched by A[i-1] and A[i] +   * @param stmt_num +   * @param level +   * @param array_name +   * @param allow_extra_read +   * @param fastest_changing_dimension +   * @param padding_stride +   * @param padding_alignment +   * @param memory_type +   * @return +   */    bool datacopy(int stmt_num, int level, const std::string &array_name, bool allow_extra_read = false, int fastest_changing_dimension = -1, int padding_stride = 1, int padding_alignment = 4, int memory_type = 0);    bool datacopy_privatized(int stmt_num, int level, const std::string &array_name, const std::vector<int> &privatized_levels, bool allow_extra_read = false, int fastest_changing_dimension = -1, int padding_stride = 1, int padding_alignment = 1, int memory_type = 0);    bool datacopy_privatized(const std::vector<std::pair<int, std::vector<int> > > &array_ref_nums, int level, const std::vector<int> &privatized_levels, bool allow_extra_read = false, int fastest_changing_dimension = -1, int padding_stride = 1, int padding_alignment = 1, int memory_type = 0);    bool datacopy_privatized(const std::vector<std::pair<int, std::vector<IR_ArrayRef *> > > &stmt_refs, int level, const std::vector<int> &privatized_levels, bool allow_extra_read, int fastest_changing_dimension, int padding_stride, int padding_alignment, int memory_type = 0); -  //std::set<int> scalar_replacement_inner(int stmt_num); -  bool find_stencil_shape( int stmt_num );  +  bool find_stencil_shape( int stmt_num );    Graph<std::set<int>, bool> construct_induced_graph_at_level(std::vector<std::set<int> > s, DependenceGraph dep, int dep_dim); @@ -170,9 +216,6 @@ public:    void scale(const std::set<int> &stmt_nums, int level, int scale_amount);    void reverse(const std::set<int> &stmt_nums, int level);    void peel(int stmt_num, int level, int peel_amount = 1); -  // -  // more fancy loop transformations -  //    void modular_shift(int stmt_num, int level, int shift_amount) {}    void diagonal_map(int stmt_num, const std::pair<int, int> &levels, int offset) {}    void modular_partition(int stmt_num, int level, int stride) {} @@ -183,9 +226,6 @@ public: -  // -  // derived loop transformations -  //    void shift_to(int stmt_num, int level, int absolute_position);    std::set<int> unroll_extra(int stmt_num, int level, int unroll_amount, int cleanup_split_level = 0);    bool is_dependence_valid_based_on_lex_order(int i, int j, @@ -193,7 +233,6 @@ public:    void split_with_alignment(int stmt_num, int level, int alignment,        int direction=0); -  // Manu:: reduction operation    void reduce(int stmt_num, std::vector<int> &level, int param, std::string func_name, std::vector<int> &seq_levels, std::vector<int> cudaized_levels = std::vector<int>(), int bound_level = -1);    void scalar_expand(int stmt_num, const std::vector<int> &levels, std::string arrName, int memory_type =0, int padding_alignment=0, int assign_then_accumulate = 1, int padding_stride = 0);    void ELLify(int stmt_num, std::vector<std::string> arrays_to_pad, int pad_to, bool dense_pad = false, std::string dense_pad_pos_array = ""); @@ -203,11 +242,7 @@ public:    void set_array_size(std::string name, int size );    omega::CG_outputRepr * iegen_parser(std::string &str, std::vector<std::string> &index_names); -  // -  // other public operations -  //    void pragma(int stmt_num, int level, const std::string &pragmaText);    void prefetch(int stmt_num, int level, const std::string &arrName, int hint); -  //void prefetch(int stmt_num, int level, const std::string &arrName, const std::string &indexName, int offset, int hint);  };  #endif  | 
