Revived grgen dumper for TTC 2011.
authorSebastian Buchwald <Sebastian.Buchwald@kit.edu>
Tue, 22 Mar 2011 18:31:38 +0000 (19:31 +0100)
committerSebastian Buchwald <Sebastian.Buchwald@kit.edu>
Fri, 8 Apr 2011 11:21:23 +0000 (13:21 +0200)
ir/ir/irdump_grgen.c [new file with mode: 0644]
ir/ir/irdump_grgen.h [new file with mode: 0644]

diff --git a/ir/ir/irdump_grgen.c b/ir/ir/irdump_grgen.c
new file mode 100644 (file)
index 0000000..2795d08
--- /dev/null
@@ -0,0 +1,524 @@
+/*
+* Copyright (C) 1995-2007 University of Karlsruhe.  All right reserved.
+*
+* This file is part of libFirm.
+*
+* This file may be distributed and/or modified under the terms of the
+* GNU General Public License version 2 as published by the Free Software
+* Foundation and appearing in the file LICENSE.GPL included in the
+* packaging of this file.
+*
+* Licensees holding valid libFirm Professional Edition licenses may use
+* this file in accordance with the libFirm Commercial License.
+* Agreement provided with the Software.
+*
+* This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+* WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+* PURPOSE.
+*/
+
+/**
+* @file
+* @brief   Write ir graph as a grgen construction rule
+* @author  Andreas Schoesser, Sebastian Buchwald
+* @version $Id$
+*/
+
+/*
+ * THIS IS A COMPLETE QUICK HACK! USE WITH CARE
+ * NOT FOR PRODUCTION BUILD ;-)
+ */
+
+#define MAX_NODENAME_LEN 100
+
+#include <assert.h>
+#include <stdio.h>
+#include <obst.h>
+
+
+#include "irgraph.h"
+#include "firm_types.h"
+#include "pmap.h"
+#include "tv.h"
+#include "irgwalk.h"
+#include "firm_types.h"
+
+#include "entity_t.h"
+#include "irnode_t.h"
+
+
+typedef struct
+{
+       ir_graph *irg;
+       struct pmap *edge_name_map;
+       struct pmap *node_name_map;  // Contains the mapping firm node -> node name
+       struct obstack node_names;   // Contains the node name data
+       struct pmap *nodes_to_dump;  // Contains firm nodes, that have to be dumped
+} grgen_dumpinfo_t;
+
+// Holds information needed througout the usage of a grgen dumper instance
+typedef struct
+{
+       // The file the grgen rules will be dumped to
+       FILE *output_file;
+} irg_grgen_dumper_env_t;
+
+static void dump_grg_node(ir_node *n, grgen_dumpinfo_t *dump_info, FILE *fp);
+static void dump_grg_edge(ir_node *n, int n_edge, grgen_dumpinfo_t *dump_info, FILE *fp);
+static void dump_grgen_eval(ir_node *n, grgen_dumpinfo_t *dump_info, FILE *fp);
+static void dump_pattern(grgen_dumpinfo_t *dump_info, FILE *fp);
+static void set_indent(int i);
+
+
+
+/*****************************************************************************
+* Program:    grgen_dumper.c
+* Function:   Dumps parts of a firm graph (those which have to be extracted
+*             as search and replace patterns) as a grGen rule.
+* Depends on: Needs the analysis info generated by the pattern creator
+* Author:     Andreas Schoesser
+* Date:       2006-12-07
+*****************************************************************************/
+
+
+// ---------------------------- INCLUDES --------------------------------
+
+
+
+
+/* #include "grgen_dumper__t.h"
+#include "create_pattern_t.h"
+#include "firm_node_ext.h" */
+
+// ----------------------------- GLOABALS --------------------------------
+
+// Saves the current indent value and keeps spaces in a string
+#define MAX_INDENT 100
+static char indent[MAX_INDENT] = "";
+
+// Saves the current node number to generate node names
+static int node_counter;
+static int edge_counter;
+
+
+
+
+/************************************************************************
+* Initializes the grgen_dumper module and dumps the GrGen File header
+* Returns:      An environment to be passed to all functions of the GrGen
+*               dumper.
+* Parameters:
+*     file:     filename of the file to dump to
+*     append:   1 if the previous file content should be maintained.
+************************************************************************/
+
+irg_grgen_dumper_env_t *init_irg_grgen_dumper(char *file, int append)
+{
+       irg_grgen_dumper_env_t *const grgen_dumper_env = xmalloc(sizeof(*grgen_dumper_env));
+       FILE *fp;
+
+       if(append)
+               fp = fopen(file, "at");
+       else
+       {
+               fp = fopen(file, "wt");
+
+               // *** Dump header
+               fprintf(fp, "%susing Firm;\n\n", indent);
+       }
+
+       grgen_dumper_env->output_file = fp;
+       return(grgen_dumper_env);
+}
+
+
+
+/************************************************************************
+* Frees information used by the grgen_dumper and closes the output file
+************************************************************************/
+
+void deinit_irg_grgen_dumper(irg_grgen_dumper_env_t *grgen_dumper_env)
+{
+       fclose(grgen_dumper_env->output_file);
+       xfree(grgen_dumper_env);
+}
+
+static void collect_nodes(ir_node *n, void * env)
+{
+       pmap *nodes_to_dump = (pmap *) env;
+
+       pmap_insert(nodes_to_dump, n, NULL);
+}
+
+
+
+/************************************************************************
+* Helper functions
+************************************************************************/
+
+static bool is_ignored(ir_node *node)
+{
+       if(is_Proj(node) && !(is_Proj(get_Proj_pred(node)) && is_Start(get_Proj_pred(get_Proj_pred(node)))))
+               return true;
+
+       return false;
+}
+
+/************************************************************************
+ * Starts dumping
+ ************************************************************************/
+
+void dump_irg_grgen_file(ir_graph *irg, char *filename, int append)
+{
+       FILE *fp;
+       grgen_dumpinfo_t dump_info;
+
+       irg_grgen_dumper_env_t *grgen_dumper_env = init_irg_grgen_dumper(filename, append);
+       fp = grgen_dumper_env->output_file;
+
+       // Do initialization
+       dump_info.irg = irg; // Basically copy the graph_ana_struct, ugly
+       dump_info.edge_name_map = pmap_create(); // node and edge name information etc.
+       dump_info.node_name_map = pmap_create();
+       dump_info.nodes_to_dump = pmap_create();
+
+       // Node and edge count start at 0 for each pattern to be dumped.
+       node_counter = 0;
+       edge_counter = 0;
+       obstack_init(&(dump_info.node_names));
+
+       // Dump rule header
+       set_indent(0);
+       fprintf(fp, "\n\n%srule %s\n%s{\n", indent, get_entity_name(get_irg_entity(irg)), indent);
+       set_indent(2);
+
+       fprintf(fp, "%sreplace\n%s{\n", indent, indent); // Graph is constructed in the replacement part
+
+       set_indent(4);
+
+       irg_walk_graph(irg, collect_nodes, NULL, dump_info.nodes_to_dump);
+       dump_pattern(&dump_info, fp);
+
+       // *** Dump footer
+       set_indent(0);
+       fprintf(fp, "%s}\n", indent);
+
+       // Clean up
+       pmap_destroy(dump_info.edge_name_map);
+       pmap_destroy(dump_info.node_name_map);
+       obstack_free(&(dump_info.node_names), NULL);
+       obstack_finish(&(dump_info.node_names));
+
+       deinit_irg_grgen_dumper(grgen_dumper_env);
+}
+
+
+void dump_irg_grgen(ir_graph *irg, char *suffix)
+{
+  char filename[100] = "";
+
+  snprintf(filename, 100, "%s-%02u", get_entity_name(get_irg_entity(irg)), irg->dump_nr++);
+  strncat(filename, suffix, 100);
+  strncat(filename, ".grg", 100);
+
+  dump_irg_grgen_file(irg, filename, 0);
+}
+
+
+/************************************************************************
+ * Dumps the left hand side of the rule
+ ************************************************************************/
+
+static void dump_pattern(grgen_dumpinfo_t *dump_info, FILE *fp)
+{
+       struct pmap *nodes_to_dump = dump_info->nodes_to_dump;
+       pmap_entry *entry;
+
+       // Dump all nodes
+       foreach_pmap(nodes_to_dump, entry)
+       {
+               ir_node *n = (ir_node *) entry->key;
+
+               // Dump node
+               dump_grg_node(n, dump_info, fp);
+       }
+
+       // Dump all edges
+       foreach_pmap(nodes_to_dump, entry)
+       {
+               ir_node *n = (ir_node *) entry->key;
+               int i = -1;
+
+               if(is_Block(n))
+                       i++;
+
+               // Dump edges
+               for(; i < get_irn_arity(n); i++)
+                       dump_grg_edge(n, i, dump_info, fp);
+       }
+
+       fprintf(fp, "%seval {\n", indent);
+       set_indent(6);
+       foreach_pmap(nodes_to_dump, entry)
+       {
+               ir_node *n = (ir_node *) entry->key;
+               dump_grgen_eval(n, dump_info, fp);
+       }
+       set_indent(4);
+       fprintf(fp, "%s}\n", indent);
+
+
+       set_indent(2);
+       fprintf(fp, "%s} /* Replacement */\n", indent);
+}
+
+
+
+/************************************************************************
+* Dumps a node in GrGen Format
+************************************************************************/
+
+static void dump_grg_node(ir_node *n, grgen_dumpinfo_t *dump_info, FILE *fp)
+{
+       char *node_name;
+
+       // Already dumped the node? Then do nothing
+       if(pmap_contains(dump_info->node_name_map, n))
+               return;
+
+       // Ignore projs
+       if(is_ignored(n))
+               return;
+
+       // Else generate new node name and dump the node
+
+       node_name = obstack_alloc(&(dump_info->node_names), MAX_NODENAME_LEN);
+
+       const char *name = get_op_name(get_irn_op(n));
+
+       if(is_Proj(n)) {
+               name = "Argument";
+       }
+       else if (n == get_irg_start_block(get_irn_irg(n))) {
+               name = "StartBlock";
+       }
+       else if (n == get_irg_end_block(get_irn_irg(n))) {
+               name = "EndBlock";
+       }
+
+       sprintf(node_name, "%s%ld", name, get_irn_node_nr(n));
+       fprintf(fp, "%s%s : %s;\n", indent, node_name, name);
+
+       pmap_insert(dump_info->node_name_map, n, node_name);
+       node_counter++;
+}
+
+
+
+/************************************************************************
+* Dumps an edge in GrGen format
+************************************************************************/
+
+static void dump_grg_edge(ir_node *n, int n_edge, grgen_dumpinfo_t *dump_info, FILE *fp)
+{
+       ir_node *to_node;
+       ir_node *op;
+       char *from_node_name, *to_node_name;
+       char **nodes_edge_names;
+
+       if(is_ignored(n))
+               return;
+
+       op = get_irn_n(n, n_edge);
+
+       if (is_Proj(op) && is_Proj(skip_Proj(op)) && is_Start(skip_Proj(skip_Proj(op))))
+               to_node = op;
+       else
+               to_node = skip_Proj(skip_Proj(op));
+
+       if(is_ignored(to_node))
+               return;
+
+       // Check if to_node has also to be dumped. If not, skip this edge
+       // We have to dump to_node here, because to_node has to be known by grgen before
+       // connecting an edge to it.
+       if(!pmap_contains(dump_info->nodes_to_dump, to_node))
+               return;
+
+       if((nodes_edge_names = pmap_get(dump_info->edge_name_map, n)) == NULL)
+       {
+               nodes_edge_names = (char **) obstack_alloc(&(dump_info->node_names), (get_irn_arity(n) + 1) * sizeof(char *));
+               memset(nodes_edge_names, 0, (get_irn_arity(n) + 1) * sizeof(char *));
+               pmap_insert(dump_info->edge_name_map, n, nodes_edge_names);
+       }
+
+       assert(pmap_contains(dump_info->node_name_map, n));
+       assert(pmap_contains(dump_info->node_name_map, to_node));
+       from_node_name = (char *) pmap_get(dump_info->node_name_map, n);
+       to_node_name = (char *) pmap_get(dump_info->node_name_map, to_node);
+
+       char edge_name[50], *edge_name_obst;
+
+       sprintf(edge_name, "pos%d_%d", n_edge + 1, edge_counter++);
+       edge_name_obst = obstack_alloc(&(dump_info->node_names), strlen(edge_name) + 1);
+       strcpy(edge_name_obst, edge_name);
+       nodes_edge_names[n_edge + 1] = edge_name_obst;
+
+       if(is_End(n) && n_edge >= 0) {
+               fprintf(fp, "%s%s -%s:Keep-> %s;\n", indent, from_node_name, edge_name_obst, to_node_name);
+       }
+       else if (get_irn_mode(op) == mode_X) {
+               if(is_Cond(to_node)) {
+                       if (get_Proj_proj(op) == pn_Cond_true) {
+                               fprintf(fp, "%s%s -%s:True-> %s;\n", indent, from_node_name, edge_name_obst, to_node_name);
+                       }
+                       else {
+                               fprintf(fp, "%s%s -%s:False-> %s;\n", indent, from_node_name, edge_name_obst, to_node_name);
+                       }
+               }
+               else {
+                       fprintf(fp, "%s%s -%s:Controlflow-> %s;\n", indent, from_node_name, edge_name_obst, to_node_name);
+               }
+       }
+       else if (get_irn_mode(op) == mode_M) {
+               fprintf(fp, "%s%s -%s:Memory-> %s;\n", indent, from_node_name, edge_name_obst, to_node_name);
+       }
+       else {
+               fprintf(fp, "%s%s -%s:Dataflow-> %s;\n", indent, from_node_name, edge_name_obst, to_node_name);
+       }
+}
+
+/************************************************************************
+* Dumps the condition for the given node, depending on the node's
+* attributes and the node's opcode
+************************************************************************/
+
+static void dump_grgen_eval(ir_node *n, grgen_dumpinfo_t *dump_info, FILE *fp)
+{
+       char *node_name;
+       ir_opcode code = get_irn_opcode(n);
+
+       if(is_ignored(n))
+               return;
+
+       if(code == iro_Const)
+       {
+               node_name = pmap_get(dump_info->node_name_map, n);
+               fprintf(fp, "%s%s.value = %ld;\n", indent, node_name, get_tarval_long(get_Const_tarval(n)));
+       }
+
+
+       if(code == iro_Proj)
+       {
+               ir_node *skip = skip_Proj(skip_Proj((n)));
+               if (is_Start(skip)) {
+                       node_name = pmap_get(dump_info->node_name_map, n);
+                       fprintf(fp, "%s%s.position = %ld;\n", indent, node_name, get_Proj_proj(n));
+               }
+       }
+
+       if (code == iro_Cmp)
+       {
+               ir_relation rel = get_Cmp_relation(n);
+               node_name = pmap_get(dump_info->node_name_map, n);
+               switch (rel) {
+                       case ir_relation_false:
+                               fprintf(fp, "%s%s.relation = Relation::FALSE;\n", indent, node_name);
+                               break;
+                       case ir_relation_greater:
+                               fprintf(fp, "%s%s.relation = Relation::GREATER;\n", indent, node_name);
+                               break;
+                       case ir_relation_equal:
+                               fprintf(fp, "%s%s.relation = Relation::EQUAL;\n", indent, node_name);
+                               break;
+                       case ir_relation_greater_equal:
+                               fprintf(fp, "%s%s.relation = Relation::GREATER_EQUAL;\n", indent, node_name);
+                               break;
+                       case ir_relation_less:
+                               fprintf(fp, "%s%s.relation = Relation::LESS;\n", indent, node_name);
+                               break;
+                       case ir_relation_less_greater:
+                               fprintf(fp, "%s%s.relation = Relation::NOT_EQUAL;\n", indent, node_name);
+                               break;
+                       case ir_relation_less_equal:
+                               fprintf(fp, "%s%s.relation = Relation::LESS_EQUAL;\n", indent, node_name);
+                               break;
+                       case ir_relation_true:
+                               fprintf(fp, "%s%s.relation = Relation::TRUE;\n", indent, node_name);
+                               break;
+                       default:;
+               }
+       }
+
+       /*if(code == iro_Block)
+       {
+               node_name = pmap_get(dump_info->node_name_map, n);
+               fprintf(fp, "%s%s.pos = %d;\n", indent, node_name, ??);
+       }
+
+       if(code == iro_Phi)
+       {
+               node_name = pmap_get(dump_info->node_name_map, n);
+               fprintf(fp, "%s%s.pos = %d;\n", indent, node_name, ??);
+       }*/
+
+       // TODO: Dump Block evals: edge numbers
+
+
+       //if(code == iro_Phi || code == iro_Block)
+       {
+               char **edge_names;
+               int i = 0;
+
+               //assert((get_irn_arity(n) == get_irn_arity(phi_block)) && "Phi has other arity than it's block! Pattern seems to be broken.");
+
+               // Load the edge names that have been saved
+               edge_names = pmap_get(dump_info->edge_name_map, n);
+               //assert(edge_names && "Some edge names have not been dumped!");
+
+               // Correlate the matched phi edges with the matched block edges
+               // Caution: Position 0 in the edge_names array is the block edge, so start at 1
+               if(is_Block(n))
+                       i++;
+
+               for(; i < get_irn_arity(n) + 1; i++)
+               {
+                       ir_node *op = get_irn_n(n, i-1);
+                       ir_node *to_node;
+
+                       if (is_Proj(n) && is_Proj(skip_Proj(n)) && is_Start(skip_Proj(skip_Proj(n))))
+                               to_node = op;
+                       else
+                               to_node = skip_Proj(skip_Proj(op));
+
+                       if(is_ignored(to_node))
+                               continue;
+
+                       assert(edge_names[i] != NULL && "Some edges have not been dumped!");
+
+                       fprintf(fp, "%s%s.position = %d;\n", indent, edge_names[i], i - 1);
+               }
+               return;
+       }
+}
+
+
+
+
+
+/************************************************************************
+* Sets current indent
+************************************************************************/
+
+static void set_indent(int i)
+{
+       int j;
+
+       // Generate a string containing i blank characters
+       if(i < MAX_INDENT - 1)
+       {
+               for(j = 0; j < i; j++)
+                       indent[j] = ' ';
+               indent[j] = 0x0;
+       }
+}
diff --git a/ir/ir/irdump_grgen.h b/ir/ir/irdump_grgen.h
new file mode 100644 (file)
index 0000000..a0246cc
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+* Copyright (C) 1995-2007 University of Karlsruhe.  All right reserved.
+*
+* This file is part of libFirm.
+*
+* This file may be distributed and/or modified under the terms of the
+* GNU General Public License version 2 as published by the Free Software
+* Foundation and appearing in the file LICENSE.GPL included in the
+* packaging of this file.
+*
+* Licensees holding valid libFirm Professional Edition licenses may use
+* this file in accordance with the libFirm Commercial License.
+* Agreement provided with the Software.
+*
+* This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+* WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+* PURPOSE.
+*/
+
+/**
+* @file
+* @brief   Write ir graph as a grgen construction rule
+* @author  Andreas Schoesser
+* @version $Id$
+*/
+
+
+/**
+ * Dumps a complete irg in the grgen format
+ * irg:      irg to dump
+ * filename: text file to dump to
+ * append:   1 if the new rule should be appended to the file,
+ *           otherwise the previous contents are deleted
+ **/
+void dump_irg_grgen_file(ir_graph *irg, char *filename, int append);
+
+/**
+ * Like dump_irg_grgen_file dumps a complete irg in the grgen format
+ * irg:    irg to dump
+ * suffix: suffix for the output file (e.g. "main"+ suffix +".grg")
+ **/
+void dump_irg_grgen(ir_graph *irg, char *suffix);