From 80f0648113a67e5f40ab1c19bed50d37262dbfdf Mon Sep 17 00:00:00 2001 From: rth Date: Fri, 16 Jul 2004 21:13:08 +0000 Subject: [PATCH] * 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. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@84833 138bc75d-0d04-0410-961f-82ee72b054a4 --- gcc/ChangeLog | 28 +++++++ gcc/calls.c | 1 + gcc/explow.c | 25 ++++--- gcc/expr.c | 6 ++ gcc/gimplify.c | 94 ++++++++++++++++-------- gcc/testsuite/ChangeLog | 4 + gcc/testsuite/gcc.c-torture/compile/20020210-1.c | 1 - gcc/tree-alias-common.c | 3 + gcc/tree-eh.c | 9 ++- gcc/tree-gimple.c | 37 ++++++++-- gcc/tree-inline.c | 6 ++ gcc/tree-nested.c | 3 +- gcc/tree-pretty-print.c | 8 ++ gcc/tree-sra.c | 5 ++ gcc/tree-ssa-alias.c | 3 + gcc/tree-ssa-ccp.c | 16 ++-- gcc/tree-ssa-operands.c | 37 +++++++--- gcc/tree-tailcall.c | 2 + gcc/tree.def | 7 ++ 19 files changed, 226 insertions(+), 69 deletions(-) diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 054c04a..2647e88 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,5 +1,33 @@ 2004-07-16 Richard Henderson + * 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 + * langhooks-def.h (LANG_HOOKS_TREE_INLINING_COPY_RES_DECL_FOR_INLINING, lhd_tree_inlining_copy_res_decl_for_inlining): Remove. * langhooks.c (lhd_tree_inlining_copy_res_decl_for_inlining): Remove. diff --git a/gcc/calls.c b/gcc/calls.c index 231d69b..c48fd82 100644 --- a/gcc/calls.c +++ b/gcc/calls.c @@ -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; diff --git a/gcc/explow.c b/gcc/explow.c index 54a8635..3fb0f94 100644 --- a/gcc/explow.c +++ b/gcc/explow.c @@ -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); - - 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) + tree size; + + 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 diff --git a/gcc/expr.c b/gcc/expr.c index 302c4ee..dd1aad9 100644 --- a/gcc/expr.c +++ b/gcc/expr.c @@ -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); diff --git a/gcc/gimplify.c b/gcc/gimplify.c index 642cff9..6cf5d48 100644 --- a/gcc/gimplify.c +++ b/gcc/gimplify.c @@ -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 diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 83f2839..bdf36ea 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,7 @@ +2004-07-16 Richard Henderson + + * gcc.c-torture/compile/20020210-1.c: Remove XFAIL. + 2004-07-16 Tobias Schlueter * lib/fortran-torture.exp (fortran-torture): Don't test compile diff --git a/gcc/testsuite/gcc.c-torture/compile/20020210-1.c b/gcc/testsuite/gcc.c-torture/compile/20020210-1.c index 960e3d5..5ca27f4 100644 --- a/gcc/testsuite/gcc.c-torture/compile/20020210-1.c +++ b/gcc/testsuite/gcc.c-torture/compile/20020210-1.c @@ -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) {} diff --git a/gcc/tree-alias-common.c b/gcc/tree-alias-common.c index 790d70a..a7ce22d 100644 --- a/gcc/tree-alias-common.c +++ b/gcc/tree-alias-common.c @@ -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) diff --git a/gcc/tree-eh.c b/gcc/tree-eh.c index b0638c0..b7fe64d 100644 --- a/gcc/tree-eh.c +++ b/gcc/tree-eh.c @@ -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) diff --git a/gcc/tree-gimple.c b/gcc/tree-gimple.c index 193f093..c081b5a 100644 --- a/gcc/tree-gimple.c +++ b/gcc/tree-gimple.c @@ -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; diff --git a/gcc/tree-inline.c b/gcc/tree-inline.c index 705216a..edd5fae 100644 --- a/gcc/tree-inline.c +++ b/gcc/tree-inline.c @@ -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; diff --git a/gcc/tree-nested.c b/gcc/tree-nested.c index fdcaaf8..16db5cf 100644 --- a/gcc/tree-nested.c +++ b/gcc/tree-nested.c @@ -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; diff --git a/gcc/tree-pretty-print.c b/gcc/tree-pretty-print.c index 65d362a..c187b1a 100644 --- a/gcc/tree-pretty-print.c +++ b/gcc/tree-pretty-print.c @@ -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; diff --git a/gcc/tree-sra.c b/gcc/tree-sra.c index 423ee3c..73866b4 100644 --- a/gcc/tree-sra.c +++ b/gcc/tree-sra.c @@ -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; diff --git a/gcc/tree-ssa-alias.c b/gcc/tree-ssa-alias.c index 0d96b16..ed4ffd9 100644 --- a/gcc/tree-ssa-alias.c +++ b/gcc/tree-ssa-alias.c @@ -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 diff --git a/gcc/tree-ssa-ccp.c b/gcc/tree-ssa-ccp.c index 7f28a9f..0c35717 100644 --- a/gcc/tree-ssa-ccp.c +++ b/gcc/tree-ssa-ccp.c @@ -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; diff --git a/gcc/tree-ssa-operands.c b/gcc/tree-ssa-operands.c index af21f12..bb60bd8 100644 --- a/gcc/tree-ssa-operands.c +++ b/gcc/tree-ssa-operands.c @@ -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; + + 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; - 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, 0), subflags, prev_vops); + return; + } case VA_ARG_EXPR: /* Mark VA_ARG_EXPR nodes as making volatile references. FIXME, diff --git a/gcc/tree-tailcall.c b/gcc/tree-tailcall.c index f69bf34..5a89868 100644 --- a/gcc/tree-tailcall.c +++ b/gcc/tree-tailcall.c @@ -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 { diff --git a/gcc/tree.def b/gcc/tree.def index 8068f26..65fd479 100644 --- a/gcc/tree.def +++ b/gcc/tree.def @@ -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 -- 2.7.4