https://hal.archives-ouvertes.fr/hal-03445821
Raw File
ddg_xml.c
/*
   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/>.
*/
#include <assert.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <libxml/tree.h>
#include <libxml/parser.h>

#include "util.h"
#include "opcode.h"
#include "arch.h"
#include "ddg.h"
#include "ddg_xml.h"

/** Include xml utilities functions */
#include "xmlutil.h"

#include "boxed.h"

typedef struct {
  GDD_Arch *arch;
  SCEDA_Graph *graph;
  SCEDA_HashMap *vertice; // id -> vertex
  int keep_lambda;
  int ii_min;
  int undef;
  int error;
} BuildCtxt;

static SCEDA_Vertex *get_nth_vertex(BuildCtxt *ctxt, int n) {
  boxed(int) key = boxed_create(int, n);

  SCEDA_Vertex *v = SCEDA_hashmap_get(ctxt->vertice, key);
  if(v != NULL) {
/*     fprintf(stderr,"fetching vertex #%d\n",n);  */
    boxed_delete(key);
    return v;
  } 

/*   fprintf(stderr,"creating vertex #%d\n",n);  */
  v = SCEDA_graph_add_vertex(ctxt->graph, NULL);
  SCEDA_hashmap_put(ctxt->vertice, key, v, NULL);
  ctxt->undef++;
  return v;
}

static void readVertex(BuildCtxt *ctxt, const xmlChar **attrs) {
  int i;

  i = findAttr("id", attrs);
  int v_id = atoi_xml(attrs[i]);

  i = findAttr("type", attrs);
  char *mnemo = (char *)attrs[i];

  GDD_Opcode *op = GDD_arch_get_opcode(ctxt->arch, mnemo);
  if(op == NULL) {
    fprintf(stderr,"unknown mnemonic %s\n", mnemo);
    ctxt->error = TRUE;
    return;
  }

  SCEDA_Vertex *v = get_nth_vertex(ctxt, v_id);
  if(SCEDA_vertex_get_data(GDD_NodeLabel *, v) == NULL) {
/*     fprintf(stderr,"------------------\n"); */
/*     fprintf(stderr,"binding vertex #%d to opcode\n",v_id); */
/*     GDD_opcode_fprint(stderr, op); */
/*     fprintf(stderr,"------------------\n"); */
    SCEDA_vertex_set_data(v, GDD_node_label_create(v_id, op));
    ctxt->undef--;
  }
}

static void readEdge(BuildCtxt *ctxt, const xmlChar **attrs) {
  int i;
  
  i = findAttr("distance", attrs);
  int distance = atoi_xml(attrs[i]);
  if((distance == 0) || (ctxt->keep_lambda)) {
    i = findAttr("src", attrs);
    int vs_id = atoi_xml(attrs[i]);
    SCEDA_Vertex *v_s = get_nth_vertex(ctxt, vs_id);
    
    i = findAttr("dst", attrs);
    int vt_id = atoi_xml(attrs[i]);
    SCEDA_Vertex *v_t = get_nth_vertex(ctxt, vt_id);

    i = findAttr("latency", attrs);
    int latency = atoi_xml(attrs[i]);

    i = findAttr("typedep", attrs);
    char *dep = (char *)attrs[i];
    if(strcmp(dep, "virtual") == 0) {
      fprintf(stderr,"error: virtual dependency forbidden\n");
      ctxt->error = TRUE;
      return;
    }

    char *regtype = NULL;
    i = findOptAttr("regtype", attrs);
    if(i != -1) {
      regtype = (char *)attrs[i];
      if(strcmp(regtype, "(null)") == 0) {
	regtype = NULL;
      } else {
	if(GDD_arch_get_regtype(ctxt->arch, regtype) <= 0) {
	  fprintf(stderr,"unknown register type %s\n",regtype);
	  ctxt->error = TRUE;
	  return;
	}
      }
    } 

    GDD_EdgeLabel *e = GDD_edge_label_create(regtype, dep, latency, distance);

/*     fprintf(stderr,"adding an edge from #%d to #%d\n", vs_id, vt_id); */

    SCEDA_graph_add_edge(ctxt->graph, v_s, v_t, e);
  } else {
    fprintf(stderr,"ignoring interloop dependency\n");
  }
}

// Appelée à chaque début d'élément
static void beginElement(void *user_data, const xmlChar *name, const xmlChar **attrs) {
  BuildCtxt *ctxt = (BuildCtxt *)user_data;
  if(ctxt->error) {
    return;
  }

  if (xmlStrEqual(name, (xmlChar *)"operation")) {
    readVertex(ctxt, attrs);
  } else if (xmlStrEqual(name, (xmlChar *)"edge")) {
    readEdge(ctxt, attrs);
  } else if(xmlStrEqual(name, (xmlChar *)"siraloop")) {
    int i;

    i = findAttr("version", attrs);
    int version = atoi_xml(attrs[i]);
    if(version != 1) {
      fprintf(stderr,"wrong ddg version: %d\n",version);
      ctxt->error = TRUE;
      return;
    }
    i = findAttr("II_min", attrs);
    ctxt->ii_min = atoi_xml(attrs[i]);
  } else {
    fprintf(stderr,"ignoring %s tag\n", name);
  }
}

static int boxed_int_match(boxed(int) x, boxed(int) y) {
  return boxed_get(x) == boxed_get(y);
}

static unsigned int boxed_int_hash(boxed(int) x) {
  return boxed_get(x);
}

/** Parse a GDD from a file stream.

    @param[in] ignore_interloop = TRUE to ignore interloop dependency, FALSE otherwise
    @param[in] arch = associated architecture
    @param[in] stream = file stream
    @param[out] ii_min = min II (filled by the function if not NULL)

    @return the parsed GDD or NULL in case of error */
SCEDA_Graph *GDD_of_xml_stream(int ignore_interloop, GDD_Arch *arch, FILE *stream, int *ii_min) {
  BuildCtxt ctxt;
  
  ctxt.arch = arch;
  ctxt.graph = SCEDA_graph_create((SCEDA_delete_fun)GDD_node_label_delete, (SCEDA_delete_fun)GDD_edge_label_delete);
  ctxt.vertice = SCEDA_hashmap_create((SCEDA_delete_fun)boxed_delete, 
				   NULL, 
				   (SCEDA_match_fun)boxed_int_match, 
				   (SCEDA_hash_fun)boxed_int_hash);
  ctxt.keep_lambda = !ignore_interloop;
  ctxt.ii_min = 0;
  ctxt.undef = 0;
  ctxt.error = FALSE;

  xmlParserCtxtPtr xmlctxt;
  xmlSAXHandler sax = { 0 };
 
  // initialise SAX callbacks
  sax.startElement = beginElement;
 
  // create SAX context
  if ((xmlctxt = xmlCreateIOParserCtxt(&sax, &ctxt, sax_read, sax_close, stream, XML_CHAR_ENCODING_NONE)) == NULL) {
    fprintf(stderr,"error while creating SAX context\n");
    SCEDA_hashmap_delete(ctxt.vertice);
    SCEDA_graph_delete(ctxt.graph);
    return NULL;
  }

  // parse stream
  if(xmlParseDocument(xmlctxt) != 0) {
    ctxt.error = TRUE;
  }
  //

  if(ctxt.undef != 0) {
    fprintf(stderr,"error: there remains an undefined vertex.\n");
    ctxt.error = TRUE;
  }

  xmlFreeParserCtxt(xmlctxt);

  if(ctxt.error) {
    fprintf(stderr,"error while parsing ddg file\n");
    SCEDA_hashmap_delete(ctxt.vertice);
    SCEDA_graph_delete(ctxt.graph);
    return NULL;
  } 

  if(ii_min != NULL) {
    *ii_min = ctxt.ii_min;
  }

  SCEDA_hashmap_delete(ctxt.vertice);

  return ctxt.graph;
}

/** Parse a GDD from a file.

    @param[in] ignore_interloop = TRUE to ignore interloop dependency, FALSE otherwise
    @param[in] arch = associated architecture
    @param[in] filename = filename
    @param[out] ii_min = min II (filled by the function if not NULL)

    @return the parsed GDD or NULL in case of error */
SCEDA_Graph *GDD_of_xml_file(int ignore_interloop, GDD_Arch *arch, const char *filename, int *ii_min) {
  FILE *f = fopen(filename, "r");
  if(f == NULL) {
    fprintf(stderr,"error while opening %s\n", filename);
    return NULL;
  }
  SCEDA_Graph *dag = GDD_of_xml_stream(ignore_interloop, arch, f, ii_min);
  fclose(f);
  return dag;
}

/** XML dump of a GDD to a stream

    @param[in] stream = stream on which the dump will occur 
    @param[in] ddg = DDG
    @param[in] ii_min = MII
*/
void GDD_to_xml_stream(FILE *stream, SCEDA_Graph *ddg, int ii_min) {
  fprintf(stream,"<?xml version=\"1.0\"?>\n"); 
  fprintf(stream,"<siraloop version=\"1\" II_min=\"%d\">\n",ii_min);
  {
    SCEDA_VerticesIterator vertices;
    SCEDA_vertices_iterator_init(ddg, &vertices);
    while(SCEDA_vertices_iterator_has_next(&vertices)) {
      SCEDA_Vertex *v = SCEDA_vertices_iterator_next(&vertices);
      int idx = GDD_vertex_get_id(v);
      fprintf(stream,"\t<operation type=\"%s\" id=\"%d\"/>\n",GDD_vertex_mnemonic(v),idx);
    }
    SCEDA_vertices_iterator_cleanup(&vertices);
  }
  {
    SCEDA_EdgesIterator edges;
    SCEDA_edges_iterator_init(ddg, &edges);
    while(SCEDA_edges_iterator_has_next(&edges)) {
      SCEDA_Edge *e = SCEDA_edges_iterator_next(&edges);
      SCEDA_Vertex *u = SCEDA_edge_source(e);
      SCEDA_Vertex *v = SCEDA_edge_target(e);
      int idx_u = GDD_vertex_get_id(u);
      int idx_v = GDD_vertex_get_id(v);
      char *depkind = "unknown";
      char *regtype = "(null)";
      switch(GDD_edge_depkind(e)) {
      case GDD_FLOWDEP_REG:
	depkind="flowdep_reg";
	regtype = GDD_edge_regtype(e);
	break;
      case GDD_ANTIDEP_REG:
	depkind="antidep_reg";
	regtype = GDD_edge_regtype(e);
	break;
      case GDD_OUTPUTDEP_REG:
	depkind="outputdep_reg";
	regtype = GDD_edge_regtype(e);
	break;
      case GDD_INPUTDEP_REG:
	depkind="inputdep_reg";
	regtype = GDD_edge_regtype(e);
	break;
      case GDD_KILLERDEP:
	depkind="killerdep";
	regtype = GDD_edge_regtype(e);
	break;
      case GDD_REUSEDEP:
	depkind="reusedep";
	regtype = GDD_edge_regtype(e);
	break;
      case GDD_FLOWDEP_MEM:
	depkind="flowdep_mem";
	break;
      case GDD_ANTIDEP_MEM:
	depkind="antidep_mem";
	break;
      case GDD_OUTPUTDEP_MEM:
	depkind="outputdep_mem";
	break;
      case GDD_INPUTDEP_MEM:
	depkind="inputdep_mem";
	break;
      case GDD_SPILLDEP_MEM:
	depkind="spilldep_mem";
	break;
      case GDD_OTHERDEP_MEM:
	depkind="otherdep_mem";
	break;
      case GDD_SERIALDEP:
	depkind="serial";
	break;
      default:
	depkind="unknown";
      }

      fprintf(stream,"\t<edge src=\"%d\" dst=\"%d\" latency=\"%d\" distance=\"%d\" typedep=\"%s\" regtype=\"%s\"/>\n",idx_u,idx_v,GDD_edge_latency(e),GDD_edge_distance(e),depkind,regtype);
    }
    SCEDA_edges_iterator_cleanup(&edges);
  }
  fprintf(stream,"</siraloop>\n");
}

back to top