ipa-prop.h (enum jump_func_type): New value IPA_JF_ANCESTOR, changed comments.
authorMartin Jambor <mjambor@suse.cz>
Fri, 7 Aug 2009 07:15:41 +0000 (09:15 +0200)
committerMartin Jambor <jamborm@gcc.gnu.org>
Fri, 7 Aug 2009 07:15:41 +0000 (09:15 +0200)
2009-08-07  Martin Jambor  <mjambor@suse.cz>

* ipa-prop.h (enum jump_func_type): New value IPA_JF_ANCESTOR, changed
comments.
(struct ipa_pass_through_data): New type.
(struct ipa_ancestor_jf_data): New type.
(union jump_func_value): Removed field formal_id, added fields
pass_through and ancestor.
(struct ipa_param_call_note): Changed type of formal_id to int from
unsigned.
* ipa-prop.c (ipa_print_node_jump_functions): Print pass through with
operations jump functions and ancestor jump functions.
(compute_complex_pass_through): New function.
(compute_scalar_jump_functions): Call compute_complex_pass_through,
reflect changes in the jump function strucutre.
(update_jump_functions_after_inlining): Ignore complex pass-through
and ancestor jump functions.
* ipa-cp.c (ipcp_lattice_from_jfunc): Added support for ancestor and
polynomial pass-through with operation jump functions.

From-SVN: r150554

gcc/ChangeLog
gcc/ipa-cp.c
gcc/ipa-prop.c
gcc/ipa-prop.h

index 1a76d9acef676ac6b82b14b38c0034a435fc2a10..96b291a5ae4c620b675a40ba2b242307304fbf47 100644 (file)
@@ -1,3 +1,23 @@
+2009-08-07  Martin Jambor  <mjambor@suse.cz>
+
+       * ipa-prop.h (enum jump_func_type): New value IPA_JF_ANCESTOR, changed
+       comments.
+       (struct ipa_pass_through_data): New type.
+       (struct ipa_ancestor_jf_data): New type.
+       (union jump_func_value): Removed field formal_id, added fields
+       pass_through and ancestor.
+       (struct ipa_param_call_note): Changed type of formal_id to int from
+       unsigned.
+       * ipa-prop.c (ipa_print_node_jump_functions): Print pass through with
+       operations jump functions and ancestor jump functions.
+       (compute_complex_pass_through): New function.
+       (compute_scalar_jump_functions): Call compute_complex_pass_through,
+       reflect changes in the jump function strucutre.
+       (update_jump_functions_after_inlining): Ignore complex pass-through
+       and ancestor jump functions.
+       * ipa-cp.c (ipcp_lattice_from_jfunc): Added support for ancestor and
+       polynomial pass-through with operation jump functions.
+
 2009-08-07  Jakub Jelinek  <jakub@redhat.com>
 
        * dwarf2out.c (output_fde): When doing hot/cold partitioning, use
index fe335c4f0fa4f4bd46c8695d54ae50c0c2cd68fe..df6972417bd8b61f94adf4e975e3f5ccbd3dc9a7 100644 (file)
@@ -290,10 +290,43 @@ ipcp_lattice_from_jfunc (struct ipa_node_params *info, struct ipcp_lattice *lat,
   else if (jfunc->type == IPA_JF_PASS_THROUGH)
     {
       struct ipcp_lattice *caller_lat;
+      tree cst;
 
-      caller_lat = ipcp_get_lattice (info, jfunc->value.formal_id);
+      caller_lat = ipcp_get_lattice (info, jfunc->value.pass_through.formal_id);
       lat->type = caller_lat->type;
-      lat->constant = caller_lat->constant;
+      if (caller_lat->type != IPA_CONST_VALUE)
+       return;
+      cst = caller_lat->constant;
+
+      if (jfunc->value.pass_through.operation != NOP_EXPR)
+       cst = fold_binary (jfunc->value.pass_through.operation,
+                          TREE_TYPE (cst), cst,
+                          jfunc->value.pass_through.operand);
+      gcc_assert (cst && is_gimple_ip_invariant (cst));
+      lat->constant = cst;
+    }
+  else if (jfunc->type == IPA_JF_ANCESTOR)
+    {
+      struct ipcp_lattice *caller_lat;
+      tree t;
+      bool ok;
+
+      caller_lat = ipcp_get_lattice (info, jfunc->value.ancestor.formal_id);
+      lat->type = caller_lat->type;
+      if (caller_lat->type != IPA_CONST_VALUE)
+       return;
+      if (TREE_CODE (caller_lat->constant) != ADDR_EXPR)
+       {
+         /* This can happen when the constant is a NULL pointer.  */
+         lat->type = IPA_BOTTOM;
+         return;
+       }
+      t = TREE_OPERAND (caller_lat->constant, 0);
+      ok = build_ref_for_offset (&t, TREE_TYPE (t),
+                                jfunc->value.ancestor.offset,
+                                jfunc->value.ancestor.type, false);
+      gcc_assert (ok);
+      lat->constant = build_fold_addr_expr (t);
     }
   else
     lat->type = IPA_BOTTOM;
index fcc4f70435c70941fb3bac9ac8bacb8324059c8e..2842088d8f1b9d075c6f9456170edab6a06b50c7 100644 (file)
@@ -300,8 +300,22 @@ ipa_print_node_jump_functions (FILE *f, struct cgraph_node *node)
          else if (type == IPA_JF_PASS_THROUGH)
            {
              fprintf (f, "PASS THROUGH: ");
-             fprintf (f, "%d\n", jump_func->value.formal_id);
+             fprintf (f, "%d, op %s ",
+                      jump_func->value.pass_through.formal_id,
+                      tree_code_name[(int)
+                                     jump_func->value.pass_through.operation]);
+             if (jump_func->value.pass_through.operation != NOP_EXPR)
+               print_generic_expr (dump_file,
+                                   jump_func->value.pass_through.operand, 0);
+             fprintf (dump_file, "\n");
            }
+         else if (type == IPA_JF_ANCESTOR)
+           {
+             fprintf (f, "ANCESTOR: ");
+             fprintf (f, "%d, offset "HOST_WIDE_INT_PRINT_DEC"\n",
+                      jump_func->value.ancestor.formal_id,
+                      jump_func->value.ancestor.offset);
+           }
        }
     }
 }
@@ -320,6 +334,67 @@ ipa_print_all_jump_functions (FILE *f)
     }
 }
 
+/* Determine whether passing ssa name NAME constitutes a polynomial
+   pass-through function or getting an address of an acestor and if so, write
+   such a jump function to JFUNC.  INFO describes the caller.  */
+
+static void
+compute_complex_pass_through (struct ipa_node_params *info,
+                             struct ipa_jump_func *jfunc,
+                             tree name)
+{
+  HOST_WIDE_INT offset, size, max_size;
+  tree op1, op2, type;
+  int index;
+  gimple stmt = SSA_NAME_DEF_STMT (name);
+
+  if (!is_gimple_assign (stmt))
+    return;
+  op1 = gimple_assign_rhs1 (stmt);
+  op2 = gimple_assign_rhs2 (stmt);
+
+  if (op2)
+    {
+      if (TREE_CODE (op1) != SSA_NAME
+         || !SSA_NAME_IS_DEFAULT_DEF (op1)
+         || !is_gimple_ip_invariant (op2))
+       return;
+
+      index = ipa_get_param_decl_index (info, SSA_NAME_VAR (op1));
+      if (index >= 0)
+       {
+         jfunc->type = IPA_JF_PASS_THROUGH;
+         jfunc->value.pass_through.formal_id = index;
+         jfunc->value.pass_through.operation = gimple_assign_rhs_code (stmt);
+         jfunc->value.pass_through.operand = op2;
+       }
+      return;
+    }
+
+  if (TREE_CODE (op1) != ADDR_EXPR)
+    return;
+  op1 = TREE_OPERAND (op1, 0);
+  type = TREE_TYPE (op1);
+
+  op1 = get_ref_base_and_extent (op1, &offset, &size, &max_size);
+  if (TREE_CODE (op1) != INDIRECT_REF)
+    return;
+  op1 = TREE_OPERAND (op1, 0);
+  if (TREE_CODE (op1) != SSA_NAME
+      || !SSA_NAME_IS_DEFAULT_DEF (op1))
+    return;
+
+  index = ipa_get_param_decl_index (info, SSA_NAME_VAR (op1));
+  if (index >= 0)
+    {
+      jfunc->type = IPA_JF_ANCESTOR;
+      jfunc->value.ancestor.formal_id = index;
+      jfunc->value.ancestor.offset = offset;
+      jfunc->value.ancestor.type = type;
+    }
+}
+
+
 /* 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
@@ -343,15 +418,21 @@ compute_scalar_jump_functions (struct ipa_node_params *info,
          functions[num].type = IPA_JF_CONST;
          functions[num].value.constant = arg;
        }
-      else if ((TREE_CODE (arg) == SSA_NAME) && SSA_NAME_IS_DEFAULT_DEF (arg))
+      else if (TREE_CODE (arg) == SSA_NAME)
        {
-         int index = ipa_get_param_decl_index (info, SSA_NAME_VAR (arg));
-
-         if (index >= 0)
+         if (SSA_NAME_IS_DEFAULT_DEF (arg))
            {
-             functions[num].type = IPA_JF_PASS_THROUGH;
-             functions[num].value.formal_id = index;
+             int index = ipa_get_param_decl_index (info, SSA_NAME_VAR (arg));
+
+             if (index >= 0)
+               {
+                 functions[num].type = IPA_JF_PASS_THROUGH;
+                 functions[num].value.pass_through.formal_id = index;
+                 functions[num].value.pass_through.operation = NOP_EXPR;
+               }
            }
+         else
+           compute_complex_pass_through (info, &functions[num], arg);
        }
     }
 }
@@ -418,7 +499,8 @@ compute_pass_through_member_ptrs (struct ipa_node_params *info,
              if (!ipa_is_param_modified (info, index))
                {
                  functions[num].type = IPA_JF_PASS_THROUGH;
-                 functions[num].value.formal_id = index;
+                 functions[num].value.pass_through.formal_id = index;
+                 functions[num].value.pass_through.operation = NOP_EXPR;
                }
              else
                undecided_members = true;
@@ -883,7 +965,10 @@ ipa_analyze_params_uses (struct cgraph_node *node)
 
 /* Update the jump functions associated with call graph edge E when the call
    graph edge CS is being inlined, assuming that E->caller is already (possibly
-   indirectly) inlined into CS->callee and that E has not been inlined.  */
+   indirectly) inlined into CS->callee and that E has not been inlined.
+
+   We keep pass through functions only if they do not contain any operation.
+   This is sufficient for inlining and greately simplifies things.  */
 
 static void
 update_jump_functions_after_inlining (struct cgraph_edge *cs,
@@ -898,17 +983,26 @@ update_jump_functions_after_inlining (struct cgraph_edge *cs,
     {
       struct ipa_jump_func *src, *dst = ipa_get_ith_jump_func (args, i);
 
+      if (dst->type == IPA_JF_ANCESTOR)
+       {
+         dst->type = IPA_JF_UNKNOWN;
+         continue;
+       }
+
       if (dst->type != IPA_JF_PASS_THROUGH)
        continue;
 
-      /* We must check range due to calls with variable number of arguments:  */
-      if (dst->value.formal_id >= (unsigned) ipa_get_cs_argument_count (top))
+      /* We must check range due to calls with variable number of arguments and
+        we cannot combine jump functions with operations.  */
+      if (dst->value.pass_through.operation != NOP_EXPR
+         || (dst->value.pass_through.formal_id
+             >= ipa_get_cs_argument_count (top)))
        {
          dst->type = IPA_JF_UNKNOWN;
          continue;
        }
 
-      src = ipa_get_ith_jump_func (top, dst->value.formal_id);
+      src = ipa_get_ith_jump_func (top, dst->value.pass_through.formal_id);
       *dst = *src;
     }
 }
@@ -959,15 +1053,16 @@ update_call_notes_after_inlining (struct cgraph_edge *cs,
        continue;
 
       /* We must check range due to calls with variable number of arguments:  */
-      if (nt->formal_id >= (unsigned) ipa_get_cs_argument_count (top))
+      if (nt->formal_id >= ipa_get_cs_argument_count (top))
        {
          nt->processed = true;
          continue;
        }
 
       jfunc = ipa_get_ith_jump_func (top, nt->formal_id);
-      if (jfunc->type == IPA_JF_PASS_THROUGH)
-       nt->formal_id = jfunc->value.formal_id;
+      if (jfunc->type == IPA_JF_PASS_THROUGH
+         && jfunc->value.pass_through.operation == NOP_EXPR)
+       nt->formal_id = jfunc->value.pass_through.formal_id;
       else if (jfunc->type == IPA_JF_CONST
               || jfunc->type == IPA_JF_CONST_MEMBER_PTR)
        {
@@ -1004,6 +1099,13 @@ update_call_notes_after_inlining (struct cgraph_edge *cs,
            VEC_safe_push (cgraph_edge_p, heap, *new_edges, new_indirect_edge);
          top = IPA_EDGE_REF (cs);
        }
+      else
+       {
+         /* Ancestor jum functions and pass theoughs with operations should
+            not be used on parameters that then get called.  */
+         gcc_assert (jfunc->type == IPA_JF_UNKNOWN);
+         nt->processed = true;
+       }
     }
   return res;
 }
index 4794f691fba3669c95632a61cf26bc32fcea827f..9b5f74f87ad88f0c8271f7fcd3f631abea7ecbda 100644 (file)
@@ -31,18 +31,26 @@ along with GCC; see the file COPYING3.  If not see
 
 /* A jump function for a callsite represents the values passed as actual
    arguments of the callsite. There are three main types of values :
-   Formal - the caller's formal parameter is passed as an actual argument.
-   Constant - a constant is passed as an actual argument.
-   Unknown - neither of the above.
-   Integer and real constants are represented as IPA_JF_CONST.
-   Finally, IPA_JF_CONST_MEMBER_PTR stands for C++ member pointers
-   constants.  */
+
+   Pass-through - the caller's formal parameter is passed as an actual
+                  argument, possibly one simple operation performed on it.
+   Constant     - a constant (is_gimple_ip_invariant)is passed as an actual
+                  argument.
+   Unknown      - neither of the above.
+
+   IPA_JF_CONST_MEMBER_PTR stands for C++ member pointers, other constants are
+   represented with IPA_JF_CONST.
+
+   In addition to "ordinary" pass through functions represented by
+   IPA_JF_PASS_THROUGH, IPA_JF_ANCESTOR represents getting addresses of of
+   ancestor fields in C++ (e.g. &this_1(D)->D.1766.D.1756).  */
 enum jump_func_type
 {
   IPA_JF_UNKNOWN = 0,  /* newly allocated and zeroed jump functions default */
   IPA_JF_CONST,
   IPA_JF_CONST_MEMBER_PTR,
-  IPA_JF_PASS_THROUGH
+  IPA_JF_PASS_THROUGH,
+  IPA_JF_ANCESTOR
 };
 
 /* All formal parameters in the program have a lattice associated with it
@@ -61,6 +69,36 @@ enum ipa_lattice_type
   IPA_TOP
 };
 
+
+/* Structure holding data required to describe a pass-through jump function.  */
+
+struct ipa_pass_through_data
+{
+  /* If an operation is to be performed on the original parameter, this is the
+     second (constant) operand.  */
+  tree operand;
+  /* Number of the caller's formal parameter being passed.  */
+  int formal_id;
+  /* Operation that is performed on the argument before it is passed on.
+     NOP_EXPR means no operation.  Otherwise oper must be a simple binary
+     arithmetic operation where the caller's parameter is the first operand and
+     operand field from this structure is the second one.  */
+  enum tree_code operation;
+};
+
+/* Structure holding data required to describe and ancestor pass throu
+   funkci.  */
+
+struct ipa_ancestor_jf_data
+{
+  /* Offset of the field representing the ancestor.  */
+  HOST_WIDE_INT offset;
+  /* TYpe of the result.  */
+  tree type;
+  /* Number of the caller's formal parameter being passed.  */
+  int formal_id;
+};
+
 /* Structure holding a C++ member pointer constant.  Holds a pointer to the
    method and delta offset.  */
 struct ipa_member_ptr_cst
@@ -69,15 +107,14 @@ struct ipa_member_ptr_cst
   tree delta;
 };
 
-/* Represents a value of a jump function.  formal_id is used only in jump
-   function context and represents pass-through parameter (the formal parameter
-   of the caller is passed as argument).  constant represents the actual
-   constant in constant jump functions and member_cst holds constant c++ member
-   functions.  */
+/* Represents a value of a jump function.  pass_through is used only in jump
+   function context.  constant represents the actual constant in constant jump
+   functions and member_cst holds constant c++ member functions.  */
 union jump_func_value
 {
-  unsigned int formal_id;
   tree constant;
+  struct ipa_pass_through_data pass_through;
+  struct ipa_ancestor_jf_data ancestor;
   struct ipa_member_ptr_cst member_cst;
 };
 
@@ -109,7 +146,7 @@ struct ipa_param_call_note
   /* Statement that contains the call to the parameter above.  */
   gimple stmt;
   /* Index of the parameter that is called.  */
-  unsigned int formal_id;
+  int formal_id;
   /* Expected number of executions: calculated in profile.c.  */
   gcov_type count;
   /* Expected frequency of executions within the function. see cgraph_edge in