/* Conditional constant propagation pass for the GNU compiler.
- Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008
+ Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009
Free Software Foundation, Inc.
Adapted from original RTL SSA-CCP by Daniel Berlin <dberlin@dberlin.org>
Adapted to GIMPLE trees by Diego Novillo <dnovillo@redhat.com>
#include "langhooks.h"
#include "target.h"
#include "toplev.h"
+#include "dbgcnt.h"
/* Possible lattice values. */
have zero as the initializer if they may not be
overridden at link or run time. */
if (!val
+ && !DECL_EXTERNAL (sym)
&& targetm.binds_local_p (sym)
&& (INTEGRAL_TYPE_P (TREE_TYPE (sym))
|| SCALAR_FLOAT_TYPE_P (TREE_TYPE (sym))))
- return fold_convert (TREE_TYPE (sym), integer_zero_node);
+ return fold_convert (TREE_TYPE (sym), integer_zero_node);
}
return NULL_TREE;
{
tree sym = SSA_NAME_VAR (var);
prop_value_t val = { UNINITIALIZED, NULL_TREE };
- tree cst_val;
-
- if (!is_gimple_reg (var))
- {
- /* Short circuit for regular CCP. We are not interested in any
- non-register when DO_STORE_CCP is false. */
- val.lattice_val = VARYING;
- }
- else if ((cst_val = get_symbol_constant_value (sym)) != NULL_TREE)
+ gimple stmt;
+
+ stmt = SSA_NAME_DEF_STMT (var);
+
+ if (gimple_nop_p (stmt))
{
- /* Globals and static variables declared 'const' take their
- initial value. */
- val.lattice_val = CONSTANT;
- val.value = cst_val;
+ /* Variables defined by an empty statement are those used
+ before being initialized. If VAR is a local variable, we
+ can assume initially that it is UNDEFINED, otherwise we must
+ consider it VARYING. */
+ if (is_gimple_reg (sym) && TREE_CODE (sym) != PARM_DECL)
+ val.lattice_val = UNDEFINED;
+ else
+ val.lattice_val = VARYING;
}
- else
- {
- gimple stmt = SSA_NAME_DEF_STMT (var);
-
- if (gimple_nop_p (stmt))
+ else if (is_gimple_assign (stmt)
+ /* Value-returning GIMPLE_CALL statements assign to
+ a variable, and are treated similarly to GIMPLE_ASSIGN. */
+ || (is_gimple_call (stmt)
+ && gimple_call_lhs (stmt) != NULL_TREE)
+ || gimple_code (stmt) == GIMPLE_PHI)
+ {
+ tree cst;
+ if (gimple_assign_single_p (stmt)
+ && DECL_P (gimple_assign_rhs1 (stmt))
+ && (cst = get_symbol_constant_value (gimple_assign_rhs1 (stmt))))
{
- /* Variables defined by an empty statement are those used
- before being initialized. If VAR is a local variable, we
- can assume initially that it is UNDEFINED, otherwise we must
- consider it VARYING. */
- if (is_gimple_reg (sym) && TREE_CODE (sym) != PARM_DECL)
- val.lattice_val = UNDEFINED;
- else
- val.lattice_val = VARYING;
- }
- else if (is_gimple_assign (stmt)
- /* Value-returning GIMPLE_CALL statements assign to
- a variable, and are treated similarly to GIMPLE_ASSIGN. */
- || (is_gimple_call (stmt)
- && gimple_call_lhs (stmt) != NULL_TREE)
- || gimple_code (stmt) == GIMPLE_PHI)
- {
- /* Any other variable defined by an assignment or a PHI node
- is considered UNDEFINED. */
- val.lattice_val = UNDEFINED;
+ val.lattice_val = CONSTANT;
+ val.value = cst;
}
else
- {
- /* Otherwise, VAR will never take on a constant value. */
- val.lattice_val = VARYING;
- }
+ /* Any other variable defined by an assignment or a PHI node
+ is considered UNDEFINED. */
+ val.lattice_val = UNDEFINED;
+ }
+ else
+ {
+ /* Otherwise, VAR will never take on a constant value. */
+ val.lattice_val = VARYING;
}
return val;
bool has_constant_operand, has_undefined_operand, all_undefined_operands;
tree use;
ssa_op_iter iter;
+ unsigned i;
enum gimple_code code = gimple_code (stmt);
if (gimple_has_volatile_ops (stmt))
return VARYING;
- /* If we are not doing store-ccp, statements with loads
- and/or stores will never fold into a constant. */
- if (!ZERO_SSA_OPERANDS (stmt, SSA_OP_ALL_VIRTUALS))
- return VARYING;
-
- /* Note that only a GIMPLE_SINGLE_RHS assignment can satisfy
- is_gimple_min_invariant, so we do not consider calls or
- other forms of assignment. */
- if (gimple_assign_single_p (stmt)
- && is_gimple_min_invariant (gimple_assign_rhs1 (stmt)))
- return CONSTANT;
-
- if (code == GIMPLE_COND
- && is_gimple_min_invariant (gimple_cond_lhs (stmt))
- && is_gimple_min_invariant (gimple_cond_rhs (stmt)))
- return CONSTANT;
-
- if (code == GIMPLE_SWITCH
- && is_gimple_min_invariant (gimple_switch_index (stmt)))
- return CONSTANT;
-
/* Arrive here for more complex cases. */
-
has_constant_operand = false;
has_undefined_operand = false;
all_undefined_operands = true;
- FOR_EACH_SSA_TREE_OPERAND (use, stmt, iter, SSA_OP_USE | SSA_OP_VUSE)
+ FOR_EACH_SSA_TREE_OPERAND (use, stmt, iter, SSA_OP_USE)
{
prop_value_t *val = get_value (use);
has_constant_operand = true;
}
+ /* There may be constants in regular rhs operands. */
+ for (i = is_gimple_call (stmt) + gimple_has_lhs (stmt);
+ i < gimple_num_ops (stmt); ++i)
+ {
+ tree op = gimple_op (stmt, i);
+ if (!op || TREE_CODE (op) == SSA_NAME)
+ continue;
+ if (is_gimple_min_invariant (op))
+ has_constant_operand = true;
+ }
+
/* If the operation combines operands like COMPLEX_EXPR make sure to
not mark the result UNDEFINED if only one part of the result is
undefined. */
if (has_undefined_operand)
return VARYING;
+ /* We do not consider virtual operands here -- load from read-only
+ memory may have only VARYING virtual operands, but still be
+ constant. */
if (has_constant_operand
- /* We do not consider virtual operands here -- load from read-only
- memory may have only VARYING virtual operands, but still be
- constant. */
- || ZERO_SSA_OPERANDS (stmt, SSA_OP_USE))
+ || gimple_references_memory_p (stmt))
return CONSTANT;
return VARYING;
if (gimple_has_volatile_ops (stmt))
return true;
- if (!ZERO_SSA_OPERANDS (stmt, SSA_OP_ALL_VIRTUALS))
- return true;
-
/* If it is a call and does not return a value or is not a
builtin and not an indirect call, it is varying. */
if (is_gimple_call (stmt))
return true;
}
+ /* Any other store operation is not interesting. */
+ else if (!ZERO_SSA_OPERANDS (stmt, SSA_OP_VIRTUAL_DEFS))
+ return true;
+
/* Anything other than assignments and conditional jumps are not
interesting for CCP. */
if (gimple_code (stmt) != GIMPLE_ASSIGN
/* If the statement will not produce a constant, mark
all its outputs VARYING. */
FOR_EACH_SSA_TREE_OPERAND (def, stmt, iter, SSA_OP_ALL_DEFS)
- {
- if (is_varying)
- set_value_varying (def);
- }
+ set_value_varying (def);
}
prop_set_simulate_again (stmt, !is_varying);
}
}
}
+/* Debug count support. Reset the values of ssa names
+ VARYING when the total number ssa names analyzed is
+ beyond the debug count specified. */
+
+static void
+do_dbg_cnt (void)
+{
+ unsigned i;
+ for (i = 0; i < num_ssa_names; i++)
+ {
+ if (!dbg_cnt (ccp))
+ {
+ const_val[i].lattice_val = VARYING;
+ const_val[i].value = NULL_TREE;
+ }
+ }
+}
+
/* Do final substitution of propagated values, cleanup the flowgraph and
free allocated storage.
static bool
ccp_finalize (void)
{
+ bool something_changed;
+
+ do_dbg_cnt ();
/* Perform substitutions based on the known constant values. */
- bool something_changed = substitute_and_fold (const_val, false);
+ something_changed = substitute_and_fold (const_val, false);
free (const_val);
const_val = NULL;
gcc_assert (INDIRECT_REF_P (deref)
&& TREE_CODE (addr) == ADDR_EXPR);
+ /* Don't propagate if ADDR's operand has incomplete type. */
+ if (!COMPLETE_TYPE_P (TREE_TYPE (TREE_OPERAND (addr, 0))))
+ return false;
+
/* If the address is invariant then we do not need to preserve restrict
qualifications. But we do need to preserve volatile qualifiers until
we can annotate the folded dereference itself properly. */
return fold_unary (VIEW_CONVERT_EXPR,
TREE_TYPE (rhs), val->value);
}
+ else if (TREE_CODE (rhs) == INDIRECT_REF
+ && TREE_CODE (TREE_OPERAND (rhs, 0)) == SSA_NAME)
+ {
+ prop_value_t *val = get_value (TREE_OPERAND (rhs, 0));
+ if (val->lattice_val == CONSTANT
+ && TREE_CODE (val->value) == ADDR_EXPR
+ && useless_type_conversion_p (TREE_TYPE (rhs),
+ TREE_TYPE (TREE_TYPE (val->value))))
+ rhs = TREE_OPERAND (val->value, 0);
+ }
return fold_const_aggregate_ref (rhs);
}
else if (kind == tcc_declaration)
so this should almost always return a simplified RHS. */
tree lhs = gimple_assign_lhs (stmt);
tree op0 = gimple_assign_rhs1 (stmt);
- tree res;
/* Simplify the operand down to a constant. */
if (TREE_CODE (op0) == SSA_NAME)
return op0;
}
- res = fold_unary (subcode, gimple_expr_type (stmt), op0);
-
- /* If the operation was a conversion do _not_ mark a
- resulting constant with TREE_OVERFLOW if the original
- constant was not. These conversions have implementation
- defined behavior and retaining the TREE_OVERFLOW flag
- here would confuse later passes such as VRP. */
- if (res
- && TREE_CODE (res) == INTEGER_CST
- && TREE_CODE (op0) == INTEGER_CST
- && CONVERT_EXPR_CODE_P (subcode))
- TREE_OVERFLOW (res) = TREE_OVERFLOW (op0);
-
- return res;
+ return fold_unary_ignore_overflow (subcode,
+ gimple_expr_type (stmt), op0);
}
case GIMPLE_BINARY_RHS:
unsigned HOST_WIDE_INT cnt;
tree cfield, cval;
+ if (TREE_CODE_CLASS (TREE_CODE (t)) == tcc_declaration)
+ return get_symbol_constant_value (t);
+
switch (TREE_CODE (t))
{
case ARRAY_REF:
|| (TREE_CODE (orig) == COMPONENT_REF
&& TREE_CODE (TREE_TYPE (TREE_OPERAND (orig, 1))) == ARRAY_TYPE))
&& (TREE_CODE (t) == ARRAY_REF
- || (TREE_CODE (t) == COMPONENT_REF
- && TREE_CODE (TREE_TYPE (TREE_OPERAND (t, 1))) == ARRAY_TYPE))
+ || TREE_CODE (t) == COMPONENT_REF)
&& !operand_equal_p (TREE_CODE (orig) == ARRAY_REF
? TREE_OPERAND (orig, 0) : orig,
TREE_CODE (t) == ARRAY_REF