summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDennis, CHENG Renquan <crquan@fedoraproject.org>2010-07-11 23:11:47 +0800
committerDennis, CHENG Renquan <crquan@fedoraproject.org>2010-07-11 23:11:47 +0800
commitfc85c38529fb8c824f616d4ffaf3d1f04badd0a2 (patch)
tree1e294551dfbc126e55f73cedcbc6a814ca9e44df
downloadgcc-dot-gen-plugin-fc85c38529fb8c824f616d4ffaf3d1f04badd0a2.tar.gz
gcc-dot-gen-plugin-fc85c38529fb8c824f616d4ffaf3d1f04badd0a2.tar.xz
gcc-dot-gen-plugin-fc85c38529fb8c824f616d4ffaf3d1f04badd0a2.zip
dotgen: Generate Graphiviz format .dot dump of functions control flow graph
+/* Generate Graphiviz format .dot dump of functions control flow graph, + similar as the gcc internal vcg dump. + Copyright (C) 2010 by + Author: "Dennis, CHENG Renquan" <crquan@fedoraproject.org>
-rw-r--r--.gitignore2
-rw-r--r--Makefile26
-rw-r--r--pass-dgen.c206
-rw-r--r--test1.c21
4 files changed, 255 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..9d22eb4
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,2 @@
+*.o
+*.so
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..453fbeb
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,26 @@
+
+GCC = gcc
+CC = gcc
+
+PLUGIN_FILE = dotgen.so
+PLUGIN_SOURCE_FILES = pass-dgen.c
+PLUGIN_OBJECT_FILES = $(patsubst %.c,%.o,$(PLUGIN_SOURCE_FILES))
+
+GCCPLUGINS_DIR := $(shell $(GCC) -print-file-name=plugin)
+CFLAGS += -I$(GCCPLUGINS_DIR)/include -I$(with_gmp)/include -Wall -O2
+
+all: $(PLUGIN_FILE)
+
+$(PLUGIN_FILE): $(PLUGIN_OBJECT_FILES)
+ $(GCC) -shared -o $@ $^
+
+.PHONY: clean all test
+
+test:
+ @if [ ! -d dump-files ]; then mkdir dump-files; fi
+ $(GCC) -fplugin=./$(PLUGIN_FILE) \
+ -fdump-tree-all -dumpdir dump-files/ \
+ -c test1.c
+
+clean:
+ @-rm -f *~ *.o $(PLUGIN_FILE)
diff --git a/pass-dgen.c b/pass-dgen.c
new file mode 100644
index 0000000..3bf9634
--- /dev/null
+++ b/pass-dgen.c
@@ -0,0 +1,206 @@
+/* Generate Graphiviz format .dot dump of functions control flow graph,
+ similar as the gcc internal vcg dump.
+ Copyright (C) 2010 by
+ Author: "Dennis, CHENG Renquan" <crquan@fedoraproject.org>
+
+This software is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 3, or (at your option)
+any later version.
+
+It 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 General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3. If not see
+<http://www.gnu.org/licenses/>. */
+
+#include "gcc-plugin.h"
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "tm.h"
+#include "tree.h"
+#include "rtl.h"
+#include "basic-block.h"
+#include "function.h"
+#include "langhooks.h"
+#include "tree-flow.h"
+#include "tree-dump.h"
+#include "tree-pass.h"
+
+int plugin_is_GPL_compatible;
+
+static const char *plugin_name;
+static struct plugin_info _version_help_info =
+{
+ "0.1", /* version */
+ "Dump internal gimple cfg into Graphviz .dot format",
+ /* help */
+};
+
+static void
+gimple_cfg2dot (FILE *file)
+{
+ edge e;
+ edge_iterator ei;
+ basic_block bb;
+ const char *funcname
+ = lang_hooks.decl_printable_name (current_function_decl, 2);
+
+ /* Write the file header. */
+ fprintf (file, "// Function %s\n", funcname);
+ fprintf (file, "digraph graph_%s {\n\n", funcname);
+ fprintf (file, " graph [ label=%s, labelloc=top ];\n\n", funcname);
+
+ /* Write blocks and edges. */
+ FOR_EACH_EDGE (e, ei, ENTRY_BLOCK_PTR->succs)
+ {
+ fprintf (file, " ENTRY -> %d", e->dest->index);
+
+ /* how to represent this in Graphviz dot ??? */
+ /* if (e->flags & EDGE_FAKE) */
+ /* fprintf (file, " linestyle: dotted priority: 10"); */
+ /* else */
+ /* fprintf (file, " linestyle: solid priority: 100"); */
+
+ fprintf (file, "\n");
+ }
+ fputc ('\n', file);
+
+ FOR_EACH_BB (bb)
+ {
+ enum gimple_code head_code, end_code;
+ const char *head_name, *end_name;
+ int head_line = 0;
+ int end_line = 0;
+ gimple first = first_stmt (bb);
+ gimple last = last_stmt (bb);
+
+ if (first)
+ {
+ head_code = gimple_code (first);
+ head_name = gimple_code_name[head_code];
+ head_line = get_lineno (first);
+ }
+ else
+ head_name = "no-statement";
+
+ if (last)
+ {
+ end_code = gimple_code (last);
+ end_name = gimple_code_name[end_code];
+ end_line = get_lineno (last);
+ }
+ else
+ end_name = "no-statement";
+
+ fprintf (file, " %d [ label=\"#%d\\n%s (%d)\\n%s (%d)\" ]\n",
+ bb->index, bb->index, head_name, head_line, end_name,
+ end_line);
+
+ FOR_EACH_EDGE (e, ei, bb->succs)
+ {
+ if (e->dest == EXIT_BLOCK_PTR)
+ fprintf (file, " %d -> EXIT\n", bb->index);
+ else
+ fprintf (file, " %d -> %d", bb->index, e->dest->index);
+
+ /* if (e->flags & EDGE_FAKE) */
+ /* fprintf (file, " priority: 10 linestyle: dotted"); */
+ /* else */
+ /* fprintf (file, " priority: 100 linestyle: solid"); */
+
+ /* fprintf (file, "\n"); */
+ }
+
+ if (bb->next_bb != EXIT_BLOCK_PTR)
+ fputc ('\n', file);
+ }
+
+ fprintf (file, "}\n\n");
+}
+
+static unsigned int
+execute_pass_cfg2dot ()
+{
+ static int dot_nr;
+ FILE *dot_file = NULL;
+
+ if (!dot_nr)
+ {
+ dot_nr = dump_register (".dot", NULL, NULL, TDF_TREE);
+ /* manually set dfi->state to -1 enable it,
+ because the dump_enable is static, cannot be used
+ by plugins.
+ */
+ get_dump_file_info (dot_nr)->state = -1;
+ dot_file = dump_begin (dot_nr, NULL);
+ if (dot_file)
+ {
+ time_t now;
+ time (&now);
+ fprintf (dot_file,
+ "\n// Generated by %s gcc plugin %s at %s\n",
+ plugin_name, _version_help_info.version,
+ ctime (&now));
+ }
+ }
+
+ if (!dot_file)
+ dot_file = dump_begin (dot_nr, NULL);
+ if (dot_file)
+ {
+ gimple_cfg2dot (dot_file);
+ dump_end (dot_nr, dot_file);
+ }
+
+ return 0;
+}
+
+static struct gimple_opt_pass pass_cfg2dot =
+{
+ {
+ GIMPLE_PASS,
+ "*cfg2dot", /* name */
+ NULL, /* gate */
+ execute_pass_cfg2dot, /* execute */
+ NULL, /* sub */
+ NULL, /* next */
+ 0, /* static_pass_number */
+ TV_NONE, /* tv_id */
+ PROP_cfg, /* properties_required */
+ 0, /* properties_provided */
+ 0, /* properties_destroyed */
+ 0, /* todo_flags_start */
+ 0 /* todo_flags_finish */
+ }
+};
+
+int
+plugin_init (struct plugin_name_args *plugin_info,
+ struct plugin_gcc_version *version)
+{
+ struct register_pass_info regi_info;
+
+ plugin_name = plugin_info->base_name;
+
+ register_callback (plugin_name,
+ PLUGIN_INFO,
+ NULL,
+ &_version_help_info);
+
+ regi_info.pass = &pass_cfg2dot.pass;
+ regi_info.reference_pass_name = "cfg";
+ regi_info.ref_pass_instance_number = 0;
+ regi_info.pos_op = PASS_POS_INSERT_AFTER;
+
+ register_callback (plugin_name,
+ PLUGIN_PASS_MANAGER_SETUP,
+ NULL,
+ &regi_info);
+
+ return 0;
+}
diff --git a/test1.c b/test1.c
new file mode 100644
index 0000000..e6f2bac
--- /dev/null
+++ b/test1.c
@@ -0,0 +1,21 @@
+#include "stdio.h"
+
+extern int random ();
+
+int func1 (int a, int b)
+{
+ return a+b;
+}
+
+int main (void)
+{
+ int a, b;
+
+ a = random ();
+ if (a)
+ a = a + func1 (a, b);
+
+ printf ("result=%d\n", a);
+
+ return 0;
+}