val.lattice_val = UNDEFINED;
val.const_val = NULL_TREE;
- if (TREE_CODE (sym) == PARM_DECL || TREE_THIS_VOLATILE (sym))
+ if (TREE_CODE (var) == SSA_NAME
+ && SSA_NAME_VALUE (var)
+ && is_gimple_min_invariant (SSA_NAME_VALUE (var)))
+ {
+ val.lattice_val = CONSTANT;
+ val.const_val = SSA_NAME_VALUE (var);
+ }
+ else if (TREE_CODE (sym) == PARM_DECL || TREE_THIS_VOLATILE (sym))
{
/* Function arguments and volatile variables are considered VARYING. */
val.lattice_val = VARYING;
else if (val.lattice_val == CONSTANT)
/* VARYING -> CONSTANT is an invalid state transition, except
for objects which start off in a VARYING state. */
- gcc_assert (old->lattice_val == VARYING
- || get_default_value (var).lattice_val != VARYING);
+ gcc_assert (old->lattice_val != VARYING
+ || get_default_value (var).lattice_val == VARYING);
/* If the constant for VAR has changed, then this VAR is really varying. */
if (old->lattice_val == CONSTANT
FOR_EACH_SSA_USE_OPERAND (use, stmt, iter, SSA_OP_USE)
{
- value *val = get_value (USE_FROM_PTR (use));
+ tree tuse = USE_FROM_PTR (use);
+ value *val = get_value (tuse);
- if (val->lattice_val == CONSTANT)
- {
- SET_USE (use, val->const_val);
- replaced = true;
- if (POINTER_TYPE_P (TREE_TYPE (USE_FROM_PTR (use)))
- && replaced_addresses_p)
- *replaced_addresses_p = true;
- }
+ if (val->lattice_val != CONSTANT)
+ continue;
+
+ if (TREE_CODE (stmt) == ASM_EXPR
+ && !may_propagate_copy_into_asm (tuse))
+ continue;
+
+ SET_USE (use, val->const_val);
+
+ replaced = true;
+ if (POINTER_TYPE_P (TREE_TYPE (tuse)) && replaced_addresses_p)
+ *replaced_addresses_p = true;
}
return replaced;
substitute_and_fold (void)
{
basic_block bb;
+ unsigned int i;
if (dump_file && (dump_flags & TDF_DETAILS))
fprintf (dump_file,
}
}
}
+
+ /* And transfer what we learned from VALUE_VECTOR into the
+ SSA_NAMEs themselves. This probably isn't terribly important
+ since we probably constant propagated the values to their
+ use sites above. */
+ for (i = 0; i < num_ssa_names; i++)
+ {
+ tree name = ssa_name (i);
+ value *value;
+
+ if (!name)
+ continue;
+
+ value = get_value (name);
+ if (value->lattice_val == CONSTANT
+ && is_gimple_reg (name)
+ && is_gimple_min_invariant (value->const_val))
+ SSA_NAME_VALUE (name) = value->const_val;
+ }
}
{
tree rhs = get_rhs (stmt);
enum tree_code code = TREE_CODE (rhs);
- int kind = TREE_CODE_CLASS (code);
+ enum tree_code_class kind = TREE_CODE_CLASS (code);
tree retval = NULL_TREE;
vuse_optype vuses;
/* Unary operators. Note that we know the single operand must
be a constant. So this should almost always return a
simplified RHS. */
- if (kind == '1')
+ if (kind == tcc_unary)
{
/* Handle unary operators which can appear in GIMPLE form. */
tree op0 = TREE_OPERAND (rhs, 0);
/* Binary and comparison operators. We know one or both of the
operands are constants. */
- else if (kind == '2'
- || kind == '<'
+ else if (kind == tcc_binary
+ || kind == tcc_comparison
|| code == TRUTH_AND_EXPR
|| code == TRUTH_OR_EXPR
|| code == TRUTH_XOR_EXPR)
maybe_fold_offset_to_component_ref (tree record_type, tree base, tree offset,
tree orig_type, bool base_is_ptr)
{
- tree f, t, field_type, tail_array_field;
+ tree f, t, field_type, tail_array_field, field_offset;
if (TREE_CODE (record_type) != RECORD_TYPE
&& TREE_CODE (record_type) != UNION_TYPE
continue;
if (DECL_BIT_FIELD (f))
continue;
- if (TREE_CODE (DECL_FIELD_OFFSET (f)) != INTEGER_CST)
+
+ field_offset = byte_position (f);
+ if (TREE_CODE (field_offset) != INTEGER_CST)
continue;
/* ??? Java creates "interesting" fields for representing base classes.
tail_array_field = NULL_TREE;
/* Check to see if this offset overlaps with the field. */
- cmp = tree_int_cst_compare (DECL_FIELD_OFFSET (f), offset);
+ cmp = tree_int_cst_compare (field_offset, offset);
if (cmp > 0)
continue;
if (TREE_CODE (callee) == OBJ_TYPE_REF
&& lang_hooks.fold_obj_type_ref
&& TREE_CODE (OBJ_TYPE_REF_OBJECT (callee)) == ADDR_EXPR
- && DECL_P (TREE_OPERAND (OBJ_TYPE_REF_OBJECT (callee), 0)))
+ && DECL_P (TREE_OPERAND
+ (OBJ_TYPE_REF_OBJECT (callee), 0)))
{
tree t;
}
\f
+/* Convert EXPR into a GIMPLE value suitable for substitution on the
+ RHS of an assignment. Insert the necessary statements before
+ iterator *SI_P. */
+
+static tree
+convert_to_gimple_builtin (block_stmt_iterator *si_p, tree expr)
+{
+ tree_stmt_iterator ti;
+ tree stmt = bsi_stmt (*si_p);
+ tree tmp, stmts = NULL;
+
+ push_gimplify_context ();
+ tmp = get_initialized_tmp_var (expr, &stmts, NULL);
+ pop_gimplify_context (NULL);
+
+ /* The replacement can expose previously unreferenced variables. */
+ for (ti = tsi_start (stmts); !tsi_end_p (ti); tsi_next (&ti))
+ {
+ find_new_referenced_vars (tsi_stmt_ptr (ti));
+ mark_new_vars_to_rename (tsi_stmt (ti), vars_to_rename);
+ }
+
+ if (EXPR_HAS_LOCATION (stmt))
+ annotate_all_with_locus (&stmts, EXPR_LOCATION (stmt));
+
+ bsi_insert_before (si_p, stmts, BSI_SAME_STMT);
+
+ return tmp;
+}
+
+
/* A simple pass that attempts to fold all builtin functions. This pass
is run after we've propagated as many constants as we can. */
static void
execute_fold_all_builtins (void)
{
+ bool cfg_changed = false;
basic_block bb;
FOR_EACH_BB (bb)
{
print_generic_stmt (dump_file, *stmtp, dump_flags);
}
- if (set_rhs (stmtp, result))
- modify_stmt (*stmtp);
+ if (!set_rhs (stmtp, result))
+ {
+ result = convert_to_gimple_builtin (&i, result);
+ if (result && !set_rhs (stmtp, result))
+ abort ();
+ }
+ modify_stmt (*stmtp);
+ if (maybe_clean_eh_stmt (*stmtp)
+ && tree_purge_dead_eh_edges (bb))
+ cfg_changed = true;
if (dump_file && (dump_flags & TDF_DETAILS))
{
}
}
}
+
+ /* Delete unreachable blocks. */
+ if (cfg_changed)
+ cleanup_tree_cfg ();
}
0, /* properties_provided */
0, /* properties_destroyed */
0, /* todo_flags_start */
- TODO_dump_func | TODO_verify_ssa, /* todo_flags_finish */
+ TODO_dump_func
+ | TODO_verify_ssa
+ | TODO_rename_vars, /* todo_flags_finish */
0 /* letter */
};