On Mon, Nov 7, 2011 at 4:57 PM, Michael Matz <m...@suse.de> wrote: > Hi, > > On Thu, 3 Nov 2011, Richard Guenther wrote: > >> Otherwise the patch looks ok, but given the Ada issue let's wait until >> that is sorted out in some way. That also gives others the chance to >> comment on the patch. > > So, this is what I came up with. As discussed I didn't do the uintptr_t > case and didn't use auto_var_in_fn_p (but added a DECL_CONTEXT check). > I've added the gimple_clobber_p helper and used it in some places and now > dump the clobbers as > lhs ={v} {CLOBBER} > > I haven't yet worked on the whole try/finally optimizations. > > Regstrapped (all default langs, now with Ada) on x86_64-linux. Okay for > trunk?
Ok. Thanks, Richard. > Ciao, > Michael. > > * gengtype.c (write_field_root): Avoid out-of-scope access of newv. > > * tree-stdarg.c (execute_optimize_stdarg): Accept clobbers. > > * tree.h (TREE_CLOBBER_P): New macro. > * gimple.h (gimple_clobber_p): New inline function. > * gimplify.c (gimplify_bind_expr): Add clobbers for all variables > that go out of scope and live in memory. > * tree-ssa-operands.c (get_expr_operands): Transfer volatility also > for constructors. > * cfgexpand.c (decl_to_stack_part): New static variable. > (add_stack_var): Allocate it, and remember mapping. > (fini_vars_expansion): Deallocate it. > (stack_var_conflict_p): Add early outs. > (visit_op, visit_conflict, add_scope_conflicts_1, > add_scope_conflicts): New static functions. > (expand_used_vars_for_block): Don't call add_stack_var_conflict, tidy. > (expand_used_vars): Add scope conflicts. > (expand_gimple_stmt_1): Expand clobbers to nothing. > (expand_debug_expr): Ditto. > > * tree-pretty-print.c (dump_generic_node): Dump clobbers nicely. > * tree-ssa-live.c (remove_unused_locals): Remove clobbers that > refer to otherwise unused locals. > * tree-sra.c (build_accesses_from_assign): Ignore clobbers. > * tree-ssa-dce.c (mark_stmt_if_obviously_necessary): Clobbers of > SSA names aren't necessary. > (propagate_necessity): Accept and ignore constructors on the rhs, > tidy. > * gimple.c (walk_gimple_op): Accept constructors like mem_rhs. > * tree-ssa-structalias.c (find_func_aliases): Clobbers don't store > any known value. > * tree-ssa-sccvn.c (vn_reference_lookup_3): Ditto, in particular they > don't zero-initialize something. > * tree-ssa-phiopt.c (cond_if_else_store_replacement_1): Ignore > clobber RHS, we don't want PHI nodes with those. > > testsuite/ > * gcc.dg/tree-ssa/20031015-1.c: Adjust. > * g++.dg/tree-ssa/ehcleanup-1.C: Ditto. > * g++.dg/eh/builtin1.C: Rewrite to not use local variables. > * g++.dg/eh/builtin2.C: Ditto. > * g++.dg/eh/builtin3.C: Ditto. > > Index: gengtype.c > =================================================================== > --- gengtype.c.orig 2011-11-07 15:56:25.000000000 +0100 > +++ gengtype.c 2011-11-07 16:12:35.000000000 +0100 > @@ -3650,14 +3650,13 @@ write_field_root (outf_p f, pair_p v, ty > int has_length, struct fileloc *line, const char *if_marked, > bool emit_pch, type_p field_type, const char *field_name) > { > + struct pair newv; > /* If the field reference is relative to V, rather than to some > subcomponent of V, we can mark any subarrays with a single stride. > We're effectively treating the field as a global variable in its > own right. */ > if (v && type == v->type) > { > - struct pair newv; > - > newv = *v; > newv.type = field_type; > newv.name = ACONCAT ((v->name, ".", field_name, NULL)); > Index: tree.h > =================================================================== > --- tree.h (revision 180833) > +++ tree.h (working copy) > @@ -1637,6 +1637,14 @@ struct GTY(()) tree_vec { > #define CONSTRUCTOR_BITFIELD_P(NODE) \ > (DECL_BIT_FIELD (FIELD_DECL_CHECK (NODE)) && DECL_MODE (NODE) != BLKmode) > > +/* True if NODE is a clobber right hand side, an expression of indeterminate > + value that clobbers the LHS in a copy instruction. We use a volatile > + empty CONSTRUCTOR for this, as it matches most of the necessary semantic. > + In particular the volatile flag causes us to not prematurely remove > + such clobber instructions. */ > +#define TREE_CLOBBER_P(NODE) \ > + (TREE_CODE (NODE) == CONSTRUCTOR && TREE_THIS_VOLATILE (NODE)) > + > /* A single element of a CONSTRUCTOR. VALUE holds the actual value of the > element. INDEX can optionally design the position of VALUE: in arrays, > it is the index where VALUE has to be placed; in structures, it is the > Index: gimple.h > =================================================================== > --- gimple.h.orig 2011-11-07 15:56:25.000000000 +0100 > +++ gimple.h 2011-11-07 16:12:35.000000000 +0100 > @@ -2000,6 +2000,14 @@ gimple_assign_cast_p (gimple s) > return false; > } > > +/* Return true if S is a clobber statement. */ > + > +static inline bool > +gimple_clobber_p (gimple s) > +{ > + return gimple_assign_single_p (s) > + && TREE_CLOBBER_P (gimple_assign_rhs1 (s)); > +} > > /* Return true if GS is a GIMPLE_CALL. */ > > Index: gimplify.c > =================================================================== > --- gimplify.c.orig 2011-11-07 15:56:25.000000000 +0100 > +++ gimplify.c 2011-11-07 16:12:35.000000000 +0100 > @@ -1127,7 +1127,8 @@ gimplify_bind_expr (tree *expr_p, gimple > bool old_save_stack = gimplify_ctxp->save_stack; > tree t; > gimple gimple_bind; > - gimple_seq body; > + gimple_seq body, cleanup; > + gimple stack_save; > > tree temp = voidify_wrapper_expr (bind_expr, NULL); > > @@ -1173,22 +1174,50 @@ gimplify_bind_expr (tree *expr_p, gimple > gimplify_stmt (&BIND_EXPR_BODY (bind_expr), &body); > gimple_bind_set_body (gimple_bind, body); > > + cleanup = NULL; > + stack_save = NULL; > if (gimplify_ctxp->save_stack) > { > - gimple stack_save, stack_restore, gs; > - gimple_seq cleanup, new_body; > + gimple stack_restore; > > /* Save stack on entry and restore it on exit. Add a try_finally > block to achieve this. Note that mudflap depends on the > format of the emitted code: see mx_register_decls(). */ > build_stack_save_restore (&stack_save, &stack_restore); > > - cleanup = new_body = NULL; > gimplify_seq_add_stmt (&cleanup, stack_restore); > + } > + > + /* Add clobbers for all variables that go out of scope. */ > + for (t = BIND_EXPR_VARS (bind_expr); t ; t = DECL_CHAIN (t)) > + { > + if (TREE_CODE (t) == VAR_DECL > + && !is_global_var (t) > + && DECL_CONTEXT (t) == current_function_decl > + && !DECL_HARD_REGISTER (t) > + && !TREE_THIS_VOLATILE (t) > + && !DECL_HAS_VALUE_EXPR_P (t) > + /* Only care for variables that have to be in memory. Others > + will be rewritten into SSA names, hence moved to the top-level. > */ > + && needs_to_live_in_memory (t)) > + { > + tree clobber = build_constructor (TREE_TYPE (t), NULL); > + TREE_THIS_VOLATILE (clobber) = 1; > + gimplify_seq_add_stmt (&cleanup, gimple_build_assign (t, clobber)); > + } > + } > + > + if (cleanup) > + { > + gimple gs; > + gimple_seq new_body; > + > + new_body = NULL; > gs = gimple_build_try (gimple_bind_body (gimple_bind), cleanup, > GIMPLE_TRY_FINALLY); > > - gimplify_seq_add_stmt (&new_body, stack_save); > + if (stack_save) > + gimplify_seq_add_stmt (&new_body, stack_save); > gimplify_seq_add_stmt (&new_body, gs); > gimple_bind_set_body (gimple_bind, new_body); > } > Index: cfgexpand.c > =================================================================== > --- cfgexpand.c.orig 2011-11-07 15:56:25.000000000 +0100 > +++ cfgexpand.c 2011-11-07 16:12:35.000000000 +0100 > @@ -135,7 +135,7 @@ set_rtl (tree t, rtx x) > /* If we don't yet have something recorded, just record it now. */ > if (!DECL_RTL_SET_P (var)) > SET_DECL_RTL (var, x); > - /* If we have it set alrady to "multiple places" don't > + /* If we have it set already to "multiple places" don't > change this. */ > else if (DECL_RTL (var) == pc_rtx) > ; > @@ -184,6 +184,7 @@ struct stack_var > static struct stack_var *stack_vars; > static size_t stack_vars_alloc; > static size_t stack_vars_num; > +static struct pointer_map_t *decl_to_stack_part; > > /* An array of indices such that stack_vars[stack_vars_sorted[i]].size > is non-decreasing. */ > @@ -262,7 +263,11 @@ add_stack_var (tree decl) > stack_vars > = XRESIZEVEC (struct stack_var, stack_vars, stack_vars_alloc); > } > + if (!decl_to_stack_part) > + decl_to_stack_part = pointer_map_create (); > + > v = &stack_vars[stack_vars_num]; > + * (size_t *)pointer_map_insert (decl_to_stack_part, decl) = stack_vars_num; > > v->decl = decl; > v->size = tree_low_cst (DECL_SIZE_UNIT (SSAVAR (decl)), 1); > @@ -309,6 +314,14 @@ stack_var_conflict_p (size_t x, size_t y > { > struct stack_var *a = &stack_vars[x]; > struct stack_var *b = &stack_vars[y]; > + if (x == y) > + return false; > + /* Partitions containing an SSA name result from gimple registers > + with things like unsupported modes. They are top-level and > + hence conflict with everything else. */ > + if (TREE_CODE (a->decl) == SSA_NAME || TREE_CODE (b->decl) == SSA_NAME) > + return true; > + > if (!a->conflicts || !b->conflicts) > return false; > return bitmap_bit_p (a->conflicts, y); > @@ -379,6 +392,163 @@ add_alias_set_conflicts (void) > } > } > > +/* Callback for walk_stmt_ops. If OP is a decl touched by add_stack_var > + enter its partition number into bitmap DATA. */ > + > +static bool > +visit_op (gimple stmt ATTRIBUTE_UNUSED, tree op, void *data) > +{ > + bitmap active = (bitmap)data; > + op = get_base_address (op); > + if (op > + && DECL_P (op) > + && DECL_RTL_IF_SET (op) == pc_rtx) > + { > + size_t *v = (size_t *) pointer_map_contains (decl_to_stack_part, op); > + if (v) > + bitmap_set_bit (active, *v); > + } > + return false; > +} > + > +/* Callback for walk_stmt_ops. If OP is a decl touched by add_stack_var > + record conflicts between it and all currently active other partitions > + from bitmap DATA. */ > + > +static bool > +visit_conflict (gimple stmt ATTRIBUTE_UNUSED, tree op, void *data) > +{ > + bitmap active = (bitmap)data; > + op = get_base_address (op); > + if (op > + && DECL_P (op) > + && DECL_RTL_IF_SET (op) == pc_rtx) > + { > + size_t *v = > + (size_t *) pointer_map_contains (decl_to_stack_part, op); > + if (v && bitmap_set_bit (active, *v)) > + { > + size_t num = *v; > + bitmap_iterator bi; > + unsigned i; > + gcc_assert (num < stack_vars_num); > + EXECUTE_IF_SET_IN_BITMAP (active, 0, i, bi) > + add_stack_var_conflict (num, i); > + } > + } > + return false; > +} > + > +/* Helper routine for add_scope_conflicts, calculating the active partitions > + at the end of BB, leaving the result in WORK. We're called to generate > + conflicts when FOR_CONFLICT is true, otherwise we're just tracking > + liveness. */ > + > +static void > +add_scope_conflicts_1 (basic_block bb, bitmap work, bool for_conflict) > +{ > + edge e; > + edge_iterator ei; > + gimple_stmt_iterator gsi; > + bool (*visit)(gimple, tree, void *); > + > + bitmap_clear (work); > + FOR_EACH_EDGE (e, ei, bb->preds) > + bitmap_ior_into (work, (bitmap)e->src->aux); > + > + if (for_conflict) > + { > + /* We need to add conflicts for everything life at the start of > + this block. Unlike classical lifeness for named objects we can't > + rely on seeing a def/use of the names we're interested in. > + There might merely be indirect loads/stores. We'd not add any > + conflicts for such partitions. */ > + bitmap_iterator bi; > + unsigned i; > + EXECUTE_IF_SET_IN_BITMAP (work, 0, i, bi) > + { > + unsigned j; > + bitmap_iterator bj; > + EXECUTE_IF_SET_IN_BITMAP (work, i, j, bj) > + add_stack_var_conflict (i, j); > + } > + visit = visit_conflict; > + } > + else > + visit = visit_op; > + > + for (gsi = gsi_start_phis (bb); !gsi_end_p (gsi); gsi_next (&gsi)) > + { > + gimple stmt = gsi_stmt (gsi); > + if (!is_gimple_debug (stmt)) > + walk_stmt_load_store_addr_ops (stmt, work, visit, visit, visit); > + } > + for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi)) > + { > + gimple stmt = gsi_stmt (gsi); > + > + if (gimple_clobber_p (stmt)) > + { > + tree lhs = gimple_assign_lhs (stmt); > + size_t *v; > + /* Nested function lowering might introduce LHSs > + that are COMPONENT_REFs. */ > + if (TREE_CODE (lhs) != VAR_DECL) > + continue; > + if (DECL_RTL_IF_SET (lhs) == pc_rtx > + && (v = (size_t *) > + pointer_map_contains (decl_to_stack_part, lhs))) > + bitmap_clear_bit (work, *v); > + } > + else if (!is_gimple_debug (stmt)) > + walk_stmt_load_store_addr_ops (stmt, work, visit, visit, visit); > + } > +} > + > +/* Generate stack partition conflicts between all partitions that are > + simultaneously live. */ > + > +static void > +add_scope_conflicts (void) > +{ > + basic_block bb; > + bool changed; > + bitmap work = BITMAP_ALLOC (NULL); > + > + /* We approximate the life range of a stack variable by taking the first > + mention of its name as starting point(s), and by the end-of-scope > + death clobber added by gimplify as ending point(s) of the range. > + This overapproximates in the case we for instance moved an address-taken > + operation upward, without also moving a dereference to it upwards. > + But it's conservatively correct as a variable never can hold values > + before its name is mentioned at least once. > + > + We then do a mostly classical bitmap lifeness algorithm. */ > + > + FOR_ALL_BB (bb) > + bb->aux = BITMAP_ALLOC (NULL); > + > + changed = true; > + while (changed) > + { > + changed = false; > + FOR_EACH_BB (bb) > + { > + bitmap active = (bitmap)bb->aux; > + add_scope_conflicts_1 (bb, work, false); > + if (bitmap_ior_into (active, work)) > + changed = true; > + } > + } > + > + FOR_EACH_BB (bb) > + add_scope_conflicts_1 (bb, work, true); > + > + BITMAP_FREE (work); > + FOR_ALL_BB (bb) > + BITMAP_FREE (bb->aux); > +} > + > /* A subroutine of partition_stack_vars. A comparison function for qsort, > sorting an array of indices by the properties of the object. */ > > @@ -1095,11 +1265,8 @@ expand_one_var (tree var, bool toplevel, > static void > expand_used_vars_for_block (tree block, bool toplevel) > { > - size_t i, j, old_sv_num, this_sv_num, new_sv_num; > tree t; > > - old_sv_num = toplevel ? 0 : stack_vars_num; > - > /* Expand all variables at this level. */ > for (t = BLOCK_VARS (block); t ; t = DECL_CHAIN (t)) > if (TREE_USED (t) > @@ -1107,24 +1274,9 @@ expand_used_vars_for_block (tree block, > || !DECL_NONSHAREABLE (t))) > expand_one_var (t, toplevel, true); > > - this_sv_num = stack_vars_num; > - > /* Expand all variables at containing levels. */ > for (t = BLOCK_SUBBLOCKS (block); t ; t = BLOCK_CHAIN (t)) > expand_used_vars_for_block (t, false); > - > - /* Since we do not track exact variable lifetimes (which is not even > - possible for variables whose address escapes), we mirror the block > - tree in the interference graph. Here we cause all variables at this > - level, and all sublevels, to conflict. */ > - if (old_sv_num < this_sv_num) > - { > - new_sv_num = stack_vars_num; > - > - for (i = old_sv_num; i < new_sv_num; ++i) > - for (j = i < this_sv_num ? i : this_sv_num; j-- > old_sv_num ;) > - add_stack_var_conflict (i, j); > - } > } > > /* A subroutine of expand_used_vars. Walk down through the BLOCK tree > @@ -1312,6 +1464,8 @@ fini_vars_expansion (void) > XDELETEVEC (stack_vars_sorted); > stack_vars = NULL; > stack_vars_alloc = stack_vars_num = 0; > + pointer_map_destroy (decl_to_stack_part); > + decl_to_stack_part = NULL; > } > > /* Make a fair guess for the size of the stack frame of the function > @@ -1466,6 +1620,7 @@ expand_used_vars (void) > > if (stack_vars_num > 0) > { > + add_scope_conflicts (); > /* Due to the way alias sets work, no variables with non-conflicting > alias sets may be assigned the same address. Add conflicts to > reflect this. */ > @@ -1974,8 +2129,13 @@ expand_gimple_stmt_1 (gimple stmt) > == GIMPLE_SINGLE_RHS); > if (gimple_has_location (stmt) && CAN_HAVE_LOCATION_P (rhs)) > SET_EXPR_LOCATION (rhs, gimple_location (stmt)); > - expand_assignment (lhs, rhs, > - gimple_assign_nontemporal_move_p (stmt)); > + if (TREE_CLOBBER_P (rhs)) > + /* This is a clobber to mark the going out of scope for > + this LHS. */ > + ; > + else > + expand_assignment (lhs, rhs, > + gimple_assign_nontemporal_move_p (stmt)); > } > else > { > @@ -3165,7 +3325,9 @@ expand_debug_expr (tree exp) > /* Fall through. */ > > case CONSTRUCTOR: > - if (TREE_CODE (TREE_TYPE (exp)) == VECTOR_TYPE) > + if (TREE_CLOBBER_P (exp)) > + return NULL; > + else if (TREE_CODE (TREE_TYPE (exp)) == VECTOR_TYPE) > { > unsigned i; > tree val; > Index: tree-pretty-print.c > =================================================================== > --- tree-pretty-print.c.orig 2011-10-27 14:48:01.000000000 +0200 > +++ tree-pretty-print.c 2011-11-07 16:19:17.000000000 +0100 > @@ -1271,8 +1271,10 @@ dump_generic_node (pretty_printer *buffe > bool is_array_init = false; > double_int curidx = double_int_zero; > pp_character (buffer, '{'); > - if (TREE_CODE (TREE_TYPE (node)) == RECORD_TYPE > - || TREE_CODE (TREE_TYPE (node)) == UNION_TYPE) > + if (TREE_CLOBBER_P (node)) > + pp_string (buffer, "CLOBBER"); > + else if (TREE_CODE (TREE_TYPE (node)) == RECORD_TYPE > + || TREE_CODE (TREE_TYPE (node)) == UNION_TYPE) > is_struct_init = true; > else if (TREE_CODE (TREE_TYPE (node)) == ARRAY_TYPE > && TYPE_DOMAIN (TREE_TYPE (node)) > Index: tree-stdarg.c > =================================================================== > --- tree-stdarg.c.orig 2011-11-07 15:56:25.000000000 +0100 > +++ tree-stdarg.c 2011-11-07 16:12:35.000000000 +0100 > @@ -872,8 +872,11 @@ execute_optimize_stdarg (void) > if (get_gimple_rhs_class (gimple_assign_rhs_code (stmt)) > == GIMPLE_SINGLE_RHS) > { > + /* Check for ap ={v} {}. */ > + if (TREE_CLOBBER_P (rhs)) > + continue; > /* Check for ap[0].field = temp. */ > - if (va_list_counter_struct_op (&si, lhs, rhs, true)) > + else if (va_list_counter_struct_op (&si, lhs, rhs, > true)) > continue; > > /* Check for temp = ap[0].field. */ > Index: tree-ssa-live.c > =================================================================== > --- tree-ssa-live.c.orig 2011-11-07 15:56:25.000000000 +0100 > +++ tree-ssa-live.c 2011-11-07 16:12:35.000000000 +0100 > @@ -688,6 +688,7 @@ remove_unused_locals (void) > referenced_var_iterator rvi; > bitmap global_unused_vars = NULL; > unsigned srcidx, dstidx, num; > + bool have_local_clobbers = false; > > /* Removing declarations from lexical blocks when not optimizing is > not only a waste of time, it actually causes differences in stack > @@ -720,6 +721,12 @@ remove_unused_locals (void) > if (is_gimple_debug (stmt)) > continue; > > + if (gimple_clobber_p (stmt)) > + { > + have_local_clobbers = true; > + continue; > + } > + > if (b) > TREE_USED (b) = true; > > @@ -753,6 +760,41 @@ remove_unused_locals (void) > TREE_USED (e->goto_block) = true; > } > > + /* We do a two-pass approach about the out-of-scope clobbers. We want > + to remove them if they are the only references to a local variable, > + but we want to retain them when there's any other. So the first pass > + ignores them, and the second pass (if there were any) tries to remove > + them. */ > + if (have_local_clobbers) > + FOR_EACH_BB (bb) > + { > + gimple_stmt_iterator gsi; > + > + for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi);) > + { > + gimple stmt = gsi_stmt (gsi); > + tree b = gimple_block (stmt); > + > + if (gimple_clobber_p (stmt)) > + { > + tree lhs = gimple_assign_lhs (stmt); > + lhs = get_base_address (lhs); > + if (TREE_CODE (lhs) == SSA_NAME) > + lhs = SSA_NAME_VAR (lhs); > + if (DECL_P (lhs) && (!var_ann (lhs) || !is_used_p (lhs))) > + { > + unlink_stmt_vdef (stmt); > + gsi_remove (&gsi, true); > + release_defs (stmt); > + continue; > + } > + if (b) > + TREE_USED (b) = true; > + } > + gsi_next (&gsi); > + } > + } > + > cfun->has_local_explicit_reg_vars = false; > > /* Remove unmarked local vars from local_decls. */ > Index: tree-sra.c > =================================================================== > --- tree-sra.c.orig 2011-11-07 15:56:25.000000000 +0100 > +++ tree-sra.c 2011-11-07 16:12:35.000000000 +0100 > @@ -1103,7 +1103,9 @@ build_accesses_from_assign (gimple stmt) > tree lhs, rhs; > struct access *lacc, *racc; > > - if (!gimple_assign_single_p (stmt)) > + if (!gimple_assign_single_p (stmt) > + /* Scope clobbers don't influence scalarization. */ > + || gimple_clobber_p (stmt)) > return false; > > lhs = gimple_assign_lhs (stmt); > Index: tree-ssa-dce.c > =================================================================== > --- tree-ssa-dce.c.orig 2011-11-07 15:56:25.000000000 +0100 > +++ tree-ssa-dce.c 2011-11-07 16:12:35.000000000 +0100 > @@ -351,6 +351,12 @@ mark_stmt_if_obviously_necessary (gimple > mark_stmt_necessary (stmt, true); > break; > > + case GIMPLE_ASSIGN: > + if (TREE_CODE (gimple_assign_lhs (stmt)) == SSA_NAME > + && TREE_CLOBBER_P (gimple_assign_rhs1 (stmt))) > + return; > + break; > + > default: > break; > } > @@ -917,19 +923,17 @@ propagate_necessity (struct edge_list *e > else if (gimple_assign_single_p (stmt)) > { > tree rhs; > - bool rhs_aliased = false; > /* If this is a load mark things necessary. */ > rhs = gimple_assign_rhs1 (stmt); > if (TREE_CODE (rhs) != SSA_NAME > - && !is_gimple_min_invariant (rhs)) > + && !is_gimple_min_invariant (rhs) > + && TREE_CODE (rhs) != CONSTRUCTOR) > { > if (!ref_may_be_aliased (rhs)) > mark_aliased_reaching_defs_necessary (stmt, rhs); > else > - rhs_aliased = true; > + mark_all_reaching_defs_necessary (stmt); > } > - if (rhs_aliased) > - mark_all_reaching_defs_necessary (stmt); > } > else if (gimple_code (stmt) == GIMPLE_RETURN) > { > @@ -937,7 +941,8 @@ propagate_necessity (struct edge_list *e > /* A return statement may perform a load. */ > if (rhs > && TREE_CODE (rhs) != SSA_NAME > - && !is_gimple_min_invariant (rhs)) > + && !is_gimple_min_invariant (rhs) > + && TREE_CODE (rhs) != CONSTRUCTOR) > { > if (!ref_may_be_aliased (rhs)) > mark_aliased_reaching_defs_necessary (stmt, rhs); > @@ -955,6 +960,7 @@ propagate_necessity (struct edge_list *e > tree op = TREE_VALUE (gimple_asm_input_op (stmt, i)); > if (TREE_CODE (op) != SSA_NAME > && !is_gimple_min_invariant (op) > + && TREE_CODE (op) != CONSTRUCTOR > && !ref_may_be_aliased (op)) > mark_aliased_reaching_defs_necessary (stmt, op); > } > Index: gimple.c > =================================================================== > --- gimple.c.orig 2011-11-07 15:56:25.000000000 +0100 > +++ gimple.c 2011-11-07 16:12:35.000000000 +0100 > @@ -1471,7 +1471,9 @@ walk_gimple_op (gimple stmt, walk_tree_f > { > /* If the RHS has more than 1 operand, it is not appropriate > for the memory. */ > - wi->val_only = !is_gimple_mem_rhs (gimple_assign_rhs1 (stmt)) > + wi->val_only = !(is_gimple_mem_rhs (gimple_assign_rhs1 (stmt)) > + || TREE_CODE (gimple_assign_rhs1 (stmt)) > + == CONSTRUCTOR) > || !gimple_assign_single_p (stmt); > wi->is_lhs = true; > } > Index: tree-ssa-structalias.c > =================================================================== > --- tree-ssa-structalias.c.orig 2011-11-07 15:56:25.000000000 +0100 > +++ tree-ssa-structalias.c 2011-11-07 16:12:35.000000000 +0100 > @@ -4437,7 +4437,11 @@ find_func_aliases (gimple origt) > tree lhsop = gimple_assign_lhs (t); > tree rhsop = (gimple_num_ops (t) == 2) ? gimple_assign_rhs1 (t) : NULL; > > - if (rhsop && AGGREGATE_TYPE_P (TREE_TYPE (lhsop))) > + if (rhsop && TREE_CLOBBER_P (rhsop)) > + /* Ignore clobbers, they don't actually store anything into > + the LHS. */ > + ; > + else if (rhsop && AGGREGATE_TYPE_P (TREE_TYPE (lhsop))) > do_structure_copy (lhsop, rhsop); > else > { > Index: tree-ssa-reassoc.c > =================================================================== > --- tree-ssa-reassoc.c.orig 2011-11-07 15:56:25.000000000 +0100 > +++ tree-ssa-reassoc.c 2011-11-07 16:12:35.000000000 +0100 > @@ -2869,6 +2869,12 @@ reassociate_bb (basic_block bb) > rhs1 = gimple_assign_rhs1 (stmt); > rhs2 = gimple_assign_rhs2 (stmt); > > + /* We don't want to destroy reduction like patterns > + with reassociation, simply don't start at such > + statements. */ > + if (is_phi_for_stmt (stmt, rhs1) || is_phi_for_stmt (stmt, rhs2)) > + continue; > + > /* For non-bit or min/max operations we can't associate > all types. Verify that here. */ > if (rhs_code != BIT_IOR_EXPR > Index: tree-ssa-operands.c > =================================================================== > --- tree-ssa-operands.c.orig 2011-11-07 15:56:25.000000000 +0100 > +++ tree-ssa-operands.c 2011-11-07 16:12:35.000000000 +0100 > @@ -956,6 +956,12 @@ get_expr_operands (gimple stmt, tree *ex > constructor_elt *ce; > unsigned HOST_WIDE_INT idx; > > + /* A volatile constructor is actually TREE_CLOBBER_P, transfer > + the volatility to the statement, don't use TREE_CLOBBER_P for > + mirroring the other uses of THIS_VOLATILE in this file. */ > + if (TREE_THIS_VOLATILE (expr)) > + gimple_set_has_volatile_ops (stmt, true); > + > for (idx = 0; > VEC_iterate (constructor_elt, CONSTRUCTOR_ELTS (expr), idx, ce); > idx++) > Index: tree-ssa-sccvn.c > =================================================================== > --- tree-ssa-sccvn.c.orig 2011-11-07 15:56:25.000000000 +0100 > +++ tree-ssa-sccvn.c 2011-11-07 16:12:35.000000000 +0100 > @@ -1388,8 +1388,12 @@ vn_reference_lookup_3 (ao_ref *ref, tree > if (maxsize == -1) > return (void *)-1; > > + /* We can't deduce anything useful from clobbers. */ > + if (gimple_clobber_p (def_stmt)) > + return (void *)-1; > + > /* def_stmt may-defs *ref. See if we can derive a value for *ref > - from that defintion. > + from that definition. > 1) Memset. */ > if (is_gimple_reg_type (vr->type) > && gimple_call_builtin_p (def_stmt, BUILT_IN_MEMSET) > Index: tree-ssa-phiopt.c > =================================================================== > --- tree-ssa-phiopt.c.orig 2011-11-07 15:56:25.000000000 +0100 > +++ tree-ssa-phiopt.c 2011-11-07 16:12:35.000000000 +0100 > @@ -1318,8 +1318,10 @@ cond_if_else_store_replacement_1 (basic_ > > if (then_assign == NULL > || !gimple_assign_single_p (then_assign) > + || gimple_clobber_p (then_assign) > || else_assign == NULL > - || !gimple_assign_single_p (else_assign)) > + || !gimple_assign_single_p (else_assign) > + || gimple_clobber_p (else_assign)) > return false; > > lhs = gimple_assign_lhs (then_assign); > Index: testsuite/gcc.dg/tree-ssa/20031015-1.c > =================================================================== > --- testsuite/gcc.dg/tree-ssa/20031015-1.c.orig 2011-11-07 15:56:25.000000000 > +0100 > +++ testsuite/gcc.dg/tree-ssa/20031015-1.c 2011-11-07 16:12:35.000000000 > +0100 > @@ -13,6 +13,6 @@ main(void) > return 0; > } > > -/* The VDEF comes from the initial assignment and the asm. */ > -/* { dg-final { scan-tree-dump-times "DEF" 2 "alias" } } */ > +/* The VDEF comes from the initial assignment, the asm, and the clobber. */ > +/* { dg-final { scan-tree-dump-times "DEF" 3 "alias" } } */ > /* { dg-final { cleanup-tree-dump "alias" } } */ > Index: testsuite/g++.dg/tree-ssa/ehcleanup-1.C > =================================================================== > --- testsuite/g++.dg/tree-ssa/ehcleanup-1.C.orig 2011-11-07 > 15:56:25.000000000 +0100 > +++ testsuite/g++.dg/tree-ssa/ehcleanup-1.C 2011-11-07 16:12:35.000000000 > +0100 > @@ -16,9 +16,9 @@ t (void) > can_throw (); > } > // We ought to remove implicit cleanup, since destructor is empty. > -// { dg-final { scan-tree-dump-times "Empty EH handler" 1 "ehcleanup1" } } > +// { dg-final { scan-tree-dump-times "Empty EH handler" 2 "ehcleanup1" } } > // > // And as a result also contained control flow. > -// { dg-final { scan-tree-dump-times "Removing unreachable" 2 "ehcleanup1" } > } > +// { dg-final { scan-tree-dump-times "Removing unreachable" 4 "ehcleanup1" } > } > // > // { dg-final { cleanup-tree-dump "ehcleanup1" } } > Index: testsuite/g++.dg/eh/builtin1.C > =================================================================== > --- testsuite/g++.dg/eh/builtin1.C.orig 2011-11-07 15:56:25.000000000 +0100 > +++ testsuite/g++.dg/eh/builtin1.C 2011-11-07 16:12:35.000000000 +0100 > @@ -6,20 +6,26 @@ > > extern "C" int printf (const char *, ...); > > -struct A { A (); ~A (); int i; }; > +extern void callme (void) throw(); > > int > -foo () > +foo (int i) > { > - A a; > - printf ("foo %d\n", a.i); > + try { > + printf ("foo %d\n", i); > + } catch (...) { > + callme(); > + } > } > > int > -bar () > +bar (int i) > { > - A a; > - __builtin_printf ("foo %d\n", a.i); > + try { > + __builtin_printf ("foo %d\n", i); > + } catch (...) { > + callme(); > + } > } > > /* { dg-final { scan-tree-dump-times "resx" 2 "eh" } } */ > Index: testsuite/g++.dg/eh/builtin2.C > =================================================================== > --- testsuite/g++.dg/eh/builtin2.C.orig 2011-11-07 15:56:25.000000000 +0100 > +++ testsuite/g++.dg/eh/builtin2.C 2011-11-07 16:12:35.000000000 +0100 > @@ -5,20 +5,26 @@ > > extern "C" int printf (const char *, ...) throw(); > > -struct A { A (); ~A (); int i; }; > +extern void callme (void) throw(); > > int > -foo () > +foo (int i) > { > - A a; > - printf ("foo %d\n", a.i); > + try { > + printf ("foo %d\n", i); > + } catch (...) { > + callme(); > + } > } > > int > -bar () > +bar (int i) > { > - A a; > - __builtin_printf ("foo %d\n", a.i); > + try { > + __builtin_printf ("foo %d\n", i); > + } catch (...) { > + callme(); > + } > } > > /* { dg-final { scan-tree-dump-times "resx" 0 "eh" } } */ > Index: testsuite/g++.dg/eh/builtin3.C > =================================================================== > --- testsuite/g++.dg/eh/builtin3.C.orig 2011-11-07 15:56:25.000000000 +0100 > +++ testsuite/g++.dg/eh/builtin3.C 2011-11-07 16:12:35.000000000 +0100 > @@ -3,13 +3,16 @@ > // { dg-do compile } > // { dg-options "-fdump-tree-eh" } > > -struct A { A (); ~A (); int i; }; > +extern void callme (void) throw(); > > int > -bar () > +bar (int i) > { > - A a; > - __builtin_printf ("foo %d\n", a.i); > + try { > + __builtin_printf ("foo %d\n", i); > + } catch (...) { > + callme(); > + } > } > > /* { dg-final { scan-tree-dump-times "resx" 1 "eh" } } */ >