/* 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 . */ #include #include #include #include #include #include #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,"\n"); fprintf(stream,"\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\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\n",idx_u,idx_v,GDD_edge_latency(e),GDD_edge_distance(e),depkind,regtype); } SCEDA_edges_iterator_cleanup(&edges); } fprintf(stream,"\n"); }