/* Conditional constant propagation pass for the GNU compiler.
- Copyright (C) 2000, 2001, 2002, 2003, 2004 Free Software Foundation, Inc.
+ Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005
+ 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>
}
-/* Function indicating whether we ought to include information for VAR
- when calculating immediate uses. */
-
-static bool
-need_imm_uses_for (tree var)
-{
- return get_value (var)->lattice_val != VARYING;
-}
-
-
/* Initialize local data structures for CCP. */
static void
}
sbitmap_free (is_may_def);
-
- /* Compute immediate uses for variables we care about. */
- compute_immediate_uses (TDFA_USE_OPS | TDFA_USE_VOPS, need_imm_uses_for);
}
if (maybe_clean_eh_stmt (stmt))
tree_purge_dead_eh_edges (bb);
- modify_stmt (stmt);
+ update_stmt (stmt);
}
if (dump_file && (dump_flags & TDF_DETAILS))
if (NUM_USES (uses) != 0)
{
tree *orig;
+ tree fndecl, arglist;
size_t i;
/* Preserve the original values of every operand. */
/* Substitute operands with their values and try to fold. */
replace_uses_in (stmt, NULL);
- retval = fold_builtin (rhs, false);
+ fndecl = get_callee_fndecl (rhs);
+ arglist = TREE_OPERAND (rhs, 1);
+ retval = fold_builtin (fndecl, arglist, false);
/* Restore operands to their original form. */
for (i = 0; i < NUM_USES (uses); i++)
val = evaluate_stmt (stmt);
/* If the original LHS was a VIEW_CONVERT_EXPR, modify the constant
- value to be a VIEW_CONVERT_EXPR of the old constant value. This is
- valid because a VIEW_CONVERT_EXPR is valid everywhere an operand of
- aggregate type is valid.
+ value to be a VIEW_CONVERT_EXPR of the old constant value.
??? Also, if this was a definition of a bitfield, we need to widen
the constant value into the type of the destination variable. This
if (TREE_CODE (orig_lhs) == VIEW_CONVERT_EXPR
&& val.lattice_val == CONSTANT)
{
- val.const_val = build1 (VIEW_CONVERT_EXPR,
- TREE_TYPE (TREE_OPERAND (orig_lhs, 0)),
- val.const_val);
+ tree w = fold (build1 (VIEW_CONVERT_EXPR,
+ TREE_TYPE (TREE_OPERAND (orig_lhs, 0)),
+ val.const_val));
+
orig_lhs = TREE_OPERAND (orig_lhs, 1);
+ if (w && is_gimple_min_invariant (w))
+ val.const_val = w;
+ else
+ {
+ val.lattice_val = VARYING;
+ val.const_val = NULL;
+ }
}
if (val.lattice_val == CONSTANT
for (i = 0, mask = 0; i < field_size; i++)
mask |= ((HOST_WIDE_INT) 1) << i;
- wide_val = build (BIT_AND_EXPR, TREE_TYPE (var), val,
- fold_convert (TREE_TYPE (var),
- build_int_cst (NULL_TREE, mask)));
+ wide_val = build2 (BIT_AND_EXPR, TREE_TYPE (var), val,
+ build_int_cst (TREE_TYPE (var), mask));
}
else
{
for (i = 0, mask = 0; i < (var_size - field_size); i++)
mask |= ((HOST_WIDE_INT) 1) << (var_size - i - 1);
- wide_val = build (BIT_IOR_EXPR, TREE_TYPE (var), val,
- fold_convert (TREE_TYPE (var),
- build_int_cst (NULL_TREE, mask)));
+ wide_val = build2 (BIT_IOR_EXPR, TREE_TYPE (var), val,
+ build_int_cst (TREE_TYPE (var), mask));
}
return fold (wide_val);
continue;
field_type = TREE_TYPE (f);
- if (cmp < 0)
- {
- /* Don't care about offsets into the middle of scalars. */
- if (!AGGREGATE_TYPE_P (field_type))
- continue;
-
- /* Check for array at the end of the struct. This is often
- used as for flexible array members. We should be able to
- turn this into an array access anyway. */
- if (TREE_CODE (field_type) == ARRAY_TYPE)
- tail_array_field = f;
-
- /* Check the end of the field against the offset. */
- if (!DECL_SIZE_UNIT (f)
- || TREE_CODE (DECL_SIZE_UNIT (f)) != INTEGER_CST)
- continue;
- t = int_const_binop (MINUS_EXPR, offset, DECL_FIELD_OFFSET (f), 1);
- if (!tree_int_cst_lt (t, DECL_SIZE_UNIT (f)))
- continue;
-
- /* If we matched, then set offset to the displacement into
- this field. */
- offset = t;
- }
/* Here we exactly match the offset being checked. If the types match,
then we can return that field. */
- else if (lang_hooks.types_compatible_p (orig_type, field_type))
+ if (cmp == 0
+ && lang_hooks.types_compatible_p (orig_type, field_type))
{
if (base_is_ptr)
base = build1 (INDIRECT_REF, record_type, base);
t = build (COMPONENT_REF, field_type, base, f, NULL_TREE);
return t;
}
+
+ /* Don't care about offsets into the middle of scalars. */
+ if (!AGGREGATE_TYPE_P (field_type))
+ continue;
- /* Don't care about type-punning of scalars. */
- else if (!AGGREGATE_TYPE_P (field_type))
- return NULL_TREE;
+ /* Check for array at the end of the struct. This is often
+ used as for flexible array members. We should be able to
+ turn this into an array access anyway. */
+ if (TREE_CODE (field_type) == ARRAY_TYPE)
+ tail_array_field = f;
+ /* Check the end of the field against the offset. */
+ if (!DECL_SIZE_UNIT (f)
+ || TREE_CODE (DECL_SIZE_UNIT (f)) != INTEGER_CST)
+ continue;
+ t = int_const_binop (MINUS_EXPR, offset, field_offset, 1);
+ if (!tree_int_cst_lt (t, DECL_SIZE_UNIT (f)))
+ continue;
+
+ /* If we matched, then set offset to the displacement into
+ this field. */
+ offset = t;
goto found;
}
f = tail_array_field;
field_type = TREE_TYPE (f);
+ offset = int_const_binop (MINUS_EXPR, offset, byte_position (f), 1);
found:
/* If we get here, we've got an aggregate field, and a possibly
/* We can get here for out-of-range string constant accesses,
such as "_"[3]. Bail out of the entire substitution search
and arrange for the entire statement to be replaced by a
- call to __builtin_trap. In all likelyhood this will all be
+ call to __builtin_trap. In all likelihood this will all be
constant-folded away, but in the meantime we can't leave with
something that get_expr_operands can't understand. */
/* First try the generic builtin folder. If that succeeds, return the
result directly. */
- result = fold_builtin (fn, ignore);
+ callee = get_callee_fndecl (fn);
+ arglist = TREE_OPERAND (fn, 1);
+ result = fold_builtin (callee, arglist, ignore);
if (result)
{
if (ignore)
}
/* Ignore MD builtins. */
- callee = get_callee_fndecl (fn);
if (DECL_BUILT_IN_CLASS (callee) == BUILT_IN_MD)
return NULL_TREE;
/* If the builtin could not be folded, and it has no argument list,
we're done. */
- arglist = TREE_OPERAND (fn, 1);
if (!arglist)
return NULL_TREE;
}
/* Try to use the dataflow information gathered by the CCP process. */
- visited = BITMAP_XMALLOC ();
+ visited = BITMAP_ALLOC (NULL);
memset (strlen_val, 0, sizeof (strlen_val));
for (i = 0, a = arglist;
strlen_val[i] = NULL_TREE;
}
- BITMAP_XFREE (visited);
+ BITMAP_FREE (visited);
result = NULL_TREE;
switch (DECL_FUNCTION_CODE (callee))
case BUILT_IN_STRCPY:
if (strlen_val[1] && is_gimple_val (strlen_val[1]))
- result = fold_builtin_strcpy (fn, strlen_val[1]);
+ {
+ tree fndecl = get_callee_fndecl (fn);
+ tree arglist = TREE_OPERAND (fn, 1);
+ result = fold_builtin_strcpy (fndecl, arglist, strlen_val[1]);
+ }
break;
case BUILT_IN_STRNCPY:
if (strlen_val[1] && is_gimple_val (strlen_val[1]))
- result = fold_builtin_strncpy (fn, strlen_val[1]);
+ {
+ tree fndecl = get_callee_fndecl (fn);
+ tree arglist = TREE_OPERAND (fn, 1);
+ result = fold_builtin_strncpy (fndecl, arglist, strlen_val[1]);
+ }
break;
case BUILT_IN_FPUTS:
if (!set_rhs (stmtp, result))
{
result = convert_to_gimple_builtin (&i, result);
- if (result && !set_rhs (stmtp, result))
- abort ();
+ if (result)
+ {
+ bool ok = set_rhs (stmtp, result);
+
+ gcc_assert (ok);
+ }
}
- modify_stmt (*stmtp);
+ update_stmt (*stmtp);
if (maybe_clean_eh_stmt (*stmtp)
&& tree_purge_dead_eh_edges (bb))
cfg_changed = true;