aboutsummaryrefslogtreecommitdiff
path: root/gcc/tree-ssa-ccp.c
diff options
context:
space:
mode:
authorZdenek Dvorak <dvorakz@suse.cz>2006-11-09 01:09:43 +0100
committerZdenek Dvorak <rakdver@gcc.gnu.org>2006-11-09 00:09:43 +0000
commit106dec717fad0279496049194edfbcad782b40da (patch)
treef954bb3cfcd6ce1c81fbe5f7585478ecdae6ff10 /gcc/tree-ssa-ccp.c
parent5e3c2d4c683546748ea64ac2904e1fcc40300d64 (diff)
downloadgcc-106dec717fad0279496049194edfbcad782b40da.zip
gcc-106dec717fad0279496049194edfbcad782b40da.tar.gz
gcc-106dec717fad0279496049194edfbcad782b40da.tar.bz2
re PR tree-optimization/29738 (Missed constant propagation into loops)
PR tree-optimization/29738 * tree-ssa-ccp.c: Remove UNKNOWN_VAL from comments. (ccp_lattice_t): Remove UNKNOWN_VAL. (dump_lattice_value, ccp_lattice_meet, ccp_visit_phi_node): Do not handle UNKNOWN_VAL. (get_default_value): Set initial value of virtual operands to VARYING. (get_value): Always use get_default_value on uninitialized operands. (set_value_varying, surely_varying_stmt_p): New functions. (set_lattice_value): Do not pass argument to get_value. Do not handle UNKNOWN_VAL. (likely_value): Follow the semantics described in the comment. (ccp_initialize): Use surely_varying_stmt_p. Do not mark phi nodes DONT_SIMULATE_AGAIN. (ccp_fold): Do not pass argument to get_value. (fold_const_aggregate_ref, visit_assignment): Ditto. Do not handle UNKNOWN_VAL. * gcc.dg/tree-ssa/ssa-ccp-14.c: New test. * gcc.dg/tree-ssa/ssa-ccp-15.c: New test. From-SVN: r118602
Diffstat (limited to 'gcc/tree-ssa-ccp.c')
-rw-r--r--gcc/tree-ssa-ccp.c300
1 files changed, 121 insertions, 179 deletions
diff --git a/gcc/tree-ssa-ccp.c b/gcc/tree-ssa-ccp.c
index 0ecd221..ca96471 100644
--- a/gcc/tree-ssa-ccp.c
+++ b/gcc/tree-ssa-ccp.c
@@ -29,8 +29,13 @@ Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
with SSA names. Given an SSA name V_i, it may take one of the
following values:
- UNINITIALIZED -> This is the default starting value. V_i
- has not been processed yet.
+ UNINITIALIZED -> the initial state of the value. This value
+ is replaced with a correct initial value
+ the first time the value is used, so the
+ rest of the pass does not need to care about
+ it. Using this value simplifies initialization
+ of the pass, and prevents us from needlessly
+ scanning statements that are never reached.
UNDEFINED -> V_i is a local variable whose definition
has not been processed yet. Therefore we
@@ -143,11 +148,8 @@ Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
it would be wrong to replace the load from 'a.b' with '2', because
'2' had been stored into a.a.
- To support STORE-CCP, it is necessary to add a new value to the
- constant propagation lattice. When evaluating a load for a memory
- reference we can no longer assume a value of UNDEFINED if we
- haven't seen a preceding store to the same memory location.
- Consider, for instance global variables:
+ Note that the initial value of virtual operands is VARYING, not
+ UNDEFINED. Consider, for instance global variables:
int A;
@@ -165,10 +167,7 @@ Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
The value of A_2 cannot be assumed to be UNDEFINED, as it may have
been defined outside of foo. If we were to assume it UNDEFINED, we
- would erroneously optimize the above into 'return 3;'. Therefore,
- when doing STORE-CCP, we introduce a fifth lattice value
- (UNKNOWN_VAL), which overrides any other value when computing the
- meet operation in PHI nodes.
+ would erroneously optimize the above into 'return 3;'.
Though STORE-CCP is not too expensive, it does have to do more work
than regular CCP, so it is only enabled at -O2. Both regular CCP
@@ -214,9 +213,8 @@ Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
/* Possible lattice values. */
typedef enum
{
- UNINITIALIZED = 0,
+ UNINITIALIZED,
UNDEFINED,
- UNKNOWN_VAL,
CONSTANT,
VARYING
} ccp_lattice_t;
@@ -248,9 +246,6 @@ dump_lattice_value (FILE *outf, const char *prefix, prop_value_t val)
case VARYING:
fprintf (outf, "%sVARYING", prefix);
break;
- case UNKNOWN_VAL:
- fprintf (outf, "%sUNKNOWN_VAL", prefix);
- break;
case CONSTANT:
fprintf (outf, "%sCONSTANT ", prefix);
print_generic_expr (outf, val.value, dump_flags);
@@ -317,17 +312,15 @@ ccp_decl_initial_min_invariant (tree t)
4- Variables defined by statements other than assignments and PHI
nodes are considered VARYING.
- 5- Variables that are not GIMPLE registers are considered
- UNKNOWN_VAL, which is really a stronger version of UNDEFINED.
- It's used to avoid the short circuit evaluation implied by
- UNDEFINED in ccp_lattice_meet. */
+ 5- Initial values of variables that are not GIMPLE registers are
+ considered VARYING. */
static prop_value_t
get_default_value (tree var)
{
tree sym = SSA_NAME_VAR (var);
prop_value_t val = { UNINITIALIZED, NULL_TREE, NULL_TREE };
-
+
if (!do_store_ccp && !is_gimple_reg (var))
{
/* Short circuit for regular CCP. We are not interested in any
@@ -360,15 +353,10 @@ get_default_value (tree var)
{
/* 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. If we are
- doing STORE-CCP, function arguments and non-register
- variables are initially UNKNOWN_VAL, because we cannot
- discard the value incoming from outside of this function
- (see ccp_lattice_meet for details). */
+ 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 if (do_store_ccp)
- val.lattice_val = UNKNOWN_VAL;
else
val.lattice_val = VARYING;
}
@@ -376,9 +364,8 @@ get_default_value (tree var)
|| TREE_CODE (stmt) == PHI_NODE)
{
/* Any other variable defined by an assignment or a PHI node
- is considered UNDEFINED (or UNKNOWN_VAL if VAR is not a
- GIMPLE register). */
- val.lattice_val = is_gimple_reg (sym) ? UNDEFINED : UNKNOWN_VAL;
+ is considered UNDEFINED. */
+ val.lattice_val = UNDEFINED;
}
else
{
@@ -391,20 +378,30 @@ get_default_value (tree var)
}
-/* Get the constant value associated with variable VAR. If
- MAY_USE_DEFAULT_P is true, call get_default_value on variables that
- have the lattice value UNINITIALIZED. */
+/* Get the constant value associated with variable VAR. */
-static prop_value_t *
-get_value (tree var, bool may_use_default_p)
+static inline prop_value_t *
+get_value (tree var)
{
prop_value_t *val = &const_val[SSA_NAME_VERSION (var)];
- if (may_use_default_p && val->lattice_val == UNINITIALIZED)
+
+ if (val->lattice_val == UNINITIALIZED)
*val = get_default_value (var);
return val;
}
+/* Sets the value associated with VAR to VARYING. */
+
+static inline void
+set_value_varying (tree var)
+{
+ prop_value_t *val = &const_val[SSA_NAME_VERSION (var)];
+
+ val->lattice_val = VARYING;
+ val->value = NULL_TREE;
+ val->mem_ref = NULL_TREE;
+}
/* Set the value for variable VAR to NEW_VAL. Return true if the new
value is different from VAR's previous value. */
@@ -412,42 +409,29 @@ get_value (tree var, bool may_use_default_p)
static bool
set_lattice_value (tree var, prop_value_t new_val)
{
- prop_value_t *old_val = get_value (var, false);
+ prop_value_t *old_val = get_value (var);
/* Lattice transitions must always be monotonically increasing in
- value. We allow two exceptions:
-
- 1- If *OLD_VAL and NEW_VAL are the same, return false to
- inform the caller that this was a non-transition.
-
- 2- If we are doing store-ccp (i.e., DOING_STORE_CCP is true),
- allow CONSTANT->UNKNOWN_VAL. The UNKNOWN_VAL state is a
- special type of UNDEFINED state which prevents the short
- circuit evaluation of PHI arguments (see ccp_visit_phi_node
- and ccp_lattice_meet). */
+ value. If *OLD_VAL and NEW_VAL are the same, return false to
+ inform the caller that this was a non-transition. */
+
gcc_assert (old_val->lattice_val <= new_val.lattice_val
|| (old_val->lattice_val == new_val.lattice_val
&& old_val->value == new_val.value
- && old_val->mem_ref == new_val.mem_ref)
- || (do_store_ccp
- && old_val->lattice_val == CONSTANT
- && new_val.lattice_val == UNKNOWN_VAL));
+ && old_val->mem_ref == new_val.mem_ref));
if (old_val->lattice_val != new_val.lattice_val)
{
if (dump_file && (dump_flags & TDF_DETAILS))
{
dump_lattice_value (dump_file, "Lattice value changed to ", new_val);
- fprintf (dump_file, ". %sdding SSA edges to worklist.\n",
- new_val.lattice_val != UNDEFINED ? "A" : "Not a");
+ fprintf (dump_file, ". Adding SSA edges to worklist.\n");
}
*old_val = new_val;
- /* Transitions UNINITIALIZED -> UNDEFINED are never interesting
- for propagation purposes. In these cases return false to
- avoid doing useless work. */
- return (new_val.lattice_val != UNDEFINED);
+ gcc_assert (new_val.lattice_val != UNDEFINED);
+ return true;
}
return false;
@@ -467,7 +451,7 @@ set_lattice_value (tree var, prop_value_t new_val)
static ccp_lattice_t
likely_value (tree stmt)
{
- bool found_constant;
+ bool has_constant_operand;
stmt_ann_t ann;
tree use;
ssa_op_iter iter;
@@ -494,6 +478,7 @@ likely_value (tree stmt)
/* Anything other than assignments and conditional jumps are not
interesting for CCP. */
if (TREE_CODE (stmt) != MODIFY_EXPR
+ && !(TREE_CODE (stmt) == RETURN_EXPR && get_rhs (stmt) != NULL_TREE)
&& TREE_CODE (stmt) != COND_EXPR
&& TREE_CODE (stmt) != SWITCH_EXPR)
return VARYING;
@@ -501,33 +486,63 @@ likely_value (tree stmt)
if (is_gimple_min_invariant (get_rhs (stmt)))
return CONSTANT;
- found_constant = false;
- FOR_EACH_SSA_TREE_OPERAND (use, stmt, iter, SSA_OP_USE|SSA_OP_VUSE)
+ has_constant_operand = false;
+ FOR_EACH_SSA_TREE_OPERAND (use, stmt, iter, SSA_OP_USE | SSA_OP_VUSE)
{
- prop_value_t *val = get_value (use, true);
+ prop_value_t *val = get_value (use);
- if (val->lattice_val == VARYING)
- return VARYING;
-
- if (val->lattice_val == UNKNOWN_VAL)
- {
- /* UNKNOWN_VAL is invalid when not doing STORE-CCP. */
- gcc_assert (do_store_ccp);
- return UNKNOWN_VAL;
- }
+ if (val->lattice_val == UNDEFINED)
+ return UNDEFINED;
if (val->lattice_val == CONSTANT)
- found_constant = true;
+ has_constant_operand = true;
}
- if (found_constant
- || ZERO_SSA_OPERANDS (stmt, SSA_OP_USE)
- || ZERO_SSA_OPERANDS (stmt, SSA_OP_VUSE))
+ 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))
return CONSTANT;
- return UNDEFINED;
+ return VARYING;
}
+/* Returns true if STMT cannot be constant. */
+
+static bool
+surely_varying_stmt_p (tree stmt)
+{
+ /* If the statement has operands that we cannot handle, it cannot be
+ constant. */
+ if (stmt_ann (stmt)->has_volatile_ops)
+ return true;
+
+ if (!ZERO_SSA_OPERANDS (stmt, SSA_OP_ALL_VIRTUALS))
+ {
+ if (!do_store_ccp)
+ return true;
+
+ /* We can only handle simple loads and stores. */
+ if (!stmt_makes_single_load (stmt)
+ && !stmt_makes_single_store (stmt))
+ return true;
+ }
+
+ /* If it contains a call, it is varying. */
+ if (get_call_expr_in (stmt) != NULL_TREE)
+ return true;
+
+ /* Anything other than assignments and conditional jumps are not
+ interesting for CCP. */
+ if (TREE_CODE (stmt) != MODIFY_EXPR
+ && !(TREE_CODE (stmt) == RETURN_EXPR && get_rhs (stmt) != NULL_TREE)
+ && TREE_CODE (stmt) != COND_EXPR
+ && TREE_CODE (stmt) != SWITCH_EXPR)
+ return true;
+
+ return false;
+}
/* Initialize local data structures for CCP. */
@@ -546,11 +561,10 @@ ccp_initialize (void)
for (i = bsi_start (bb); !bsi_end_p (i); bsi_next (&i))
{
- bool is_varying = false;
tree stmt = bsi_stmt (i);
+ bool is_varying = surely_varying_stmt_p (stmt);
- if (likely_value (stmt) == VARYING)
-
+ if (is_varying)
{
tree def;
ssa_op_iter iter;
@@ -558,44 +572,29 @@ ccp_initialize (void)
/* 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)
- get_value (def, false)->lattice_val = VARYING;
-
- /* Never mark conditional jumps with DONT_SIMULATE_AGAIN,
- otherwise the propagator will never add the outgoing
- control edges. */
- if (TREE_CODE (stmt) != COND_EXPR
- && TREE_CODE (stmt) != SWITCH_EXPR)
- is_varying = true;
+ {
+ if (is_varying)
+ set_value_varying (def);
+ }
}
DONT_SIMULATE_AGAIN (stmt) = is_varying;
}
}
- /* Now process PHI nodes. */
+ /* Now process PHI nodes. We never set DONT_SIMULATE_AGAIN on phi node,
+ since we do not know which edges are executable yet, except for
+ phi nodes for virtual operands when we do not do store ccp. */
FOR_EACH_BB (bb)
{
tree phi;
for (phi = phi_nodes (bb); phi; phi = PHI_CHAIN (phi))
{
- int i;
- tree arg;
- prop_value_t *val = get_value (PHI_RESULT (phi), false);
-
- for (i = 0; i < PHI_NUM_ARGS (phi); i++)
- {
- arg = PHI_ARG_DEF (phi, i);
-
- if (TREE_CODE (arg) == SSA_NAME
- && get_value (arg, false)->lattice_val == VARYING)
- {
- val->lattice_val = VARYING;
- break;
- }
- }
-
- DONT_SIMULATE_AGAIN (phi) = (val->lattice_val == VARYING);
+ if (!do_store_ccp && !is_gimple_reg (PHI_RESULT (phi)))
+ DONT_SIMULATE_AGAIN (phi) = true;
+ else
+ DONT_SIMULATE_AGAIN (phi) = false;
}
}
}
@@ -618,36 +617,10 @@ ccp_finalize (void)
in VAL1.
any M UNDEFINED = any
- any M UNKNOWN_VAL = UNKNOWN_VAL
any M VARYING = VARYING
Ci M Cj = Ci if (i == j)
Ci M Cj = VARYING if (i != j)
-
- Lattice values UNKNOWN_VAL and UNDEFINED are similar but have
- different semantics at PHI nodes. Both values imply that we don't
- know whether the variable is constant or not. However, UNKNOWN_VAL
- values override all others. For instance, suppose that A is a
- global variable:
-
- +------+
- | |
- | / \
- | / \
- | | A_1 = 4
- | \ /
- | \ /
- | A_3 = PHI (A_2, A_1)
- | ... = A_3
- | |
- +----+
-
- If the edge into A_2 is not executable, the first visit to A_3 will
- yield the constant 4. But the second visit to A_3 will be with A_2
- in state UNKNOWN_VAL. We can no longer conclude that A_3 is 4
- because A_2 may have been set in another function. If we had used
- the lattice value UNDEFINED, we would have had wrongly concluded
- that A_3 is 4. */
-
+ */
static void
ccp_lattice_meet (prop_value_t *val1, prop_value_t *val2)
@@ -663,17 +636,6 @@ ccp_lattice_meet (prop_value_t *val1, prop_value_t *val2)
Nothing to do. VAL1 already contains the value we want. */
;
}
- else if (val1->lattice_val == UNKNOWN_VAL
- || val2->lattice_val == UNKNOWN_VAL)
- {
- /* UNKNOWN_VAL values are invalid if we are not doing STORE-CCP. */
- gcc_assert (do_store_ccp);
-
- /* any M UNKNOWN_VAL = UNKNOWN_VAL. */
- val1->lattice_val = UNKNOWN_VAL;
- val1->value = NULL_TREE;
- val1->mem_ref = NULL_TREE;
- }
else if (val1->lattice_val == VARYING
|| val2->lattice_val == VARYING)
{
@@ -725,7 +687,7 @@ ccp_visit_phi_node (tree phi)
print_generic_expr (dump_file, phi, dump_flags);
}
- old_val = get_value (PHI_RESULT (phi), false);
+ old_val = get_value (PHI_RESULT (phi));
switch (old_val->lattice_val)
{
case VARYING:
@@ -735,19 +697,7 @@ ccp_visit_phi_node (tree phi)
new_val = *old_val;
break;
- case UNKNOWN_VAL:
- /* To avoid the default value of UNKNOWN_VAL overriding
- that of its possible constant arguments, temporarily
- set the PHI node's default lattice value to be
- UNDEFINED. If the PHI node's old value was UNKNOWN_VAL and
- the new value is UNDEFINED, then we prevent the invalid
- transition by not calling set_lattice_value. */
- gcc_assert (do_store_ccp);
-
- /* FALLTHRU */
-
case UNDEFINED:
- case UNINITIALIZED:
new_val.lattice_val = UNDEFINED;
new_val.value = NULL_TREE;
new_val.mem_ref = NULL_TREE;
@@ -785,7 +735,7 @@ ccp_visit_phi_node (tree phi)
arg_val.mem_ref = NULL_TREE;
}
else
- arg_val = *(get_value (arg, true));
+ arg_val = *(get_value (arg));
ccp_lattice_meet (&new_val, &arg_val);
@@ -808,13 +758,7 @@ ccp_visit_phi_node (tree phi)
fprintf (dump_file, "\n\n");
}
- /* Check for an invalid change from UNKNOWN_VAL to UNDEFINED. */
- if (do_store_ccp
- && old_val->lattice_val == UNKNOWN_VAL
- && new_val.lattice_val == UNDEFINED)
- return SSA_PROP_NOT_INTERESTING;
-
- /* Otherwise, make the transition to the new value. */
+ /* Make the transition to the new value. */
if (set_lattice_value (PHI_RESULT (phi), new_val))
{
if (new_val.lattice_val == VARYING)
@@ -848,7 +792,7 @@ ccp_fold (tree stmt)
{
/* If the RHS is an SSA_NAME, return its known constant value,
if any. */
- return get_value (rhs, true)->value;
+ return get_value (rhs)->value;
}
else if (do_store_ccp && stmt_makes_single_load (stmt))
{
@@ -881,9 +825,9 @@ ccp_fold (tree stmt)
/* Simplify the operand down to a constant. */
if (TREE_CODE (op0) == SSA_NAME)
{
- prop_value_t *val = get_value (op0, true);
+ prop_value_t *val = get_value (op0);
if (val->lattice_val == CONSTANT)
- op0 = get_value (op0, true)->value;
+ op0 = get_value (op0)->value;
}
if ((code == NOP_EXPR || code == CONVERT_EXPR)
@@ -909,14 +853,14 @@ ccp_fold (tree stmt)
/* Simplify the operands down to constants when appropriate. */
if (TREE_CODE (op0) == SSA_NAME)
{
- prop_value_t *val = get_value (op0, true);
+ prop_value_t *val = get_value (op0);
if (val->lattice_val == CONSTANT)
op0 = val->value;
}
if (TREE_CODE (op1) == SSA_NAME)
{
- prop_value_t *val = get_value (op1, true);
+ prop_value_t *val = get_value (op1);
if (val->lattice_val == CONSTANT)
op1 = val->value;
}
@@ -1022,7 +966,7 @@ fold_const_aggregate_ref (tree t)
switch (TREE_CODE (idx))
{
case SSA_NAME:
- if ((value = get_value (idx, true))
+ if ((value = get_value (idx))
&& value->lattice_val == CONSTANT
&& TREE_CODE (value->value) == INTEGER_CST)
idx = value->value;
@@ -1151,7 +1095,7 @@ evaluate_stmt (tree stmt)
/* The statement produced a nonconstant value. If the statement
had UNDEFINED operands, then the result of the statement
should be UNDEFINED. Otherwise, the statement is VARYING. */
- if (likelyvalue == UNDEFINED || likelyvalue == UNKNOWN_VAL)
+ if (likelyvalue == UNDEFINED)
val.lattice_val = likelyvalue;
else
val.lattice_val = VARYING;
@@ -1181,18 +1125,19 @@ visit_assignment (tree stmt, tree *output_p)
if (TREE_CODE (rhs) == SSA_NAME)
{
/* For a simple copy operation, we copy the lattice values. */
- prop_value_t *nval = get_value (rhs, true);
+ prop_value_t *nval = get_value (rhs);
val = *nval;
}
else if (do_store_ccp && stmt_makes_single_load (stmt))
{
/* Same as above, but the RHS is not a gimple register and yet
- has a known VUSE. If STMT is loading from the same memory
+ has a known VUSE. If STMT is loading from the same memory
location that created the SSA_NAMEs for the virtual operands,
we can propagate the value on the RHS. */
prop_value_t *nval = get_value_loaded_by (stmt, const_val);
- if (nval && nval->mem_ref
+ if (nval
+ && nval->mem_ref
&& operand_equal_p (nval->mem_ref, rhs, 0))
val = *nval;
else
@@ -1271,12 +1216,9 @@ visit_assignment (tree stmt, tree *output_p)
tree vdef;
bool changed;
- /* Stores cannot take on an UNDEFINED value. */
- if (val.lattice_val == UNDEFINED)
- val.lattice_val = UNKNOWN_VAL;
-
/* Mark VAL as stored in the LHS of this assignment. */
- val.mem_ref = lhs;
+ if (val.lattice_val == CONSTANT)
+ val.mem_ref = lhs;
/* Set the value of every VDEF to VAL. */
changed = false;