OSDN Git Service

Move libgcc_tm_file to toplevel libgcc
[pf3gnuchains/gcc-fork.git] / gcc / ipa-prop.c
index 54ba417..e624426 100644 (file)
@@ -419,31 +419,154 @@ detect_type_change_ssa (tree arg, gimple call, struct ipa_jump_func *jfunc)
   return detect_type_change (arg, arg, call, jfunc, 0);
 }
 
+/* Callback of walk_aliased_vdefs.  Flags that it has been invoked to the
+   boolean variable pointed to by DATA.  */
+
+static bool
+mark_modified (ao_ref *ao ATTRIBUTE_UNUSED, tree vdef ATTRIBUTE_UNUSED,
+                    void *data)
+{
+  bool *b = (bool *) data;
+  *b = true;
+  return true;
+}
+
+/* Return true if the formal parameter PARM might have been modified in this
+   function before reaching the statement STMT.  PARM_AINFO is a pointer to a
+   structure containing temporary information about PARM.  */
+
+static bool
+is_parm_modified_before_stmt (struct param_analysis_info *parm_ainfo,
+                             gimple stmt, tree parm)
+{
+  bool modified = false;
+  ao_ref refd;
+
+  if (parm_ainfo->modified)
+    return true;
+
+  gcc_checking_assert (gimple_vuse (stmt) != NULL_TREE);
+  ao_ref_init (&refd, parm);
+  walk_aliased_vdefs (&refd, gimple_vuse (stmt), mark_modified,
+                     &modified, &parm_ainfo->visited_statements);
+  if (modified)
+    {
+      parm_ainfo->modified = true;
+      return true;
+    }
+  return false;
+}
+
+/* If STMT is an assignment that loads a value from an parameter declaration,
+   return the index of the parameter in ipa_node_params which has not been
+   modified.  Otherwise return -1.  */
+
+static int
+load_from_unmodified_param (struct ipa_node_params *info,
+                           struct param_analysis_info *parms_ainfo,
+                           gimple stmt)
+{
+  int index;
+  tree op1;
+
+  if (!gimple_assign_single_p (stmt))
+    return -1;
+
+  op1 = gimple_assign_rhs1 (stmt);
+  if (TREE_CODE (op1) != PARM_DECL)
+    return -1;
+
+  index = ipa_get_param_decl_index (info, op1);
+  if (index < 0
+      || is_parm_modified_before_stmt (&parms_ainfo[index], stmt, op1))
+    return -1;
+
+  return index;
+}
 
 /* Given that an actual argument is an SSA_NAME (given in NAME) and is a result
-   of an assignment statement STMT, try to find out whether NAME can be
-   described by a (possibly polynomial) pass-through jump-function or an
-   ancestor jump function and if so, write the appropriate function into
-   JFUNC */
+   of an assignment statement STMT, try to determine whether we are actually
+   handling any of the following cases and construct an appropriate jump
+   function into JFUNC if so:
+
+   1) The passed value is loaded from a formal parameter which is not a gimple
+   register (most probably because it is addressable, the value has to be
+   scalar) and we can guarantee the value has not changed.  This case can
+   therefore be described by a simple pass-through jump function.  For example:
+
+      foo (int a)
+      {
+        int a.0;
+
+        a.0_2 = a;
+        bar (a.0_2);
+
+   2) The passed value can be described by a simple arithmetic pass-through
+   jump function. E.g.
+
+      foo (int a)
+      {
+        int D.2064;
+
+        D.2064_4 = a.1(D) + 4;
+        bar (D.2064_4);
+
+   This case can also occur in combination of the previous one, e.g.:
+
+      foo (int a, int z)
+      {
+        int a.0;
+        int D.2064;
+
+       a.0_3 = a;
+       D.2064_4 = a.0_3 + 4;
+       foo (D.2064_4);
+
+   3) The passed value is an address of an object within another one (which
+   also passed by reference).  Such situations are described by an ancestor
+   jump function and describe situations such as:
+
+     B::foo() (struct B * const this)
+     {
+       struct A * D.1845;
+
+       D.1845_2 = &this_1(D)->D.1748;
+       A::bar (D.1845_2);
+
+   INFO is the structure describing individual parameters access different
+   stages of IPA optimizations.  PARMS_AINFO contains the information that is
+   only needed for intraprocedural analysis.  */
 
 static void
 compute_complex_assign_jump_func (struct ipa_node_params *info,
+                                 struct param_analysis_info *parms_ainfo,
                                  struct ipa_jump_func *jfunc,
                                  gimple call, gimple stmt, tree name)
 {
   HOST_WIDE_INT offset, size, max_size;
-  tree op1, op2, base, ssa;
+  tree op1, tc_ssa, base, ssa;
   int index;
 
   op1 = gimple_assign_rhs1 (stmt);
-  op2 = gimple_assign_rhs2 (stmt);
 
-  if (TREE_CODE (op1) == SSA_NAME
-      && SSA_NAME_IS_DEFAULT_DEF (op1))
+  if (TREE_CODE (op1) == SSA_NAME)
     {
-      index = ipa_get_param_decl_index (info, SSA_NAME_VAR (op1));
-      if (index < 0)
-       return;
+      if (SSA_NAME_IS_DEFAULT_DEF (op1))
+       index = ipa_get_param_decl_index (info, SSA_NAME_VAR (op1));
+      else
+       index = load_from_unmodified_param (info, parms_ainfo,
+                                           SSA_NAME_DEF_STMT (op1));
+      tc_ssa = op1;
+    }
+  else
+    {
+      index = load_from_unmodified_param (info, parms_ainfo, stmt);
+      tc_ssa = gimple_assign_lhs (stmt);
+    }
+
+  if (index >= 0)
+    {
+      tree op2 = gimple_assign_rhs2 (stmt);
 
       if (op2)
        {
@@ -458,8 +581,8 @@ compute_complex_assign_jump_func (struct ipa_node_params *info,
          jfunc->value.pass_through.operation = gimple_assign_rhs_code (stmt);
          jfunc->value.pass_through.operand = op2;
        }
-      else if (gimple_assign_unary_nop_p (stmt)
-              && !detect_type_change_ssa (op1, call, jfunc))
+      else if (gimple_assign_single_p (stmt)
+              && !detect_type_change_ssa (tc_ssa, call, jfunc))
        {
          jfunc->type = IPA_JF_PASS_THROUGH;
          jfunc->value.pass_through.formal_id = index;
@@ -665,12 +788,14 @@ compute_known_type_jump_func (tree op, struct ipa_jump_func *jfunc,
 
 /* Determine the jump functions of scalar arguments.  Scalar means SSA names
    and constants of a number of selected types.  INFO is the ipa_node_params
-   structure associated with the caller, FUNCTIONS is a pointer to an array of
-   jump function structures associated with CALL which is the call statement
-   being examined.*/
+   structure associated with the caller, PARMS_AINFO describes state of
+   analysis with respect to individual formal parameters.  ARGS is the
+   ipa_edge_args structure describing the callsite CALL which is the call
+   statement being examined.*/
 
 static void
 compute_scalar_jump_functions (struct ipa_node_params *info,
+                              struct param_analysis_info *parms_ainfo,
                               struct ipa_edge_args *args,
                               gimple call)
 {
@@ -705,7 +830,8 @@ compute_scalar_jump_functions (struct ipa_node_params *info,
            {
              gimple stmt = SSA_NAME_DEF_STMT (arg);
              if (is_gimple_assign (stmt))
-               compute_complex_assign_jump_func (info, jfunc, call, stmt, arg);
+               compute_complex_assign_jump_func (info, parms_ainfo, jfunc,
+                                                 call, stmt, arg);
              else if (gimple_code (stmt) == GIMPLE_PHI)
                compute_complex_ancestor_jump_func (info, jfunc, call, stmt);
            }
@@ -748,43 +874,6 @@ type_like_member_ptr_p (tree type, tree *method_ptr, tree *delta)
   return true;
 }
 
-/* Callback of walk_aliased_vdefs.  Flags that it has been invoked to the
-   boolean variable pointed to by DATA.  */
-
-static bool
-mark_modified (ao_ref *ao ATTRIBUTE_UNUSED, tree vdef ATTRIBUTE_UNUSED,
-                    void *data)
-{
-  bool *b = (bool *) data;
-  *b = true;
-  return true;
-}
-
-/* Return true if the formal parameter PARM might have been modified in this
-   function before reaching the statement CALL.  PARM_INFO is a pointer to a
-   structure containing intermediate information about PARM.  */
-
-static bool
-is_parm_modified_before_call (struct param_analysis_info *parm_info,
-                             gimple call, tree parm)
-{
-  bool modified = false;
-  ao_ref refd;
-
-  if (parm_info->modified)
-    return true;
-
-  ao_ref_init (&refd, parm);
-  walk_aliased_vdefs (&refd, gimple_vuse (call), mark_modified,
-                     &modified, &parm_info->visited_statements);
-  if (modified)
-    {
-      parm_info->modified = true;
-      return true;
-    }
-  return false;
-}
-
 /* Go through arguments of the CALL and for every one that looks like a member
    pointer, check whether it can be safely declared pass-through and if so,
    mark that to the corresponding item of jump FUNCTIONS.  Return true iff
@@ -794,7 +883,7 @@ is_parm_modified_before_call (struct param_analysis_info *parm_info,
 
 static bool
 compute_pass_through_member_ptrs (struct ipa_node_params *info,
-                                 struct param_analysis_info *parms_info,
+                                 struct param_analysis_info *parms_ainfo,
                                  struct ipa_edge_args *args,
                                  gimple call)
 {
@@ -813,7 +902,8 @@ compute_pass_through_member_ptrs (struct ipa_node_params *info,
              int index = ipa_get_param_decl_index (info, arg);
 
              gcc_assert (index >=0);
-             if (!is_parm_modified_before_call (&parms_info[index], call, arg))
+             if (!is_parm_modified_before_stmt (&parms_ainfo[index], call,
+                                                arg))
                {
                  struct ipa_jump_func *jfunc = ipa_get_ith_jump_func (args,
                                                                       num);
@@ -968,7 +1058,7 @@ compute_cst_member_ptr_arguments (struct ipa_edge_args *args,
    to this callsite.  */
 
 static void
-ipa_compute_jump_functions_for_edge (struct param_analysis_info *parms_info,
+ipa_compute_jump_functions_for_edge (struct param_analysis_info *parms_ainfo,
                                     struct cgraph_edge *cs)
 {
   struct ipa_node_params *info = IPA_NODE_REF (cs->caller);
@@ -981,11 +1071,11 @@ ipa_compute_jump_functions_for_edge (struct param_analysis_info *parms_info,
   VEC_safe_grow_cleared (ipa_jump_func_t, gc, args->jump_functions, arg_num);
 
   /* We will deal with constants and SSA scalars first:  */
-  compute_scalar_jump_functions (info, args, call);
+  compute_scalar_jump_functions (info, parms_ainfo, args, call);
 
   /* Let's check whether there are any potential member pointers and if so,
      whether we can determine their functions as pass_through.  */
-  if (!compute_pass_through_member_ptrs (info, parms_info, args, call))
+  if (!compute_pass_through_member_ptrs (info, parms_ainfo, args, call))
     return;
 
   /* Finally, let's check whether we actually pass a new constant member
@@ -998,7 +1088,7 @@ ipa_compute_jump_functions_for_edge (struct param_analysis_info *parms_info,
 
 static void
 ipa_compute_jump_functions (struct cgraph_node *node,
-                           struct param_analysis_info *parms_info)
+                           struct param_analysis_info *parms_ainfo)
 {
   struct cgraph_edge *cs;
 
@@ -1010,11 +1100,11 @@ ipa_compute_jump_functions (struct cgraph_node *node,
         functions unless they may become known during lto/whopr.  */
       if (!callee->analyzed && !flag_lto)
        continue;
-      ipa_compute_jump_functions_for_edge (parms_info, cs);
+      ipa_compute_jump_functions_for_edge (parms_ainfo, cs);
     }
 
   for (cs = node->indirect_calls; cs; cs = cs->next_callee)
-    ipa_compute_jump_functions_for_edge (parms_info, cs);
+    ipa_compute_jump_functions_for_edge (parms_ainfo, cs);
 }
 
 /* If RHS looks like a rhs of a statement loading pfn from a member
@@ -1111,7 +1201,7 @@ ipa_note_param_call (struct cgraph_node *node, int param_index, gimple stmt)
 }
 
 /* Analyze the CALL and examine uses of formal parameters of the caller NODE
-   (described by INFO).  PARMS_INFO is a pointer to a vector containing
+   (described by INFO).  PARMS_AINFO is a pointer to a vector containing
    intermediate information about each formal parameter.  Currently it checks
    whether the call calls a pointer that is a formal parameter and if so, the
    parameter is marked with the called flag and an indirect call graph edge
@@ -1170,7 +1260,7 @@ ipa_note_param_call (struct cgraph_node *node, int param_index, gimple stmt)
 static void
 ipa_analyze_indirect_call_uses (struct cgraph_node *node,
                                struct ipa_node_params *info,
-                               struct param_analysis_info *parms_info,
+                               struct param_analysis_info *parms_ainfo,
                                gimple call, tree target)
 {
   gimple def;
@@ -1283,7 +1373,7 @@ ipa_analyze_indirect_call_uses (struct cgraph_node *node,
     return;
 
   index = ipa_get_param_decl_index (info, rec);
-  if (index >= 0 && !is_parm_modified_before_call (&parms_info[index],
+  if (index >= 0 && !is_parm_modified_before_stmt (&parms_ainfo[index],
                                                   call, rec))
     ipa_note_param_call (node, index, call);
 
@@ -1347,20 +1437,20 @@ ipa_analyze_virtual_call_uses (struct cgraph_node *node,
 }
 
 /* Analyze a call statement CALL whether and how it utilizes formal parameters
-   of the caller (described by INFO).  PARMS_INFO is a pointer to a vector
+   of the caller (described by INFO).  PARMS_AINFO is a pointer to a vector
    containing intermediate information about each formal parameter.  */
 
 static void
 ipa_analyze_call_uses (struct cgraph_node *node,
                       struct ipa_node_params *info,
-                      struct param_analysis_info *parms_info, gimple call)
+                      struct param_analysis_info *parms_ainfo, gimple call)
 {
   tree target = gimple_call_fn (call);
 
   if (!target)
     return;
   if (TREE_CODE (target) == SSA_NAME)
-    ipa_analyze_indirect_call_uses (node, info, parms_info, call, target);
+    ipa_analyze_indirect_call_uses (node, info, parms_ainfo, call, target);
   else if (TREE_CODE (target) == OBJ_TYPE_REF)
     ipa_analyze_virtual_call_uses (node, info, call, target);
 }
@@ -1368,15 +1458,15 @@ ipa_analyze_call_uses (struct cgraph_node *node,
 
 /* Analyze the call statement STMT with respect to formal parameters (described
    in INFO) of caller given by NODE.  Currently it only checks whether formal
-   parameters are called.  PARMS_INFO is a pointer to a vector containing
+   parameters are called.  PARMS_AINFO is a pointer to a vector containing
    intermediate information about each formal parameter.  */
 
 static void
 ipa_analyze_stmt_uses (struct cgraph_node *node, struct ipa_node_params *info,
-                      struct param_analysis_info *parms_info, gimple stmt)
+                      struct param_analysis_info *parms_ainfo, gimple stmt)
 {
   if (is_gimple_call (stmt))
-    ipa_analyze_call_uses (node, info, parms_info, stmt);
+    ipa_analyze_call_uses (node, info, parms_ainfo, stmt);
 }
 
 /* Callback of walk_stmt_load_store_addr_ops for the visit_load.
@@ -1403,12 +1493,12 @@ visit_ref_for_mod_analysis (gimple stmt ATTRIBUTE_UNUSED,
 
 /* Scan the function body of NODE and inspect the uses of formal parameters.
    Store the findings in various structures of the associated ipa_node_params
-   structure, such as parameter flags, notes etc.  PARMS_INFO is a pointer to a
+   structure, such as parameter flags, notes etc.  PARMS_AINFO is a pointer to a
    vector containing intermediate information about each formal parameter.   */
 
 static void
 ipa_analyze_params_uses (struct cgraph_node *node,
-                        struct param_analysis_info *parms_info)
+                        struct param_analysis_info *parms_ainfo)
 {
   tree decl = node->decl;
   basic_block bb;
@@ -1440,7 +1530,7 @@ ipa_analyze_params_uses (struct cgraph_node *node,
          if (is_gimple_debug (stmt))
            continue;
 
-         ipa_analyze_stmt_uses (node, info, parms_info, stmt);
+         ipa_analyze_stmt_uses (node, info, parms_ainfo, stmt);
          walk_stmt_load_store_addr_ops (stmt, info,
                                         visit_ref_for_mod_analysis,
                                         visit_ref_for_mod_analysis,
@@ -1464,7 +1554,7 @@ void
 ipa_analyze_node (struct cgraph_node *node)
 {
   struct ipa_node_params *info;
-  struct param_analysis_info *parms_info;
+  struct param_analysis_info *parms_ainfo;
   int i, param_count;
 
   ipa_check_create_node_params ();
@@ -1475,15 +1565,15 @@ ipa_analyze_node (struct cgraph_node *node)
   ipa_initialize_node_params (node);
 
   param_count = ipa_get_param_count (info);
-  parms_info = XALLOCAVEC (struct param_analysis_info, param_count);
-  memset (parms_info, 0, sizeof (struct param_analysis_info) * param_count);
+  parms_ainfo = XALLOCAVEC (struct param_analysis_info, param_count);
+  memset (parms_ainfo, 0, sizeof (struct param_analysis_info) * param_count);
 
-  ipa_analyze_params_uses (node, parms_info);
-  ipa_compute_jump_functions (node, parms_info);
+  ipa_analyze_params_uses (node, parms_ainfo);
+  ipa_compute_jump_functions (node, parms_ainfo);
 
   for (i = 0; i < param_count; i++)
-    if (parms_info[i].visited_statements)
-      BITMAP_FREE (parms_info[i].visited_statements);
+    if (parms_ainfo[i].visited_statements)
+      BITMAP_FREE (parms_ainfo[i].visited_statements);
 
   current_function_decl = NULL;
   pop_cfun ();