This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[ast-optimizer-branch] Call graph for C (2/5)



The following patch allows to print the call graph in an XML file
by passing the option -fdump-call-graph.

Seb.



2002-02-28  Sebastian Pop  <s.pop@laposte.net>

	* Makefile.in : Add c-call-graph.o dependence.
	* c-call-graph.c : New file.
	* c-decl.c (c_expand_body): Add an entry point for call-graph.
	* tree-dump.c (dump_files): Add the flag dump-call-graph.
	* tree.h (tree_dump_index): Add TDI_xml.

Index: gcc/Makefile.in
===================================================================
RCS file: /cvs/gcc/gcc/gcc/Makefile.in,v
retrieving revision 1.701.2.13
diff -d -p -d -u -p -r1.701.2.13 Makefile.in
--- gcc/Makefile.in	2002/01/26 22:01:54	1.701.2.13
+++ gcc/Makefile.in	2002/02/28 01:56:19
@@ -703,7 +703,7 @@ C_AND_OBJC_OBJS = attribs.o c-errors.o c
   c-convert.o c-aux-info.o c-common.o c-format.o c-semantics.o \
   c-objc-common.o libcpp.a $(C_TARGET_OBJS) \
   tree-cfg.o tree-dfa.o tree-ssa.o tree-optimize.o c-pretty-print.o \
-  c-simplify.o
+  c-simplify.o c-call-graph.o
 
 # Language-specific object files for C.
 C_OBJS = c-parse.o c-lang.o $(C_AND_OBJC_OBJS)
Index: gcc/c-call-graph.c
===================================================================
RCS file: c-call-graph.c
diff -N c-call-graph.c
--- /dev/null	Tue May  5 13:32:27 1998
+++ gcc/c-call-graph.c	Wed Feb 27 17:56:19 2002
@@ -0,0 +1,351 @@
+/* Construction of the function call graph.
+   Copyright (C) 2002 Free Software Foundation, Inc.
+   Contributed by Sebastian Pop <s.pop@laposte.net>
+
+This file is part of GCC.
+
+GCC 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 2, or (at your option) any later
+version.
+
+GCC 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 COPYING.  If not, write to the Free
+Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA.  */
+
+#include "config.h"
+#include "system.h"
+#include "tree.h"
+#include "c-tree.h"
+#include "c-common.h"
+#include "hard-reg-set.h"
+#include "basic-block.h"
+#include "tree-flow.h"
+#include "diagnostic.h"
+
+/* Declarations to be moved in a .h file : which one ?  */
+extern void print_call_graph PARAMS ((FILE*, tree));
+extern void debug_call_graph PARAMS ((tree));
+extern void construct_call_graph PARAMS ((output_buffer *, tree, HOST_WIDE_INT));
+
+/* Static declarations.  */
+static void write_dtd PARAMS ((output_buffer *));
+static void print_callee PARAMS ((output_buffer *, tree, int));
+
+#define INDENT(SPACE) do { \
+  int i; for (i = 0; i<SPACE; i++) output_add_space (buffer); } while (0)
+#define NIY do { \
+  debug_output_buffer (buffer); debug_tree (node); abort (); } while (0)
+
+
+/* Print the call graph associated to the tree T, in the file FILE.  */
+
+void 
+print_call_graph (file, t)
+     FILE *file;
+     tree t;
+{
+  output_buffer buffer_rec;
+  output_buffer *buffer = &buffer_rec;
+  
+  init_output_buffer (buffer, /* prefix */NULL, /* line-width */0);
+  output_clear_message_text (buffer);
+  /* write_dtd (buffer);  */
+  output_printf (buffer, "<file>\n");
+  construct_call_graph (buffer, t, 0);
+  output_printf (buffer, "</file>\n");
+  fprintf (file, "%s", output_finalize_message (buffer));
+}
+
+/* Print the call graph on stderr.  */
+
+void 
+debug_call_graph (t)
+     tree t;
+{
+  print_call_graph (stderr, t);
+}
+
+
+/* Scan the tree T searching for callee/caller functions, then output found 
+   function calls/callers in the output_buffer BUFFER under the DTD format 
+   described above.  
+   Not Yet Implemented : the dump of global variables and their use.  */
+
+void 
+construct_call_graph (buffer, t, spc)
+     output_buffer *buffer;
+     tree t;
+     HOST_WIDE_INT spc;
+{
+  static unsigned int decision_points;
+  static unsigned int nb_statements;
+  static unsigned int nb_calls;
+  tree node = t;
+
+  while (node && node != error_mark_node)
+    {
+      enum tree_code code = TREE_CODE (node);
+      if (is_ctrl_stmt (node)) decision_points++;
+      if (is_exec_stmt (node)) nb_statements++;
+
+      switch (code)
+	{
+	case TYPE_DECL:
+	case FIELD_DECL:
+	case VAR_DECL:
+	case PARM_DECL:
+	  /* Some nodes on which we need to stop the recursion.  */
+	  return;
+	  
+	case FUNCTION_DECL:
+	  if (BUILT_IN_FRONTEND)
+
+	  INDENT (spc);
+	  output_printf (buffer, "<caller id = \"");
+	  print_function_decl (buffer, node, 0);
+	  output_printf (buffer, "\">\n");
+
+	  /* What about definition of nested functions?  That will reset the
+	     current value of decision_points and nb_statements...  */
+	  decision_points = 0;
+	  nb_statements = 0;
+	  nb_calls = 0;
+	  construct_call_graph (buffer, DECL_SAVED_TREE (node), spc+1);
+
+	  /* Statements based statistics.  */
+	  INDENT (spc+1);
+	  output_printf (buffer, "<stats calls=\"%d\" decisions=\"%d\" stmts=\"%d\" Gilb=\"%f\"", 
+			 nb_calls, decision_points, nb_statements, 
+			 ((nb_statements == 0) ? 0 : 
+			  ((float)decision_points / (float)nb_statements)));
+	  
+	  /* Control flow statistics.  */
+	  init_flow ();
+	  tree_find_basic_blocks (DECL_SAVED_TREE (node));
+	  output_printf (buffer, " CFG-edges=\"%d\" CFG-BB=\"%d\" McCabe=\"%d\">\n",
+			 n_edges, n_basic_blocks, n_edges - n_basic_blocks + 2);
+	  delete_cfg ();
+
+	  /* End of the node.  */
+	  INDENT (spc);
+	  output_printf (buffer, "</caller>\n");
+	  return;
+
+	case CALL_EXPR:
+	  {
+	    tree op0;
+	    op0 = TREE_OPERAND (node, 0);
+
+	    nb_calls++;
+	    if (TREE_CODE (op0) == NON_LVALUE_EXPR)
+	      op0 = TREE_OPERAND (op0, 0);
+
+	    switch (TREE_CODE (op0))
+	      {
+	      case VAR_DECL:
+	      case PARM_DECL:
+		/* if (TREE_CODE (op0) == PARM_DECL)
+		   This function pointer was received in parameter.  
+		   I think that this should not enter in the call graph.  
+		   Or otherwise it enters but with a special mark
+		   saying that the name of this function is a parameter, 
+		   and thus for this name we don't expect a declaration.
+		   Example: 
+		   /gcc/libiberty/splay_tree.c:splay_tree_foreach_helper ().  */
+		print_callee (buffer, op0, spc);
+		break;
+
+	      case ADDR_EXPR:
+	      case INDIRECT_REF:
+	      case NOP_EXPR:
+		print_callee (buffer, TREE_OPERAND (op0, 0), spc);
+		break;
+
+	      case COND_EXPR:
+		//print_callee (buffer, TREE_OPERAND (TREE_OPERAND (op0, 0), 1), spc);
+		//print_callee (buffer, TREE_OPERAND (TREE_OPERAND (op0, 0), 2), spc);
+		break;
+
+	      case COMPONENT_REF:
+		/* The function is a pointer contained in a structure.  */
+		if (TREE_CODE (TREE_OPERAND (op0, 0)) == INDIRECT_REF ||
+		    TREE_CODE (TREE_OPERAND (op0, 0)) == VAR_DECL)
+		  print_callee (buffer, TREE_OPERAND (op0, 1), spc);
+		/* else
+		   We can have several levels of structures and a function 
+		   pointer inside.  This is not implemented yet...  */
+		//		  NIY;
+		break;
+	      
+	      case ARRAY_REF:
+		if (TREE_CODE (TREE_OPERAND (op0, 0)) == VAR_DECL)
+		  print_callee (buffer, TREE_OPERAND (op0, 0), spc);
+		else
+		  print_callee (buffer, TREE_OPERAND (op0, 1), spc);
+		break;
+
+	      default:
+		NIY;
+	      }
+	    /* Walk through function's arguments.  */
+	    construct_call_graph (buffer, TREE_OPERAND (node, 1), spc);	  
+	    node = TREE_CHAIN (node);
+	    break;
+	  }
+
+	case METHOD_CALL_EXPR:
+	  NIY;
+
+	case ADDR_EXPR:
+	  /* May be a function pointer passed as a parameter to a function.  */
+	  if (TREE_CODE (TREE_OPERAND (node, 0)) == FUNCTION_DECL)
+	    print_callee (buffer, TREE_OPERAND (node, 0), spc);
+	  else
+	    construct_call_graph (buffer, TREE_OPERAND (node, 0), spc);
+	  node = TREE_CHAIN (node);
+	  break;
+
+	case ARRAY_REF:
+	  if (TREE_CODE (TREE_OPERAND (node, 0)) == ARRAY_REF)
+	    construct_call_graph (buffer, TREE_OPERAND (node, 0), spc);
+	  
+	  construct_call_graph (buffer, TREE_OPERAND (node, 1), spc);
+	  node = TREE_CHAIN (node);
+	  break;
+
+	case TREE_LIST:
+	  construct_call_graph (buffer, TREE_VALUE (node), spc);
+	  node = TREE_CHAIN (node);
+	  break;
+
+	case FIX_TRUNC_EXPR:
+	case FIX_CEIL_EXPR:
+	case FIX_FLOOR_EXPR:
+	case FIX_ROUND_EXPR:
+	case FLOAT_EXPR:
+	case TRUTH_NOT_EXPR:
+	case BIT_NOT_EXPR:
+	case NE_EXPR:
+	case INDIRECT_REF:
+	case COMPOUND_STMT:
+	case EXPR_STMT:
+	case NOP_EXPR:
+	case RETURN_STMT:
+	  /* Unary nodes.  */
+	  construct_call_graph (buffer, TREE_OPERAND (node, 0), spc);
+	  node = TREE_CHAIN (node);
+	  break;
+
+	case DO_STMT:
+	case WHILE_STMT:
+	case SWITCH_STMT:
+	case LSHIFT_EXPR:
+	case RSHIFT_EXPR:
+	case LROTATE_EXPR:
+	case RROTATE_EXPR:
+	case BIT_IOR_EXPR:
+	case BIT_XOR_EXPR:
+	case BIT_AND_EXPR:
+	case BIT_ANDTC_EXPR:
+	case TRUTH_ANDIF_EXPR:
+	case TRUTH_ORIF_EXPR:
+	case TRUTH_AND_EXPR:
+	case TRUTH_OR_EXPR:
+	case TRUTH_XOR_EXPR:
+	case LT_EXPR:
+	case LE_EXPR:
+	case GT_EXPR:
+	case GE_EXPR:
+	case EQ_EXPR:
+	case PLUS_EXPR:
+	case MINUS_EXPR:
+	case MULT_EXPR:
+	case TRUNC_DIV_EXPR:
+	case MODIFY_EXPR:
+	  /* Binary nodes.  */
+	  construct_call_graph (buffer, TREE_OPERAND (node, 0), spc);
+	  construct_call_graph (buffer, TREE_OPERAND (node, 1), spc);
+	  node = TREE_CHAIN (node);
+	  break;
+
+	case COND_EXPR:
+	case IF_STMT:
+	  /* Ternary nodes.  */
+	  construct_call_graph (buffer, TREE_OPERAND (node, 0), spc);
+	  construct_call_graph (buffer, TREE_OPERAND (node, 1), spc);
+	  construct_call_graph (buffer, TREE_OPERAND (node, 2), spc);
+	  node = TREE_CHAIN (node);
+	  break;
+
+	case FOR_STMT:
+	  /* Quaternary nodes.  */
+	  construct_call_graph (buffer, TREE_OPERAND (node, 0), spc);
+	  construct_call_graph (buffer, TREE_OPERAND (node, 1), spc);
+	  construct_call_graph (buffer, TREE_OPERAND (node, 2), spc);
+	  construct_call_graph (buffer, TREE_OPERAND (node, 3), spc);
+	  node = TREE_CHAIN (node);
+	  break;
+
+	default:
+	  node = TREE_CHAIN (node);
+	  break;
+	}
+    }
+}
+
+
+/* Print the callee function declaration.  */
+
+static void 
+print_callee (buffer, node, spc)
+     output_buffer *buffer;
+     tree node;
+     int spc;
+{
+  int i;
+
+  /* Indent.  */
+  for (i = 0; i<spc; i++) 
+    output_add_space (buffer);
+
+  /* Print the node.  */
+  output_printf (buffer, "<callee idref = \"");
+  print_function_decl (buffer, node, 0);
+  output_printf (buffer, "\"/>\n");
+}
+
+/* Write the DTD in the given buffer.  */
+
+static void 
+write_dtd (buffer)
+     output_buffer *buffer;
+{
+  output_printf (buffer, "\
+<?xml version=\"1.0\"?>\n\
+<!DOCTYPE functions [\n\
+  <!ELEMENT file (caller|gvar)*>\n\
+  <!ELEMENT gvar EMPTY>\n\
+    <!ATTLIST gvar vid        ID #REQUIRED>\n\
+  <!ELEMENT caller ((uvar|callee|caller)*, stats)>\n\
+    <!ATTLIST caller fid      ID #REQUIRED>\n\
+  <!ELEMENT callee EMPTY>\n\
+    <!ATTLIST callee fid      IDREF #REQUIRED>\n\
+  <!ELEMENT uvar EMPTY>\n\
+    <!ATTLIST uvar vid        IDREF #REQUIRED>\n\
+  <!ELEMENT stats EMPTY>\n\
+    <!ATTLIST stats calls     CDATA>\n\
+    <!ATTLIST stats decisions CDATA>\n\
+    <!ATTLIST stats stmts     CDATA>\n\
+    <!ATTLIST stats Gilb      CDATA>\n\
+    <!ATTLIST stats CFG-edges CDATA>\n\
+    <!ATTLIST stats CFG-BB    CDATA>\n\
+    <!ATTLIST stats McCabe    CDATA>\n\
+]>\n");
+}
Index: gcc/c-decl.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/c-decl.c,v
retrieving revision 1.239.2.8
diff -d -p -d -u -p -r1.239.2.8 c-decl.c
--- gcc/c-decl.c	2002/01/26 22:01:57	1.239.2.8
+++ gcc/c-decl.c	2002/02/28 01:56:20
@@ -6944,6 +6946,21 @@ c_expand_body (fndecl, nested_p, can_def
 {
   int uninlinable = 1;
 
+  /* Dump the function call graph.  */
+  {  
+    FILE *dumpfile;
+    int dump_flags;
+    dumpfile = dump_begin (TDI_xml, &dump_flags);
+    if (dumpfile)
+      {
+	/* Dump the function call graph.  */
+	print_call_graph (dumpfile, fndecl);
+	dump_end (TDI_xml, dumpfile);
+      }
+  }
+
+  //  debug_c_tree (fndecl);
+
   /* There's no reason to do any of the work here if we're only doing
      semantic analysis; this code just generates RTL.  */
   if (flag_syntax_only)
Index: gcc/tree-dump.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/tree-dump.c,v
retrieving revision 1.2.4.4
diff -d -p -d -u -p -r1.2.4.4 tree-dump.c
--- gcc/tree-dump.c	2002/01/26 22:03:11	1.2.4.4
+++ gcc/tree-dump.c	2002/02/28 01:56:21
@@ -804,6 +804,7 @@ static struct dump_file_info dump_files[
   {".dot", "dump-tree-graphviz", 0, 0},
   {".ssa", "dump-tree-ssa", 0, 0},
   {".simple", "dump-tree-simple", 0, 0},
+  {".xml", "dump-call-graph", 0, 0},
 };
 
 /* Define a name->number mapping for a dump flag value.  */
Index: gcc/tree.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/tree.h,v
retrieving revision 1.257.2.4
diff -d -p -d -u -p -r1.257.2.4 tree.h
--- gcc/tree.h	2002/01/26 22:03:12	1.257.2.4
+++ gcc/tree.h	2002/02/28 01:56:22
@@ -3127,6 +3133,7 @@ enum tree_dump_index
   TDI_ssa,			/* dump SSA information for each function.  */
   TDI_simple,			/* dump each function before and after 
 				   simplifying it.  */
+  TDI_xml,                      /* dump function call graph.  */
   TDI_end
 };
 


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]