public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* Mark objects death at end of scope
@ 2011-11-03  0:05 Michael Matz
  2011-11-03  1:21 ` Eric Botcazou
                   ` (2 more replies)
  0 siblings, 3 replies; 30+ messages in thread
From: Michael Matz @ 2011-11-03  0:05 UTC (permalink / raw)
  To: gcc-patches

Hi,

[Eric, see below for an Ada issue]

so, this is a more complete resubmission of an old patch, trying to get it 
into 4.7.  In order not to have to rely on TREE_BLOCK of variables to 
determine valid sharing (which never really worked that well when all the 
intermediate code movements that could have taken place in the gimple 
optimizers), we make the knowledge explicit in the IL, by emitting clobber 
instructions when variables (that possibly can go into memory) go out of 
scope.  Such a clobber looks like a normal memory store, except that the 
RHS has an indeterminate value, and with bonus point for not moving that 
instruction around too much (in order to not create artificial overlaps 
which never existed in the sources).  A volatile empty CONSTRUCTOR fits 
that quite nicely.

We emit these clobbers at gimplification time by wrapping BIND_EXPR in a 
try/finally block (the clobbers being in the finally part), and let 
gimplification and EH lowering do the hard work.

In some passes we need some tidying to not disable optimizations 
unnecessarily.  At expansion time we use these clobbers to end lifetime 
of local variables (we start life at the first mention of a variables 
name), a normal bitmap pass then creates conflicts.  This is conservative 
in that if a clobber goes missing the respective variable simply will have 
extended lifetime (and therefore more conflicts than necessary, ergo less 
sharing).

I had to change some testcases, because of the use of our EH mechanism to 
implement placing the clobbers (due to the additional cleanup region some 
counts change).

And there's also one issue with Ada that I need help with: it doesn't 
build anymore. ;-)  Well, the tools don't link when C++ bootstrap is 
active.  This is because our whole libbackend is compiled with g++, and 
hence uses the gxx_personality_v0 routines.  But the gnattools are linked 
with a hardcoded ../../xgcc (missing all the C++ libs) leading to the 
symbol not found.  Up to now this accidentally was no problem because g++ 
is so nice that if no EH mechanisms are used it doesn't force any 
personality.  I'm not sure what the best fix here is.  The rest of the 
compiler uses COMPILER and LINKER make variables that are set correctly 
depending on bootstrap configuration.  But the gnattools Makefile.in 
doesn't know about these, so I'm don't see how this ever was supposed to 
work.

As for some measurements: buildtime difference for cpu2006 is in the noise 
(19:31 vs 19:30 minutes), runtime we'll see (I once had benchmarked a 
similar patch months ago, it didn't matter).

Regstrapped on x86_64-linux, all languages, but without Ada (see above).
No regressions.


Ciao,
Michael.

	* gengtype.c (write_field_root): Avoid out-of-scope access of newv.

	* tree.h (TREE_CLOBBER_P): New macro.
	* 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-stdarg.c (execute_optimize_stdarg): Accept clobbers.
	* 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-02 21:18:45.000000000 +0100
+++ gengtype.c	2011-11-02 21:19:51.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 180700)
+++ tree.h	(working copy)
@@ -1636,6 +1636,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: gimplify.c
===================================================================
--- gimplify.c.orig	2011-11-02 21:18:45.000000000 +0100
+++ gimplify.c	2011-11-02 21:19:51.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,49 @@ 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_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-02 21:18:45.000000000 +0100
+++ cfgexpand.c	2011-11-02 23:14:17.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,164 @@ 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_assign_single_p (stmt)
+	  && TREE_CLOBBER_P (gimple_assign_rhs1 (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 +1266,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 +1275,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 +1465,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 +1621,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 +2130,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 +3326,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-stdarg.c
===================================================================
--- tree-stdarg.c.orig	2011-11-02 21:18:45.000000000 +0100
+++ tree-stdarg.c	2011-11-02 21:19:51.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-02 21:18:45.000000000 +0100
+++ tree-ssa-live.c	2011-11-02 21:19:51.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,13 @@ remove_unused_locals (void)
 	  if (is_gimple_debug (stmt))
 	    continue;
 
+	  if (gimple_assign_single_p (stmt)
+	      && TREE_CLOBBER_P (gimple_assign_rhs1 (stmt)))
+	    {
+	      have_local_clobbers = true;
+	      continue;
+	    }
+
 	  if (b)
 	    TREE_USED (b) = true;
 
@@ -753,6 +761,42 @@ 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_assign_single_p (stmt)
+		&& TREE_CLOBBER_P (gimple_assign_rhs1 (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-02 21:18:45.000000000 +0100
+++ tree-sra.c	2011-11-02 21:19:51.000000000 +0100
@@ -1112,6 +1112,10 @@ build_accesses_from_assign (gimple stmt)
   if (disqualify_ops_if_throwing_stmt (stmt, lhs, rhs))
     return false;
 
+  /* Scope clobbers don't influence scalarization.  */
+  if (TREE_CLOBBER_P (rhs))
+    return false;
+
   racc = build_access_from_expr_1 (rhs, stmt, false);
   lacc = build_access_from_expr_1 (lhs, stmt, true);
 
Index: tree-ssa-dce.c
===================================================================
--- tree-ssa-dce.c.orig	2011-11-02 21:18:45.000000000 +0100
+++ tree-ssa-dce.c	2011-11-02 21:19:51.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-02 21:18:45.000000000 +0100
+++ gimple.c	2011-11-02 21:19:51.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-02 21:18:45.000000000 +0100
+++ tree-ssa-structalias.c	2011-11-02 21:19:51.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-operands.c
===================================================================
--- tree-ssa-operands.c.orig	2011-11-02 21:18:45.000000000 +0100
+++ tree-ssa-operands.c	2011-11-02 21:19:51.000000000 +0100
@@ -956,6 +956,9 @@ get_expr_operands (gimple stmt, tree *ex
 	constructor_elt *ce;
 	unsigned HOST_WIDE_INT idx;
 
+	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-phiopt.c
===================================================================
--- tree-ssa-phiopt.c.orig	2011-09-01 14:01:13.000000000 +0200
+++ tree-ssa-phiopt.c	2011-11-02 23:22:17.000000000 +0100
@@ -1318,8 +1318,10 @@ cond_if_else_store_replacement_1 (basic_
 
   if (then_assign == NULL
       || !gimple_assign_single_p (then_assign)
+      || TREE_CLOBBER_P (gimple_assign_rhs1 (then_assign))
       || else_assign == NULL
-      || !gimple_assign_single_p (else_assign))
+      || !gimple_assign_single_p (else_assign)
+      || TREE_CLOBBER_P (gimple_assign_rhs1 (else_assign)))
     return false;
 
   lhs = gimple_assign_lhs (then_assign);
Index: tree-ssa-sccvn.c
===================================================================
--- tree-ssa-sccvn.c.orig	2011-11-02 21:18:45.000000000 +0100
+++ tree-ssa-sccvn.c	2011-11-02 21:19:51.000000000 +0100
@@ -1422,6 +1422,7 @@ vn_reference_lookup_3 (ao_ref *ref, tree
   else if (is_gimple_reg_type (vr->type)
 	   && gimple_assign_single_p (def_stmt)
 	   && gimple_assign_rhs_code (def_stmt) == CONSTRUCTOR
+	   && !TREE_CLOBBER_P (gimple_assign_rhs1 (def_stmt))
 	   && CONSTRUCTOR_NELTS (gimple_assign_rhs1 (def_stmt)) == 0)
     {
       tree base2;
Index: testsuite/gcc.dg/tree-ssa/20031015-1.c
===================================================================
--- testsuite/gcc.dg/tree-ssa/20031015-1.c.orig	2011-11-02 21:18:45.000000000 +0100
+++ testsuite/gcc.dg/tree-ssa/20031015-1.c	2011-11-02 21:19:51.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-02 21:18:45.000000000 +0100
+++ testsuite/g++.dg/tree-ssa/ehcleanup-1.C	2011-11-02 21:19:51.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-02 21:18:45.000000000 +0100
+++ testsuite/g++.dg/eh/builtin1.C	2011-11-02 21:19:51.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-02 21:18:45.000000000 +0100
+++ testsuite/g++.dg/eh/builtin2.C	2011-11-02 21:19:51.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-02 21:18:45.000000000 +0100
+++ testsuite/g++.dg/eh/builtin3.C	2011-11-02 21:19:51.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" } } */

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: Mark objects death at end of scope
  2011-11-03  0:05 Mark objects death at end of scope Michael Matz
@ 2011-11-03  1:21 ` Eric Botcazou
  2011-11-03  9:24   ` Richard Guenther
  2011-11-03  9:59 ` Mark objects death at end of scope Richard Guenther
  2011-11-03 10:57 ` Mark objects death at end " Jakub Jelinek
  2 siblings, 1 reply; 30+ messages in thread
From: Eric Botcazou @ 2011-11-03  1:21 UTC (permalink / raw)
  To: Michael Matz; +Cc: gcc-patches

> And there's also one issue with Ada that I need help with: it doesn't
> build anymore. ;-)  Well, the tools don't link when C++ bootstrap is
> active.  This is because our whole libbackend is compiled with g++, and
> hence uses the gxx_personality_v0 routines.  But the gnattools are linked
> with a hardcoded ../../xgcc (missing all the C++ libs) leading to the
> symbol not found.  Up to now this accidentally was no problem because g++
> is so nice that if no EH mechanisms are used it doesn't force any
> personality.  I'm not sure what the best fix here is.

Compile with -fno-exceptions?  Generating EH stuff for code that doesn't make 
use of EH at all doesn't look very appealing to me.

-- 
Eric Botcazou

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: Mark objects death at end of scope
  2011-11-03  1:21 ` Eric Botcazou
@ 2011-11-03  9:24   ` Richard Guenther
  2011-11-03 10:26     ` Eric Botcazou
  0 siblings, 1 reply; 30+ messages in thread
From: Richard Guenther @ 2011-11-03  9:24 UTC (permalink / raw)
  To: Eric Botcazou; +Cc: Michael Matz, gcc-patches

On Thu, Nov 3, 2011 at 2:10 AM, Eric Botcazou <ebotcazou@adacore.com> wrote:
>> And there's also one issue with Ada that I need help with: it doesn't
>> build anymore. ;-)  Well, the tools don't link when C++ bootstrap is
>> active.  This is because our whole libbackend is compiled with g++, and
>> hence uses the gxx_personality_v0 routines.  But the gnattools are linked
>> with a hardcoded ../../xgcc (missing all the C++ libs) leading to the
>> symbol not found.  Up to now this accidentally was no problem because g++
>> is so nice that if no EH mechanisms are used it doesn't force any
>> personality.  I'm not sure what the best fix here is.
>
> Compile with -fno-exceptions?  Generating EH stuff for code that doesn't make
> use of EH at all doesn't look very appealing to me.

There is a bug about not using -fexceptions (50857).  If gnattools are
built with
the C++ compiler they should also link with the G++ driver, so that's
worth fixing
anyway I think.

Richard.

> --
> Eric Botcazou
>

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: Mark objects death at end of scope
  2011-11-03  0:05 Mark objects death at end of scope Michael Matz
  2011-11-03  1:21 ` Eric Botcazou
@ 2011-11-03  9:59 ` Richard Guenther
  2011-11-03 11:07   ` Michael Matz
  2011-11-07 16:05   ` Michael Matz
  2011-11-03 10:57 ` Mark objects death at end " Jakub Jelinek
  2 siblings, 2 replies; 30+ messages in thread
From: Richard Guenther @ 2011-11-03  9:59 UTC (permalink / raw)
  To: Michael Matz; +Cc: gcc-patches

On Thu, Nov 3, 2011 at 12:15 AM, Michael Matz <matz@suse.de> wrote:
> Hi,
>
> [Eric, see below for an Ada issue]
>
> so, this is a more complete resubmission of an old patch, trying to get it
> into 4.7.  In order not to have to rely on TREE_BLOCK of variables to
> determine valid sharing (which never really worked that well when all the
> intermediate code movements that could have taken place in the gimple
> optimizers), we make the knowledge explicit in the IL, by emitting clobber
> instructions when variables (that possibly can go into memory) go out of
> scope.  Such a clobber looks like a normal memory store, except that the
> RHS has an indeterminate value, and with bonus point for not moving that
> instruction around too much (in order to not create artificial overlaps
> which never existed in the sources).  A volatile empty CONSTRUCTOR fits
> that quite nicely.
>
> We emit these clobbers at gimplification time by wrapping BIND_EXPR in a
> try/finally block (the clobbers being in the finally part), and let
> gimplification and EH lowering do the hard work.
>
> In some passes we need some tidying to not disable optimizations
> unnecessarily.  At expansion time we use these clobbers to end lifetime
> of local variables (we start life at the first mention of a variables
> name), a normal bitmap pass then creates conflicts.  This is conservative
> in that if a clobber goes missing the respective variable simply will have
> extended lifetime (and therefore more conflicts than necessary, ergo less
> sharing).
>
> I had to change some testcases, because of the use of our EH mechanism to
> implement placing the clobbers (due to the additional cleanup region some
> counts change).
>
> And there's also one issue with Ada that I need help with: it doesn't
> build anymore. ;-)  Well, the tools don't link when C++ bootstrap is
> active.  This is because our whole libbackend is compiled with g++, and
> hence uses the gxx_personality_v0 routines.  But the gnattools are linked
> with a hardcoded ../../xgcc (missing all the C++ libs) leading to the
> symbol not found.  Up to now this accidentally was no problem because g++
> is so nice that if no EH mechanisms are used it doesn't force any
> personality.  I'm not sure what the best fix here is.  The rest of the
> compiler uses COMPILER and LINKER make variables that are set correctly
> depending on bootstrap configuration.  But the gnattools Makefile.in
> doesn't know about these, so I'm don't see how this ever was supposed to
> work.
>
> As for some measurements: buildtime difference for cpu2006 is in the noise
> (19:31 vs 19:30 minutes), runtime we'll see (I once had benchmarked a
> similar patch months ago, it didn't matter).
>
> Regstrapped on x86_64-linux, all languages, but without Ada (see above).
> No regressions.
>
>
> Ciao,
> Michael.
>
>        * gengtype.c (write_field_root): Avoid out-of-scope access of newv.
>
>        * tree.h (TREE_CLOBBER_P): New macro.
>        * 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-stdarg.c (execute_optimize_stdarg): Accept clobbers.
>        * 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-02 21:18:45.000000000 +0100
> +++ gengtype.c  2011-11-02 21:19:51.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 180700)
> +++ tree.h      (working copy)
> @@ -1636,6 +1636,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: gimplify.c
> ===================================================================
> --- gimplify.c.orig     2011-11-02 21:18:45.000000000 +0100
> +++ gimplify.c  2011-11-02 21:19:51.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,49 @@ 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)

I think you want to use auto_var_in_fn () here.

> +         && !DECL_HARD_REGISTER (t)
> +         && !TREE_THIS_VOLATILE (t)

Any reason for that?

> +         && !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))

Looking at the predicate this will exclude non-address-taken aggregates.
We talked about this as an optimization, but that would need a real computation
of a life problem for those.  Thus, does this mean that
non-address-taken aggregates
won't get their stack slots shared right now?

> +       {
> +         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-02 21:18:45.000000000 +0100
> +++ cfgexpand.c 2011-11-02 23:14:17.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;

Use uintptr_t.

>   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,164 @@ 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_assign_single_p (stmt)
> +         && TREE_CLOBBER_P (gimple_assign_rhs1 (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 +1266,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 +1275,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 +1465,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 +1621,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 +2130,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 +3326,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-stdarg.c
> ===================================================================
> --- tree-stdarg.c.orig  2011-11-02 21:18:45.000000000 +0100
> +++ tree-stdarg.c       2011-11-02 21:19:51.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-02 21:18:45.000000000 +0100
> +++ tree-ssa-live.c     2011-11-02 21:19:51.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,13 @@ remove_unused_locals (void)
>          if (is_gimple_debug (stmt))
>            continue;
>
> +         if (gimple_assign_single_p (stmt)
> +             && TREE_CLOBBER_P (gimple_assign_rhs1 (stmt)))

Can you introduce a gimple_clobber_p (stmt) predicate for this?
(not sure if I like "clobber" too much, that sounds like a may-kill
while this should have the semantic of a true kill operation, thus,
maybe change s/clobber/kill/ throughout the patch?)

> +           {
> +             have_local_clobbers = true;
> +             continue;
> +           }
> +
>          if (b)
>            TREE_USED (b) = true;
>
> @@ -753,6 +761,42 @@ 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_assign_single_p (stmt)
> +               && TREE_CLOBBER_P (gimple_assign_rhs1 (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-02 21:18:45.000000000 +0100
> +++ tree-sra.c  2011-11-02 21:19:51.000000000 +0100
> @@ -1112,6 +1112,10 @@ build_accesses_from_assign (gimple stmt)
>   if (disqualify_ops_if_throwing_stmt (stmt, lhs, rhs))
>     return false;
>
> +  /* Scope clobbers don't influence scalarization.  */
> +  if (TREE_CLOBBER_P (rhs))
> +    return false;
> +
>   racc = build_access_from_expr_1 (rhs, stmt, false);
>   lacc = build_access_from_expr_1 (lhs, stmt, true);
>
> Index: tree-ssa-dce.c
> ===================================================================
> --- tree-ssa-dce.c.orig 2011-11-02 21:18:45.000000000 +0100
> +++ tree-ssa-dce.c      2011-11-02 21:19:51.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-02 21:18:45.000000000 +0100
> +++ gimple.c    2011-11-02 21:19:51.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-02 21:18:45.000000000 +0100
> +++ tree-ssa-structalias.c      2011-11-02 21:19:51.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-operands.c
> ===================================================================
> --- tree-ssa-operands.c.orig    2011-11-02 21:18:45.000000000 +0100
> +++ tree-ssa-operands.c 2011-11-02 21:19:51.000000000 +0100
> @@ -956,6 +956,9 @@ get_expr_operands (gimple stmt, tree *ex
>        constructor_elt *ce;
>        unsigned HOST_WIDE_INT idx;
>
> +       if (TREE_THIS_VOLATILE (expr))
> +         gimple_set_has_volatile_ops (stmt, true);
> +

Please add a comment before this.  volatile constructors look weird.

>        for (idx = 0;
>             VEC_iterate (constructor_elt, CONSTRUCTOR_ELTS (expr), idx, ce);
>             idx++)
> Index: tree-ssa-phiopt.c
> ===================================================================
> --- tree-ssa-phiopt.c.orig      2011-09-01 14:01:13.000000000 +0200
> +++ tree-ssa-phiopt.c   2011-11-02 23:22:17.000000000 +0100
> @@ -1318,8 +1318,10 @@ cond_if_else_store_replacement_1 (basic_
>
>   if (then_assign == NULL
>       || !gimple_assign_single_p (then_assign)
> +      || TREE_CLOBBER_P (gimple_assign_rhs1 (then_assign))
>       || else_assign == NULL
> -      || !gimple_assign_single_p (else_assign))
> +      || !gimple_assign_single_p (else_assign)
> +      || TREE_CLOBBER_P (gimple_assign_rhs1 (else_assign)))
>     return false;
>
>   lhs = gimple_assign_lhs (then_assign);
> Index: tree-ssa-sccvn.c
> ===================================================================
> --- tree-ssa-sccvn.c.orig       2011-11-02 21:18:45.000000000 +0100
> +++ tree-ssa-sccvn.c    2011-11-02 21:19:51.000000000 +0100
> @@ -1422,6 +1422,7 @@ vn_reference_lookup_3 (ao_ref *ref, tree
>   else if (is_gimple_reg_type (vr->type)
>           && gimple_assign_single_p (def_stmt)
>           && gimple_assign_rhs_code (def_stmt) == CONSTRUCTOR
> +          && !TREE_CLOBBER_P (gimple_assign_rhs1 (def_stmt))

Does that really matter?  We can as well assume zeros for the new content.  OTOH
we shouldn't ever come here ...

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.

Thanks,
Richard.

>           && CONSTRUCTOR_NELTS (gimple_assign_rhs1 (def_stmt)) == 0)
>     {
>       tree base2;
> Index: testsuite/gcc.dg/tree-ssa/20031015-1.c
> ===================================================================
> --- testsuite/gcc.dg/tree-ssa/20031015-1.c.orig 2011-11-02 21:18:45.000000000 +0100
> +++ testsuite/gcc.dg/tree-ssa/20031015-1.c      2011-11-02 21:19:51.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-02 21:18:45.000000000 +0100
> +++ testsuite/g++.dg/tree-ssa/ehcleanup-1.C     2011-11-02 21:19:51.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-02 21:18:45.000000000 +0100
> +++ testsuite/g++.dg/eh/builtin1.C      2011-11-02 21:19:51.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-02 21:18:45.000000000 +0100
> +++ testsuite/g++.dg/eh/builtin2.C      2011-11-02 21:19:51.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-02 21:18:45.000000000 +0100
> +++ testsuite/g++.dg/eh/builtin3.C      2011-11-02 21:19:51.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" } } */
>

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: Mark objects death at end of scope
  2011-11-03  9:24   ` Richard Guenther
@ 2011-11-03 10:26     ` Eric Botcazou
  2011-11-03 12:52       ` Richard Guenther
  2011-11-03 14:23       ` Build gcc/ with -fno-exceptions -fno-rtti Michael Matz
  0 siblings, 2 replies; 30+ messages in thread
From: Eric Botcazou @ 2011-11-03 10:26 UTC (permalink / raw)
  To: Richard Guenther; +Cc: gcc-patches, Michael Matz

> There is a bug about not using -fexceptions (50857).

Then let's fix it, as you said there "We fail to pass -fno-exceptions -fno-rtti 
to g++ for stage2 and stage3 building the host binaries.  That leads to 
increased compile-time and possibly runtime."  And now that will be worse.

> If gnattools are built with the C++ compiler they should also link with the
> G++ driver, so that's  worth fixing anyway I think.

gnattools is built with the C compiler, but it reuses a couple of object files 
of libbackend.a that are now compiled with C++.

-- 
Eric Botcazou

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: Mark objects death at end of scope
  2011-11-03  0:05 Mark objects death at end of scope Michael Matz
  2011-11-03  1:21 ` Eric Botcazou
  2011-11-03  9:59 ` Mark objects death at end of scope Richard Guenther
@ 2011-11-03 10:57 ` Jakub Jelinek
  2011-11-03 11:57   ` Michael Matz
  2 siblings, 1 reply; 30+ messages in thread
From: Jakub Jelinek @ 2011-11-03 10:57 UTC (permalink / raw)
  To: Michael Matz; +Cc: gcc-patches

On Thu, Nov 03, 2011 at 12:15:49AM +0100, Michael Matz wrote:
> And there's also one issue with Ada that I need help with: it doesn't 
> build anymore. ;-)  Well, the tools don't link when C++ bootstrap is 
> active.  This is because our whole libbackend is compiled with g++, and 
> hence uses the gxx_personality_v0 routines.  But the gnattools are linked 
> with a hardcoded ../../xgcc (missing all the C++ libs) leading to the 
> symbol not found.  Up to now this accidentally was no problem because g++ 
> is so nice that if no EH mechanisms are used it doesn't force any 
> personality.  I'm not sure what the best fix here is.  The rest of the 
> compiler uses COMPILER and LINKER make variables that are set correctly 
> depending on bootstrap configuration.  But the gnattools Makefile.in 
> doesn't know about these, so I'm don't see how this ever was supposed to 
> work.

I must say I'm worried a little bit about using EH for something that isn't
EH at all in the source.  Do your artificial EH regions survive into
.gcc_except_table, or is it just that when we are deciding whether to use
any personality routine at all they are still present and thus we decide to
use the personality routine?  If the latter, perhaps we could mark those
artificial regions with some flag and disregard them for the decision
whether we need a personality routine or not.  If we force a use of a
personality routine to every C++ file compiled without -fexceptions, it
would mean .eh_frame would grow unnecessarily.

	Jakub

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: Mark objects death at end of scope
  2011-11-03  9:59 ` Mark objects death at end of scope Richard Guenther
@ 2011-11-03 11:07   ` Michael Matz
  2011-11-07 16:05   ` Michael Matz
  1 sibling, 0 replies; 30+ messages in thread
From: Michael Matz @ 2011-11-03 11:07 UTC (permalink / raw)
  To: Richard Guenther; +Cc: gcc-patches

[-- Attachment #1: Type: TEXT/PLAIN, Size: 3971 bytes --]

Hi,

On Thu, 3 Nov 2011, Richard Guenther wrote:

> > +  /* 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)
> 
> I think you want to use auto_var_in_fn () here.

I don't think so.  It accepts LABEL_DECLs (and others, though I'm only 
interested in VAR_DECLs here), and barring the check on DECL_CONTEXT 
(which I don't need) it's exactly equivalent to !is_global_var.

> > +         && !DECL_HARD_REGISTER (t)
> > +         && !TREE_THIS_VOLATILE (t)
> 
> Any reason for that?

We must not introduce new writes (which the clobbers are) to 
volatile storage.  And HARD_REGs obviously never will be placed on the 
stack.

> > +         && !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))
> 
> Looking at the predicate this will exclude non-address-taken aggregates. 
> We talked about this as an optimization, but that would need a real 
> computation of a life problem for those.

Hmm?  The whole thing would work exactly the same for address-taken and 
non-address-taken aggregates.

> Thus, does this mean that non-address-taken aggregates won't get their 
> stack slots shared right now?

Correct.  I considered them unimportant enough to not deserve the special 
treatment.  There aren't many things you can do with non-address-taken 
aggregates that SRA wouldn't decompose.

> > +  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;
> 
> Use uintptr_t.

Oh?  Since when can we use that?  It's used nowhere else in GCC.

> > +         if (gimple_assign_single_p (stmt)
> > +             && TREE_CLOBBER_P (gimple_assign_rhs1 (stmt)))
> 
> Can you introduce a gimple_clobber_p (stmt) predicate for this?

Yes.

> (not sure if I like "clobber" too much, that sounds like a may-kill
> while this should have the semantic of a true kill operation, thus,
> maybe change s/clobber/kill/ throughout the patch?)

Ah, bikeshedding :) A clobber is indeed a may-kill.  The indeterminate 
value stored into it may as well be the original content (without that 
it's a must-kill).  Like for a kill, which also seems to imply an 
indeterminate value.  From that perspective also a kill is a may-kill, or 
IOW "clobber" and "kill" are equivalent.  I don't like the notion of 
"killing" variables or storage, they remain in existence, just the 
contents aren't, I really prefer clobber.

> > Index: tree-ssa-sccvn.c
> > ===================================================================
> > --- tree-ssa-sccvn.c.orig       2011-11-02 21:18:45.000000000 +0100
> > +++ tree-ssa-sccvn.c    2011-11-02 21:19:51.000000000 +0100
> > @@ -1422,6 +1422,7 @@ vn_reference_lookup_3 (ao_ref *ref, tree
> >   else if (is_gimple_reg_type (vr->type)
> >           && gimple_assign_single_p (def_stmt)
> >           && gimple_assign_rhs_code (def_stmt) == CONSTRUCTOR
> > +          && !TREE_CLOBBER_P (gimple_assign_rhs1 (def_stmt))
> 
> Does that really matter?  We can as well assume zeros for the new content.

No, we cannot.  If we assume so then a second store also storing zeros 
into it might be removed because it's "already filled with zeros", where 
at runtime this doesn't hold and the second store would have been 
significant:

for (i<N) { aggr.i=0; use(&aggr); aggr <= clobber }
-->
aggr.i=0; for (i<N) { use(&aggr); aggr <= clobber }


Ciao,
Michael.

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: Mark objects death at end of scope
  2011-11-03 10:57 ` Mark objects death at end " Jakub Jelinek
@ 2011-11-03 11:57   ` Michael Matz
  2011-11-03 12:47     ` Jakub Jelinek
  0 siblings, 1 reply; 30+ messages in thread
From: Michael Matz @ 2011-11-03 11:57 UTC (permalink / raw)
  To: Jakub Jelinek; +Cc: gcc-patches

Hi,

On Thu, 3 Nov 2011, Jakub Jelinek wrote:

> > personality.  I'm not sure what the best fix here is.  The rest of the 
> > compiler uses COMPILER and LINKER make variables that are set 
> > correctly depending on bootstrap configuration.  But the gnattools 
> > Makefile.in doesn't know about these, so I'm don't see how this ever 
> > was supposed to work.
> 
> I must say I'm worried a little bit about using EH for something that 
> isn't EH at all in the source.

(see below for -fno-exceptions)

The point is, if I wouldn't rely on our existing cleanups handling I'd 
have to do exactly the same work via some other means with the same 
effects.  The clobbers need to be emitted at any possible scope exit path, 
including the EH exits (well, strictly speaking they don't _have_ to be, 
but then the lifetime will extend until function end, and cause 
unnecessary non-sharing).

> Do your artificial EH regions survive into .gcc_except_table,

It's possible.  At expansion time the clobbers expand to nothing, so those 
regions theoretically are mergeable with outer regions, but we don't have 
EH cleanups on RTL anymore.

> or is it just that when we are deciding whether to use any personality 
> routine at all they are still present and thus we decide to use the 
> personality routine?

That is the case, yes.

> If the latter, perhaps we could mark those artificial regions with some 
> flag and disregard them for the decision whether we need a personality 
> routine or not.

That's possible I guess, but is it worth it?  A file compiled with g++ is 
completely fine in requiring the c++ personality.  Disabling this for some 
special cases just seems like a hack.

> If we force a use of a personality routine to every C++ 
> file compiled without -fexceptions, it would mean .eh_frame would grow 
> unnecessarily.

With -fno-exceptions no personality routine is forced, and no cleanup 
regions remain.  The Ada problem is, that we don't compile our middle-end 
with -fno-exceptions.


Ciao,
Michael.

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: Mark objects death at end of scope
  2011-11-03 11:57   ` Michael Matz
@ 2011-11-03 12:47     ` Jakub Jelinek
  2011-11-03 13:14       ` Michael Matz
  0 siblings, 1 reply; 30+ messages in thread
From: Jakub Jelinek @ 2011-11-03 12:47 UTC (permalink / raw)
  To: Michael Matz; +Cc: gcc-patches

On Thu, Nov 03, 2011 at 12:01:05PM +0100, Michael Matz wrote:
> > Do your artificial EH regions survive into .gcc_except_table,
> 
> It's possible.  At expansion time the clobbers expand to nothing, so those 
> regions theoretically are mergeable with outer regions, but we don't have 
> EH cleanups on RTL anymore.

That is unfortunate.  Can't EH cleanups be taught about these stmts
and optimize them as if those clobbering stmts weren't present?
I.e. similarly to the VTA first rule, don't base decisions on their
presence, and just take them into account when doing the transformation
if decided it should be done?

> That's possible I guess, but is it worth it?  A file compiled with g++ is 
> completely fine in requiring the c++ personality.  Disabling this for some 
> special cases just seems like a hack.

It is important, for several tools the size of .eh_frame section matters a
lot (e.g. when you need to pin all the .eh_frame/.eh_frame_hdr
sections into memory for kernel unwinding).

	Jakub

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: Mark objects death at end of scope
  2011-11-03 10:26     ` Eric Botcazou
@ 2011-11-03 12:52       ` Richard Guenther
  2011-11-03 13:42         ` Michael Matz
  2011-11-03 14:23       ` Build gcc/ with -fno-exceptions -fno-rtti Michael Matz
  1 sibling, 1 reply; 30+ messages in thread
From: Richard Guenther @ 2011-11-03 12:52 UTC (permalink / raw)
  To: Eric Botcazou; +Cc: gcc-patches, Michael Matz

On Thu, Nov 3, 2011 at 10:23 AM, Eric Botcazou <ebotcazou@adacore.com> wrote:
>> There is a bug about not using -fexceptions (50857).
>
> Then let's fix it, as you said there "We fail to pass -fno-exceptions -fno-rtti
> to g++ for stage2 and stage3 building the host binaries.  That leads to
> increased compile-time and possibly runtime."  And now that will be worse.
>
>> If gnattools are built with the C++ compiler they should also link with the
>> G++ driver, so that's  worth fixing anyway I think.
>
> gnattools is built with the C compiler, but it reuses a couple of object files
> of libbackend.a that are now compiled with C++.

Hmm, maybe we should re-build them with the C compiler then?  What
are these common object files?

Richard.

> --
> Eric Botcazou
>

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: Mark objects death at end of scope
  2011-11-03 12:47     ` Jakub Jelinek
@ 2011-11-03 13:14       ` Michael Matz
  2011-11-04 12:28         ` Jakub Jelinek
  0 siblings, 1 reply; 30+ messages in thread
From: Michael Matz @ 2011-11-03 13:14 UTC (permalink / raw)
  To: Jakub Jelinek; +Cc: gcc-patches

Hi,

On Thu, 3 Nov 2011, Jakub Jelinek wrote:

> > It's possible.  At expansion time the clobbers expand to nothing, so 
> > those regions theoretically are mergeable with outer regions, but we 
> > don't have EH cleanups on RTL anymore.
> 
> That is unfortunate.  Can't EH cleanups be taught about these stmts and 
> optimize them as if those clobbering stmts weren't present? I.e. 
> similarly to the VTA first rule, don't base decisions on their presence, 
> and just take them into account when doing the transformation if decided 
> it should be done?

Perhaps that's possible, though I don't immediately see how in the general 
case; I don't want to tackle this as part of the patch unless absolutely 
required.  Let's take a typical example:

# cat x.cc
struct A { A(); ~A(); int i[10];};
extern void callme (int*);
int foo (int cond)
{
  if (cond)
    {
      A a;
      callme (a.i);
    }
}

That's gimplified like so:
# cat x.cc.004.gimple
int foo(int) (int cond)
{
  {
    if (cond != 0) goto <D.2113>; else goto <D.2114>;
    <D.2113>:
    {
      struct A a;

      try
        {
          A::A (&a);
          try
            {
              callme (&a.i);   //1
            }
          finally
            {
              A::~A (&a);      //2
            }
                               //3
        }
      finally
        {
          a = {};
        }
    }
    goto <D.2115>;
    <D.2114>:
    <D.2115>:
  }
}

There are three exits of the scope that must somehow reach the clobber, 
callme can throw, the dtor can throw, and the fall thru.  Right now 
ehcleanup does this:

After removal of unreachable regions:
Eh tree:
   1 cleanup land:{1,<L4>}
     3 must_not_throw
     2 cleanup land:{2,<L3>}
int foo(int) (int cond)
{
  struct A a;

<bb 2>:
  if (cond_1(D) != 0)
    goto <bb 3>;
  else
    goto <bb 7>;

<bb 3>:
  A::A (&a);

<bb 4>:
  callme (&a.i);

<bb 5>:
  A::~A (&a);

<bb 6>:
  a ={v} {};

<bb 7>:
  return;

<L3>:
  A::~A (&a);
  resx 2

<L4>:
  a ={v} {};
  resx 1
}

L4 is the landing pad that is reached by resx 2 and by the throwing dtor.  
Now, suppose we would be somehow removing that region.  We need places to 
put the clobber to, we can't move it upward, because while the edge L3->L4 
is explicit (and we could move the clobber there) the edge bb5->L4 isn't.

In this specific case we could notice that resx1 actually is the outermost 
resume, hence only will leave the function and therefore the clobber is 
useless (as in, moving them down actually removes them from the function 
body).  But suppose the whole code above would itself be contained in some 
other region to which the resx1 would lead.  We could move the clobber 
there (and to the fall thru path that skips that region, which is the case 
with catch region), that it safe (outer cleanup regions are always outer 
or following scopes, and moving clobber outwards or lower is 
conservatively correct), but extends the life area of the variables in 
question.

> > That's possible I guess, but is it worth it?  A file compiled with g++ is 
> > completely fine in requiring the c++ personality.  Disabling this for some 
> > special cases just seems like a hack.
> 
> It is important, for several tools the size of .eh_frame section matters a
> lot (e.g. when you need to pin all the .eh_frame/.eh_frame_hdr
> sections into memory for kernel unwinding).

I suppose I could disable generating the clobbers for the outermost scopes 
(hence no outer try/finally pair), which requires extending the inliner to 
generate those clobbers at inlining time.

The other possibility would be removing the clobbers (all of them) right 
before ehcleanup2 (shortly before expand) and somehow remember the edges 
over which the variables die.  That seems a bit fragile as there are some 
more passes between them that fiddle with edges.


Ciao,
Michael.

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: Mark objects death at end of scope
  2011-11-03 12:52       ` Richard Guenther
@ 2011-11-03 13:42         ` Michael Matz
  2011-11-03 14:33           ` Eric Botcazou
  0 siblings, 1 reply; 30+ messages in thread
From: Michael Matz @ 2011-11-03 13:42 UTC (permalink / raw)
  To: Richard Guenther; +Cc: Eric Botcazou, gcc-patches

[-- Attachment #1: Type: TEXT/PLAIN, Size: 769 bytes --]

Hi,

On Thu, 3 Nov 2011, Richard Guenther wrote:

> >> If gnattools are built with the C++ compiler they should also link 
> >> with the G++ driver, so that's  worth fixing anyway I think.
> >
> > gnattools is built with the C compiler, but it reuses a couple of 
> > object files of libbackend.a that are now compiled with C++.
> 
> Hmm, maybe we should re-build them with the C compiler then?  What are 
> these common object files?

libcpp and libcommon and libcommon-target, the latter are:

diagnostic.o pretty-print.o intl.o input.o version.o
prefix.o params.o opts.o opts-common.o options.o vec.o hooks.o 
common/common-targhooks.o
<target>-common.o

Doesn't read as if these were good candidates to compile with C only when 
the rest is C++.


Ciao,
Michael.

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Build gcc/ with -fno-exceptions -fno-rtti
  2011-11-03 10:26     ` Eric Botcazou
  2011-11-03 12:52       ` Richard Guenther
@ 2011-11-03 14:23       ` Michael Matz
  2011-11-03 14:26         ` Paolo Bonzini
  1 sibling, 1 reply; 30+ messages in thread
From: Michael Matz @ 2011-11-03 14:23 UTC (permalink / raw)
  To: Paolo Bonzini, Ralf.Wildenhues
  Cc: Eric Botcazou, Richard Guenther, Ian Lance Taylor, gcc-patches

Hi,


On Thu, 3 Nov 2011, Eric Botcazou wrote:

> > There is a bug about not using -fexceptions (50857).
> 
> Then let's fix it, as you said there "We fail to pass -fno-exceptions 
> -fno-rtti to g++ for stage2 and stage3 building the host binaries.  
> That leads to increased compile-time and possibly runtime."

This follows Ians suggestion from PR50857, testing in libcpp/ and gcc/ if 
-fno-exceptions and -fno-rtti work with the compiler, and add them to 
ALL_CXXFLAGS.  It does fix bootstrap with c,c++,ada and my patch.  No yet 
put through an all-language bootstrap of testsuite.  What do you think?
(I also looked at doing this from top-level configure/Makefile/whatever, 
but that's too complicated for me it seems).


Ciao,
Michael.

libcpp/
	* configure.ac: Check for -fno-exceptions -fno-rtti.
	* configure: Regenerate.
	* Makefile.in (NOEXCEPTION_FLAGS): New flag.
	(ALL_CXXFLAGS): Use it.

gcc/
	* configure.ac: Check for -fno-exceptions -fno-rtti.
	* configure: Regenerate.
	* Makefile.in (NOEXCEPTION_FLAGS): New flag.
	(ALL_CXXFLAGS): Use it.
	
Index: libcpp/configure.ac
===================================================================
--- libcpp/configure.ac	(revision 180700)
+++ libcpp/configure.ac	(working copy)
@@ -39,6 +39,10 @@ ACX_PROG_CC_WARNING_OPTS([-Wstrict-proto
 			  -Wold-style-definition -Wc++-compat], [c_warn])
 ACX_PROG_CC_WARNING_ALMOST_PEDANTIC([-Wno-long-long])
 
+# Disable exceptions and RTTI if building with g++
+ACX_PROG_CC_WARNING_OPTS(
+       m4_quote(m4_do([-fno-exceptions -fno-rtti])), [noexception_flags])
+
 # Only enable with --enable-werror-always until existing warnings are
 # corrected.
 ACX_PROG_CC_WARNINGS_ARE_ERRORS([manual])
Index: libcpp/Makefile.in
===================================================================
--- libcpp/Makefile.in	(revision 180700)
+++ libcpp/Makefile.in	(working copy)
@@ -56,6 +56,7 @@ XGETTEXT = @XGETTEXT@
 CCDEPMODE = @CCDEPMODE@
 CXXDEPMODE = @CXXDEPMODE@
 DEPDIR = @DEPDIR@
+NOEXCEPTION_FLAGS = @noexception_flags@
 
 datarootdir = @datarootdir@
 datadir = @datadir@
@@ -72,7 +73,8 @@ INCLUDES = -I$(srcdir) -I. -I$(srcdir)/.
 	-I$(srcdir)/include
 
 ALL_CFLAGS = $(CFLAGS) $(WARN_CFLAGS) $(INCLUDES) $(CPPFLAGS)
-ALL_CXXFLAGS = $(CXXFLAGS) $(WARN_CXXFLAGS) $(INCLUDES) $(CPPFLAGS)
+ALL_CXXFLAGS = $(CXXFLAGS) $(WARN_CXXFLAGS) $(NOEXCEPTION_FLAGS) $(INCLUDES) \
+	$(CPPFLAGS)
 
 # The name of the compiler to use.
 ENABLE_BUILD_WITH_CXX = @ENABLE_BUILD_WITH_CXX@
Index: gcc/configure.ac
===================================================================
--- gcc/configure.ac	(revision 180700)
+++ gcc/configure.ac	(working copy)
@@ -357,6 +357,10 @@ fi
 AC_SUBST(warn_cflags)
 AC_SUBST(warn_cxxflags)
 
+# Disable exceptions and RTTI if building with g++
+ACX_PROG_CC_WARNING_OPTS(
+	m4_quote(m4_do([-fno-exceptions -fno-rtti])), [noexception_flags])
+	
 # Enable expensive internal checks
 is_release=
 if test x"`cat $srcdir/DEV-PHASE`" != xexperimental; then
Index: gcc/Makefile.in
===================================================================
--- gcc/Makefile.in	(revision 180700)
+++ gcc/Makefile.in	(working copy)
@@ -164,6 +164,8 @@ C_STRICT_WARN = @c_strict_warn@
 # "extern" tags in header files.
 NOCOMMON_FLAG = @nocommon_flag@
 
+NOEXCEPTION_FLAGS = @noexception_flags@
+
 # This is set by --disable-maintainer-mode (default) to "#"
 # FIXME: 'MAINT' will always be set to an empty string, no matter if
 # --disable-maintainer-mode is used or not.  This is because the
@@ -1033,7 +1035,7 @@ ALL_CFLAGS = $(T_CFLAGS) $(CFLAGS-$@) \
 
 # The C++ version.
 ALL_CXXFLAGS = $(T_CFLAGS) $(CFLAGS-$@) $(CXXFLAGS) $(INTERNAL_CFLAGS) \
-  $(COVERAGE_FLAGS) $(WARN_CXXFLAGS) @DEFS@
+  $(COVERAGE_FLAGS) $(NOEXCEPTION_FLAGS) $(WARN_CXXFLAGS) @DEFS@
 
 # Likewise.  Put INCLUDES at the beginning: this way, if some autoconf macro
 # puts -I options in CPPFLAGS, our include files in the srcdir will always

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: Build gcc/ with -fno-exceptions -fno-rtti
  2011-11-03 14:23       ` Build gcc/ with -fno-exceptions -fno-rtti Michael Matz
@ 2011-11-03 14:26         ` Paolo Bonzini
  2011-11-03 14:31           ` Richard Guenther
  0 siblings, 1 reply; 30+ messages in thread
From: Paolo Bonzini @ 2011-11-03 14:26 UTC (permalink / raw)
  To: Michael Matz
  Cc: Ralf.Wildenhues, Eric Botcazou, Richard Guenther,
	Ian Lance Taylor, gcc-patches

On 11/03/2011 03:16 PM, Michael Matz wrote:
>
>>> >  >  There is a bug about not using -fexceptions (50857).
>> >
>> >  Then let's fix it, as you said there "We fail to pass -fno-exceptions
>> >  -fno-rtti to g++ for stage2 and stage3 building the host binaries.
>> >  That leads to increased compile-time and possibly runtime."
> This follows Ians suggestion from PR50857, testing in libcpp/ and gcc/ if
> -fno-exceptions and -fno-rtti work with the compiler, and add them to
> ALL_CXXFLAGS.  It does fix bootstrap with c,c++,ada and my patch.  No yet
> put through an all-language bootstrap of testsuite.  What do you think?
> (I also looked at doing this from top-level configure/Makefile/whatever,
> but that's too complicated for me it seems).

I think it's good this way.  We know the subset of C++ we use (aka C) 
doesn't have either exceptions or RTTI.

Paolo

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: Build gcc/ with -fno-exceptions -fno-rtti
  2011-11-03 14:26         ` Paolo Bonzini
@ 2011-11-03 14:31           ` Richard Guenther
  2011-11-03 15:08             ` Eric Botcazou
  0 siblings, 1 reply; 30+ messages in thread
From: Richard Guenther @ 2011-11-03 14:31 UTC (permalink / raw)
  To: Paolo Bonzini
  Cc: Michael Matz, Ralf.Wildenhues, Eric Botcazou, Ian Lance Taylor,
	gcc-patches

On Thu, Nov 3, 2011 at 3:19 PM, Paolo Bonzini <bonzini@gnu.org> wrote:
> On 11/03/2011 03:16 PM, Michael Matz wrote:
>>
>>>> >  >  There is a bug about not using -fexceptions (50857).
>>>
>>> >
>>> >  Then let's fix it, as you said there "We fail to pass -fno-exceptions
>>> >  -fno-rtti to g++ for stage2 and stage3 building the host binaries.
>>> >  That leads to increased compile-time and possibly runtime."
>>
>> This follows Ians suggestion from PR50857, testing in libcpp/ and gcc/ if
>> -fno-exceptions and -fno-rtti work with the compiler, and add them to
>> ALL_CXXFLAGS.  It does fix bootstrap with c,c++,ada and my patch.  No yet
>> put through an all-language bootstrap of testsuite.  What do you think?
>> (I also looked at doing this from top-level configure/Makefile/whatever,
>> but that's too complicated for me it seems).
>
> I think it's good this way.  We know the subset of C++ we use (aka C)
> doesn't have either exceptions or RTTI.

Yes.  It's also one of the premises of switching to C++, not use that
features (intially at least).

Thus, ok if it passes some testing.

Richard.

> Paolo
>

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: Mark objects death at end of scope
  2011-11-03 13:42         ` Michael Matz
@ 2011-11-03 14:33           ` Eric Botcazou
  2011-11-03 14:46             ` Michael Matz
  0 siblings, 1 reply; 30+ messages in thread
From: Eric Botcazou @ 2011-11-03 14:33 UTC (permalink / raw)
  To: Michael Matz; +Cc: Richard Guenther, gcc-patches

> libcpp and libcommon and libcommon-target, the latter are:
>
> diagnostic.o pretty-print.o intl.o input.o version.o
> prefix.o params.o opts.o opts-common.o options.o vec.o hooks.o
> common/common-targhooks.o
> <target>-common.o
>
> Doesn't read as if these were good candidates to compile with C only when
> the rest is C++.

Yes, compiling everything with -fno-exceptions seems by far the simplest route.

-- 
Eric Botcazou

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: Mark objects death at end of scope
  2011-11-03 14:33           ` Eric Botcazou
@ 2011-11-03 14:46             ` Michael Matz
  2011-11-03 14:55               ` Eric Botcazou
  0 siblings, 1 reply; 30+ messages in thread
From: Michael Matz @ 2011-11-03 14:46 UTC (permalink / raw)
  To: Eric Botcazou; +Cc: Richard Guenther, gcc-patches

Hi,

On Thu, 3 Nov 2011, Eric Botcazou wrote:

> > libcpp and libcommon and libcommon-target, the latter are:
> >
> > diagnostic.o pretty-print.o intl.o input.o version.o
> > prefix.o params.o opts.o opts-common.o options.o vec.o hooks.o
> > common/common-targhooks.o
> > <target>-common.o
> >
> > Doesn't read as if these were good candidates to compile with C only when
> > the rest is C++.
> 
> Yes, compiling everything with -fno-exceptions seems by far the simplest 
> route.

Note, though, that eventually you'll probably have to link with g++ for 
real anyway, as soon as somebody starts using c++ features in those files.
Meanwhile I've put the -fno-exceptions flag to real testing, will commit 
if that succeeds.


Ciao,
Michael.

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: Mark objects death at end of scope
  2011-11-03 14:46             ` Michael Matz
@ 2011-11-03 14:55               ` Eric Botcazou
  0 siblings, 0 replies; 30+ messages in thread
From: Eric Botcazou @ 2011-11-03 14:55 UTC (permalink / raw)
  To: Michael Matz; +Cc: Richard Guenther, gcc-patches

> Note, though, that eventually you'll probably have to link with g++ for
> real anyway, as soon as somebody starts using c++ features in those files.

Given the current pace, probably at the end of the decade, yes. :-)

> Meanwhile I've put the -fno-exceptions flag to real testing, will commit
> if that succeeds.

Thanks a lot.

-- 
Eric Botcazou

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: Build gcc/ with -fno-exceptions -fno-rtti
  2011-11-03 14:31           ` Richard Guenther
@ 2011-11-03 15:08             ` Eric Botcazou
  2011-11-03 17:46               ` Michael Matz
  0 siblings, 1 reply; 30+ messages in thread
From: Eric Botcazou @ 2011-11-03 15:08 UTC (permalink / raw)
  To: Richard Guenther
  Cc: Paolo Bonzini, Michael Matz, Ralf.Wildenhues, Ian Lance Taylor,
	gcc-patches

> Thus, ok if it passes some testing.

And with PR bootstrap/50857 in the ChangeLog for extra brownie points.

-- 
Eric Botcazou

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: Build gcc/ with -fno-exceptions -fno-rtti
  2011-11-03 15:08             ` Eric Botcazou
@ 2011-11-03 17:46               ` Michael Matz
  0 siblings, 0 replies; 30+ messages in thread
From: Michael Matz @ 2011-11-03 17:46 UTC (permalink / raw)
  To: Eric Botcazou
  Cc: Richard Guenther, Paolo Bonzini, Ralf.Wildenhues,
	Ian Lance Taylor, gcc-patches

Hi,

On Thu, 3 Nov 2011, Eric Botcazou wrote:

> > Thus, ok if it passes some testing.
> 
> And with PR bootstrap/50857 in the ChangeLog for extra brownie points.

r180833.


Ciao,
Michael.

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: Mark objects death at end of scope
  2011-11-03 13:14       ` Michael Matz
@ 2011-11-04 12:28         ` Jakub Jelinek
  2011-11-04 12:45           ` Jakub Jelinek
  0 siblings, 1 reply; 30+ messages in thread
From: Jakub Jelinek @ 2011-11-04 12:28 UTC (permalink / raw)
  To: Michael Matz; +Cc: gcc-patches

On Thu, Nov 03, 2011 at 02:07:31PM +0100, Michael Matz wrote:
> In this specific case we could notice that resx1 actually is the outermost 
> resume, hence only will leave the function and therefore the clobber is 
> useless (as in, moving them down actually removes them from the function 
> body).  But suppose the whole code above would itself be contained in some 
> other region to which the resx1 would lead.  We could move the clobber 
> there (and to the fall thru path that skips that region, which is the case 
> with catch region), that it safe (outer cleanup regions are always outer 
> or following scopes, and moving clobber outwards or lower is 
> conservatively correct), but extends the life area of the variables in 
> question.

Well, for just the clobber stmts followed by resx that isn't caught in the
function at least we definitely shouldn't catch it, do nothing and rethrow.

struct POD { char a[10]; };
extern void bar (POD *);
extern void baz ();

void
foo (bool cond)
{
  if (cond)
    {
      POD pod;
      bar (&pod);
    }
  baz ();
}

I'd certainly hope we don't generate here any catch/rethrow (similarly for
non-PODs with trivial dtors).

> The other possibility would be removing the clobbers (all of them) right 
> before ehcleanup2 (shortly before expand) and somehow remember the edges 
> over which the variables die.  That seems a bit fragile as there are some 
> more passes between them that fiddle with edges.

Can't you, if you detect only clobber stmts followed up by rethrow, just
move the clobber stmts to where the throw would be caught resp. remove if
not caught?

	Jakub

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: Mark objects death at end of scope
  2011-11-04 12:28         ` Jakub Jelinek
@ 2011-11-04 12:45           ` Jakub Jelinek
  0 siblings, 0 replies; 30+ messages in thread
From: Jakub Jelinek @ 2011-11-04 12:45 UTC (permalink / raw)
  To: Michael Matz; +Cc: gcc-patches

On Fri, Nov 04, 2011 at 12:39:47PM +0100, Jakub Jelinek wrote:
> Well, for just the clobber stmts followed by resx that isn't caught in the
> function at least we definitely shouldn't catch it, do nothing and rethrow.

Forgot to mention, I'm not opposing the inclusion of your patch at this
point until something is done about it, I just hope that something will be
done about it during stage3.  After all, if the extra rethrow pads will
be emitted somewhere, it will be a regression and thus it will be possible
to fix it.

	Jakub

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: Mark objects death at end of scope
  2011-11-03  9:59 ` Mark objects death at end of scope Richard Guenther
  2011-11-03 11:07   ` Michael Matz
@ 2011-11-07 16:05   ` Michael Matz
  2011-11-07 22:10     ` Richard Guenther
                       ` (2 more replies)
  1 sibling, 3 replies; 30+ messages in thread
From: Michael Matz @ 2011-11-07 16:05 UTC (permalink / raw)
  To: Richard Guenther; +Cc: gcc-patches

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.

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

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: Mark objects death at end of scope
  2011-11-07 16:05   ` Michael Matz
@ 2011-11-07 22:10     ` Richard Guenther
  2011-11-10 23:57     ` Steve Ellcey
  2011-11-11 16:20     ` Mark objects death@end " Ulrich Weigand
  2 siblings, 0 replies; 30+ messages in thread
From: Richard Guenther @ 2011-11-07 22:10 UTC (permalink / raw)
  To: Michael Matz; +Cc: gcc-patches

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

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: Mark objects death at end of scope
  2011-11-07 16:05   ` Michael Matz
  2011-11-07 22:10     ` Richard Guenther
@ 2011-11-10 23:57     ` Steve Ellcey
  2011-11-11 15:32       ` Michael Matz
  2011-11-11 16:20     ` Mark objects death@end " Ulrich Weigand
  2 siblings, 1 reply; 30+ messages in thread
From: Steve Ellcey @ 2011-11-10 23:57 UTC (permalink / raw)
  To: Michael Matz; +Cc: Richard Guenther, gcc-patches

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

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: Mark objects death at end of scope
  2011-11-10 23:57     ` Steve Ellcey
@ 2011-11-11 15:32       ` Michael Matz
  0 siblings, 0 replies; 30+ messages in thread
From: Michael Matz @ 2011-11-11 15:32 UTC (permalink / raw)
  To: Steve Ellcey; +Cc: Richard Guenther, gcc-patches

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.

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: Mark objects death@end of scope
  2011-11-07 16:05   ` Michael Matz
  2011-11-07 22:10     ` Richard Guenther
  2011-11-10 23:57     ` Steve Ellcey
@ 2011-11-11 16:20     ` Ulrich Weigand
  2011-11-11 17:22       ` Michael Matz
  2 siblings, 1 reply; 30+ messages in thread
From: Ulrich Weigand @ 2011-11-11 16:20 UTC (permalink / raw)
  To: Michael Matz; +Cc: Richard Guenther, gcc-patches

Michael Matz wrote:

> 	* gimplify.c (gimplify_bind_expr): Add clobbers for all variables
> 	that go out of scope and live in memory.

This seems to have completely broken SPU exception handling (note that
SPU is currently completely broken anyway due to the libgcc move).

What happens is that with that patch, some of the core internal routines
of the unwinder itself, including _Unwind_SjLj_Resume, themselves get
exception regions.

While the DWARF unwinder may be able to cope with this, the SjLj unwinder
- which SPU uses - appears to get totally confused by this.  We end up in
an endless loop where _Unwind_SjLj_Resumes "resumes" to a location within
itself.

One reason why this happens is that the unwind*.c files are specifically
built with -fexception.  I think this is for the benefit of the DWARF
unwinder, to ensure CFI records are available for those routines.  But
for the SjLj unwinder, it's a bit counter-productive ...

Any thoughts how to fix this?

Bye,
Ulrich

-- 
  Dr. Ulrich Weigand
  GNU Toolchain for Linux on System z and Cell BE
  Ulrich.Weigand@de.ibm.com

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: Mark objects death@end of scope
  2011-11-11 16:20     ` Mark objects death@end " Ulrich Weigand
@ 2011-11-11 17:22       ` Michael Matz
  2011-11-11 17:45         ` Ulrich Weigand
  0 siblings, 1 reply; 30+ messages in thread
From: Michael Matz @ 2011-11-11 17:22 UTC (permalink / raw)
  To: Ulrich Weigand; +Cc: Richard Guenther, gcc-patches

Hi,

On Fri, 11 Nov 2011, Ulrich Weigand wrote:

> One reason why this happens is that the unwind*.c files are specifically 
> built with -fexception.  I think this is for the benefit of the DWARF 
> unwinder, to ensure CFI records are available for those routines.

Except for the routines that start the backtracing (e.g.
_Unwind_RaiseException) I don't see how descriptors for them are useful.  
But even those use local variables that would be handled by the scope-end 
clobbers.  Hmpf.  Why does the sjlj unwinder go into an endless loop, and 
only in _Resume, not already in the first phase (i.e. from 
_RaiseException), which also iterates over the backtrace.

If we can't fix the sjlj unwinder to cope with this situation I don't see 
much choice than implementing a command line flag disabling the clobbers 
and use that for compiling the unwinder :-/


Ciao,
Michael.

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: Mark objects death@end of scope
  2011-11-11 17:45         ` Ulrich Weigand
@ 2011-11-11 17:45           ` Michael Matz
  0 siblings, 0 replies; 30+ messages in thread
From: Michael Matz @ 2011-11-11 17:45 UTC (permalink / raw)
  To: Ulrich Weigand; +Cc: Richard Guenther, gcc-patches

Hi,

On Fri, 11 Nov 2011, Ulrich Weigand wrote:

> I haven't fully debugged it yet, but it seems to be related to the 
> linked list of unwind contexts that are maintained by the SjLj logic.  
> During unwinding, those are pulled off the list one by one; it seems the 
> routines that do that don't expect that new contexts for the _Unwind 
> routines themselves are being implicitly pushed onto that list while the 
> unwinding happens ...
> 
> > If we can't fix the sjlj unwinder to cope with this situation I don't 
> > see much choice than implementing a command line flag disabling the 
> > clobbers and use that for compiling the unwinder :-/
> 
> I guess one attempt might be to build the unwinder files with 
> -funwind-tables instead of -fexceptions ...

Hmm, that could work.  Or marking all routines that the unwinder calls as 
nothrow.


Ciao,
Michael.

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: Mark objects death@end of scope
  2011-11-11 17:22       ` Michael Matz
@ 2011-11-11 17:45         ` Ulrich Weigand
  2011-11-11 17:45           ` Michael Matz
  0 siblings, 1 reply; 30+ messages in thread
From: Ulrich Weigand @ 2011-11-11 17:45 UTC (permalink / raw)
  To: Michael Matz; +Cc: Richard Guenther, gcc-patches

Michael Matz wrote:
> On Fri, 11 Nov 2011, Ulrich Weigand wrote:
> 
> > One reason why this happens is that the unwind*.c files are specifically 
> > built with -fexception.  I think this is for the benefit of the DWARF 
> > unwinder, to ensure CFI records are available for those routines.
> 
> Except for the routines that start the backtracing (e.g.
> _Unwind_RaiseException) I don't see how descriptors for them are useful.  
> But even those use local variables that would be handled by the scope-end 
> clobbers.  Hmpf.  Why does the sjlj unwinder go into an endless loop, and 
> only in _Resume, not already in the first phase (i.e. from 
> _RaiseException), which also iterates over the backtrace.

I haven't fully debugged it yet, but it seems to be related to the linked
list of unwind contexts that are maintained by the SjLj logic.  During
unwinding, those are pulled off the list one by one; it seems the routines
that do that don't expect that new contexts for the _Unwind routines
themselves are being implicitly pushed onto that list while the unwinding
happens ...

> If we can't fix the sjlj unwinder to cope with this situation I don't see 
> much choice than implementing a command line flag disabling the clobbers 
> and use that for compiling the unwinder :-/

I guess one attempt might be to build the unwinder files with
-funwind-tables instead of -fexceptions ...

Bye,
Ulrich

-- 
  Dr. Ulrich Weigand
  GNU Toolchain for Linux on System z and Cell BE
  Ulrich.Weigand@de.ibm.com

^ permalink raw reply	[flat|nested] 30+ messages in thread

end of thread, other threads:[~2011-11-11 17:22 UTC | newest]

Thread overview: 30+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2011-11-03  0:05 Mark objects death at end of scope Michael Matz
2011-11-03  1:21 ` Eric Botcazou
2011-11-03  9:24   ` Richard Guenther
2011-11-03 10:26     ` Eric Botcazou
2011-11-03 12:52       ` Richard Guenther
2011-11-03 13:42         ` Michael Matz
2011-11-03 14:33           ` Eric Botcazou
2011-11-03 14:46             ` Michael Matz
2011-11-03 14:55               ` Eric Botcazou
2011-11-03 14:23       ` Build gcc/ with -fno-exceptions -fno-rtti Michael Matz
2011-11-03 14:26         ` Paolo Bonzini
2011-11-03 14:31           ` Richard Guenther
2011-11-03 15:08             ` Eric Botcazou
2011-11-03 17:46               ` Michael Matz
2011-11-03  9:59 ` Mark objects death at end of scope Richard Guenther
2011-11-03 11:07   ` Michael Matz
2011-11-07 16:05   ` Michael Matz
2011-11-07 22:10     ` Richard Guenther
2011-11-10 23:57     ` Steve Ellcey
2011-11-11 15:32       ` Michael Matz
2011-11-11 16:20     ` Mark objects death@end " Ulrich Weigand
2011-11-11 17:22       ` Michael Matz
2011-11-11 17:45         ` Ulrich Weigand
2011-11-11 17:45           ` Michael Matz
2011-11-03 10:57 ` Mark objects death at end " Jakub Jelinek
2011-11-03 11:57   ` Michael Matz
2011-11-03 12:47     ` Jakub Jelinek
2011-11-03 13:14       ` Michael Matz
2011-11-04 12:28         ` Jakub Jelinek
2011-11-04 12:45           ` Jakub Jelinek

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).