* tree.h (decl_address_ip_invariant_p): Declare.
* gimple.c (strip_invariant_refs): Break out from ...
(is_gimple_invariant_address): ... here
(is_gimple_ip_invariant_address): New function.
(is_gimple_ip_invariant): New function.
* gimple.h (is_gimple_ip_invariant_address, is_gimple_ip_invariant):
Declare.
* ipa-cp.c (ipcp_lat_is_const): Remove handling of IPA_CONST_VALUE_REF.
(ipcp_lat_is_insertable): All constants are insertable.
(ipcp_lattice_from_jfunc, ipcp_print_all_lattices): Remove handling of
IPA_CONST_VALUE_REF.
(ipcp_initialize_node_lattices): Propagate all types of operands.
(build_const_val): Do not handle IPA_CONST_VALUE_REF.
(ipcp_create_replace_map): Reformat.
(ipcp_need_redirect_p): Simplify.
(ipcp_insert_stage): Check that argument is used before clonning.
* ipa-prop.c (ipa_print_node_jump_functions): Do not handle IPA_CONST_REF.
(compute_scalar_jump_functions): Simplify using is_gimple_ip_invariat.
(determine_cst_member_ptr): Keep wrapping ADDR_EXPR of members.
(update_call_notes_after_inlining): Expect ADDR_EXPR in operand.
* ipa-prop.h (jump_func_type): Remove IPA_CONST_REF.
(jump_func_type): Remove IPA_CONST_VALUE_REF.
* tree-inline.c (tree_function_versioning): Add variables referenced by
replacing trees.
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@139523
138bc75d-0d04-0410-961f-
82ee72b054a4
2008-08-23 Jan Hubicka <jh@suse.cz>
+ * tree.c (decl_address_ip_invariant_p): New function.
+ * tree.h (decl_address_ip_invariant_p): Declare.
+ * gimple.c (strip_invariant_refs): Break out from ...
+ (is_gimple_invariant_address): ... here
+ (is_gimple_ip_invariant_address): New function.
+ (is_gimple_ip_invariant): New function.
+ * gimple.h (is_gimple_ip_invariant_address, is_gimple_ip_invariant):
+ Declare.
+
+ * ipa-cp.c (ipcp_lat_is_const): Remove handling of IPA_CONST_VALUE_REF.
+ (ipcp_lat_is_insertable): All constants are insertable.
+ (ipcp_lattice_from_jfunc, ipcp_print_all_lattices): Remove handling of
+ IPA_CONST_VALUE_REF.
+ (ipcp_initialize_node_lattices): Propagate all types of operands.
+ (build_const_val): Do not handle IPA_CONST_VALUE_REF.
+ (ipcp_create_replace_map): Reformat.
+ (ipcp_need_redirect_p): Simplify.
+ (ipcp_insert_stage): Check that argument is used before clonning.
+ * ipa-prop.c (ipa_print_node_jump_functions): Do not handle IPA_CONST_REF.
+ (compute_scalar_jump_functions): Simplify using is_gimple_ip_invariat.
+ (determine_cst_member_ptr): Keep wrapping ADDR_EXPR of members.
+ (update_call_notes_after_inlining): Expect ADDR_EXPR in operand.
+ * ipa-prop.h (jump_func_type): Remove IPA_CONST_REF.
+ (jump_func_type): Remove IPA_CONST_VALUE_REF.
+ * tree-inline.c (tree_function_versioning): Add variables referenced by
+ replacing trees.
+
+2008-08-23 Jan Hubicka <jh@suse.cz>
+
PR target/37094
* i386.c (standard_80387_constant_p): Use optimize_size.
}
}
-/* Return true if T is a gimple invariant address. */
+/* Strip out all handled components that produce invariant
+ offsets. */
-bool
-is_gimple_invariant_address (const_tree t)
+static const_tree
+strip_invariant_refs (const_tree op)
{
- tree op;
-
- if (TREE_CODE (t) != ADDR_EXPR)
- return false;
-
- op = TREE_OPERAND (t, 0);
while (handled_component_p (op))
{
switch (TREE_CODE (op))
if (!is_gimple_constant (TREE_OPERAND (op, 1))
|| TREE_OPERAND (op, 2) != NULL_TREE
|| TREE_OPERAND (op, 3) != NULL_TREE)
- return false;
+ return NULL;
break;
case COMPONENT_REF:
if (TREE_OPERAND (op, 2) != NULL_TREE)
- return false;
+ return NULL;
break;
default:;
op = TREE_OPERAND (op, 0);
}
- return CONSTANT_CLASS_P (op) || decl_address_invariant_p (op);
+ return op;
+}
+
+/* Return true if T is a gimple invariant address. */
+
+bool
+is_gimple_invariant_address (const_tree t)
+{
+ const_tree op;
+
+ if (TREE_CODE (t) != ADDR_EXPR)
+ return false;
+
+ op = strip_invariant_refs (TREE_OPERAND (t, 0));
+
+ return op && (CONSTANT_CLASS_P (op) || decl_address_invariant_p (op));
+}
+
+/* Return true if T is a gimple invariant address at IPA level
+ (so addresses of variables on stack are not allowed). */
+
+bool
+is_gimple_ip_invariant_address (const_tree t)
+{
+ const_tree op;
+
+ if (TREE_CODE (t) != ADDR_EXPR)
+ return false;
+
+ op = strip_invariant_refs (TREE_OPERAND (t, 0));
+
+ return op && (CONSTANT_CLASS_P (op) || decl_address_ip_invariant_p (op));
}
/* Return true if T is a GIMPLE minimal invariant. It's a restricted
return is_gimple_constant (t);
}
+/* Return true if T is a GIMPLE interprocedural invariant. It's a restricted
+ form of gimple minimal invariant. */
+
+bool
+is_gimple_ip_invariant (const_tree t)
+{
+ if (TREE_CODE (t) == ADDR_EXPR)
+ return is_gimple_ip_invariant_address (t);
+
+ return is_gimple_constant (t);
+}
+
/* Return true if T looks like a valid GIMPLE statement. */
bool
bool is_gimple_address (const_tree);
/* Returns true iff T is a GIMPLE invariant address. */
bool is_gimple_invariant_address (const_tree);
+/* Returns true iff T is a GIMPLE invariant address at interprocedural
+ level. */
+bool is_gimple_ip_invariant_address (const_tree);
/* Returns true iff T is a valid GIMPLE constant. */
bool is_gimple_constant (const_tree);
/* Returns true iff T is a GIMPLE restricted function invariant. */
extern bool is_gimple_min_invariant (const_tree);
+/* Returns true iff T is a GIMPLE restricted interprecodural invariant. */
+extern bool is_gimple_ip_invariant (const_tree);
/* Returns true iff T is a GIMPLE rvalue. */
extern bool is_gimple_val (tree);
/* Returns true iff T is a GIMPLE asm statement input. */
static inline bool
ipcp_lat_is_const (struct ipcp_lattice *lat)
{
- if (lat->type == IPA_CONST_VALUE || lat->type == IPA_CONST_VALUE_REF)
+ if (lat->type == IPA_CONST_VALUE)
return true;
else
return false;
static inline bool
ipcp_lat_is_insertable (struct ipcp_lattice *lat)
{
- if ((lat->type == IPA_CONST_VALUE || lat->type == IPA_CONST_VALUE_REF)
- && !POINTER_TYPE_P (TREE_TYPE (lat->constant)))
- return true;
- else
- return false;
+ return lat->type == IPA_CONST_VALUE;
}
/* Return true if LAT1 and LAT2 are equal. */
lat->type = IPA_CONST_VALUE;
lat->constant = jfunc->value.constant;
}
- else if (jfunc->type == IPA_CONST_REF)
- {
- lat->type = IPA_CONST_VALUE_REF;
- lat->constant = jfunc->value.constant;
- }
else if (jfunc->type == IPA_PASS_THROUGH)
{
struct ipcp_lattice *caller_lat;
struct ipcp_lattice *lat = ipcp_get_ith_lattice (info, i);
fprintf (f, " param [%d]: ", i);
- if (lat->type == IPA_CONST_VALUE || lat->type == IPA_CONST_VALUE_REF)
+ if (lat->type == IPA_CONST_VALUE)
{
fprintf (f, "type is CONST ");
print_generic_expr (f, lat->constant, 0);
info->ipcp_lattices = XCNEWVEC (struct ipcp_lattice,
ipa_get_param_count (info));
for (i = 0; i < ipa_get_param_count (info) ; i++)
- {
- tree parm_tree = ipa_get_ith_param (info, i);
- struct ipcp_lattice *lat = ipcp_get_ith_lattice (info, i);
-
- if (INTEGRAL_TYPE_P (TREE_TYPE (parm_tree))
- || SCALAR_FLOAT_TYPE_P (TREE_TYPE (parm_tree))
- || POINTER_TYPE_P (TREE_TYPE (parm_tree)))
- lat->type = IPA_TOP;
- else
- lat->type = IPA_BOTTOM;
- }
+ ipcp_get_ith_lattice (info, i)->type = IPA_TOP;
}
/* Create a new assignment statement and make it the first statement in the
gcc_assert (ipcp_lat_is_const (lat));
val = lat->constant;
- /* compute_jump_functions inserts FUNCTION_DECL as value of parameter
- when address of function is taken. It would make more sense to pass
- whole ADDR_EXPR, but for now compensate here. */
- if ((lat->type == IPA_CONST_VALUE
- && TREE_CODE (val) == FUNCTION_DECL)
- || lat->type == IPA_CONST_VALUE_REF)
- return build_fold_addr_expr_with_type (val, tree_type);
-
if (!useless_type_conversion_p (tree_type, TREE_TYPE (val)))
{
if (fold_convertible_p (tree_type, val))
tree const_val;
replace_map = XCNEW (struct ipa_replace_map);
- if (is_gimple_reg (parm_tree) && gimple_default_def (func, parm_tree)
+ if (is_gimple_reg (parm_tree)
+ && gimple_default_def (func, parm_tree)
&& !SSA_NAME_OCCURS_IN_ABNORMAL_PHI (gimple_default_def (func,
parm_tree)))
{
if (ipcp_lat_is_const (lat))
{
jump_func = ipa_get_ith_jump_func (IPA_EDGE_REF (cs), i);
- if (jump_func->type != IPA_CONST && jump_func->type != IPA_CONST_REF
- && jump_func->type != IPA_CONST_MEMBER_PTR)
+ if (jump_func->type != IPA_CONST)
return true;
}
}
for (i = 0; i < count; i++)
{
struct ipcp_lattice *lat = ipcp_get_ith_lattice (info, i);
- if (ipcp_lat_is_insertable (lat))
+ tree parm_tree = ipa_get_ith_param (info, i);
+ if (ipcp_lat_is_insertable (lat)
+ /* Do not count obviously unused arguments. */
+ && (!is_gimple_reg (parm_tree)
+ || gimple_default_def (DECL_STRUCT_FUNCTION (node->decl), parm_tree)))
const_param++;
}
if (const_param == 0)
for (i = 0; i < count; i++)
{
struct ipcp_lattice *lat = ipcp_get_ith_lattice (info, i);
- if (lat->type == IPA_CONST_VALUE
- && !POINTER_TYPE_P (TREE_TYPE (lat->constant)))
+ if (lat->type == IPA_CONST_VALUE)
{
parm_tree = ipa_get_ith_param (info, i);
replace_param =
if (ipcp_lat_is_insertable (lat))
{
parm_tree = ipa_get_ith_param (info, i);
- if (lat->type != IPA_CONST_VALUE_REF
- && !is_gimple_reg (parm_tree))
+ if (!is_gimple_reg (parm_tree))
ipcp_propagate_one_const (node1, i, lat);
}
}
fprintf (f, " param %d: ", i);
if (type == IPA_UNKNOWN)
fprintf (f, "UNKNOWN\n");
- else if (type == IPA_CONST || type == IPA_CONST_REF)
+ else if (type == IPA_CONST)
{
tree val = jump_func->value.constant;
fprintf (f, "CONST: ");
{
arg = gimple_call_arg (call, num);
- if (TREE_CODE (arg) == INTEGER_CST
- || TREE_CODE (arg) == REAL_CST
- || TREE_CODE (arg) == FIXED_CST)
+ if (is_gimple_ip_invariant (arg))
{
functions[num].type = IPA_CONST;
functions[num].value.constant = arg;
}
- else if (TREE_CODE (arg) == ADDR_EXPR)
- {
- if (TREE_CODE (TREE_OPERAND (arg, 0)) == FUNCTION_DECL)
- {
- functions[num].type = IPA_CONST;
- functions[num].value.constant = TREE_OPERAND (arg, 0);
- }
- else if (TREE_CODE (TREE_OPERAND (arg, 0)) == CONST_DECL)
- {
- tree cst_decl = TREE_OPERAND (arg, 0);
-
- if (TREE_CODE (DECL_INITIAL (cst_decl)) == INTEGER_CST
- || TREE_CODE (DECL_INITIAL (cst_decl)) == REAL_CST
- || TREE_CODE (DECL_INITIAL (cst_decl)) == FIXED_CST)
- {
- functions[num].type = IPA_CONST_REF;
- functions[num].value.constant = cst_decl;
- }
- }
- }
else if ((TREE_CODE (arg) == SSA_NAME) && SSA_NAME_IS_DEFAULT_DEF (arg))
{
int index = ipa_get_param_decl_index (info, SSA_NAME_VAR (arg));
method = TREE_OPERAND (rhs, 0);
if (delta)
{
- fill_member_ptr_cst_jump_function (jfunc, method, delta);
+ fill_member_ptr_cst_jump_function (jfunc, rhs, delta);
return;
}
}
delta = rhs;
if (method)
{
- fill_member_ptr_cst_jump_function (jfunc, method, delta);
+ fill_member_ptr_cst_jump_function (jfunc, rhs, delta);
return;
}
}
else
decl = jfunc->value.constant;
+ if (TREE_CODE (decl) != ADDR_EXPR)
+ continue;
+ decl = TREE_OPERAND (decl, 0);
+
if (TREE_CODE (decl) != FUNCTION_DECL)
continue;
callee = cgraph_node (decl);
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_CONST and Fortran
- constants are represented as IPA_CONST_REF. Finally, IPA_CONST_MEMBER_PTR
- stands for C++ member pointers constants. */
+ Integer and real constants are represented as IPA_CONST.
+ Finally, IPA_CONST_MEMBER_PTR stands for C++ member pointers constants. */
enum jump_func_type
{
IPA_UNKNOWN = 0, /* newly allocated and zeroed jump functions default */
IPA_CONST,
- IPA_CONST_REF,
IPA_CONST_MEMBER_PTR,
IPA_PASS_THROUGH
};
IPA_CONST_VALUE - simple scalar constant,
Cval of formal f will have a constant value if all callsites to this
function have the same constant value passed to f.
- Integer and real constants are represented as IPA_CONST and Fortran
- constants are represented as IPA_CONST_REF. */
+ Integer and real constants are represented as IPA_CONST. */
enum ipa_lattice_type
{
IPA_BOTTOM,
IPA_CONST_VALUE,
- IPA_CONST_VALUE_REF,
IPA_TOP
};
replace_info
= (struct ipa_replace_map *) VARRAY_GENERIC_PTR (tree_map, i);
if (replace_info->replace_p)
- insert_decl_map (&id, replace_info->old_tree,
- replace_info->new_tree);
+ {
+ if (TREE_CODE (replace_info->new_tree) == ADDR_EXPR)
+ {
+ tree op = TREE_OPERAND (replace_info->new_tree, 0);
+ while (handled_component_p (op))
+ op = TREE_OPERAND (op, 0);
+ if (TREE_CODE (op) == VAR_DECL)
+ add_referenced_var (op);
+ }
+ insert_decl_map (&id, replace_info->old_tree,
+ replace_info->new_tree);
+ }
}
DECL_INITIAL (new_decl) = remap_blocks (DECL_INITIAL (id.src_fn), &id);
return false;
}
+/* Return whether OP is a DECL whose address is interprocedural-invariant. */
+
+bool
+decl_address_ip_invariant_p (const_tree op)
+{
+ /* The conditions below are slightly less strict than the one in
+ staticp. */
+
+ switch (TREE_CODE (op))
+ {
+ case LABEL_DECL:
+ case FUNCTION_DECL:
+ case STRING_CST:
+ return true;
+
+ case VAR_DECL:
+ if (((TREE_STATIC (op) || DECL_EXTERNAL (op))
+ && !DECL_DLLIMPORT_P (op))
+ || DECL_THREAD_LOCAL_P (op))
+ return true;
+ break;
+
+ case CONST_DECL:
+ if ((TREE_STATIC (op) || DECL_EXTERNAL (op)))
+ return true;
+ break;
+
+ default:
+ break;
+ }
+
+ return false;
+}
+
/* Return true if T is function-invariant (internal function, does
not handle arithmetic; that's handled in skip_simple_arithmetic and
/* In tree.c */
extern int really_constant_p (const_tree);
extern bool decl_address_invariant_p (const_tree);
+extern bool decl_address_ip_invariant_p (const_tree);
extern int int_fits_type_p (const_tree, const_tree);
#ifndef GENERATOR_FILE
extern void get_type_static_bounds (const_tree, mpz_t, mpz_t);