+2017-11-28 Prathamesh Kulkarni <prathamesh.kulkarni@linaro.org>
+ Martin Jambor <mjambor@suse.cz>
+
+ 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 <law@redhat.com>
* gimple-ssa-evrp-analyze.c
}
/* 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;
/* 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);
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);
}
/* 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<tree> *src_lat,
- ipcp_lattice<tree> *dest_lat, int src_idx)
+ ipcp_lattice<tree> *dest_lat, int src_idx,
+ tree parm_type)
{
ipcp_value<tree> *src_val;
bool ret = false;
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);
}
/* 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<tree> *dest_lat)
+ ipcp_lattice<tree> *dest_lat,
+ tree param_type)
{
if (dest_lat->bottom)
return false;
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);
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
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;
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))
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;
}
&& !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);
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))
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. */
/* 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;
{
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 ();
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)
{
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)
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;
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 *,
+2017-11-28 Prathamesh Kulkarni <prathamesh.kulkarni@linaro.org>
+ Martin Jambor <mjambor@suse.cz>
+
+ PR ipa/82808
+ * gcc.dg/ipa/pr82808.c: New test.
+
2017-11-28 Julia Koval <julia.koval@intel.com>
* gcc.target/i386/avx-1.c: Handle new intrinsics.
--- /dev/null
+/* { 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;
+}
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.
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);