https://hal.archives-ouvertes.fr/hal-03445821
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"
*/