https://hal.archives-ouvertes.fr/hal-03445821
Raw File
ddg.h
/*
   Copyright Universite de Versailles Saint-Quentin en Yvelines 2009
   AUTHORS: Sebastien Briais, Sid Touati

   This file is part of GDD.
   
   GDD is free software: you can redistribute it and/or modify it
   under the terms of the GNU Lesser General Public License as
   published by the Free Software Foundation, either version 3 of the
   License, or (at your option) any later version.
   
   GDD is distributed in the hope that it will be useful, but
   WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   Lesser General Public License for more details.
   
   You should have received a copy of the GNU Lesser General Public
   License along with GDD.  If not, see
   <http://www.gnu.org/licenses/>.
*/
#ifndef __GDD_H
#define __GDD_H
/** \file ddg.h
    \brief Basic definitions & algorithms related to DDG */

#include <SCEDA/graph.h>
#include <limits.h>
#include "arch.h"
#include "opcode.h"

/** Type of dependency */
typedef enum { 
  /* register dependencies */
  /** Flow Dependency (register) */
  GDD_FLOWDEP_REG, 
  /** Anti Dependency (register) */
  GDD_ANTIDEP_REG,
  /** Output Dependency (register) */
  GDD_OUTPUTDEP_REG,
  /** Input Dependency (register) */
  GDD_INPUTDEP_REG,
  /** Killer */
  GDD_KILLERDEP,
  /** Reuse */
  GDD_REUSEDEP,
  /* memory dependencies */
  /** Flow Dependency (memory) */
  GDD_FLOWDEP_MEM, 
  /** Anti Dependency (memory) */
  GDD_ANTIDEP_MEM,
  /** Output Dependency (memory) */
  GDD_OUTPUTDEP_MEM,
  /** Input Dependency (memory) */
  GDD_INPUTDEP_MEM,
  /** Spill */
  GDD_SPILLDEP_MEM,
  /** Other kind of dependencies (memory) */
  GDD_OTHERDEP_MEM,
  /* other dependencies */
  /** Serial Dependency */
  GDD_SERIALDEP,
  /** For creating virtual edges */
  GDD_VIRTUALDEP,
  /** Open type to support other kind of dependencies */
  GDD_UNKNOWNDEP 
} GDD_DepKind;

/** Type of GDD edge labels */
typedef struct {
  char *regtype;
  GDD_DepKind dep;
  int latency;
  int distance;
} GDD_EdgeLabel;

/** Type of GDD node labels */
typedef struct {
  int id;
  GDD_Opcode *op;
} GDD_NodeLabel;

/** Create a new DDG node label.
    
    @param[in] id = id of operation (must be unique in the graph)
    @param[in] op = opcode

    @return the DDG node label */
GDD_NodeLabel *GDD_node_label_create(int id, GDD_Opcode *op);

/** Delete a DDG node label 

    @param[in] node = DDG edge label to delete */
void GDD_node_label_delete(GDD_NodeLabel *node);

/** Copy a DDG node label

    @param[in] x = DDG node label to copy

    @return a (deep) copy of x (must be freed by delete) */
GDD_NodeLabel *GDD_node_label_copy(GDD_NodeLabel *x);

/** Create a new DDG edge label.
    
    @param[in] regtype = considered type or NULL if not applicable
    @param[in] dep = dependency kind (converted to GDD_DepKind)
    @param[in] latency = latency 
    @param[in] distance = interloop distance

    @return the DDG edge label */
GDD_EdgeLabel *GDD_edge_label_create(const char *regtype, const char *dep, int latency, int distance);

/** Delete a DDG edge label.

    @param[in] edge = DDG edge label to delete */
void GDD_edge_label_delete(GDD_EdgeLabel *edge);

/** Copy a DDG edge label.

    @param[in] x = DDG edge label to copy 

    @return a (deep) copy of x (must be freed by delete) */
GDD_EdgeLabel *GDD_edge_label_copy(GDD_EdgeLabel *x); 

/** Delete edges in a DDG and the associated edge labels.

    @param[in] g = DDG
    @param[in] edges = list of edges to delete 

    The list is cleared but not deleted. */
void GDD_delete_edges(SCEDA_Graph *g, SCEDA_List *edges);

/** Test whether the given DDG edge label is a flow dependency of
    considered type.

    @param[in] e = DDG edge label
    @param[in] type = considered type
    
    @return TRUE iff e is a flow dependency of given type */
int GDD_edge_label_is_flowdep_of_type(GDD_EdgeLabel *e, const char *type);

/** Get the latency of a DDG edge label.

    @param[in] e = DDG edge label
    
    @return the latency 

    \hideinitializer */
#define GDD_edge_label_latency(e) ((e)->latency)

/** Get the distance of a DDG edge label.

    @param[in] e = DDG edge label

    @return the distance 
    
    \hideinitializer */
#define GDD_edge_label_distance(e) ((e)->distance)

/** Get the dependency kind of a DDG edge label.

    @param[in] e = DDG edge label
    
    @return the dependency kind

    \hideinitializer */
#define GDD_edge_label_depkind(e) ((e)->dep)

/** Get the dependency register type of a DDG edge label.

    @param[in] e = DDG edge label
    
    @return the dependency register type or NULL 

    \hideinitializer */
#define GDD_edge_label_regtype(e) ((e)->regtype)

/** Get the id of a DDG node label.

    @param[in] n = DDG node label

    @return the id 

    \hideinitializer */
#define GDD_node_label_get_id(n) ((n)->id)

/** Get the opcode of a DDG node label.

    @param[in] n = DDG node label

    @return the opcode 

    \hideinitializer */
#define GDD_node_label_get_opcode(n) ((n)->op)

/** Get the node label of a DDG vertex.

    @param[in] v = vertex

    @return the node label of v

    \hideinitializer */
#define GDD_vertex_get_node_label(v) (SCEDA_vertex_get_data(GDD_NodeLabel *, v))

/** Get the id of the given DDG vertex.

    @param[in] v = vertex

    @return the id
    
    \hideinitializer */
#define GDD_vertex_get_id(v) (GDD_node_label_get_id(GDD_vertex_get_node_label(v)))

/** Return the opcode of the given DDG vertex.

    @param[in] v = vertex

    @return the opcode

    \hideinitializer */
#define GDD_vertex_get_opcode(v) (GDD_node_label_get_opcode(GDD_vertex_get_node_label(v)))

/** Return the edge label of the given DDG edge.

    @param[in] e = edge

    @return the edge label

    \hideinitializer */
#define GDD_edge_get_edge_label(e) (SCEDA_edge_get_data(GDD_EdgeLabel *, e))

/** Test whether the given DDG edge is a flow dependency of
    considered type.

    @param[in] e = edge
    @param[in] t = considered type

    @return TRUE iff e is a flow dependency of given type 

    \hideinitializer */
#define GDD_edge_is_flowdep_of_type(e, t) (GDD_edge_label_is_flowdep_of_type(GDD_edge_get_edge_label(e), t))

/** Return the latency of the given DDG edge.

    @param[in] e = edge
    
    @return the latency 

    \hideinitializer */
#define GDD_edge_latency(e) (GDD_edge_label_latency(GDD_edge_get_edge_label(e)))

/** Return the distance of the given DDG edge.

    @param[in] e = edge
    
    @return the distance 

    \hideinitializer */
#define GDD_edge_distance(e) (GDD_edge_label_distance(GDD_edge_get_edge_label(e)))

/** Return the dependency kind of the given DDG edge.

    @param[in] e = edge
    
    @return the dependency kind

    \hideinitializer */
#define GDD_edge_depkind(e) (GDD_edge_label_depkind(GDD_edge_get_edge_label(e)))

/** Return the dependency register type of the given DDG edge.

    @param[in] e = edge
    
    @return the dependency register type or NULL

    \hideinitializer */
#define GDD_edge_regtype(e) (GDD_edge_label_regtype(GDD_edge_get_edge_label(e)))

/** Test whether the given (DDG) vertex is a value of considered type.
    
    @param[in] v = vertex
    @param[in] t = considered type

    @return TRUE iff v is a value of type t

    \hideinitializer */
#define GDD_vertex_is_value_of_type(v, t) (GDD_opcode_is_value(GDD_vertex_get_opcode(v), t))

/** Return the latency of the given DDG vertex.

    @param[in] v = vertex

    @return the latency

    \hideinitializer */
#define GDD_vertex_latency(v) (GDD_opcode_latency(GDD_vertex_get_opcode(v)))

/** Return the read delay offset of the given DDG vertex for a given type.

    @param[in] v = vertex
    @param[in] t = considered type

    @return the read delay offset

    \hideinitializer */
#define GDD_vertex_delta_r(v, t) (GDD_opcode_delta_r(GDD_vertex_get_opcode(v), t))

/** Return the write delay offset of the given DDG vertex for a given type.

    @param[in] v = vertex
    @param[in] t = considered type

    @return the write delay offset

    \hideinitializer */
#define GDD_vertex_delta_w(v, t) (GDD_opcode_delta_w(GDD_vertex_get_opcode(v), t))

/** Return the mnemonic of the given DDG vertex.

    @param[in] v = vertex

    @return the mnemonic

    \hideinitializer */
#define GDD_vertex_mnemonic(v) (GDD_opcode_mnemonic(GDD_vertex_get_opcode(v)))

/** Get the number of values of considered type.

    @param[in] g = DDG
    @param[in] type = considered type

    @return the number of values of given type in the DDG */
int GDD_nb_values(SCEDA_Graph *g, const char *type);

/** Get the number of flow dependency edges in the DDG of considered
    type.

    @param[in] g = DDG
    @param[in] type = considered type

    @return the number of flow dependency edges of given type in the
    GDD */
int GDD_nb_flowdeps(SCEDA_Graph *g, const char *type);

/** Returns the set of values of a given type.

    @param[in] g = DDG
    @param[in] type = considered type

    @return the set of values of the given type in the DDG */
SCEDA_HashSet *GDD_get_values_of_type(SCEDA_Graph *g, const char *type);

/** Returns the set of consumers of a given DDG vertex. 

    @param[in] v = vertex
    @param[in] type = considered type

    @return the set of consumers */
SCEDA_HashSet *GDD_consumers_of_type(SCEDA_Vertex *v, const char *type);

/** Computes the maximal distance of flowdep edges between v_s and v_t.

    @param[in] v_s = source vertex
    @param[in] v_t = target vertex
    @param[in] type = considered type

    @return the maximal distance of flowdep edges (of given type)
    between v_s and v_t or INT_MIN if no such edges exist */
int GDD_max_distance_flowdep(SCEDA_Vertex *v_s, SCEDA_Vertex *v_t, const char *type);

/** Tests whether the given DDG is lexicographic positive.

    @param[in] g = DDG
    @param[out] cycle = cycle that has a negative distance.

    @return TRUE iff g is lexicographic positive. When FALSE, a cycle
    with a negative distance is also returned. */
int GDD_is_lexicographic_positive(SCEDA_Graph *g, SCEDA_List **cycle);

/** Computes the MII ratio of the DDG and the cycle that realises the ratio.

    @param[in] g = DDG
    @param[out] MIInum = numerator
    @param[out] MIIden = denominator
    @param[out] cycle = list of edges

    @return 0 in case of success, -1 otherwise */
int GDD_MII_ratio_cycle(SCEDA_Graph *g, int *MIInum, int *MIIden, SCEDA_List **cycle);

/** Compute the MII of the DDG. It is just ceil value of MII ratio.

    @param[in] g = DDG

    @return the MII or -1 in case of error (acyclic graph) */
int GDD_MII(SCEDA_Graph *g);

/** Compute the longest path of the DDG.

    @param[in] g = DDG

    @return the longest path or -1 in case of error (non acyclic graph) */
int GDD_longest_path(SCEDA_Graph *g);

#endif

/** \page ddg Data Dependency Graphs representation and manipulation

    \section ddg_intro Introduction

    A DDG (Data Dependency Graph) is a graph \f$G = (V,E)\f$ where
    \f$V\f$ is the set of vertices (operations) and \f$E\f$ is the set
    of edges representing dependencies between operations.

    Each vertice is labelled by an opcode (see \ref opcode) and an
    id. All these information are gathered into a GDD_NodeLabel
    structure.

    Each edge \f$e\f$ is labelled by a kind (and possibly an
    associated type), a latency and an (interloop) distance. All these
    information are gathered into a GDD_EdgeLabel structure.

    By abuse of notation, if \f$e\f$ is an edge belonging to a DDG, we
    will write \f$\delta(e)\f$ for the latency of \f$e\f$,
    \f$\lambda(e)\f$ for the distance of \f$e\f$,
    \f$\mathop{depkind}(e)\f$ for the dependency kind of \f$e\f$ and
    \f$\mathop{regtype}(e)\f$ for the register type of \f$e\f$

    Similarly, if \f$v\f$ is a vertex belonging to a DDG, we will
    write \f$\mathop{lat}(v)\f$ for the latency of the opcode that
    corresponds to \f$v\f$ and \f$\mathop{mnemo}(v)\f$ for the
    mnemonic of this opcode.  Moreover, if \f$t \in \mathcal{T}\f$ is
    a register type, we write \f$\delta_r^t(v)\f$
    (resp. \f$\delta_w^t(v)\f$) for the read (resp. write) delay
    offset of opcode corresponding to \f$v\f$.

    If \f$v\f$ is a DDG vertex and \f$t\f$ is a type, we say that it
    is a value of type \f$t\f$ if the corresponding opcode writes
    to a register of type \f$t\f$.

    The set of values of a given type in a DDG is written \f$V_R^t =
    \{ v \in V \mid v\f$ is a value of type \f$t \}\f$.

    If \f$e\f$ is a DDG edge and \f$t\f$ is a type, we say that \f$e\f$ is
    a flow dependency edge of type \f$t\f$ if \f$\mathop{depkind}(e) =
    \texttt{flowdep}\f$ and \f$\mathop{regtype}(e) = t\f$.

    The set of flow dependency edges of type \f$t\f$ is written
    \f$E_R^t = \{ e \in E \mid e\f$ is a flow dependency edge of type
    \f$t \}\f$.
    
    When \f$u \in V_R^t\f$, the set of consumers of type \f$t\f$ of
    \f$u\f$ is defined by \f$\mathop{Cons}^t(u) = \{ v \mid (u,v) \in
    E_R^t \}\f$

    We say that a DDG is lexicographic positive if it does not contain
    any circuit having a (cumulated) distance \f$\Lambda \leq 0\f$.

    When a DDG contains at least one cycle, the MII is defined to be
    the least integer greater than \f$\frac{\delta(c)}{\lambda(c)}\f$
    for any cycle \f$c\f$ in the DDG, where \f$\delta(c)\f$
    (resp. \f$\lambda(c)\f$) represents the cumulated latencies
    (resp. distances) of \f$c\f$. Otherwise (when the DDG is acyclic)
    it is undefined.

    Acyclic DDG are of particular interest. An enriched structure
    offer some more functions to reason on these (see \ref dag).

    \section ddg_api_aux DDG node and edge labels manipulation

    \code
    GDD_NodeLabel *GDD_node_label_create(int id, GDD_Opcode *op);
    \endcode

    Create a DDG node label of given characteristics.

    Note that the provided id must be fresh in order to avoid failure
    of some DDG operations.

    \code
    void GDD_node_label_delete(GDD_NodeLabel *node);
    \endcode

    Delete a DDG node label.

    \code
    GDD_NodeLabel *GDD_node_label_copy(GDD_NodeLabel *edge);
    \endcode

    Perform a deep copy of a node label.

    \code
    GDD_EdgeLabel *GDD_edge_label_create(const char *regtype, const char *dep, int latency, int distance);
    \endcode

    Create a DDG edge label, of given characteristics. 

    Dependency string is converted to a value belonging to the GDD_DepKind
    enumeration, according to the following translation procedure:
    \li "flowdep_reg" is converted to GDD_DepKind::GDD_FLOWDEP_REG. A register type must be given.
    \li "antidep_reg" is converted to GDD_DepKind::GDD_ANTIDEP_REG. A register type must be given.
    \li "outputdep_reg" is converted to GDD_DepKind::GDD_OUTPUTDEP_REG. A register type must be given.
    \li "inputdep_reg" is converted to GDD_DepKind::GDD_INPUTDEP_REG. A register type must be given.
    \li "flowdep_mem" is converted to GDD_DepKind::GDD_FLOWDEP_MEM. 
    \li "antidep_mem" is converted to GDD_DepKind::GDD_ANTIDEP_MEM. 
    \li "outputdep_mem" is converted to GDD_DepKind::GDD_OUTPUTDEP_MEM.
    \li "inputdep_mem" is converted to GDD_DepKind::GDD_INPUTDEP_MEM.
    \li "spilldep_mem" is converted to GDD_DepKind::GDD_SPILLDEP_MEM.
    \li "other_mem" is converted to GDD_DepKind::GDD_OTHERDEP_MEM.
    \li "killerdep" is converted to GDD_DepKind::GDD_KILLERDEP. A register type must be given.
    \li "reusedep" is converted to GDD_DepKind::GDD_REUSEDEP. A register type must be given.
    \li "serial" is converted to GDD_DepKind::GDD_SERIALDEP.
    \li "virtual" is converted to GDD_DepKind::GDD_VIRTUALDEP.
    \li any other string is converted to GDD_DepKind::GDD_UNKNOWNDEP.

    \code
    void GDD_edge_label_delete(GDD_EdgeLabel *edge);
    \endcode

    Delete a DDG edge label.

    \code
    GDD_EdgeLabel *GDD_edge_label_copy(GDD_EdgeLabel *edge);
    \endcode

    Perform a deep copy of an edge label.

    \code
    int GDD_edge_label_is_flowdep_of_type(GDD_EdgeLabel *edge, const char *type);
    \endcode

    Test whether a DDG edge label is a flow dependency of given type.

    \code
    int GDD_edge_label_latency(GDD_EdgeLabel *edge);
    int GDD_edge_label_distance(GDD_EdgeLabel *edge);
    GDD_DepKind GDD_edge_label_depkind(GDD_EdgeLabel *edge);
    char *GDD_edge_label_regtype(GDD_EdgeLabel *edge);
    \endcode

    Return the latency (resp. the distance, the dependency kind, the
    dependency register type) of the given DDG edge label.

    \section ddg_api DDG support functions

    To ease the manipulation of DDG, several functions are provided
    over DDG edges and vertices.

    \code 
    GDD_NodeLabel *GDD_vertex_get_node_label(SCEDA_Vertex *v);
    \endcode

    Return the label of the DDG vertex v.

    \code
    GDD_Opcode *GDD_vertex_get_opcode(SCEDA_Vertex *v);
    \endcode

    Return the opcode which labels the DDG vertex v.

    \code
    GDD_EdgeLabel *GDD_edge_get_edge_label(SCEDA_Edge *e);
    \endcode

    Return the edge label which labels the DDG edge e.

    \code
    int GDD_edge_is_flowdep_of_type(SCEDA_Edge *e, const char *type);
    \endcode

    Test whether the given DDG edge is labelled with a flow dependency
    of given type, ie perform the test \f$\mathop{depkind}(e) =
    \texttt{flowdep} \wedge \mathop{regtype}(e) = t\f$.

    \code 
    int GDD_edge_latency(SCEDA_Edge *e);
    int GDD_edge_distance(SCEDA_Edge *e);
    GDD_DepKind GDD_edge_depkind(SCEDA_Edge *e);
    char *GDD_edge_regtype(SCEDA_Edge *e);
    \endcode

    Return the latency (resp. the distance, the dependency kind, the
    dependency register type) of the DDG edge, ie return
    \f$\delta(e)\f$ (resp. \f$\lambda(e)\f$,
    \f$\mathop{depkind}(e)\f$, \f$\mathop{regtype}(e)\f$).

    \code
    int GDD_vertex_is_value_of_type(SCEDA_Vertex *v, const char *type);
    \endcode

    Test whether the given DDG vertex is labelled with a value of
    given type, ie perform the test \f$v \in V_R^t\f$.

    \code
    int GDD_vertex_latency(SCEDA_Vertex *v);
    \endcode

    Return the latency of the given DDG vertex, ie return \f$\mathop{lat}(v)\f$.

    \code
    int GDD_vertex_delta_r(SCEDA_Vertex *v, const char *type);
    int GDD_vertex_delta_w(SCEDA_Vertex *v, const char *type);
    \endcode

    Return the read delay offset (resp. write delay offset) of the
    given DDG vertex for the given type, ie return \f$\delta_r^t(v)\f$
    (resp. \f$\delta_w^t(v)\f$).

    \code
    char *GDD_vertex_mnemonic(SCEDA_Vertex *v);
    \endcode
    
    Return the mnemonic of the given DDG vertex, ie return
    \f$\mathop{mnemo}(v)\f$.

    \code
    int GDD_nb_values(SCEDA_Graph *g, const char *type);
    int GDD_nb_flowdeps(SCEDA_Graph *g, const char *type);
    \endcode

    Return the number of values (resp. flow dependency edges) of given
    type in the DDG, ie return \f$|V_R^t|\f$ (resp. \f$|E_R^t|\f$).

    \section ddg_alg_sec DDG general algorithms

    \code
    SCEDA_HashSet *GDD_get_values_of_type(SCEDA_Graph *g, const char *type);
    \endcode

    Return the set of values of given type in the DDG, ie return \f$V_R^t\f$.

    \code
    SCEDA_HashSet *GDD_consumers_of_type(SCEDA_Vertex *v, const char *type);
    \endcode

    Return the set of consumers of a vertex for the given type, ie
    return \f$\mathop{Cons}^t(v)\f$.

    \code
    int GDD_max_distance_flowdep(SCEDA_Vertex *v_s, SCEDA_Vertex *v_t, const char *type);
    \endcode

    Return the maximal distance of flow dependency edges of given type
    going from DDG vertex v_s to DDG vertex v_t, ie return \f$\max_{e
    \in E_R^t \wedge \mathop{source}(e) = v_s \wedge
    \mathop{target}(e) = v_t} \lambda(e)\f$.

    \code
    int GDD_is_lexicographic_positive(SCEDA_Graph *g, SCEDA_List **cycle);
    \endcode

    Test whether the given DDG is lexicographic positive and returns a
    cycle with a negative distance when the test fails.

    \code
    int GDD_MII_ratio_cycle(SCEDA_Graph *g, int *MIInum, int *MIIden, SCEDA_List **cycle);
    int GDD_MII(SCEDA_Graph *g);
    \endcode

    Compute the MII ratio of given DDG and a circuit that reaches the
    ratio, ie compute a cycle \f$c\f$ that maximises
    \f$\frac{\delta(c)}{\lambda(c)}\f$.

    Note that the computed ratio is not normalised. Thus MIInum is the
    cumulated latency of the cycle and MIIden is the cumulated
    distance of the cycle.

    \section ddg_exa Example

    \include "ddg/main.c"

*/
back to top