Commit 685b0d13 by Martin Jambor Committed by Martin Jambor

ipa-prop.h (enum jump_func_type): New value IPA_JF_ANCESTOR, changed comments.

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
parent 17f6e37d
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> 2009-08-07 Jakub Jelinek <jakub@redhat.com>
* dwarf2out.c (output_fde): When doing hot/cold partitioning, use * dwarf2out.c (output_fde): When doing hot/cold partitioning, use
......
...@@ -290,10 +290,43 @@ ipcp_lattice_from_jfunc (struct ipa_node_params *info, struct ipcp_lattice *lat, ...@@ -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) else if (jfunc->type == IPA_JF_PASS_THROUGH)
{ {
struct ipcp_lattice *caller_lat; 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->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 else
lat->type = IPA_BOTTOM; lat->type = IPA_BOTTOM;
......
...@@ -300,8 +300,22 @@ ipa_print_node_jump_functions (FILE *f, struct cgraph_node *node) ...@@ -300,8 +300,22 @@ ipa_print_node_jump_functions (FILE *f, struct cgraph_node *node)
else if (type == IPA_JF_PASS_THROUGH) else if (type == IPA_JF_PASS_THROUGH)
{ {
fprintf (f, "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) ...@@ -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 /* 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 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 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, ...@@ -343,15 +418,21 @@ compute_scalar_jump_functions (struct ipa_node_params *info,
functions[num].type = IPA_JF_CONST; functions[num].type = IPA_JF_CONST;
functions[num].value.constant = arg; 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 (SSA_NAME_IS_DEFAULT_DEF (arg))
if (index >= 0)
{ {
functions[num].type = IPA_JF_PASS_THROUGH; int index = ipa_get_param_decl_index (info, SSA_NAME_VAR (arg));
functions[num].value.formal_id = index;
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, ...@@ -418,7 +499,8 @@ compute_pass_through_member_ptrs (struct ipa_node_params *info,
if (!ipa_is_param_modified (info, index)) if (!ipa_is_param_modified (info, index))
{ {
functions[num].type = IPA_JF_PASS_THROUGH; 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 else
undecided_members = true; undecided_members = true;
...@@ -883,7 +965,10 @@ ipa_analyze_params_uses (struct cgraph_node *node) ...@@ -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 /* 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 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 static void
update_jump_functions_after_inlining (struct cgraph_edge *cs, update_jump_functions_after_inlining (struct cgraph_edge *cs,
...@@ -898,17 +983,26 @@ 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); 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) if (dst->type != IPA_JF_PASS_THROUGH)
continue; continue;
/* We must check range due to calls with variable number of arguments: */ /* We must check range due to calls with variable number of arguments and
if (dst->value.formal_id >= (unsigned) ipa_get_cs_argument_count (top)) 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; dst->type = IPA_JF_UNKNOWN;
continue; 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; *dst = *src;
} }
} }
...@@ -959,15 +1053,16 @@ update_call_notes_after_inlining (struct cgraph_edge *cs, ...@@ -959,15 +1053,16 @@ update_call_notes_after_inlining (struct cgraph_edge *cs,
continue; continue;
/* We must check range due to calls with variable number of arguments: */ /* 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; nt->processed = true;
continue; continue;
} }
jfunc = ipa_get_ith_jump_func (top, nt->formal_id); jfunc = ipa_get_ith_jump_func (top, nt->formal_id);
if (jfunc->type == IPA_JF_PASS_THROUGH) if (jfunc->type == IPA_JF_PASS_THROUGH
nt->formal_id = jfunc->value.formal_id; && jfunc->value.pass_through.operation == NOP_EXPR)
nt->formal_id = jfunc->value.pass_through.formal_id;
else if (jfunc->type == IPA_JF_CONST else if (jfunc->type == IPA_JF_CONST
|| jfunc->type == IPA_JF_CONST_MEMBER_PTR) || jfunc->type == IPA_JF_CONST_MEMBER_PTR)
{ {
...@@ -1004,6 +1099,13 @@ update_call_notes_after_inlining (struct cgraph_edge *cs, ...@@ -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); VEC_safe_push (cgraph_edge_p, heap, *new_edges, new_indirect_edge);
top = IPA_EDGE_REF (cs); 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; return res;
} }
......
...@@ -31,18 +31,26 @@ along with GCC; see the file COPYING3. If not see ...@@ -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 /* A jump function for a callsite represents the values passed as actual
arguments of the callsite. There are three main types of values : 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. Pass-through - the caller's formal parameter is passed as an actual
Unknown - neither of the above. argument, possibly one simple operation performed on it.
Integer and real constants are represented as IPA_JF_CONST. Constant - a constant (is_gimple_ip_invariant)is passed as an actual
Finally, IPA_JF_CONST_MEMBER_PTR stands for C++ member pointers argument.
constants. */ 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 enum jump_func_type
{ {
IPA_JF_UNKNOWN = 0, /* newly allocated and zeroed jump functions default */ IPA_JF_UNKNOWN = 0, /* newly allocated and zeroed jump functions default */
IPA_JF_CONST, IPA_JF_CONST,
IPA_JF_CONST_MEMBER_PTR, 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 /* All formal parameters in the program have a lattice associated with it
...@@ -61,6 +69,36 @@ enum ipa_lattice_type ...@@ -61,6 +69,36 @@ enum ipa_lattice_type
IPA_TOP 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 /* Structure holding a C++ member pointer constant. Holds a pointer to the
method and delta offset. */ method and delta offset. */
struct ipa_member_ptr_cst struct ipa_member_ptr_cst
...@@ -69,15 +107,14 @@ struct ipa_member_ptr_cst ...@@ -69,15 +107,14 @@ struct ipa_member_ptr_cst
tree delta; tree delta;
}; };
/* Represents a value of a jump function. formal_id is used only in jump /* Represents a value of a jump function. pass_through is used only in jump
function context and represents pass-through parameter (the formal parameter function context. constant represents the actual constant in constant jump
of the caller is passed as argument). constant represents the actual functions and member_cst holds constant c++ member functions. */
constant in constant jump functions and member_cst holds constant c++ member
functions. */
union jump_func_value union jump_func_value
{ {
unsigned int formal_id;
tree constant; tree constant;
struct ipa_pass_through_data pass_through;
struct ipa_ancestor_jf_data ancestor;
struct ipa_member_ptr_cst member_cst; struct ipa_member_ptr_cst member_cst;
}; };
...@@ -109,7 +146,7 @@ struct ipa_param_call_note ...@@ -109,7 +146,7 @@ struct ipa_param_call_note
/* Statement that contains the call to the parameter above. */ /* Statement that contains the call to the parameter above. */
gimple stmt; gimple stmt;
/* Index of the parameter that is called. */ /* Index of the parameter that is called. */
unsigned int formal_id; int formal_id;
/* Expected number of executions: calculated in profile.c. */ /* Expected number of executions: calculated in profile.c. */
gcov_type count; gcov_type count;
/* Expected frequency of executions within the function. see cgraph_edge in /* Expected frequency of executions within the function. see cgraph_edge in
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment