tree-def (WITH_SIZE_EXPR): New.

* tree-def (WITH_SIZE_EXPR): New.
        * explow.c (expr_size, int_expr_size): Handle WITH_SIZE_EXPR.
        * expr.c (expand_expr_real_1): Likewise.
        * gimplify.c (maybe_with_size_expr): New.
        (gimplify_arg, gimplify_modify_expr): Use it.
        (gimplify_modify_expr_to_memcpy): Take size parameter.
        (gimplify_modify_expr_to_memset): Likewise.
        (gimplify_expr): Handle WITH_SIZE_EXPR.
        * tree-alias-common.c (find_func_aliases): Likewise.
        * tree-eh.c (tree_could_trap_p): Likewise.
        (tree_could_throw_p): Likewise.
        * tree-gimple.c (is_gimple_lvalue): Likewise.
        (get_call_expr_in): Likewise.
        * tree-inline.c (estimate_num_insns_1): Likewise.
        (expand_calls_inline): Likewise.
        * tree-nested.c (convert_call_expr): Likewise.
        * tree-pretty-print.c (dump_generic_node): Likewise.
        * tree-sra.c (sra_walk_expr): Likewise.
        * tree-ssa-alias.c (add_pointed_to_expr): Likewise.
        * tree-ssa-ccp.c (get_rhs, set_rhs): Likewise.
        * tree-ssa-operands.c (get_expr_operands): Likewise.
        * tree-tailcall.c (find_tail_calls): Likewise.

        * calls.c (expand_call): Reset old_stack_allocated after
        calling emit_stack_restore.

        * gcc.c-torture/compile/20020210-1.c: Remove XFAIL.

From-SVN: r84833
This commit is contained in:
Richard Henderson 2004-07-16 14:13:08 -07:00 committed by Richard Henderson
parent 4c86f32571
commit d25cee4d2b
19 changed files with 225 additions and 68 deletions

View File

@ -1,3 +1,31 @@
2004-07-16 Richard Henderson <rth@redhat.com>
* tree-def (WITH_SIZE_EXPR): New.
* explow.c (expr_size, int_expr_size): Handle WITH_SIZE_EXPR.
* expr.c (expand_expr_real_1): Likewise.
* gimplify.c (maybe_with_size_expr): New.
(gimplify_arg, gimplify_modify_expr): Use it.
(gimplify_modify_expr_to_memcpy): Take size parameter.
(gimplify_modify_expr_to_memset): Likewise.
(gimplify_expr): Handle WITH_SIZE_EXPR.
* tree-alias-common.c (find_func_aliases): Likewise.
* tree-eh.c (tree_could_trap_p): Likewise.
(tree_could_throw_p): Likewise.
* tree-gimple.c (is_gimple_lvalue): Likewise.
(get_call_expr_in): Likewise.
* tree-inline.c (estimate_num_insns_1): Likewise.
(expand_calls_inline): Likewise.
* tree-nested.c (convert_call_expr): Likewise.
* tree-pretty-print.c (dump_generic_node): Likewise.
* tree-sra.c (sra_walk_expr): Likewise.
* tree-ssa-alias.c (add_pointed_to_expr): Likewise.
* tree-ssa-ccp.c (get_rhs, set_rhs): Likewise.
* tree-ssa-operands.c (get_expr_operands): Likewise.
* tree-tailcall.c (find_tail_calls): Likewise.
* calls.c (expand_call): Reset old_stack_allocated after
calling emit_stack_restore.
2004-07-16 Richard Henderson <rth@redhat.com>
* langhooks-def.h (LANG_HOOKS_TREE_INLINING_COPY_RES_DECL_FOR_INLINING,

View File

@ -3045,6 +3045,7 @@ expand_call (tree exp, rtx target, int ignore)
emit_stack_restore (SAVE_BLOCK, old_stack_level, NULL_RTX);
stack_pointer_delta = old_stack_pointer_delta;
pending_stack_adjust = old_pending_adj;
old_stack_allocated = stack_pointer_delta - pending_stack_adjust;
stack_arg_under_construction = old_stack_arg_under_construction;
highest_outgoing_arg_in_use = initial_highest_arg_in_use;
stack_usage_map = initial_stack_usage_map;

View File

@ -240,7 +240,12 @@ eliminate_constant_term (rtx x, rtx *constptr)
rtx
expr_size (tree exp)
{
tree size = SUBSTITUTE_PLACEHOLDER_IN_EXPR (lang_hooks.expr_size (exp), exp);
tree size;
if (TREE_CODE (exp) == WITH_SIZE_EXPR)
size = TREE_OPERAND (exp, 1);
else
size = SUBSTITUTE_PLACEHOLDER_IN_EXPR (lang_hooks.expr_size (exp), exp);
return expand_expr (size, NULL_RTX, TYPE_MODE (sizetype), 0);
}
@ -251,17 +256,17 @@ expr_size (tree exp)
HOST_WIDE_INT
int_expr_size (tree exp)
{
tree t = lang_hooks.expr_size (exp);
tree size;
if (t == 0
|| TREE_CODE (t) != INTEGER_CST
|| TREE_OVERFLOW (t)
|| TREE_INT_CST_HIGH (t) != 0
/* If the result would appear negative, it's too big to represent. */
|| (HOST_WIDE_INT) TREE_INT_CST_LOW (t) < 0)
if (TREE_CODE (exp) == WITH_SIZE_EXPR)
size = TREE_OPERAND (exp, 1);
else
size = lang_hooks.expr_size (exp);
if (size == 0 || !host_integerp (size, 0))
return -1;
return TREE_INT_CST_LOW (t);
return tree_low_cst (size, 0);
}
/* Return a copy of X in which all memory references

View File

@ -8651,6 +8651,12 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
expand_asm_expr (exp);
return const0_rtx;
case WITH_SIZE_EXPR:
/* WITH_SIZE_EXPR expands to its first argument. The caller should
have pulled out the size to use in whatever context it needed. */
return expand_expr_real (TREE_OPERAND (exp, 0), original_target, tmode,
modifier, alt_rtl);
default:
return lang_hooks.expand_expr (exp, original_target, tmode,
modifier, alt_rtl);

View File

@ -72,8 +72,6 @@ typedef struct gimple_temp_hash_elt
} elt_t;
/* Forward declarations. */
static enum gimplify_status gimplify_modify_expr_rhs (tree *, tree *, tree *,
tree *, tree *, bool);
static enum gimplify_status gimplify_compound_expr (tree *, tree *, bool);
@ -1788,6 +1786,27 @@ gimplify_self_mod_expr (tree *expr_p, tree *pre_p, tree *post_p,
}
}
/* If *EXPR_P has a variable sized type, wrap it in a WITH_SIZE_EXPR. */
static void
maybe_with_size_expr (tree *expr_p)
{
tree expr, type, size;
expr = *expr_p;
type = TREE_TYPE (expr);
if (type == error_mark_node)
return;
size = TYPE_SIZE_UNIT (type);
if (size && TREE_CODE (size) != INTEGER_CST)
{
size = unshare_expr (size);
size = SUBSTITUTE_PLACEHOLDER_IN_EXPR (size, expr);
*expr_p = build2 (WITH_SIZE_EXPR, type, expr, size);
}
}
/* Subroutine of gimplify_call_expr: Gimplify a single argument. */
static enum gimplify_status
@ -1806,6 +1825,9 @@ gimplify_arg (tree *expr_p, tree *pre_p)
else
test = is_gimple_lvalue, fb = fb_either;
/* If this is a variable sized type, we must remember the size. */
maybe_with_size_expr (expr_p);
/* There is a sequence point before a function call. Side effects in
the argument list must occur before the actual call. So, when
gimplifying arguments, force gimplify_expr to use an internal
@ -2316,18 +2338,14 @@ gimplify_cond_expr (tree *expr_p, tree *pre_p, tree target)
a call to __builtin_memcpy. */
static enum gimplify_status
gimplify_modify_expr_to_memcpy (tree *expr_p, bool want_value)
gimplify_modify_expr_to_memcpy (tree *expr_p, tree size, bool want_value)
{
tree args, t, to, to_ptr, from;
to = TREE_OPERAND (*expr_p, 0);
from = TREE_OPERAND (*expr_p, 1);
t = TYPE_SIZE_UNIT (TREE_TYPE (from));
t = unshare_expr (t);
t = SUBSTITUTE_PLACEHOLDER_IN_EXPR (t, to);
t = SUBSTITUTE_PLACEHOLDER_IN_EXPR (t, from);
args = tree_cons (NULL, t, NULL);
args = tree_cons (NULL, size, NULL);
t = build_fold_addr_expr (from);
args = tree_cons (NULL, t, args);
@ -2352,16 +2370,13 @@ gimplify_modify_expr_to_memcpy (tree *expr_p, bool want_value)
a CONSTRUCTOR with an empty element list. */
static enum gimplify_status
gimplify_modify_expr_to_memset (tree *expr_p, bool want_value)
gimplify_modify_expr_to_memset (tree *expr_p, tree size, bool want_value)
{
tree args, t, to, to_ptr;
to = TREE_OPERAND (*expr_p, 0);
t = TYPE_SIZE_UNIT (TREE_TYPE (TREE_OPERAND (*expr_p, 1)));
t = unshare_expr (t);
t = SUBSTITUTE_PLACEHOLDER_IN_EXPR (t, to);
args = tree_cons (NULL, t, NULL);
args = tree_cons (NULL, size, NULL);
args = tree_cons (NULL, integer_zero_node, args);
@ -2771,24 +2786,13 @@ gimplify_modify_expr (tree *expr_p, tree *pre_p, tree *post_p, bool want_value)
if (ret != GS_UNHANDLED)
return ret;
/* If the value being copied is of variable width, expose the length
if the copy by converting the whole thing to a memcpy/memset.
Note that we need to do this before gimplifying any of the operands
so that we can resolve any PLACEHOLDER_EXPRs in the size.
Also note that the RTL expander uses the size of the expression to
be copied, not of the destination, so that is what we must here.
The types on both sides of the MODIFY_EXPR should be the same,
but they aren't always and there are problems with class-wide types
in Ada where it's hard to make it "correct". */
if (TREE_CODE (TREE_TYPE (*from_p)) != ERROR_MARK
&& TYPE_SIZE_UNIT (TREE_TYPE (*from_p))
&& TREE_CODE (TYPE_SIZE_UNIT (TREE_TYPE (*from_p))) != INTEGER_CST)
{
if (TREE_CODE (*from_p) == CONSTRUCTOR)
return gimplify_modify_expr_to_memset (expr_p, want_value);
else
return gimplify_modify_expr_to_memcpy (expr_p, want_value);
}
/* If the value being copied is of variable width, compute the length
of the copy into a WITH_SIZE_EXPR. Note that we need to do this
before gimplifying any of the operands so that we can resolve any
PLACEHOLDER_EXPRs in the size. Also note that the RTL expander uses
the size of the expression to be copied, not of the destination, so
that is what we must here. */
maybe_with_size_expr (from_p);
ret = gimplify_expr (to_p, pre_p, post_p, is_gimple_lvalue, fb_lvalue);
if (ret == GS_ERROR)
@ -2805,6 +2809,23 @@ gimplify_modify_expr (tree *expr_p, tree *pre_p, tree *post_p, bool want_value)
if (ret != GS_UNHANDLED)
return ret;
/* If we've got a variable sized assignment between two lvalues (i.e. does
not involve a call), then we can make things a bit more straightforward
by converting the assignment to memcpy or memset. */
if (TREE_CODE (*from_p) == WITH_SIZE_EXPR)
{
tree from = TREE_OPERAND (*from_p, 0);
tree size = TREE_OPERAND (*from_p, 1);
if (TREE_CODE (from) == CONSTRUCTOR)
return gimplify_modify_expr_to_memset (expr_p, size, want_value);
if (is_gimple_addr_expr_arg (from))
{
*from_p = from;
return gimplify_modify_expr_to_memcpy (expr_p, size, want_value);
}
}
/* If the destination is already simple, nothing else needed. */
if (is_gimple_tmp_var (*to_p) || !want_value)
ret = GS_ALL_DONE;
@ -3784,6 +3805,17 @@ gimplify_expr (tree *expr_p, tree *pre_p, tree *post_p,
ret = gimplify_statement_list (expr_p);
break;
case WITH_SIZE_EXPR:
{
enum gimplify_status r0, r1;
r0 = gimplify_expr (&TREE_OPERAND (*expr_p, 0), pre_p,
post_p == &internal_post ? NULL : post_p,
gimple_test_f, fallback);
r1 = gimplify_expr (&TREE_OPERAND (*expr_p, 1), pre_p, post_p,
is_gimple_val, fb_rvalue);
}
break;
case VAR_DECL:
/* ??? If this is a local variable, and it has not been seen in any
outer BIND_EXPR, then it's probably the result of a duplicate

View File

@ -1,3 +1,7 @@
2004-07-16 Richard Henderson <rth@redhat.com>
* gcc.c-torture/compile/20020210-1.c: Remove XFAIL.
2004-07-16 Tobias Schlueter <tobias.schlueter@physik.uni-muenchen.de>
* lib/fortran-torture.exp (fortran-torture): Don't test compile

View File

@ -1,3 +1,2 @@
/* PR c/5615 */
/* { dg-xfail-if "regression/16417" { "*-*-*" } { "-O1" "-O2" "-O3 -fomit-frame-pointer" "-O3 -g" "-Os" } { "" } } */
void f(int a, struct {int b[a];} c) {}

View File

@ -448,7 +448,10 @@ find_func_aliases (tree stp)
{
op0 = TREE_OPERAND (stp, 0);
op1 = TREE_OPERAND (stp, 1);
if (TREE_CODE (op1) == WITH_SIZE_EXPR)
op1 = TREE_OPERAND (op1, 0);
}
/* lhsAV should always have an alias variable */
lhsAV = get_alias_var (op0);
if (!lhsAV)

View File

@ -1723,14 +1723,17 @@ tree_could_trap_p (tree expr)
honor_trapv = true;
}
restart:
switch (code)
{
case COMPONENT_REF:
case REALPART_EXPR:
case IMAGPART_EXPR:
case BIT_FIELD_REF:
t = TREE_OPERAND (expr, 0);
return tree_could_trap_p (t);
case WITH_SIZE_EXPR:
expr = TREE_OPERAND (expr, 0);
code = TREE_CODE (expr);
goto restart;
case ARRAY_RANGE_REF:
/* Let us be conservative here for now. We might be checking bounds of
@ -1843,6 +1846,8 @@ tree_could_throw_p (tree t)
t = TREE_OPERAND (t, 1);
}
if (TREE_CODE (t) == WITH_SIZE_EXPR)
t = TREE_OPERAND (t, 0);
if (TREE_CODE (t) == CALL_EXPR)
return (call_expr_flags (t) & ECF_NOTHROW) == 0;
if (flag_non_call_exceptions)

View File

@ -118,12 +118,22 @@ Boston, MA 02111-1307, USA. */
addr-expr-arg: ID
| compref
with-size-arg: addr-expr-arg
| indirectref
| call-stmt
indirectref : INDIRECT_REF
op0 -> val
lhs : addr-expr-arg
| '*' val
| bitfieldref
| indirectref
| WITH_SIZE_EXPR
op0 -> with-size-arg
op1 -> val
min-lval : ID
| '*' val
| indirectref
bitfieldref : BIT_FIELD_REF
op0 -> inner-compref
@ -155,18 +165,26 @@ Boston, MA 02111-1307, USA. */
op0 -> inner-compref
condition : val
| val RELOP val
| RELOP
op0 -> val
op1 -> val
val : ID
| CONST
rhs : lhs
| CONST
| '&' addr-expr-arg
| call_expr
| UNOP val
| val BINOP val
| val RELOP val
| call-stmt
| ADDR_EXPR
op0 -> addr-expr-arg
| UNOP
op0 -> val
| BINOP
op0 -> val
op1 -> val
| RELOP
op0 -> val
op1 -> val
*/
static inline bool is_gimple_id (tree);
@ -286,6 +304,7 @@ is_gimple_lvalue (tree t)
{
return (is_gimple_addr_expr_arg (t)
|| TREE_CODE (t) == INDIRECT_REF
|| TREE_CODE (t) == WITH_SIZE_EXPR
/* These are complex lvalues, but don't have addresses, so they
go here. */
|| TREE_CODE (t) == BIT_FIELD_REF);
@ -506,6 +525,8 @@ get_call_expr_in (tree t)
{
if (TREE_CODE (t) == MODIFY_EXPR)
t = TREE_OPERAND (t, 1);
if (TREE_CODE (t) == WITH_SIZE_EXPR)
t = TREE_OPERAND (t, 0);
if (TREE_CODE (t) == CALL_EXPR)
return t;
return NULL_TREE;

View File

@ -1262,6 +1262,7 @@ estimate_num_insns_1 (tree *tp, int *walk_subtrees, void *data)
case EXIT_EXPR:
case LOOP_EXPR:
case PHI_NODE:
case WITH_SIZE_EXPR:
break;
/* We don't account constants for now. Assume that the cost is amortized
@ -1779,6 +1780,11 @@ expand_calls_inline (tree *stmt_p, inline_data *id)
case MODIFY_EXPR:
stmt_p = &TREE_OPERAND (stmt, 1);
stmt = *stmt_p;
if (TREE_CODE (stmt) == WITH_SIZE_EXPR)
{
stmt_p = &TREE_OPERAND (stmt, 0);
stmt = *stmt_p;
}
if (TREE_CODE (stmt) != CALL_EXPR)
break;

View File

@ -1196,7 +1196,8 @@ convert_call_expr (tree *tp, int *walk_subtrees, void *data)
case RETURN_EXPR:
case MODIFY_EXPR:
/* Only return and modify may contain calls. */
case WITH_SIZE_EXPR:
/* Only return modify and with_size_expr may contain calls. */
*walk_subtrees = 1;
break;

View File

@ -1413,6 +1413,14 @@ dump_generic_node (pretty_printer *buffer, tree node, int spc, int flags,
pp_decimal_int (buffer, SSA_NAME_VERSION (node));
break;
case WITH_SIZE_EXPR:
pp_string (buffer, "WITH_SIZE_EXPR <");
dump_generic_node (buffer, TREE_OPERAND (node, 0), spc, flags, false);
pp_string (buffer, ", ");
dump_generic_node (buffer, TREE_OPERAND (node, 1), spc, flags, false);
pp_string (buffer, ">");
break;
case VALUE_HANDLE:
pp_printf (buffer, "VH.%d", VALUE_HANDLE_ID (node));
break;

View File

@ -731,6 +731,11 @@ sra_walk_expr (tree *expr_p, block_stmt_iterator *bsi, bool is_output,
type other than the one we've scalarized. */
goto use_all;
case WITH_SIZE_EXPR:
/* This is a transparent wrapper. The entire inner expression really
is being used. */
goto use_all;
use_all:
expr_p = &TREE_OPERAND (inner, 0);
inner = expr = *expr_p;

View File

@ -1680,6 +1680,9 @@ add_pointed_to_expr (tree ptr, tree value)
{
struct ptr_info_def *pi;
if (TREE_CODE (value) == WITH_SIZE_EXPR)
value = TREE_OPERAND (value, 0);
#if defined ENABLE_CHECKING
/* Pointer variables should have been handled by merge_pointed_to_info. */
if (TREE_CODE (value) == SSA_NAME

View File

@ -2085,13 +2085,16 @@ get_rhs (tree stmt)
{
case RETURN_EXPR:
stmt = TREE_OPERAND (stmt, 0);
if (stmt)
return get_rhs (stmt);
else
return NULL;
if (!stmt || TREE_CODE (stmt) != MODIFY_EXPR)
return stmt;
/* FALLTHRU */
case MODIFY_EXPR:
return TREE_OPERAND (stmt, 1);
stmt = TREE_OPERAND (stmt, 1);
if (TREE_CODE (stmt) == WITH_SIZE_EXPR)
return TREE_OPERAND (stmt, 0);
else
return stmt;
case COND_EXPR:
return COND_EXPR_COND (stmt);
@ -2143,6 +2146,9 @@ set_rhs (tree *stmt_p, tree expr)
/* FALLTHRU */
case MODIFY_EXPR:
op = TREE_OPERAND (stmt, 1);
if (TREE_CODE (op) == WITH_SIZE_EXPR)
stmt = op;
TREE_OPERAND (stmt, 1) = expr;
break;

View File

@ -931,23 +931,38 @@ get_expr_operands (tree stmt, tree *expr_p, int flags, voperands_t prev_vops)
get_expr_operands (stmt, &TREE_OPERAND (expr, 2), opf_none, prev_vops);
return;
case WITH_SIZE_EXPR:
/* WITH_SIZE_EXPR is a pass-through reference to it's first argument,
and an rvalue reference to its second argument. */
get_expr_operands (stmt, &TREE_OPERAND (expr, 1), opf_none, prev_vops);
get_expr_operands (stmt, &TREE_OPERAND (expr, 0), flags, prev_vops);
return;
case CALL_EXPR:
get_call_expr_operands (stmt, expr, prev_vops);
return;
case MODIFY_EXPR:
get_expr_operands (stmt, &TREE_OPERAND (expr, 1), opf_none, prev_vops);
{
int subflags;
tree op;
if (TREE_CODE (TREE_OPERAND (expr, 0)) == ARRAY_REF
|| TREE_CODE (TREE_OPERAND (expr, 0)) == COMPONENT_REF
|| TREE_CODE (TREE_OPERAND (expr, 0)) == REALPART_EXPR
|| TREE_CODE (TREE_OPERAND (expr, 0)) == IMAGPART_EXPR)
get_expr_operands (stmt, &TREE_OPERAND (expr, 0), opf_is_def,
prev_vops);
else
get_expr_operands (stmt, &TREE_OPERAND (expr, 0),
opf_is_def | opf_kill_def, prev_vops);
return;
get_expr_operands (stmt, &TREE_OPERAND (expr, 1), opf_none, prev_vops);
op = TREE_OPERAND (expr, 0);
if (TREE_CODE (op) == WITH_SIZE_EXPR)
op = TREE_OPERAND (expr, 0);
if (TREE_CODE (op) == ARRAY_REF
|| TREE_CODE (op) == COMPONENT_REF
|| TREE_CODE (op) == REALPART_EXPR
|| TREE_CODE (op) == IMAGPART_EXPR)
subflags = opf_is_def;
else
subflags = opf_is_def | opf_kill_def;
get_expr_operands (stmt, &TREE_OPERAND (expr, 0), subflags, prev_vops);
return;
}
case VA_ARG_EXPR:
/* Mark VA_ARG_EXPR nodes as making volatile references. FIXME,

View File

@ -384,6 +384,8 @@ find_tail_calls (basic_block bb, struct tailcall **ret)
{
ass_var = TREE_OPERAND (stmt, 0);
call = TREE_OPERAND (stmt, 1);
if (TREE_CODE (call) == WITH_SIZE_EXPR)
call = TREE_OPERAND (call, 0);
}
else
{

View File

@ -885,6 +885,13 @@ DEFTREECODE (VALUE_HANDLE, "value_handle", 'x', 0)
baseclass of itself or another class. */
DEFTREECODE (TREE_BINFO, "tree_binfo", 'x', 0)
/* Records the size for an expression of variable size type. This is
for use in contexts in which we are accessing the entire object,
such as for a function call, or block copy.
Operand 0 is the real expression.
Operand 1 is the size of the type in the expression. */
DEFTREECODE (WITH_SIZE_EXPR, "with_size_expr", 'e', 2)
/*
Local variables:
mode:c