diff mbox

Mark objects death at end of scope

Message ID Pine.LNX.4.64.1111071652430.32478@wotan.suse.de
State New
Headers show

Commit Message

Michael Matz Nov. 7, 2011, 3:57 p.m. UTC
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?


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.

Comments

Richard Biener Nov. 7, 2011, 10:02 p.m. UTC | #1
On Mon, Nov 7, 2011 at 4:57 PM, Michael Matz <matz@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" } } */
>
Steve Ellcey Nov. 10, 2011, 11:19 p.m. UTC | #2
Michael,

This patch (r181172) has broken my bootstrap of IA64 Linux and I am
trying to figure out what to do about it.

The failure happens while building libunwind (I did not configure with
--with-system-libunwind):

/ctires/gcc/nightly/build-ia64-redhat-linux-gnu-trunk/obj_gcc/./gcc/xgcc -B/ctires/gcc/nightly/build-ia64-redhat-linux-gnu-trunk/obj_gcc/./gcc/ -B/ctires/gcc/nightly/gcc-ia64-redhat-linux-gnu-trunk/ia64-redhat-linux-gnu/bin/ -B/ctires/gcc/nightly/gcc-ia64-redhat-linux-gnu-trunk/ia64-redhat-linux-gnu/lib/ -isystem /ctires/gcc/nightly/gcc-ia64-redhat-linux-gnu-trunk/ia64-redhat-linux-gnu/include -isystem /ctires/gcc/nightly/gcc-ia64-redhat-linux-gnu-trunk/ia64-redhat-linux-gnu/sys-include    -O2  -g -O2 -DIN_GCC   -DUSE_LIBUNWIND_EXCEPTIONS -W -Wall -Wno-narrowing -Wwrite-strings -Wcast-qual -Wstrict-prototypes -Wmissing-prototypes -Wold-style-definition  -isystem ./include   -fPIC -DUSE_GAS_SYMVER -g -DIN_LIBGCC2 -fbuilding-libgcc -fno-stack-protector  -shared -nodefaultlibs -Wl,-h,libunwind.so.7 -Wl,-z,text -Wl,-z,defs -o ./libunwind.so.7.tmp -g -O2 -B./ fde-glibc_s.o unwind-ia64_s.o -lc && rm -f ./libunwind.so && if [ -f ./libunwind.so.7 ]; then mv -f ./libunwind.so.7 ./libu
 nwind.so.7.backup; else true; fi && mv ./libunwind.so.7.tmp ./libunwind.so.7 && ln -s libunwind.so.7 ./libunwind.so

fde-glibc_s.o:(.IA_64.unwind_info+0x28): undefined reference to `__gcc_personality_v0'
unwind-ia64_s.o:(.IA_64.unwind_info+0x158): undefined reference to `__gcc_personality_v0'
unwind-ia64_s.o:(.IA_64.unwind_info+0x190): undefined reference to `__gcc_personality_v0'
unwind-ia64_s.o:(.IA_64.unwind_info+0x1c8): undefined reference to `__gcc_personality_v0'
unwind-ia64_s.o:(.IA_64.unwind_info+0x200): undefined reference to `__gcc_personality_v0'
unwind-ia64_s.o:(.IA_64.unwind_info+0x3e0): more undefined references to `__gcc_personality_v0' follow
collect2: error: ld returned 1 exit status

Looking at fde-glibc_s.o and unwind-ia64_s.o before your patch I see that
there are no references to __gcc_personality_v0.  Looking at the email
and PR 50857 made me think that maybe we should compile these files with
-fno-exceptions but the Makefile is currently explicitly compiling them
with -fexceptions so I am not sure if that is the right fix for this
problem or not.  Do you have any ideas or suggestions on what to do?

Steve Ellcey
sje@cup.hp.com
Michael Matz Nov. 11, 2011, 1:36 p.m. UTC | #3
Hi,

On Thu, 10 Nov 2011, Steve Ellcey wrote:

> This patch (r181172) has broken my bootstrap of IA64 Linux and I am
> trying to figure out what to do about it.
> 
> The failure happens while building libunwind (I did not configure with
> --with-system-libunwind):
> 
> /ctires/gcc/nightly/build-ia64-redhat-linux-gnu-trunk/obj_gcc/./gcc/xgcc 
> -B/ctires/gcc/nightly/build-ia64-redhat-linux-gnu-trunk/obj_gcc/./gcc/ 
> -B/ctires/gcc/nightly/gcc-ia64-redhat-linux-gnu-trunk/ia64-redhat-linux-gnu/bin/ 
> -B/ctires/gcc/nightly/gcc-ia64-redhat-linux-gnu-trunk/ia64-redhat-linux-gnu/lib/ 
> -isystem 
> /ctires/gcc/nightly/gcc-ia64-redhat-linux-gnu-trunk/ia64-redhat-linux-gnu/include 
> -isystem 
> /ctires/gcc/nightly/gcc-ia64-redhat-linux-gnu-trunk/ia64-redhat-linux-gnu/sys-include 
> -O2 -g -O2 -DIN_GCC -DUSE_LIBUNWIND_EXCEPTIONS -W -Wall -Wno-narrowing 
> -Wwrite-strings -Wcast-qual -Wstrict-prototypes -Wmissing-prototypes 
> -Wold-style-definition -isystem ./include -fPIC -DUSE_GAS_SYMVER -g 
> -DIN_LIBGCC2 -fbuilding-libgcc -fno-stack-protector -shared 
> -nodefaultlibs -Wl,-h,libunwind.so.7 -Wl,-z,text -Wl,-z,defs -o 
> ./libunwind.so.7.tmp -g -O2 -B./ fde-glibc_s.o unwind-ia64_s.o -lc && rm 
> -f ./libunwind.so && if [ -f ./libunwind.so.7 ]; then mv -f 
> ./libunwind.so.7 ./libu
>  nwind.so.7.backup; else true; fi && mv ./libunwind.so.7.tmp ./libunwind.so.7 && ln -s libunwind.so.7 ./libunwind.so
> 
> fde-glibc_s.o:(.IA_64.unwind_info+0x28): undefined reference to `__gcc_personality_v0'

Hmm, this is defined in libgcc_s and in libgcc_eh, but libunwind is linked 
with -nodefaultlibs.  I think it makes sense to require the unwinder to 
not throw or catch exceptions itself, hence -fno-exceptions should be the 
correct flag to compile it ...

> Looking at fde-glibc_s.o and unwind-ia64_s.o before your patch I see 
> that there are no references to __gcc_personality_v0.  Looking at the 
> email and PR 50857 made me think that maybe we should compile these 
> files with -fno-exceptions but the Makefile is currently explicitly 
> compiling them with -fexceptions

... so this seems incorrect.  I'd try adding -fno-exceptions for the 
LIBUNWIND objects, it should work.


Ciao,
Michael.
diff mbox

Patch

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" } } */