From 685b0d134d7e7dc210a85bdfbd189c9f69f82a62 Mon Sep 17 00:00:00 2001 From: Martin Jambor Date: Fri, 7 Aug 2009 09:15:41 +0200 Subject: [PATCH] ipa-prop.h (enum jump_func_type): New value IPA_JF_ANCESTOR, changed comments. 2009-08-07 Martin Jambor * 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 | 20 ++++++++ gcc/ipa-cp.c | 37 +++++++++++++- gcc/ipa-prop.c | 132 +++++++++++++++++++++++++++++++++++++++++++------ gcc/ipa-prop.h | 65 ++++++++++++++++++------ 4 files changed, 223 insertions(+), 31 deletions(-) diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 1a76d9acef6..96b291a5ae4 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,23 @@ +2009-08-07 Martin Jambor + + * 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 * dwarf2out.c (output_fde): When doing hot/cold partitioning, use diff --git a/gcc/ipa-cp.c b/gcc/ipa-cp.c index fe335c4f0fa..df6972417bd 100644 --- a/gcc/ipa-cp.c +++ b/gcc/ipa-cp.c @@ -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; diff --git a/gcc/ipa-prop.c b/gcc/ipa-prop.c index fcc4f70435c..2842088d8f1 100644 --- a/gcc/ipa-prop.c +++ b/gcc/ipa-prop.c @@ -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; } diff --git a/gcc/ipa-prop.h b/gcc/ipa-prop.h index 4794f691fba..9b5f74f87ad 100644 --- a/gcc/ipa-prop.h +++ b/gcc/ipa-prop.h @@ -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 -- 2.30.2