c-feedback.c   [plain text]


#include "config.h"
#include "system.h"
#include "tree.h"
#include "rtl.h"
#include "flags.h"
#include "toplev.h"
#include "output.h"
#include "c-tree.h"
#include "c-common.h"
#include "expr.h"
#include "feedback.h"
#include "basic-block.h"
#include "profile.h"
#include "tree-inline.h"
#include "gcov-io.h"
#include "ggc.h"
#include "langhooks.h"

/** Please increment the magic number in feedback.c and 
    (2 places) in libgcc2.c whenever a substantiative change
    is made to this size computation. ***/

unsigned int
c_find_control_flow_tree (t)
    tree t;
{
  unsigned int size = 0;
  switch (TREE_CODE (t))
    {
      case IF_STMT:
        size = 4;
        break;
      case FOR_STMT:
        size = 5;
	break;
      case WHILE_STMT:
      case DO_STMT:
	size = 3;
	break;
      case CONTINUE_STMT:
      case BREAK_STMT:
      case GOTO_STMT:
      case RETURN_STMT:
	size = 1;
	break;
      case SWITCH_STMT:
	/* For tablejumps, there is one arc for switch entry,
	   one between the out-of-range check and the tablejump,
	   and one per case in the table, plus one more for the
	   default when reached from the table.  The default when
	   reached from the out-of-range check is not counted
	   directly; it can be computed by subtracting the first
	   two counts.  */
	/* For switch by tree of compares, cases towards the center
	   of the tree generate 2 branches, leaves may generate 0 or 1.
	   2 per case is a safe max; I'm sure a smaller limit could
	   be derived. */
	if (TREE_CODE (SWITCH_BODY (t)) != COMPOUND_STMT)
	  /* no case labels; one branch past the body is genned */
	  size = 1;
	else if (COMPOUND_BODY (SWITCH_BODY (t)) == NULL_TREE)
	  /* empty body */
	  size = 1;
	else if (TREE_CODE (COMPOUND_BODY (SWITCH_BODY (t))) == SCOPE_STMT
	    && SCOPE_BEGIN_P (COMPOUND_BODY (SWITCH_BODY (t))))
	  {
	    tree tt = TREE_CHAIN (COMPOUND_BODY (SWITCH_BODY (t)));
	    /* Incorrect input might get this to loop or something;
	       for this purpose I don't care. */
	    int nesting = 1;
	    int default_found = 0;
	    size = 2;
	    for (; tt && nesting; tt = TREE_CHAIN (tt))
	      {
		if (TREE_CODE (tt) == SCOPE_STMT)
		  {
		    if (SCOPE_BEGIN_P (tt))
		      nesting++;
		    else if (SCOPE_END_P (tt))
		      nesting--;
		  }
		else if (TREE_CODE (tt) == CASE_LABEL && nesting == 1)
		  {
		    size += 2;
		    if (CASE_LOW (tt) == NULL_TREE) /* default: */
		      default_found = 1;
		  }
	      }
	    if (!default_found)
	      size += 2;
	  }
	break;
      default:	/* non-control-flow stmts, constants, etc. */
	break;
    }
  return size;
}

tree
c_create_feedback_counter_tree (table, ix)
     tree table;
     int ix;
{
  tree t;
  /* This produces a[i] = a[i] + 1 */
  /* Generating postincrement requires flushing the RTL queue at the right
     place later; this form is emitted immediately. */
  t = build_modify_expr (
	       build_array_ref (table, 
		  build_int_2 (ix, 0)),
	       NOP_EXPR,
	       build_binary_op (PLUS_EXPR,
		   build_array_ref (table,
		      build_int_2 (ix, 0)),
		   build_int_2 (1, 0), 0));
  return t;
}
void c_decorate_for_feedback (fndecl, find_call)
     tree fndecl;
     walk_tree_fn find_call;
{
  walk_tree_without_duplicates (&DECL_SAVED_TREE (fndecl), 
		  find_call, (void *)0);
}