From e5cf5e116da6f5c018ecc8f714935877c4636780 Mon Sep 17 00:00:00 2001 From: Prathamesh Kulkarni Date: Tue, 28 Nov 2017 18:52:49 +0000 Subject: [PATCH] [PR 82808] Use proper result types for arithmetic jump functions 2017-11-28 Prathamesh Kulkarni Martin Jambor PR ipa/82808 * tree.h (expr_type_first_operand_type_p): Declare * tree.c (expr_type_first_operand_type_p): New function. * ipa-prop.h (ipa_get_type): Allow i to be out of bounds. (ipa_value_from_jfunc): Adjust declaration. * ipa-cp.c (ipa_get_jf_pass_through_result): New parameter RES_TYPE. Use it as result type for arithmetics, unless it is NULL in which case be more conservative. (ipa_value_from_jfunc): New parameter PARM_TYPE, pass it to ipa_get_jf_pass_through_result. (propagate_vals_across_pass_through): Likewise. (propagate_scalar_across_jump_function): New parameter PARM_TYPE, pass is to propagate_vals_across_pass_through. (propagate_constants_across_call): Pass PARM_TYPE to propagate_scalar_across_jump_function. (find_more_scalar_values_for_callers_subset): Pass parameter type to ipa_value_from_jfunc. (cgraph_edge_brings_all_scalars_for_node): Likewise. * ipa-fnsummary.c (evaluate_properties_for_edge): Renamed parms_info to caller_parms_info, pass parameter type to ipa_value_from_jfunc. * ipa-prop.c (try_make_edge_direct_simple_call): New parameter target_type, pass it to ipa_value_from_jfunc. (update_indirect_edges_after_inlining): Pass parameter type to try_make_edge_direct_simple_call. testsuite/ * gcc.dg/ipa/pr82808.c: New test. Co-Authored-By: Martin Jambor From-SVN: r255212 --- gcc/ChangeLog | 28 ++++++++++++++++ gcc/ipa-cp.c | 67 +++++++++++++++++++++++--------------- gcc/ipa-fnsummary.c | 14 ++++---- gcc/ipa-prop.c | 21 ++++++++---- gcc/ipa-prop.h | 5 +-- gcc/testsuite/ChangeLog | 6 ++++ gcc/testsuite/gcc.dg/ipa/pr82808.c | 27 +++++++++++++++ gcc/tree.c | 44 +++++++++++++++++++++++++ gcc/tree.h | 1 + 9 files changed, 172 insertions(+), 41 deletions(-) create mode 100644 gcc/testsuite/gcc.dg/ipa/pr82808.c diff --git a/gcc/ChangeLog b/gcc/ChangeLog index cc548d7d7e3..52903c27c81 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,31 @@ +2017-11-28 Prathamesh Kulkarni + Martin Jambor + + PR ipa/82808 + * tree.h (expr_type_first_operand_type_p): Declare + * tree.c (expr_type_first_operand_type_p): New function. + * ipa-prop.h (ipa_get_type): Allow i to be out of bounds. + (ipa_value_from_jfunc): Adjust declaration. + * ipa-cp.c (ipa_get_jf_pass_through_result): New parameter RES_TYPE. + Use it as result type for arithmetics, unless it is NULL in which case + be more conservative. + (ipa_value_from_jfunc): New parameter PARM_TYPE, pass it to + ipa_get_jf_pass_through_result. + (propagate_vals_across_pass_through): Likewise. + (propagate_scalar_across_jump_function): New parameter PARM_TYPE, pass + is to propagate_vals_across_pass_through. + (propagate_constants_across_call): Pass PARM_TYPE to + propagate_scalar_across_jump_function. + (find_more_scalar_values_for_callers_subset): Pass parameter type to + ipa_value_from_jfunc. + (cgraph_edge_brings_all_scalars_for_node): Likewise. + * ipa-fnsummary.c (evaluate_properties_for_edge): Renamed parms_info + to caller_parms_info, pass parameter type to ipa_value_from_jfunc. + * ipa-prop.c (try_make_edge_direct_simple_call): New parameter + target_type, pass it to ipa_value_from_jfunc. + (update_indirect_edges_after_inlining): Pass parameter type to + try_make_edge_direct_simple_call. + 2017-11-28 Jeff Law * gimple-ssa-evrp-analyze.c diff --git a/gcc/ipa-cp.c b/gcc/ipa-cp.c index 05228d0582d..aa9e300d378 100644 --- a/gcc/ipa-cp.c +++ b/gcc/ipa-cp.c @@ -1220,33 +1220,38 @@ initialize_node_lattices (struct cgraph_node *node) } /* Return the result of a (possibly arithmetic) pass through jump function - JFUNC on the constant value INPUT. Return NULL_TREE if that cannot be + JFUNC on the constant value INPUT. RES_TYPE is the type of the parameter + to which the result is passed. Return NULL_TREE if that cannot be determined or be considered an interprocedural invariant. */ static tree -ipa_get_jf_pass_through_result (struct ipa_jump_func *jfunc, tree input) +ipa_get_jf_pass_through_result (struct ipa_jump_func *jfunc, tree input, + tree res_type) { - tree restype, res; + tree res; if (ipa_get_jf_pass_through_operation (jfunc) == NOP_EXPR) return input; if (!is_gimple_ip_invariant (input)) return NULL_TREE; - if (TREE_CODE_CLASS (ipa_get_jf_pass_through_operation (jfunc)) - == tcc_unary) - res = fold_unary (ipa_get_jf_pass_through_operation (jfunc), - TREE_TYPE (input), input); - else + tree_code opcode = ipa_get_jf_pass_through_operation (jfunc); + if (!res_type) { - if (TREE_CODE_CLASS (ipa_get_jf_pass_through_operation (jfunc)) - == tcc_comparison) - restype = boolean_type_node; + if (TREE_CODE_CLASS (opcode) == tcc_comparison) + res_type = boolean_type_node; + else if (expr_type_first_operand_type_p (opcode)) + res_type = TREE_TYPE (input); else - restype = TREE_TYPE (input); - res = fold_binary (ipa_get_jf_pass_through_operation (jfunc), restype, - input, ipa_get_jf_pass_through_operand (jfunc)); + return NULL_TREE; } + + if (TREE_CODE_CLASS (opcode) == tcc_unary) + res = fold_unary (opcode, res_type, input); + else + res = fold_binary (opcode, res_type, input, + ipa_get_jf_pass_through_operand (jfunc)); + if (res && !is_gimple_ip_invariant (res)) return NULL_TREE; @@ -1275,10 +1280,12 @@ ipa_get_jf_ancestor_result (struct ipa_jump_func *jfunc, tree input) /* Determine whether JFUNC evaluates to a single known constant value and if so, return it. Otherwise return NULL. INFO describes the caller node or the one it is inlined to, so that pass-through jump functions can be - evaluated. */ + evaluated. PARM_TYPE is the type of the parameter to which the result is + passed. */ tree -ipa_value_from_jfunc (struct ipa_node_params *info, struct ipa_jump_func *jfunc) +ipa_value_from_jfunc (struct ipa_node_params *info, struct ipa_jump_func *jfunc, + tree parm_type) { if (jfunc->type == IPA_JF_CONST) return ipa_get_jf_constant (jfunc); @@ -1312,7 +1319,7 @@ ipa_value_from_jfunc (struct ipa_node_params *info, struct ipa_jump_func *jfunc) return NULL_TREE; if (jfunc->type == IPA_JF_PASS_THROUGH) - return ipa_get_jf_pass_through_result (jfunc, input); + return ipa_get_jf_pass_through_result (jfunc, input, parm_type); else return ipa_get_jf_ancestor_result (jfunc, input); } @@ -1562,12 +1569,14 @@ ipcp_lattice::add_value (valtype newval, cgraph_edge *cs, /* Propagate values through a pass-through jump function JFUNC associated with edge CS, taking values from SRC_LAT and putting them into DEST_LAT. SRC_IDX - is the index of the source parameter. */ + is the index of the source parameter. PARM_TYPE is the type of the + parameter to which the result is passed. */ static bool propagate_vals_across_pass_through (cgraph_edge *cs, ipa_jump_func *jfunc, ipcp_lattice *src_lat, - ipcp_lattice *dest_lat, int src_idx) + ipcp_lattice *dest_lat, int src_idx, + tree parm_type) { ipcp_value *src_val; bool ret = false; @@ -1581,7 +1590,8 @@ propagate_vals_across_pass_through (cgraph_edge *cs, ipa_jump_func *jfunc, else for (src_val = src_lat->values; src_val; src_val = src_val->next) { - tree cstval = ipa_get_jf_pass_through_result (jfunc, src_val->value); + tree cstval = ipa_get_jf_pass_through_result (jfunc, src_val->value, + parm_type); if (cstval) ret |= dest_lat->add_value (cstval, cs, src_val, src_idx); @@ -1622,12 +1632,14 @@ propagate_vals_across_ancestor (struct cgraph_edge *cs, } /* Propagate scalar values across jump function JFUNC that is associated with - edge CS and put the values into DEST_LAT. */ + edge CS and put the values into DEST_LAT. PARM_TYPE is the type of the + parameter to which the result is passed. */ static bool propagate_scalar_across_jump_function (struct cgraph_edge *cs, struct ipa_jump_func *jfunc, - ipcp_lattice *dest_lat) + ipcp_lattice *dest_lat, + tree param_type) { if (dest_lat->bottom) return false; @@ -1662,7 +1674,7 @@ propagate_scalar_across_jump_function (struct cgraph_edge *cs, if (jfunc->type == IPA_JF_PASS_THROUGH) ret = propagate_vals_across_pass_through (cs, jfunc, src_lat, - dest_lat, src_idx); + dest_lat, src_idx, param_type); else ret = propagate_vals_across_ancestor (cs, jfunc, src_lat, dest_lat, src_idx); @@ -2279,7 +2291,8 @@ propagate_constants_across_call (struct cgraph_edge *cs) else { ret |= propagate_scalar_across_jump_function (cs, jump_func, - &dest_plats->itself); + &dest_plats->itself, + param_type); ret |= propagate_context_across_jump_function (cs, jump_func, i, &dest_plats->ctxlat); ret @@ -3857,6 +3870,7 @@ find_more_scalar_values_for_callers_subset (struct cgraph_node *node, tree newval = NULL_TREE; int j; bool first = true; + tree type = ipa_get_type (info, i); if (ipa_get_scalar_lat (info, i)->bottom || known_csts[i]) continue; @@ -3876,7 +3890,7 @@ find_more_scalar_values_for_callers_subset (struct cgraph_node *node, break; } jump_func = ipa_get_ith_jump_func (IPA_EDGE_REF (cs), i); - t = ipa_value_from_jfunc (IPA_NODE_REF (cs->caller), jump_func); + t = ipa_value_from_jfunc (IPA_NODE_REF (cs->caller), jump_func, type); if (!t || (newval && !values_equal_for_ipcp_p (t, newval)) @@ -4352,7 +4366,8 @@ cgraph_edge_brings_all_scalars_for_node (struct cgraph_edge *cs, if (i >= ipa_get_cs_argument_count (args)) return false; jump_func = ipa_get_ith_jump_func (args, i); - t = ipa_value_from_jfunc (caller_info, jump_func); + t = ipa_value_from_jfunc (caller_info, jump_func, + ipa_get_type (dest_info, i)); if (!t || !values_equal_for_ipcp_p (val, t)) return false; } diff --git a/gcc/ipa-fnsummary.c b/gcc/ipa-fnsummary.c index 9fb195a6973..7881151d6be 100644 --- a/gcc/ipa-fnsummary.c +++ b/gcc/ipa-fnsummary.c @@ -443,15 +443,16 @@ evaluate_properties_for_edge (struct cgraph_edge *e, bool inline_p, && !e->call_stmt_cannot_inline_p && ((clause_ptr && info->conds) || known_vals_ptr || known_contexts_ptr)) { - struct ipa_node_params *parms_info; + struct ipa_node_params *caller_parms_info, *callee_pi; struct ipa_edge_args *args = IPA_EDGE_REF (e); struct ipa_call_summary *es = ipa_call_summaries->get (e); int i, count = ipa_get_cs_argument_count (args); if (e->caller->global.inlined_to) - parms_info = IPA_NODE_REF (e->caller->global.inlined_to); + caller_parms_info = IPA_NODE_REF (e->caller->global.inlined_to); else - parms_info = IPA_NODE_REF (e->caller); + caller_parms_info = IPA_NODE_REF (e->caller); + callee_pi = IPA_NODE_REF (e->callee); if (count && (info->conds || known_vals_ptr)) known_vals.safe_grow_cleared (count); @@ -463,7 +464,8 @@ evaluate_properties_for_edge (struct cgraph_edge *e, bool inline_p, for (i = 0; i < count; i++) { struct ipa_jump_func *jf = ipa_get_ith_jump_func (args, i); - tree cst = ipa_value_from_jfunc (parms_info, jf); + tree cst = ipa_value_from_jfunc (caller_parms_info, jf, + ipa_get_type (callee_pi, i)); if (!cst && e->call_stmt && i < (int)gimple_call_num_args (e->call_stmt)) @@ -482,8 +484,8 @@ evaluate_properties_for_edge (struct cgraph_edge *e, bool inline_p, known_vals[i] = error_mark_node; if (known_contexts_ptr) - (*known_contexts_ptr)[i] = ipa_context_from_jfunc (parms_info, e, - i, jf); + (*known_contexts_ptr)[i] + = ipa_context_from_jfunc (caller_parms_info, e, i, jf); /* TODO: When IPA-CP starts propagating and merging aggregate jump functions, use its knowledge of the caller too, just like the scalar case above. */ diff --git a/gcc/ipa-prop.c b/gcc/ipa-prop.c index 4b3c2361418..31879a747c0 100644 --- a/gcc/ipa-prop.c +++ b/gcc/ipa-prop.c @@ -3207,19 +3207,20 @@ try_decrement_rdesc_refcount (struct ipa_jump_func *jfunc) /* Try to find a destination for indirect edge IE that corresponds to a simple call or a call of a member function pointer and where the destination is a - pointer formal parameter described by jump function JFUNC. If it can be - determined, return the newly direct edge, otherwise return NULL. + pointer formal parameter described by jump function JFUNC. TARGET_TYPE is + the type of the parameter to which the result of JFUNC is passed. If it can + be determined, return the newly direct edge, otherwise return NULL. NEW_ROOT_INFO is the node info that JFUNC lattices are relative to. */ static struct cgraph_edge * try_make_edge_direct_simple_call (struct cgraph_edge *ie, - struct ipa_jump_func *jfunc, + struct ipa_jump_func *jfunc, tree target_type, struct ipa_node_params *new_root_info) { struct cgraph_edge *cs; tree target; bool agg_contents = ie->indirect_info->agg_contents; - tree scalar = ipa_value_from_jfunc (new_root_info, jfunc); + tree scalar = ipa_value_from_jfunc (new_root_info, jfunc, target_type); if (agg_contents) { bool from_global_constant; @@ -3397,7 +3398,7 @@ update_indirect_edges_after_inlining (struct cgraph_edge *cs, { struct ipa_edge_args *top; struct cgraph_edge *ie, *next_ie, *new_direct_edge; - struct ipa_node_params *new_root_info; + struct ipa_node_params *new_root_info, *inlined_node_info; bool res = false; ipa_check_create_edge_args (); @@ -3405,6 +3406,7 @@ update_indirect_edges_after_inlining (struct cgraph_edge *cs, new_root_info = IPA_NODE_REF (cs->caller->global.inlined_to ? cs->caller->global.inlined_to : cs->caller); + inlined_node_info = IPA_NODE_REF (cs->callee->function_symbol ()); for (ie = node->indirect_calls; ie; ie = next_ie) { @@ -3445,8 +3447,13 @@ update_indirect_edges_after_inlining (struct cgraph_edge *cs, new_direct_edge = try_make_edge_direct_virtual_call (ie, jfunc, ctx); } else - new_direct_edge = try_make_edge_direct_simple_call (ie, jfunc, - new_root_info); + { + tree target_type = ipa_get_type (inlined_node_info, param_index); + new_direct_edge = try_make_edge_direct_simple_call (ie, jfunc, + target_type, + new_root_info); + } + /* If speculation was removed, then we need to do nothing. */ if (new_direct_edge && new_direct_edge != ie && new_direct_edge->callee == spec_target) diff --git a/gcc/ipa-prop.h b/gcc/ipa-prop.h index bd8ae3e8dae..c3624052bbc 100644 --- a/gcc/ipa-prop.h +++ b/gcc/ipa-prop.h @@ -464,7 +464,8 @@ ipa_get_param (struct ipa_node_params *info, int i) static inline tree ipa_get_type (struct ipa_node_params *info, int i) { - gcc_checking_assert (info->descriptors); + if (vec_safe_length (info->descriptors) <= (unsigned) i) + return NULL; tree t = (*info->descriptors)[i].decl_or_type; if (!t) return NULL; @@ -773,7 +774,7 @@ void ipcp_write_transformation_summaries (void); void ipcp_read_transformation_summaries (void); int ipa_get_param_decl_index (struct ipa_node_params *, tree); tree ipa_value_from_jfunc (struct ipa_node_params *info, - struct ipa_jump_func *jfunc); + struct ipa_jump_func *jfunc, tree type); unsigned int ipcp_transform_function (struct cgraph_node *node); ipa_polymorphic_call_context ipa_context_from_jfunc (ipa_node_params *, cgraph_edge *, diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index db8d9784a5d..67c1f272e62 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,9 @@ +2017-11-28 Prathamesh Kulkarni + Martin Jambor + + PR ipa/82808 + * gcc.dg/ipa/pr82808.c: New test. + 2017-11-28 Julia Koval * gcc.target/i386/avx-1.c: Handle new intrinsics. diff --git a/gcc/testsuite/gcc.dg/ipa/pr82808.c b/gcc/testsuite/gcc.dg/ipa/pr82808.c new file mode 100644 index 00000000000..9c95d0b6ed7 --- /dev/null +++ b/gcc/testsuite/gcc.dg/ipa/pr82808.c @@ -0,0 +1,27 @@ +/* { dg-options "-O2" } */ +/* { dg-do run } */ + +static void __attribute__((noinline)) +foo (double *a, double x) +{ + *a = x; +} + +static double __attribute__((noinline)) +f_c1 (int m, double *a) +{ + foo (a, m); + return *a; +} + +int +main (){ + double data; + double ret = 0 ; + + if ((ret = f_c1 (2, &data)) != 2) + { + __builtin_abort (); + } + return 0; +} diff --git a/gcc/tree.c b/gcc/tree.c index 28970dfcc85..b99304c2ff1 100644 --- a/gcc/tree.c +++ b/gcc/tree.c @@ -13898,6 +13898,50 @@ arg_size_in_bytes (const_tree type) return TYPE_EMPTY_P (type) ? size_zero_node : size_in_bytes (type); } +/* Return true if an expression with CODE has to have the same result type as + its first operand. */ + +bool +expr_type_first_operand_type_p (tree_code code) +{ + switch (code) + { + case NEGATE_EXPR: + case ABS_EXPR: + case BIT_NOT_EXPR: + case PAREN_EXPR: + case CONJ_EXPR: + + case PLUS_EXPR: + case MINUS_EXPR: + case MULT_EXPR: + case TRUNC_DIV_EXPR: + case CEIL_DIV_EXPR: + case FLOOR_DIV_EXPR: + case ROUND_DIV_EXPR: + case TRUNC_MOD_EXPR: + case CEIL_MOD_EXPR: + case FLOOR_MOD_EXPR: + case ROUND_MOD_EXPR: + case RDIV_EXPR: + case EXACT_DIV_EXPR: + case MIN_EXPR: + case MAX_EXPR: + case BIT_IOR_EXPR: + case BIT_XOR_EXPR: + case BIT_AND_EXPR: + + case LSHIFT_EXPR: + case RSHIFT_EXPR: + case LROTATE_EXPR: + case RROTATE_EXPR: + return true; + + default: + return false; + } +} + /* List of pointer types used to declare builtins before we have seen their real declaration. diff --git a/gcc/tree.h b/gcc/tree.h index d8912821ad5..bd713f81263 100644 --- a/gcc/tree.h +++ b/gcc/tree.h @@ -5445,6 +5445,7 @@ extern bool is_redundant_typedef (const_tree); extern bool default_is_empty_record (const_tree); extern HOST_WIDE_INT arg_int_size_in_bytes (const_tree); extern tree arg_size_in_bytes (const_tree); +extern bool expr_type_first_operand_type_p (tree_code); extern location_t set_source_range (tree expr, location_t start, location_t finish); -- 2.11.4.GIT