Re: [PATCH 2/4] Handle calls to ancestor objects in IPA-CP devirtualization

2011-04-18 Thread Martin Jambor
Hi,

On Fri, Apr 15, 2011 at 05:26:44PM +0200, Richard Guenther wrote:
 On Fri, 15 Apr 2011, Martin Jambor wrote:
 
  Hi,
  
  early inlining can create virtual calls based on the part of an object
  that represents an ancestor.  This patch makes ipa-prop analysis able
  to recognize such calls and store the required offset along with such
  calls (the field is already there for similar purposes of indirect
  inlining).  The constant propagation is then made aware of the offset
  field and takes it into account when looking up the proper BINFO.
  
  Bootstrapped and tested on x86_64-linux. OK for trunk?
  
  Thanks,
  
  Martin
  
  
  
  2011-04-13  Martin Jambor  mjam...@suse.cz
  
  * ipa-cp.c (ipcp_process_devirtualization_opportunities): Take into
  account anc_offset and otr_type from the indirect edge info.
  * ipa-prop.c (get_ancestor_addr_info): New function.
  (compute_complex_ancestor_jump_func): Assignment analysis moved to
  get_ancestor_addr_info, call it.
  (ipa_note_param_call): Do not initialize information about polymorphic
  calls, return the indirect call graph edge.  Remove the last
  parameter, adjust all callers.
  (ipa_analyze_virtual_call_uses): Process also calls to ancestors of
  parameters.  Initialize polymorphic information in the indirect edge.
  
  * testsuite/g++.dg/ipa/devirt-7.C: New test.
  
  

...

  Index: src/gcc/ipa-prop.c
  ===
  --- src.orig/gcc/ipa-prop.c
  +++ src/gcc/ipa-prop.c
  @@ -576,6 +576,49 @@ compute_complex_assign_jump_func (struct
   }
   }
   
  +/* Extract the base, offset and MEM_REF expression from a statement ASSIGN 
  if
  +   it looks like:
  +
  +   iftmp.1_3 = obj_2(D)-D.1762;
  +
  +   The base of the MEM_REF must be a default definition SSA NAME of a
  +   parameter.  Return NULL_TREE if it looks otherwise.  If case of 
  success, the
  +   whole MEM_REF expression is returned and the offset calculated from any
  +   handled components and the MEM_REF itself is stored into *OFFSET.  The 
  whole
  +   RHS stripped off the ADDR_EXPR is stored into *OBJ_P.  */
  +
  +static tree
  +get_ancestor_addr_info (gimple assign, tree *obj_p, HOST_WIDE_INT *offset)
  +{
  +  HOST_WIDE_INT size, max_size;
  +  tree expr, parm, obj;
  +
  +  if (!gimple_assign_single_p (assign))
  +return NULL_TREE;
  +  expr = gimple_assign_rhs1 (assign);
  +
  +  if (TREE_CODE (expr) != ADDR_EXPR)
  +return NULL_TREE;
  +  expr = TREE_OPERAND (expr, 0);
  +  obj = expr;
  +  expr = get_ref_base_and_extent (expr, offset, size, max_size);
  +
  +  if (TREE_CODE (expr) != MEM_REF
  +  /* If this is a varying address, punt.  */
  +  || max_size == -1
  +  || max_size != size)
  +return NULL_TREE;
  +  parm = TREE_OPERAND (expr, 0);
  +  if (TREE_CODE (parm) != SSA_NAME
  +  || !SSA_NAME_IS_DEFAULT_DEF (parm)
 
 Might be an uninitialized variable, so also check
 TREE_CODE (SSA_NAME_VAR (parm)) == PARM_DECL?
 

This was already handled by checking the return value of
ipa_get_param_decl_index but I guess that the code will be more
readable with that check explicit and an assert that
ipa_get_param_decl_index can indeed find an index for the decl so I
changed both places accordingly.

  +  || *offset  0)
 
 Check this above where you check max_size/size.

OK

...

  -  var = SSA_NAME_VAR (obj);
  -  index = ipa_get_param_decl_index (info, var);
  +  if (SSA_NAME_IS_DEFAULT_DEF (obj))
 
 Check for PARM_DECL.
 

Like above.

 Otherwise ok.
 

Thanks, this is what I'm currently testing and what I intend to commit
if all goes well.

Martin


2011-04-18  Martin Jambor  mjam...@suse.cz

* ipa-cp.c (ipcp_process_devirtualization_opportunities): Take into
account anc_offset and otr_type from the indirect edge info.
* ipa-prop.c (get_ancestor_addr_info): New function.
(compute_complex_ancestor_jump_func): Assignment analysis moved to
get_ancestor_addr_info, call it.
(ipa_note_param_call): Do not initialize information about polymorphic
calls, return the indirect call graph edge.  Remove the last
parameter, adjust all callers.
(ipa_analyze_virtual_call_uses): Process also calls to ancestors of
parameters.  Initialize polymorphic information in the indirect edge.

* testsuite/g++.dg/ipa/devirt-7.C: New test.


Index: src/gcc/ipa-cp.c
===
*** src.orig/gcc/ipa-cp.c
--- src/gcc/ipa-cp.c
*** ipcp_process_devirtualization_opportunit
*** 1247,1254 
for (ie = node-indirect_calls; ie; ie = next_ie)
  {
int param_index, types_count, j;
!   HOST_WIDE_INT token;
!   tree target, delta;
  
next_ie = ie-next_callee;
if (!ie-indirect_info-polymorphic)
--- 1247,1254 
for (ie = node-indirect_calls; ie; ie = next_ie)
  {
int param_index, 

[PATCH 2/4] Handle calls to ancestor objects in IPA-CP devirtualization

2011-04-15 Thread Martin Jambor
Hi,

early inlining can create virtual calls based on the part of an object
that represents an ancestor.  This patch makes ipa-prop analysis able
to recognize such calls and store the required offset along with such
calls (the field is already there for similar purposes of indirect
inlining).  The constant propagation is then made aware of the offset
field and takes it into account when looking up the proper BINFO.

Bootstrapped and tested on x86_64-linux. OK for trunk?

Thanks,

Martin



2011-04-13  Martin Jambor  mjam...@suse.cz

* ipa-cp.c (ipcp_process_devirtualization_opportunities): Take into
account anc_offset and otr_type from the indirect edge info.
* ipa-prop.c (get_ancestor_addr_info): New function.
(compute_complex_ancestor_jump_func): Assignment analysis moved to
get_ancestor_addr_info, call it.
(ipa_note_param_call): Do not initialize information about polymorphic
calls, return the indirect call graph edge.  Remove the last
parameter, adjust all callers.
(ipa_analyze_virtual_call_uses): Process also calls to ancestors of
parameters.  Initialize polymorphic information in the indirect edge.

* testsuite/g++.dg/ipa/devirt-7.C: New test.


Index: src/gcc/ipa-cp.c
===
--- src.orig/gcc/ipa-cp.c
+++ src/gcc/ipa-cp.c
@@ -1246,8 +1246,8 @@ ipcp_process_devirtualization_opportunit
   for (ie = node-indirect_calls; ie; ie = next_ie)
 {
   int param_index, types_count, j;
-  HOST_WIDE_INT token;
-  tree target, delta;
+  HOST_WIDE_INT token, anc_offset;
+  tree target, delta, otr_type;
 
   next_ie = ie-next_callee;
   if (!ie-indirect_info-polymorphic)
@@ -1259,14 +1259,23 @@ ipcp_process_devirtualization_opportunit
continue;
 
   token = ie-indirect_info-otr_token;
+  anc_offset = ie-indirect_info-anc_offset;
+  otr_type = ie-indirect_info-otr_type;
   target = NULL_TREE;
   types_count = VEC_length (tree, info-params[param_index].types);
   for (j = 0; j  types_count; j++)
{
  tree binfo = VEC_index (tree, info-params[param_index].types, j);
- tree d;
- tree t = gimple_get_virt_mehtod_for_binfo (token, binfo, d, true);
+ tree d, t;
 
+ binfo = get_binfo_at_offset (binfo, anc_offset, otr_type);
+ if (!binfo)
+   {
+ target = NULL_TREE;
+ break;
+   }
+
+ t = gimple_get_virt_mehtod_for_binfo (token, binfo, d, true);
  if (!t)
{
  target = NULL_TREE;
Index: src/gcc/ipa-prop.c
===
--- src.orig/gcc/ipa-prop.c
+++ src/gcc/ipa-prop.c
@@ -576,6 +576,49 @@ compute_complex_assign_jump_func (struct
 }
 }
 
+/* Extract the base, offset and MEM_REF expression from a statement ASSIGN if
+   it looks like:
+
+   iftmp.1_3 = obj_2(D)-D.1762;
+
+   The base of the MEM_REF must be a default definition SSA NAME of a
+   parameter.  Return NULL_TREE if it looks otherwise.  If case of success, the
+   whole MEM_REF expression is returned and the offset calculated from any
+   handled components and the MEM_REF itself is stored into *OFFSET.  The whole
+   RHS stripped off the ADDR_EXPR is stored into *OBJ_P.  */
+
+static tree
+get_ancestor_addr_info (gimple assign, tree *obj_p, HOST_WIDE_INT *offset)
+{
+  HOST_WIDE_INT size, max_size;
+  tree expr, parm, obj;
+
+  if (!gimple_assign_single_p (assign))
+return NULL_TREE;
+  expr = gimple_assign_rhs1 (assign);
+
+  if (TREE_CODE (expr) != ADDR_EXPR)
+return NULL_TREE;
+  expr = TREE_OPERAND (expr, 0);
+  obj = expr;
+  expr = get_ref_base_and_extent (expr, offset, size, max_size);
+
+  if (TREE_CODE (expr) != MEM_REF
+  /* If this is a varying address, punt.  */
+  || max_size == -1
+  || max_size != size)
+return NULL_TREE;
+  parm = TREE_OPERAND (expr, 0);
+  if (TREE_CODE (parm) != SSA_NAME
+  || !SSA_NAME_IS_DEFAULT_DEF (parm)
+  || *offset  0)
+return NULL_TREE;
+
+  *offset += mem_ref_offset (expr).low * BITS_PER_UNIT;
+  *obj_p = obj;
+  return expr;
+}
+
 
 /* Given that an actual argument is an SSA_NAME that is a result of a phi
statement PHI, try to find out whether NAME is in fact a
@@ -603,7 +646,7 @@ compute_complex_ancestor_jump_func (stru
struct ipa_jump_func *jfunc,
gimple call, gimple phi)
 {
-  HOST_WIDE_INT offset, size, max_size;
+  HOST_WIDE_INT offset;
   gimple assign, cond;
   basic_block phi_bb, assign_bb, cond_bb;
   tree tmp, parm, expr, obj;
@@ -626,29 +669,12 @@ compute_complex_ancestor_jump_func (stru
 
   assign = SSA_NAME_DEF_STMT (tmp);
   assign_bb = gimple_bb (assign);
-  if (!single_pred_p (assign_bb)
-  || !gimple_assign_single_p (assign))
+  if (!single_pred_p (assign_bb))
 return;
-  expr = 

Re: [PATCH 2/4] Handle calls to ancestor objects in IPA-CP devirtualization

2011-04-15 Thread Richard Guenther
On Fri, 15 Apr 2011, Martin Jambor wrote:

 Hi,
 
 early inlining can create virtual calls based on the part of an object
 that represents an ancestor.  This patch makes ipa-prop analysis able
 to recognize such calls and store the required offset along with such
 calls (the field is already there for similar purposes of indirect
 inlining).  The constant propagation is then made aware of the offset
 field and takes it into account when looking up the proper BINFO.
 
 Bootstrapped and tested on x86_64-linux. OK for trunk?
 
 Thanks,
 
 Martin
 
 
 
 2011-04-13  Martin Jambor  mjam...@suse.cz
 
   * ipa-cp.c (ipcp_process_devirtualization_opportunities): Take into
   account anc_offset and otr_type from the indirect edge info.
   * ipa-prop.c (get_ancestor_addr_info): New function.
   (compute_complex_ancestor_jump_func): Assignment analysis moved to
   get_ancestor_addr_info, call it.
   (ipa_note_param_call): Do not initialize information about polymorphic
   calls, return the indirect call graph edge.  Remove the last
   parameter, adjust all callers.
   (ipa_analyze_virtual_call_uses): Process also calls to ancestors of
   parameters.  Initialize polymorphic information in the indirect edge.
 
   * testsuite/g++.dg/ipa/devirt-7.C: New test.
 
 
 Index: src/gcc/ipa-cp.c
 ===
 --- src.orig/gcc/ipa-cp.c
 +++ src/gcc/ipa-cp.c
 @@ -1246,8 +1246,8 @@ ipcp_process_devirtualization_opportunit
for (ie = node-indirect_calls; ie; ie = next_ie)
  {
int param_index, types_count, j;
 -  HOST_WIDE_INT token;
 -  tree target, delta;
 +  HOST_WIDE_INT token, anc_offset;
 +  tree target, delta, otr_type;
  
next_ie = ie-next_callee;
if (!ie-indirect_info-polymorphic)
 @@ -1259,14 +1259,23 @@ ipcp_process_devirtualization_opportunit
   continue;
  
token = ie-indirect_info-otr_token;
 +  anc_offset = ie-indirect_info-anc_offset;
 +  otr_type = ie-indirect_info-otr_type;
target = NULL_TREE;
types_count = VEC_length (tree, info-params[param_index].types);
for (j = 0; j  types_count; j++)
   {
 tree binfo = VEC_index (tree, info-params[param_index].types, j);
 -   tree d;
 -   tree t = gimple_get_virt_mehtod_for_binfo (token, binfo, d, true);
 +   tree d, t;
  
 +   binfo = get_binfo_at_offset (binfo, anc_offset, otr_type);
 +   if (!binfo)
 + {
 +   target = NULL_TREE;
 +   break;
 + }
 +
 +   t = gimple_get_virt_mehtod_for_binfo (token, binfo, d, true);
 if (!t)
   {
 target = NULL_TREE;
 Index: src/gcc/ipa-prop.c
 ===
 --- src.orig/gcc/ipa-prop.c
 +++ src/gcc/ipa-prop.c
 @@ -576,6 +576,49 @@ compute_complex_assign_jump_func (struct
  }
  }
  
 +/* Extract the base, offset and MEM_REF expression from a statement ASSIGN if
 +   it looks like:
 +
 +   iftmp.1_3 = obj_2(D)-D.1762;
 +
 +   The base of the MEM_REF must be a default definition SSA NAME of a
 +   parameter.  Return NULL_TREE if it looks otherwise.  If case of success, 
 the
 +   whole MEM_REF expression is returned and the offset calculated from any
 +   handled components and the MEM_REF itself is stored into *OFFSET.  The 
 whole
 +   RHS stripped off the ADDR_EXPR is stored into *OBJ_P.  */
 +
 +static tree
 +get_ancestor_addr_info (gimple assign, tree *obj_p, HOST_WIDE_INT *offset)
 +{
 +  HOST_WIDE_INT size, max_size;
 +  tree expr, parm, obj;
 +
 +  if (!gimple_assign_single_p (assign))
 +return NULL_TREE;
 +  expr = gimple_assign_rhs1 (assign);
 +
 +  if (TREE_CODE (expr) != ADDR_EXPR)
 +return NULL_TREE;
 +  expr = TREE_OPERAND (expr, 0);
 +  obj = expr;
 +  expr = get_ref_base_and_extent (expr, offset, size, max_size);
 +
 +  if (TREE_CODE (expr) != MEM_REF
 +  /* If this is a varying address, punt.  */
 +  || max_size == -1
 +  || max_size != size)
 +return NULL_TREE;
 +  parm = TREE_OPERAND (expr, 0);
 +  if (TREE_CODE (parm) != SSA_NAME
 +  || !SSA_NAME_IS_DEFAULT_DEF (parm)

Might be an uninitialized variable, so also check
TREE_CODE (SSA_NAME_VAR (parm)) == PARM_DECL?

 +  || *offset  0)

Check this above where you check max_size/size.

 +return NULL_TREE;
 +
 +  *offset += mem_ref_offset (expr).low * BITS_PER_UNIT;

At some point it might be worth switching to
get_addr_base_and_unit_offsets and not use bit but unit offsets
throughout the code.

 +  *obj_p = obj;
 +  return expr;
 +}
 +
  
  /* Given that an actual argument is an SSA_NAME that is a result of a phi
 statement PHI, try to find out whether NAME is in fact a
 @@ -603,7 +646,7 @@ compute_complex_ancestor_jump_func (stru
   struct ipa_jump_func *jfunc,
   gimple call, gimple phi)
  {
 -  HOST_WIDE_INT offset, size, max_size;
 +