OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [gnu-stable/] [gcc-4.5.1/] [gcc/] [cgraphbuild.c] - Diff between revs 816 and 826

Go to most recent revision | Only display areas with differences | Details | Blame | View Log

Rev 816 Rev 826
/* Callgraph construction.
/* Callgraph construction.
   Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009
   Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009
   Free Software Foundation, Inc.
   Free Software Foundation, Inc.
   Contributed by Jan Hubicka
   Contributed by Jan Hubicka
 
 
This file is part of GCC.
This file is part of GCC.
 
 
GCC is free software; you can redistribute it and/or modify it under
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
the terms of the GNU General Public License as published by the Free
Software Foundation; either version 3, or (at your option) any later
Software Foundation; either version 3, or (at your option) any later
version.
version.
 
 
GCC is distributed in the hope that it will be useful, but WITHOUT ANY
GCC is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
for more details.
for more details.
 
 
You should have received a copy of the GNU General Public License
You should have received a copy of the GNU General Public License
along with GCC; see the file COPYING3.  If not see
along with GCC; see the file COPYING3.  If not see
<http://www.gnu.org/licenses/>.  */
<http://www.gnu.org/licenses/>.  */
 
 
#include "config.h"
#include "config.h"
#include "system.h"
#include "system.h"
#include "coretypes.h"
#include "coretypes.h"
#include "tm.h"
#include "tm.h"
#include "tree.h"
#include "tree.h"
#include "tree-flow.h"
#include "tree-flow.h"
#include "langhooks.h"
#include "langhooks.h"
#include "pointer-set.h"
#include "pointer-set.h"
#include "cgraph.h"
#include "cgraph.h"
#include "intl.h"
#include "intl.h"
#include "gimple.h"
#include "gimple.h"
#include "tree-pass.h"
#include "tree-pass.h"
 
 
/* Walk tree and record all calls and references to functions/variables.
/* Walk tree and record all calls and references to functions/variables.
   Called via walk_tree: TP is pointer to tree to be examined.
   Called via walk_tree: TP is pointer to tree to be examined.
   When DATA is non-null, record references to callgraph.
   When DATA is non-null, record references to callgraph.
   */
   */
 
 
static tree
static tree
record_reference (tree *tp, int *walk_subtrees, void *data)
record_reference (tree *tp, int *walk_subtrees, void *data)
{
{
  tree t = *tp;
  tree t = *tp;
  tree decl;
  tree decl;
  bool do_callgraph = data != NULL;
  bool do_callgraph = data != NULL;
 
 
  switch (TREE_CODE (t))
  switch (TREE_CODE (t))
    {
    {
    case VAR_DECL:
    case VAR_DECL:
      if (TREE_STATIC (t) || DECL_EXTERNAL (t))
      if (TREE_STATIC (t) || DECL_EXTERNAL (t))
        {
        {
          varpool_mark_needed_node (varpool_node (t));
          varpool_mark_needed_node (varpool_node (t));
          if (lang_hooks.callgraph.analyze_expr)
          if (lang_hooks.callgraph.analyze_expr)
            return lang_hooks.callgraph.analyze_expr (tp, walk_subtrees);
            return lang_hooks.callgraph.analyze_expr (tp, walk_subtrees);
        }
        }
      break;
      break;
 
 
    case FDESC_EXPR:
    case FDESC_EXPR:
    case ADDR_EXPR:
    case ADDR_EXPR:
      /* Record dereferences to the functions.  This makes the
      /* Record dereferences to the functions.  This makes the
         functions reachable unconditionally.  */
         functions reachable unconditionally.  */
      decl = TREE_OPERAND (*tp, 0);
      decl = TREE_OPERAND (*tp, 0);
      if (TREE_CODE (decl) == FUNCTION_DECL && do_callgraph)
      if (TREE_CODE (decl) == FUNCTION_DECL && do_callgraph)
        cgraph_mark_address_taken_node (cgraph_node (decl));
        cgraph_mark_address_taken_node (cgraph_node (decl));
      break;
      break;
 
 
    default:
    default:
      /* Save some cycles by not walking types and declaration as we
      /* Save some cycles by not walking types and declaration as we
         won't find anything useful there anyway.  */
         won't find anything useful there anyway.  */
      if (IS_TYPE_OR_DECL_P (*tp))
      if (IS_TYPE_OR_DECL_P (*tp))
        {
        {
          *walk_subtrees = 0;
          *walk_subtrees = 0;
          break;
          break;
        }
        }
 
 
      if ((unsigned int) TREE_CODE (t) >= LAST_AND_UNUSED_TREE_CODE)
      if ((unsigned int) TREE_CODE (t) >= LAST_AND_UNUSED_TREE_CODE)
        return lang_hooks.callgraph.analyze_expr (tp, walk_subtrees);
        return lang_hooks.callgraph.analyze_expr (tp, walk_subtrees);
      break;
      break;
    }
    }
 
 
  return NULL_TREE;
  return NULL_TREE;
}
}
 
 
/* Reset inlining information of all incoming call edges of NODE.  */
/* Reset inlining information of all incoming call edges of NODE.  */
 
 
void
void
reset_inline_failed (struct cgraph_node *node)
reset_inline_failed (struct cgraph_node *node)
{
{
  struct cgraph_edge *e;
  struct cgraph_edge *e;
 
 
  for (e = node->callers; e; e = e->next_caller)
  for (e = node->callers; e; e = e->next_caller)
    {
    {
      e->callee->global.inlined_to = NULL;
      e->callee->global.inlined_to = NULL;
      if (!node->analyzed)
      if (!node->analyzed)
        e->inline_failed = CIF_BODY_NOT_AVAILABLE;
        e->inline_failed = CIF_BODY_NOT_AVAILABLE;
      else if (node->local.redefined_extern_inline)
      else if (node->local.redefined_extern_inline)
        e->inline_failed = CIF_REDEFINED_EXTERN_INLINE;
        e->inline_failed = CIF_REDEFINED_EXTERN_INLINE;
      else if (!node->local.inlinable)
      else if (!node->local.inlinable)
        e->inline_failed = CIF_FUNCTION_NOT_INLINABLE;
        e->inline_failed = CIF_FUNCTION_NOT_INLINABLE;
      else if (e->call_stmt_cannot_inline_p)
      else if (e->call_stmt_cannot_inline_p)
        e->inline_failed = CIF_MISMATCHED_ARGUMENTS;
        e->inline_failed = CIF_MISMATCHED_ARGUMENTS;
      else
      else
        e->inline_failed = CIF_FUNCTION_NOT_CONSIDERED;
        e->inline_failed = CIF_FUNCTION_NOT_CONSIDERED;
    }
    }
}
}
 
 
/* Computes the frequency of the call statement so that it can be stored in
/* Computes the frequency of the call statement so that it can be stored in
   cgraph_edge.  BB is the basic block of the call statement.  */
   cgraph_edge.  BB is the basic block of the call statement.  */
int
int
compute_call_stmt_bb_frequency (tree decl, basic_block bb)
compute_call_stmt_bb_frequency (tree decl, basic_block bb)
{
{
  int entry_freq = ENTRY_BLOCK_PTR_FOR_FUNCTION
  int entry_freq = ENTRY_BLOCK_PTR_FOR_FUNCTION
                     (DECL_STRUCT_FUNCTION (decl))->frequency;
                     (DECL_STRUCT_FUNCTION (decl))->frequency;
  int freq = bb->frequency;
  int freq = bb->frequency;
 
 
  if (profile_status_for_function (DECL_STRUCT_FUNCTION (decl)) == PROFILE_ABSENT)
  if (profile_status_for_function (DECL_STRUCT_FUNCTION (decl)) == PROFILE_ABSENT)
    return CGRAPH_FREQ_BASE;
    return CGRAPH_FREQ_BASE;
 
 
  if (!entry_freq)
  if (!entry_freq)
    entry_freq = 1, freq++;
    entry_freq = 1, freq++;
 
 
  freq = freq * CGRAPH_FREQ_BASE / entry_freq;
  freq = freq * CGRAPH_FREQ_BASE / entry_freq;
  if (freq > CGRAPH_FREQ_MAX)
  if (freq > CGRAPH_FREQ_MAX)
    freq = CGRAPH_FREQ_MAX;
    freq = CGRAPH_FREQ_MAX;
 
 
  return freq;
  return freq;
}
}
 
 
/* Create cgraph edges for function calls.
/* Create cgraph edges for function calls.
   Also look for functions and variables having addresses taken.  */
   Also look for functions and variables having addresses taken.  */
 
 
static unsigned int
static unsigned int
build_cgraph_edges (void)
build_cgraph_edges (void)
{
{
  basic_block bb;
  basic_block bb;
  struct cgraph_node *node = cgraph_node (current_function_decl);
  struct cgraph_node *node = cgraph_node (current_function_decl);
  struct pointer_set_t *visited_nodes = pointer_set_create ();
  struct pointer_set_t *visited_nodes = pointer_set_create ();
  gimple_stmt_iterator gsi;
  gimple_stmt_iterator gsi;
  tree step;
  tree step;
 
 
  /* Create the callgraph edges and record the nodes referenced by the function.
  /* Create the callgraph edges and record the nodes referenced by the function.
     body.  */
     body.  */
  FOR_EACH_BB (bb)
  FOR_EACH_BB (bb)
    for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
    for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
      {
      {
        gimple stmt = gsi_stmt (gsi);
        gimple stmt = gsi_stmt (gsi);
        tree decl;
        tree decl;
 
 
        if (is_gimple_call (stmt) && (decl = gimple_call_fndecl (stmt)))
        if (is_gimple_call (stmt) && (decl = gimple_call_fndecl (stmt)))
          {
          {
            size_t i;
            size_t i;
            size_t n = gimple_call_num_args (stmt);
            size_t n = gimple_call_num_args (stmt);
            cgraph_create_edge (node, cgraph_node (decl), stmt,
            cgraph_create_edge (node, cgraph_node (decl), stmt,
                                bb->count, compute_call_stmt_bb_frequency (current_function_decl, bb),
                                bb->count, compute_call_stmt_bb_frequency (current_function_decl, bb),
                                bb->loop_depth);
                                bb->loop_depth);
            for (i = 0; i < n; i++)
            for (i = 0; i < n; i++)
              walk_tree (gimple_call_arg_ptr (stmt, i), record_reference,
              walk_tree (gimple_call_arg_ptr (stmt, i), record_reference,
                         node, visited_nodes);
                         node, visited_nodes);
            if (gimple_call_lhs (stmt))
            if (gimple_call_lhs (stmt))
              walk_tree (gimple_call_lhs_ptr (stmt), record_reference, node,
              walk_tree (gimple_call_lhs_ptr (stmt), record_reference, node,
                         visited_nodes);
                         visited_nodes);
          }
          }
        else
        else
          {
          {
            struct walk_stmt_info wi;
            struct walk_stmt_info wi;
            memset (&wi, 0, sizeof (wi));
            memset (&wi, 0, sizeof (wi));
            wi.info = node;
            wi.info = node;
            wi.pset = visited_nodes;
            wi.pset = visited_nodes;
            walk_gimple_op (stmt, record_reference, &wi);
            walk_gimple_op (stmt, record_reference, &wi);
            if (gimple_code (stmt) == GIMPLE_OMP_PARALLEL
            if (gimple_code (stmt) == GIMPLE_OMP_PARALLEL
                && gimple_omp_parallel_child_fn (stmt))
                && gimple_omp_parallel_child_fn (stmt))
              {
              {
                tree fn = gimple_omp_parallel_child_fn (stmt);
                tree fn = gimple_omp_parallel_child_fn (stmt);
                cgraph_mark_needed_node (cgraph_node (fn));
                cgraph_mark_needed_node (cgraph_node (fn));
              }
              }
            if (gimple_code (stmt) == GIMPLE_OMP_TASK)
            if (gimple_code (stmt) == GIMPLE_OMP_TASK)
              {
              {
                tree fn = gimple_omp_task_child_fn (stmt);
                tree fn = gimple_omp_task_child_fn (stmt);
                if (fn)
                if (fn)
                  cgraph_mark_needed_node (cgraph_node (fn));
                  cgraph_mark_needed_node (cgraph_node (fn));
                fn = gimple_omp_task_copy_fn (stmt);
                fn = gimple_omp_task_copy_fn (stmt);
                if (fn)
                if (fn)
                  cgraph_mark_needed_node (cgraph_node (fn));
                  cgraph_mark_needed_node (cgraph_node (fn));
              }
              }
          }
          }
      }
      }
 
 
  /* Look for initializers of constant variables and private statics.  */
  /* Look for initializers of constant variables and private statics.  */
  for (step = cfun->local_decls;
  for (step = cfun->local_decls;
       step;
       step;
       step = TREE_CHAIN (step))
       step = TREE_CHAIN (step))
    {
    {
      tree decl = TREE_VALUE (step);
      tree decl = TREE_VALUE (step);
      if (TREE_CODE (decl) == VAR_DECL
      if (TREE_CODE (decl) == VAR_DECL
          && (TREE_STATIC (decl) && !DECL_EXTERNAL (decl)))
          && (TREE_STATIC (decl) && !DECL_EXTERNAL (decl)))
        varpool_finalize_decl (decl);
        varpool_finalize_decl (decl);
      else if (TREE_CODE (decl) == VAR_DECL && DECL_INITIAL (decl))
      else if (TREE_CODE (decl) == VAR_DECL && DECL_INITIAL (decl))
        walk_tree (&DECL_INITIAL (decl), record_reference, node, visited_nodes);
        walk_tree (&DECL_INITIAL (decl), record_reference, node, visited_nodes);
    }
    }
 
 
  pointer_set_destroy (visited_nodes);
  pointer_set_destroy (visited_nodes);
  return 0;
  return 0;
}
}
 
 
struct gimple_opt_pass pass_build_cgraph_edges =
struct gimple_opt_pass pass_build_cgraph_edges =
{
{
 {
 {
  GIMPLE_PASS,
  GIMPLE_PASS,
  "*build_cgraph_edges",                        /* name */
  "*build_cgraph_edges",                        /* name */
  NULL,                                 /* gate */
  NULL,                                 /* gate */
  build_cgraph_edges,                   /* execute */
  build_cgraph_edges,                   /* execute */
  NULL,                                 /* sub */
  NULL,                                 /* sub */
  NULL,                                 /* next */
  NULL,                                 /* next */
  0,                                     /* static_pass_number */
  0,                                     /* static_pass_number */
  TV_NONE,                              /* tv_id */
  TV_NONE,                              /* tv_id */
  PROP_cfg,                             /* properties_required */
  PROP_cfg,                             /* properties_required */
  0,                                     /* properties_provided */
  0,                                     /* properties_provided */
  0,                                     /* properties_destroyed */
  0,                                     /* properties_destroyed */
  0,                                     /* todo_flags_start */
  0,                                     /* todo_flags_start */
  0                                      /* todo_flags_finish */
  0                                      /* todo_flags_finish */
 }
 }
};
};
 
 
/* Record references to functions and other variables present in the
/* Record references to functions and other variables present in the
   initial value of DECL, a variable.
   initial value of DECL, a variable.
   When ONLY_VARS is true, we mark needed only variables, not functions.  */
   When ONLY_VARS is true, we mark needed only variables, not functions.  */
 
 
void
void
record_references_in_initializer (tree decl, bool only_vars)
record_references_in_initializer (tree decl, bool only_vars)
{
{
  struct pointer_set_t *visited_nodes = pointer_set_create ();
  struct pointer_set_t *visited_nodes = pointer_set_create ();
  walk_tree (&DECL_INITIAL (decl), record_reference,
  walk_tree (&DECL_INITIAL (decl), record_reference,
            only_vars ? NULL : decl, visited_nodes);
            only_vars ? NULL : decl, visited_nodes);
  pointer_set_destroy (visited_nodes);
  pointer_set_destroy (visited_nodes);
}
}
 
 
/* Rebuild cgraph edges for current function node.  This needs to be run after
/* Rebuild cgraph edges for current function node.  This needs to be run after
   passes that don't update the cgraph.  */
   passes that don't update the cgraph.  */
 
 
unsigned int
unsigned int
rebuild_cgraph_edges (void)
rebuild_cgraph_edges (void)
{
{
  basic_block bb;
  basic_block bb;
  struct cgraph_node *node = cgraph_node (current_function_decl);
  struct cgraph_node *node = cgraph_node (current_function_decl);
  gimple_stmt_iterator gsi;
  gimple_stmt_iterator gsi;
 
 
  cgraph_node_remove_callees (node);
  cgraph_node_remove_callees (node);
 
 
  node->count = ENTRY_BLOCK_PTR->count;
  node->count = ENTRY_BLOCK_PTR->count;
 
 
  FOR_EACH_BB (bb)
  FOR_EACH_BB (bb)
    for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
    for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
      {
      {
        gimple stmt = gsi_stmt (gsi);
        gimple stmt = gsi_stmt (gsi);
        tree decl;
        tree decl;
 
 
        if (is_gimple_call (stmt) && (decl = gimple_call_fndecl (stmt)))
        if (is_gimple_call (stmt) && (decl = gimple_call_fndecl (stmt)))
          cgraph_create_edge (node, cgraph_node (decl), stmt,
          cgraph_create_edge (node, cgraph_node (decl), stmt,
                              bb->count,
                              bb->count,
                              compute_call_stmt_bb_frequency
                              compute_call_stmt_bb_frequency
                                (current_function_decl, bb),
                                (current_function_decl, bb),
                              bb->loop_depth);
                              bb->loop_depth);
 
 
      }
      }
  gcc_assert (!node->global.inlined_to);
  gcc_assert (!node->global.inlined_to);
 
 
  return 0;
  return 0;
}
}
 
 
struct gimple_opt_pass pass_rebuild_cgraph_edges =
struct gimple_opt_pass pass_rebuild_cgraph_edges =
{
{
 {
 {
  GIMPLE_PASS,
  GIMPLE_PASS,
  "*rebuild_cgraph_edges",              /* name */
  "*rebuild_cgraph_edges",              /* name */
  NULL,                                 /* gate */
  NULL,                                 /* gate */
  rebuild_cgraph_edges,                 /* execute */
  rebuild_cgraph_edges,                 /* execute */
  NULL,                                 /* sub */
  NULL,                                 /* sub */
  NULL,                                 /* next */
  NULL,                                 /* next */
  0,                                     /* static_pass_number */
  0,                                     /* static_pass_number */
  TV_NONE,                              /* tv_id */
  TV_NONE,                              /* tv_id */
  PROP_cfg,                             /* properties_required */
  PROP_cfg,                             /* properties_required */
  0,                                     /* properties_provided */
  0,                                     /* properties_provided */
  0,                                     /* properties_destroyed */
  0,                                     /* properties_destroyed */
  0,                                     /* todo_flags_start */
  0,                                     /* todo_flags_start */
  0,                                     /* todo_flags_finish */
  0,                                     /* todo_flags_finish */
 }
 }
};
};
 
 
 
 
static unsigned int
static unsigned int
remove_cgraph_callee_edges (void)
remove_cgraph_callee_edges (void)
{
{
  cgraph_node_remove_callees (cgraph_node (current_function_decl));
  cgraph_node_remove_callees (cgraph_node (current_function_decl));
  return 0;
  return 0;
}
}
 
 
struct gimple_opt_pass pass_remove_cgraph_callee_edges =
struct gimple_opt_pass pass_remove_cgraph_callee_edges =
{
{
 {
 {
  GIMPLE_PASS,
  GIMPLE_PASS,
  "*remove_cgraph_callee_edges",                /* name */
  "*remove_cgraph_callee_edges",                /* name */
  NULL,                                 /* gate */
  NULL,                                 /* gate */
  remove_cgraph_callee_edges,           /* execute */
  remove_cgraph_callee_edges,           /* execute */
  NULL,                                 /* sub */
  NULL,                                 /* sub */
  NULL,                                 /* next */
  NULL,                                 /* next */
  0,                                     /* static_pass_number */
  0,                                     /* static_pass_number */
  TV_NONE,                              /* tv_id */
  TV_NONE,                              /* tv_id */
  0,                                     /* properties_required */
  0,                                     /* properties_required */
  0,                                     /* properties_provided */
  0,                                     /* properties_provided */
  0,                                     /* properties_destroyed */
  0,                                     /* properties_destroyed */
  0,                                     /* todo_flags_start */
  0,                                     /* todo_flags_start */
  0,                                     /* todo_flags_finish */
  0,                                     /* todo_flags_finish */
 }
 }
};
};
 
 

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.