We should be able to deduce that the predicate 'a.a != B' is always
false. To achieve this, we associate constant values to the SSA
- names in the V_MAY_DEF and V_MUST_DEF operands for each store.
- Additionally, since we also glob partial loads/stores with the base
- symbol, we also keep track of the memory reference where the
- constant value was stored (in the MEM_REF field of PROP_VALUE_T).
- For instance,
+ names in the VDEF operands for each store. Additionally,
+ since we also glob partial loads/stores with the base symbol, we
+ also keep track of the memory reference where the constant value
+ was stored (in the MEM_REF field of PROP_VALUE_T). For instance,
- # a_5 = V_MAY_DEF <a_4>
+ # a_5 = VDEF <a_4>
a.a = 2;
# VUSE <a_5>
/* Array of propagated constant values. After propagation,
CONST_VAL[I].VALUE holds the constant value for SSA_NAME(I). If
the constant is held in an SSA name representing a memory store
- (i.e., a V_MAY_DEF or V_MUST_DEF), CONST_VAL[I].MEM_REF will
- contain the actual memory reference used to store (i.e., the LHS of
- the assignment doing the store). */
+ (i.e., a VDEF), CONST_VAL[I].MEM_REF will contain the actual
+ memory reference used to store (i.e., the LHS of the assignment
+ doing the store). */
static prop_value_t *const_val;
/* True if we are also propagating constants in stores and loads. */
return true;
}
+/* If SYM is a constant variable with known value, return the value.
+ NULL_TREE is returned otherwise. */
+
+static tree
+get_symbol_constant_value (tree sym)
+{
+ if (TREE_STATIC (sym)
+ && TREE_READONLY (sym)
+ && !MTAG_P (sym))
+ {
+ tree val = DECL_INITIAL (sym);
+ if (val
+ && ccp_decl_initial_min_invariant (val))
+ return val;
+ }
+
+ return NULL_TREE;
+}
/* Compute a default value for variable VAR and store it in the
CONST_VAL array. The following rules are used to get default
{
tree sym = SSA_NAME_VAR (var);
prop_value_t val = { UNINITIALIZED, NULL_TREE, NULL_TREE };
+ tree cst_val;
if (!do_store_ccp && !is_gimple_reg (var))
{
val.lattice_val = CONSTANT;
val.value = SSA_NAME_VALUE (var);
}
- else if (TREE_STATIC (sym)
- && TREE_READONLY (sym)
- && !MTAG_P (sym)
- && DECL_INITIAL (sym)
- && ccp_decl_initial_min_invariant (DECL_INITIAL (sym)))
+ else if ((cst_val = get_symbol_constant_value (sym)) != NULL_TREE)
{
/* Globals and static variables declared 'const' take their
initial value. */
val.lattice_val = CONSTANT;
- val.value = DECL_INITIAL (sym);
+ val.value = cst_val;
val.mem_ref = sym;
}
else
else
val.lattice_val = VARYING;
}
- else if (TREE_CODE (stmt) == MODIFY_EXPR
+ else if (TREE_CODE (stmt) == GIMPLE_MODIFY_STMT
|| TREE_CODE (stmt) == PHI_NODE)
{
/* Any other variable defined by an assignment or a PHI node
val->mem_ref = NULL_TREE;
}
+/* For float types, modify the value of VAL to make ccp work correctly
+ for non-standard values (-0, NaN):
+
+ If HONOR_SIGNED_ZEROS is false, and VAL = -0, we canonicalize it to 0.
+ If HONOR_NANS is false, and VAL is NaN, we canonicalize it to UNDEFINED.
+ This is to fix the following problem (see PR 29921): Suppose we have
+
+ x = 0.0 * y
+
+ and we set value of y to NaN. This causes value of x to be set to NaN.
+ When we later determine that y is in fact VARYING, fold uses the fact
+ that HONOR_NANS is false, and we try to change the value of x to 0,
+ causing an ICE. With HONOR_NANS being false, the real appearance of
+ NaN would cause undefined behavior, though, so claiming that y (and x)
+ are UNDEFINED initially is correct. */
+
+static void
+canonicalize_float_value (prop_value_t *val)
+{
+ enum machine_mode mode;
+ tree type;
+ REAL_VALUE_TYPE d;
+
+ if (val->lattice_val != CONSTANT
+ || TREE_CODE (val->value) != REAL_CST)
+ return;
+
+ d = TREE_REAL_CST (val->value);
+ type = TREE_TYPE (val->value);
+ mode = TYPE_MODE (type);
+
+ if (!HONOR_SIGNED_ZEROS (mode)
+ && REAL_VALUE_MINUS_ZERO (d))
+ {
+ val->value = build_real (type, dconst0);
+ return;
+ }
+
+ if (!HONOR_NANS (mode)
+ && REAL_VALUE_ISNAN (d))
+ {
+ val->lattice_val = UNDEFINED;
+ val->value = NULL;
+ val->mem_ref = NULL;
+ return;
+ }
+}
+
/* Set the value for variable VAR to NEW_VAL. Return true if the new
value is different from VAR's previous value. */
{
prop_value_t *old_val = get_value (var);
+ canonicalize_float_value (&new_val);
+
/* Lattice transitions must always be monotonically increasing in
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
+ 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->value && !new_val.value)
+ || operand_equal_p (old_val->value, new_val.value, 0))
&& old_val->mem_ref == new_val.mem_ref));
if (old_val->lattice_val != new_val.lattice_val)
/* Anything other than assignments and conditional jumps are not
interesting for CCP. */
- if (TREE_CODE (stmt) != MODIFY_EXPR
+ if (TREE_CODE (stmt) != GIMPLE_MODIFY_STMT
&& !(TREE_CODE (stmt) == RETURN_EXPR && get_rhs (stmt) != NULL_TREE)
&& TREE_CODE (stmt) != COND_EXPR
&& TREE_CODE (stmt) != SWITCH_EXPR)
/* Anything other than assignments and conditional jumps are not
interesting for CCP. */
- if (TREE_CODE (stmt) != MODIFY_EXPR
+ if (TREE_CODE (stmt) != GIMPLE_MODIFY_STMT
&& !(TREE_CODE (stmt) == RETURN_EXPR && get_rhs (stmt) != NULL_TREE)
&& TREE_CODE (stmt) != COND_EXPR
&& TREE_CODE (stmt) != SWITCH_EXPR)
tree lhs, rhs;
enum ssa_prop_result retval;
- lhs = TREE_OPERAND (stmt, 0);
- rhs = TREE_OPERAND (stmt, 1);
+ lhs = GIMPLE_STMT_OPERAND (stmt, 0);
+ rhs = GIMPLE_STMT_OPERAND (stmt, 1);
if (TREE_CODE (rhs) == SSA_NAME)
{
the constant value into the type of the destination variable. This
should not be necessary if GCC represented bitfields properly. */
{
- tree orig_lhs = TREE_OPERAND (stmt, 0);
+ tree orig_lhs = GIMPLE_STMT_OPERAND (stmt, 0);
if (TREE_CODE (orig_lhs) == VIEW_CONVERT_EXPR
&& val.lattice_val == CONSTANT)
}
else if (do_store_ccp && stmt_makes_single_store (stmt))
{
- /* Otherwise, set the names in V_MAY_DEF/V_MUST_DEF operands
- to the new constant value and mark the LHS as the memory
- reference associated with VAL. */
+ /* Otherwise, set the names in VDEF operands to the new
+ constant value and mark the LHS as the memory reference
+ associated with VAL. */
ssa_op_iter i;
tree vdef;
bool changed;
/* Set the value of every VDEF to VAL. */
changed = false;
FOR_EACH_SSA_TREE_OPERAND (vdef, stmt, i, SSA_OP_VIRTUAL_DEFS)
- changed |= set_lattice_value (vdef, val);
+ {
+ /* See PR 29801. We may have VDEFs for read-only variables
+ (see the handling of unmodifiable variables in
+ add_virtual_operand); do not attempt to change their value. */
+ if (get_symbol_constant_value (SSA_NAME_VAR (vdef)) != NULL_TREE)
+ continue;
+
+ changed |= set_lattice_value (vdef, val);
+ }
/* Note that for propagation purposes, we are only interested in
visiting statements that load the exact same memory reference
fprintf (dump_file, "\n");
}
- if (TREE_CODE (stmt) == MODIFY_EXPR)
+ if (TREE_CODE (stmt) == GIMPLE_MODIFY_STMT)
{
/* If the statement is an assignment that produces a single
output value, evaluate its RHS to see if the lattice value of
TV_TREE_CCP, /* tv_id */
PROP_cfg | PROP_ssa | PROP_alias, /* properties_required */
0, /* properties_provided */
- PROP_smt_usage, /* properties_destroyed */
+ 0, /* properties_destroyed */
0, /* todo_flags_start */
- TODO_cleanup_cfg | TODO_dump_func | TODO_update_ssa
- | TODO_ggc_collect | TODO_verify_ssa
- | TODO_verify_stmts | TODO_update_smt_usage, /* todo_flags_finish */
+ TODO_cleanup_cfg
+ | TODO_dump_func
+ | TODO_update_ssa
+ | TODO_ggc_collect
+ | TODO_verify_ssa
+ | TODO_verify_stmts
+ | TODO_update_smt_usage, /* todo_flags_finish */
0 /* letter */
};
TV_TREE_STORE_CCP, /* tv_id */
PROP_cfg | PROP_ssa | PROP_alias, /* properties_required */
0, /* properties_provided */
- PROP_smt_usage, /* properties_destroyed */
+ 0, /* properties_destroyed */
0, /* todo_flags_start */
- TODO_dump_func | TODO_update_ssa
- | TODO_ggc_collect | TODO_verify_ssa
+ TODO_dump_func
+ | TODO_update_ssa
+ | TODO_ggc_collect
+ | TODO_verify_ssa
| TODO_cleanup_cfg
- | TODO_verify_stmts | TODO_update_smt_usage, /* todo_flags_finish */
+ | TODO_verify_stmts
+ | TODO_update_smt_usage, /* todo_flags_finish */
0 /* letter */
};
switch (TREE_CODE (def_stmt))
{
- case MODIFY_EXPR:
+ case GIMPLE_MODIFY_STMT:
{
tree rhs;
/* The RHS of the statement defining VAR must either have a
constant length or come from another SSA_NAME with a constant
length. */
- rhs = TREE_OPERAND (def_stmt, 1);
+ rhs = GIMPLE_STMT_OPERAND (def_stmt, 1);
STRIP_NOPS (rhs);
return get_maxval_strlen (rhs, length, visited, type);
}
bitmap visited;
bool ignore;
- ignore = TREE_CODE (stmt) != MODIFY_EXPR;
+ ignore = TREE_CODE (stmt) != GIMPLE_MODIFY_STMT;
/* First try the generic builtin folder. If that succeeds, return the
result directly. */
case BUILT_IN_FPUTS:
result = fold_builtin_fputs (arglist,
- TREE_CODE (stmt) != MODIFY_EXPR, 0,
+ TREE_CODE (stmt) != GIMPLE_MODIFY_STMT, 0,
val[0]);
break;
case BUILT_IN_FPUTS_UNLOCKED:
result = fold_builtin_fputs (arglist,
- TREE_CODE (stmt) != MODIFY_EXPR, 1,
+ TREE_CODE (stmt) != GIMPLE_MODIFY_STMT, 1,
val[0]);
break;
tree new_stmt = tsi_stmt (ti);
find_new_referenced_vars (tsi_stmt_ptr (ti));
bsi_insert_before (si_p, new_stmt, BSI_NEW_STMT);
- mark_new_vars_to_rename (bsi_stmt (*si_p));
+ mark_symbols_for_renaming (new_stmt);
bsi_next (si_p);
}
print_generic_stmt (dump_file, *stmtp, dump_flags);
}
+ push_stmt_changes (stmtp);
+
if (!set_rhs (stmtp, result))
{
result = convert_to_gimple_builtin (&i, result,
TREE_CODE (old_stmt)
- != MODIFY_EXPR);
+ != GIMPLE_MODIFY_STMT);
if (result)
{
bool ok = set_rhs (stmtp, result);
-
gcc_assert (ok);
}
}
- mark_new_vars_to_rename (*stmtp);
+
+ pop_stmt_changes (stmtp);
+
if (maybe_clean_or_replace_eh_stmt (old_stmt, *stmtp)
&& tree_purge_dead_eh_edges (bb))
cfg_changed = true;