This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

PR tree-optimization/37709: debug info at -g3 and more prunning of scope block structures


Hi,
the problem exposed by testcase is that early inliner does a lot of inlining of
functions that compile into empty code. This causes scope blocks to commulate
and we end up with functions with massive trees of scope blocks attaches that
all describe optimized out function parameters and contain no statements in
them.

The following patch adds a dumping infrastructure so we are more aware of what
is going on with scope blocks (enabled at TDF_DETAILS dumped in every pass
doing scope prunning). 

I believe that even at -g3 it should be safe to drop blocks that
 1) contains no statements
 2) contains no live nested blocks
 3) contains no live variables
to be eliminated from block tree.  Note that dead variables are not elliminated
from the block at -g2+ (or pre inlining) until the whole block becomes dead so
we get proper "variable optimized out" info from gdb.

I also enabled block prunning at -O0 since we have SSA now and it gives more
stress on correctness of the infrastructure (and obviously same disaster would
happen with always_inline added to testcase) This actually triggered bug in
stabs output (debug-1.c and debug-2.c testcases compiled only at -O0).  It is
testing TREE_USED flag bit on block to see if it should be output.  We now set
TREE_USED flag bit on block only if itself is containing used vars or
statements, so subblocks of block without the flag can be used, but dbxout is
not looking into them.  Since we now take care to remove unused blocks from our
datastructures, I guess we ought to output all blocks there.  (perhaps we can
do dead block removal on RTL land as well to avoid extra blocks to be output,
but we don't do that for a while and this is how dwarf2out behaves)

The patch does have effect on resulting -g3 debug info reducing the testcase assembly
from 100MB to few KB, but I hope that all the info eliminated is
useless since there is no way to query it in debugger anyway. 

I've run testsuite and GDB testsuite and there is just "noise" difference:

--- bez-patche/gdb.sum	2009-02-22 18:26:02.000000000 +0100
+++ gdb/testsuite/gdb.sum	2009-02-22 18:37:51.000000000 +0100
@@ -1,4 +1,4 @@
@@ -11541,7 +11541,7 @@
 PASS: gdb.threads/watchthreads.exp: watch args[1]
 FAIL: gdb.threads/watchthreads.exp: threaded watch loop
 PASS: gdb.threads/watchthreads.exp: first watchpoint on args[0] hit
-FAIL: gdb.threads/watchthreads.exp: first watchpoint on args[1] hit
+PASS: gdb.threads/watchthreads.exp: first watchpoint on args[1] hit
 FAIL: gdb.threads/watchthreads.exp: watchpoint on args[0] hit in thread
 FAIL: gdb.threads/watchthreads.exp: watchpoint on args[1] hit in thread
 FAIL: gdb.threads/watchthreads.exp: combination of threaded watchpoints = 30
@@ -11686,8 +11686,8 @@
 
 		=== gdb Summary ===
 
-# of expected passes		11059
-# of unexpected failures	135
+# of expected passes		11060
+# of unexpected failures	134
 # of unexpected successes	2
 # of expected failures		42
 # of known failures		63

So actually an improvement.  Note that we have quite few regressions relative to GCC 4.1.0:

@@ -3622,7 +3622,7 @@
 PASS: gdb.base/maint.exp: maint internal-error
 PASS: gdb.base/maint.exp: internal-error resync
 Running ../../../gdb/testsuite/gdb.base/mips_pro.exp ...
-PASS: gdb.base/mips_pro.exp: backtrace
+FAIL: gdb.base/mips_pro.exp: running to middle in runto
 Running ../../../gdb/testsuite/gdb.base/miscexprs.exp ...
 PASS: gdb.base/miscexprs.exp: up from marker1
 PASS: gdb.base/miscexprs.exp: print value of &ibig.i[0]
@@ -3649,7 +3649,7 @@
 PASS: gdb.base/miscexprs.exp: print value of lbig.l[333] >> 6
 Running ../../../gdb/testsuite/gdb.base/multi-forks.exp ...
 PASS: gdb.base/multi-forks.exp: Break at exit
-FAIL: gdb.base/multi-forks.exp: follow child, print pids (timeout)
+PASS: gdb.base/multi-forks.exp: follow child, print pids
 PASS: gdb.base/multi-forks.exp: Break at exit
 PASS: gdb.base/multi-forks.exp: follow parent, print pids
 PASS: gdb.base/multi-forks.exp: help set detach
@@ -6349,35 +6349,35 @@
 PASS: gdb.base/store.exp: tbreak add_charest
 PASS: gdb.base/store.exp: continue to add_charest
 PASS: gdb.base/store.exp: upvar charest l; up
-PASS: gdb.base/store.exp: upvar charest l; print old l, expecting -1 .*
+FAIL: gdb.base/store.exp: upvar charest l; print old l, expecting -1 .*
 PASS: gdb.base/store.exp: upvar charest l; print old r, expecting -2 .*
 PASS: gdb.base/store.exp: upvar charest l; set l to 4
 PASS: gdb.base/store.exp: upvar charest l; print new l, expecting 4 ..004.
 PASS: gdb.base/store.exp: tbreak add_short
 PASS: gdb.base/store.exp: continue to add_short
 PASS: gdb.base/store.exp: upvar short l; up
-PASS: gdb.base/store.exp: upvar short l; print old l, expecting -1
+FAIL: gdb.base/store.exp: upvar short l; print old l, expecting -1
 PASS: gdb.base/store.exp: upvar short l; print old r, expecting -2
 PASS: gdb.base/store.exp: upvar short l; set l to 4
 PASS: gdb.base/store.exp: upvar short l; print new l, expecting 4
 PASS: gdb.base/store.exp: tbreak add_int
 PASS: gdb.base/store.exp: continue to add_int
 PASS: gdb.base/store.exp: upvar int l; up
-PASS: gdb.base/store.exp: upvar int l; print old l, expecting -1
+FAIL: gdb.base/store.exp: upvar int l; print old l, expecting -1
 PASS: gdb.base/store.exp: upvar int l; print old r, expecting -2
 PASS: gdb.base/store.exp: upvar int l; set l to 4
 PASS: gdb.base/store.exp: upvar int l; print new l, expecting 4
 PASS: gdb.base/store.exp: tbreak add_long
 PASS: gdb.base/store.exp: continue to add_long
 PASS: gdb.base/store.exp: upvar long l; up
-PASS: gdb.base/store.exp: upvar long l; print old l, expecting -1
+FAIL: gdb.base/store.exp: upvar long l; print old l, expecting -1
 PASS: gdb.base/store.exp: upvar long l; print old r, expecting -2
 PASS: gdb.base/store.exp: upvar long l; set l to 4
 PASS: gdb.base/store.exp: upvar long l; print new l, expecting 4
 PASS: gdb.base/store.exp: tbreak add_longest
 PASS: gdb.base/store.exp: continue to add_longest
 PASS: gdb.base/store.exp: upvar longest l; up
-PASS: gdb.base/store.exp: upvar longest l; print old l, expecting -1
+FAIL: gdb.base/store.exp: upvar longest l; print old l, expecting -1
 PASS: gdb.base/store.exp: upvar longest l; print old r, expecting -2
 PASS: gdb.base/store.exp: upvar longest l; set l to 4
 PASS: gdb.base/store.exp: upvar longest l; print new l, expecting 4
@@ -6398,7 +6398,7 @@
 PASS: gdb.base/store.exp: tbreak add_doublest
 PASS: gdb.base/store.exp: continue to add_doublest
 PASS: gdb.base/store.exp: upvar doublest l; up
-PASS: gdb.base/store.exp: upvar doublest l; print old l, expecting -1
+FAIL: gdb.base/store.exp: upvar doublest l; print old l, expecting -1
 PASS: gdb.base/store.exp: upvar doublest l; print old r, expecting -2
 PASS: gdb.base/store.exp: upvar doublest l; set l to 4
 PASS: gdb.base/store.exp: upvar doublest l; print new l, expecting 4
@@ -7415,7 +7415,7 @@
 PASS: gdb.cp/annota2.exp: run until main breakpoint
 PASS: gdb.cp/annota2.exp: set watch on a.x
 KFAIL: gdb.cp/annota2.exp: watch triggered on a.x (PRMS: gdb/38)
-KFAIL: gdb.cp/annota2.exp: annotate-quit (PRMS: gdb/544)
+PASS: gdb.cp/annota2.exp: annotate-quit
 Running ../../../gdb/testsuite/gdb.cp/annota3.exp ...
 PASS: gdb.cp/annota3.exp: breakpoint main
 PASS: gdb.cp/annota3.exp: annotation set at level 3
@@ -7427,7 +7427,7 @@
 PASS: gdb.cp/annota3.exp: second run until main breakpoint
 PASS: gdb.cp/annota3.exp: set watch on a.x
 KFAIL: gdb.cp/annota3.exp: watch triggered on a.x (PRMS: gdb/38)
-FAIL: gdb.cp/annota3.exp: annotate-quit (pattern 1)
+PASS: gdb.cp/annota3.exp: annotate-quit
 Running ../../../gdb/testsuite/gdb.cp/anon-union.exp ...
 PASS: gdb.cp/anon-union.exp: next 1
 PASS: gdb.cp/anon-union.exp: print foo 1
@@ -7548,9 +7548,9 @@
 PASS: gdb.cp/classes.exp: continue to enums2(\(\)|)
 PASS: gdb.cp/classes.exp: print obj_with_enum (1)
 PASS: gdb.cp/classes.exp: next
-PASS: gdb.cp/classes.exp: print obj_with_enum (2)
-PASS: gdb.cp/classes.exp: print obj_with_enum.priv_enum
-PASS: gdb.cp/classes.exp: ptype obj_with_enum.priv_enum
+FAIL: gdb.cp/classes.exp: print obj_with_enum (2)
+FAIL: gdb.cp/classes.exp: print obj_with_enum.priv_enum
+FAIL: gdb.cp/classes.exp: ptype obj_with_enum.priv_enum
 KFAIL: gdb.cp/classes.exp: ptype obj_with_enum // unrecognized line type 1: PrivEnum priv_enum; (PRMS: gdb/57)
 KFAIL: gdb.cp/classes.exp: print (ClassWithEnum::PrivEnum) 42 (PRMS: gdb/1588)
 KFAIL: gdb.cp/classes.exp: print ('ClassWithEnum::PrivEnum') 42 (PRMS: gdb/57)
@@ -7571,7 +7571,7 @@
 PASS: gdb.cp/classes.exp: print csi with static members
 PASS: gdb.cp/classes.exp: print cnsi with static members
 PASS: gdb.cp/classes.exp: finish from marker_reg1
-PASS: gdb.cp/classes.exp: calling method for small class
+XFAIL: gdb.cp/classes.exp: calling method for small class (PRMS 2972)
 Running ../../../gdb/testsuite/gdb.cp/cplusfuncs.exp ...
 PASS: gdb.cp/cplusfuncs.exp: detect dm_operator_comma
 PASS: gdb.cp/cplusfuncs.exp: detect dm_type_char_star
@@ -8625,7 +8625,7 @@
 PASS: gdb.cp/inherit.exp: ptype class C
 PASS: gdb.cp/inherit.exp: ptype g_C
 FAIL: gdb.cp/inherit.exp: ptype tagless struct
-PASS: gdb.cp/inherit.exp: ptype variable of type tagless struct
+FAIL: gdb.cp/inherit.exp: ptype variable of type tagless struct
 PASS: gdb.cp/inherit.exp: ptype D
 PASS: gdb.cp/inherit.exp: ptype class D
 PASS: gdb.cp/inherit.exp: ptype g_D
@@ -8731,7 +8731,7 @@
 PASS: gdb.cp/inherit.exp: print g_E
 PASS: gdb.cp/inherit.exp: print anonymous union member
 PASS: gdb.cp/inherit.exp: print variable of type anonymous union
-FAIL: gdb.cp/inherit.exp: print type of anonymous union // unrecognized line type 1: class_with_anon_union::._0;
+FAIL: gdb.cp/inherit.exp: print type of anonymous union // unrecognized line type 1: class_with_anon_union::<anonymous union>;
 PASS: gdb.cp/inherit.exp: print g_vA.vA::va
 PASS: gdb.cp/inherit.exp: print g_vA.vA::vx
 PASS: gdb.cp/inherit.exp: print g_vA.va
@@ -8789,17 +8789,17 @@
 PASS: gdb.cp/m-data.exp: simple object, const bool
 PASS: gdb.cp/m-data.exp: simple object, const int
 PASS: gdb.cp/m-data.exp: simple object, long
-PASS: gdb.cp/m-data.exp: simple object, enum
+FAIL: gdb.cp/m-data.exp: simple object, enum
 PASS: gdb.cp/m-data.exp: derived template object, base const bool
 PASS: gdb.cp/m-data.exp: derived template object, base const int
 PASS: gdb.cp/m-data.exp: derived template object, base long
 PASS: gdb.cp/m-data.exp: derived template object, base enum
-PASS: gdb.cp/m-data.exp: derived template object, derived enum
+FAIL: gdb.cp/m-data.exp: derived template object, derived enum
 PASS: gdb.cp/m-data.exp: template object, const bool
 PASS: gdb.cp/m-data.exp: template object, const int
 PASS: gdb.cp/m-data.exp: template object, long
 PASS: gdb.cp/m-data.exp: template object, base enum
-PASS: gdb.cp/m-data.exp: template object, derived enum
+FAIL: gdb.cp/m-data.exp: template object, derived enum
 PASS: gdb.cp/m-data.exp: continue to breakpoint: continue to shadow breakpoint
 PASS: gdb.cp/m-data.exp: shadowing member
 PASS: gdb.cp/m-data.exp: shadowed global variable
@@ -8813,12 +8813,12 @@
 PASS: gdb.cp/m-static.exp: derived template object, base static const int
 PASS: gdb.cp/m-static.exp: derived template object, base static long
 PASS: gdb.cp/m-static.exp: derived template object, base static enum
-PASS: gdb.cp/m-static.exp: derived template object, static enum
+FAIL: gdb.cp/m-static.exp: derived template object, static enum
 PASS: gdb.cp/m-static.exp: template object, static const bool
 PASS: gdb.cp/m-static.exp: template object, static const int
 PASS: gdb.cp/m-static.exp: template object, static long
 PASS: gdb.cp/m-static.exp: template object, static enum
-PASS: gdb.cp/m-static.exp: template object, static derived enum
+FAIL: gdb.cp/m-static.exp: template object, static derived enum
 PASS: gdb.cp/m-static.exp: static const int initialized elsewhere
 PASS: gdb.cp/m-static.exp: static const int initialized nowhere
 Running ../../../gdb/testsuite/gdb.cp/maint.exp ...
@@ -8941,15 +8941,15 @@
 KFAIL: gdb.cp/namespace.exp: ptype ::C::OtherFileClass (PRMS: gdb/1448)
 PASS: gdb.cp/namespace.exp: ptype C::OtherFileClass
 PASS: gdb.cp/namespace.exp: print cX
-PASS: gdb.cp/namespace.exp: print 'F::cXf'
-PASS: gdb.cp/namespace.exp: print F::cXf
-PASS: gdb.cp/namespace.exp: print F::cXfX
+FAIL: gdb.cp/namespace.exp: print 'F::cXf'
+FAIL: gdb.cp/namespace.exp: print F::cXf
+FAIL: gdb.cp/namespace.exp: print F::cXfX
 PASS: gdb.cp/namespace.exp: print X
-PASS: gdb.cp/namespace.exp: print 'G::Xg'
-PASS: gdb.cp/namespace.exp: print G::Xg
-PASS: gdb.cp/namespace.exp: print G::XgX
-PASS: gdb.cp/namespace.exp: print cXOtherFile
-PASS: gdb.cp/namespace.exp: print XOtherFile
+FAIL: gdb.cp/namespace.exp: print 'G::Xg'
+FAIL: gdb.cp/namespace.exp: print G::Xg
+FAIL: gdb.cp/namespace.exp: print G::XgX
+FAIL: gdb.cp/namespace.exp: print cXOtherFile
+FAIL: gdb.cp/namespace.exp: print XOtherFile
 Running ../../../gdb/testsuite/gdb.cp/overload.exp ...
 PASS: gdb.cp/overload.exp: up from marker1
 PASS: gdb.cp/overload.exp: print foo_instance1
 
While looking at the code I also notice that dwarf2out is bit more
conservative about removing blocks containing class definitions:


/* Returns nonzero if it is appropriate not to emit any debugging
   information for BLOCK, because it doesn't contain any instructions.

   Don't allow this for blocks with nested functions or local classes
   as we would end up with orphans, and in the presence of scheduling
   we may end up calling them anyway.  */

static bool
dwarf2out_ignore_block (const_tree block)
{
  tree decl;

  for (decl = BLOCK_VARS (block); decl; decl = TREE_CHAIN (decl))
    if (TREE_CODE (decl) == FUNCTION_DECL
	|| (TREE_CODE (decl) == TYPE_DECL && TYPE_DECL_IS_STUB (decl)))
      return 0;

  return 1;
}

While tree-ssa-live.c looks only for FUNCTION_DECL.
As I understand it is looking for function internal classes that
contains functions that are still called even if the block appears dead
otherwise.  Can we somehow construct testcase for this?  I don't quite
follow TYPE_DECL_IS_STUB definition anyway so I don't feel safe to just
move same check to tree-ssa-live.c...

Bootstrapped/regtested i686-linux. Seems sane?

	PR tree-optimization/37709
	* tree.c (block_ultimate_origin): Move here from dwarf2out.
	* tree.h (block_ultimate_origin): Declare.
	* dwarf2out.c (block_ultimate_origin): Move to tree.c
	* tree-ssa-live.c (remove_unused_scope_block_p): Eliminate blocks
	contaiing no instructions nor live variables nor nested blocks.
	(dump_scope_block): New function.
	(remove_unused_locals): Enable removal of dead blocks by default;
	enable dumping at TDF_DETAILS.

Index: tree.c
===================================================================
*** tree.c	(revision 144373)
--- tree.c	(working copy)
*************** build_target_option_node (void)
*** 9199,9202 ****
--- 9199,9247 ----
    return t;
  }
  
+ /* Determine the "ultimate origin" of a block.  The block may be an inlined
+    instance of an inlined instance of a block which is local to an inline
+    function, so we have to trace all of the way back through the origin chain
+    to find out what sort of node actually served as the original seed for the
+    given block.  */
+ 
+ tree
+ block_ultimate_origin (const_tree block)
+ {
+   tree immediate_origin = BLOCK_ABSTRACT_ORIGIN (block);
+ 
+   /* output_inline_function sets BLOCK_ABSTRACT_ORIGIN for all the
+      nodes in the function to point to themselves; ignore that if
+      we're trying to output the abstract instance of this function.  */
+   if (BLOCK_ABSTRACT (block) && immediate_origin == block)
+     return NULL_TREE;
+ 
+   if (immediate_origin == NULL_TREE)
+     return NULL_TREE;
+   else
+     {
+       tree ret_val;
+       tree lookahead = immediate_origin;
+ 
+       do
+ 	{
+ 	  ret_val = lookahead;
+ 	  lookahead = (TREE_CODE (ret_val) == BLOCK
+ 		       ? BLOCK_ABSTRACT_ORIGIN (ret_val) : NULL);
+ 	}
+       while (lookahead != NULL && lookahead != ret_val);
+ 
+       /* The block's abstract origin chain may not be the *ultimate* origin of
+ 	 the block. It could lead to a DECL that has an abstract origin set.
+ 	 If so, we want that DECL's abstract origin (which is what DECL_ORIGIN
+ 	 will give us if it has one).  Note that DECL's abstract origins are
+ 	 supposed to be the most distant ancestor (or so decl_ultimate_origin
+ 	 claims), so we don't need to loop following the DECL origins.  */
+       if (DECL_P (ret_val))
+ 	return DECL_ORIGIN (ret_val);
+ 
+       return ret_val;
+     }
+ }
+ 
  #include "gt-tree.h"
Index: tree.h
===================================================================
*** tree.h	(revision 144373)
--- tree.h	(working copy)
*************** extern bool gimple_alloca_call_p (const_
*** 5022,5027 ****
--- 5022,5028 ----
  extern bool alloca_call_p (const_tree);
  extern bool must_pass_in_stack_var_size (enum machine_mode, const_tree);
  extern bool must_pass_in_stack_var_size_or_pad (enum machine_mode, const_tree);
+ extern tree block_ultimate_origin (const_tree);
  
  /* In attribs.c.  */
  
Index: dbxout.c
===================================================================
*** dbxout.c	(revision 144373)
--- dbxout.c	(working copy)
*************** dbxout_block (tree block, int depth, tre
*** 3593,3599 ****
    while (block)
      {
        /* Ignore blocks never expanded or otherwise marked as real.  */
!       if (TREE_USED (block) && TREE_ASM_WRITTEN (block))
  	{
  	  int did_output;
  	  int blocknum = BLOCK_NUMBER (block);
--- 3593,3599 ----
    while (block)
      {
        /* Ignore blocks never expanded or otherwise marked as real.  */
!       if (TREE_ASM_WRITTEN (block))
  	{
  	  int did_output;
  	  int blocknum = BLOCK_NUMBER (block);
Index: dwarf2out.c
===================================================================
*** dwarf2out.c	(revision 144373)
--- dwarf2out.c	(working copy)
*************** static const char *dwarf_tag_name (unsig
*** 4947,4953 ****
  static const char *dwarf_attr_name (unsigned);
  static const char *dwarf_form_name (unsigned);
  static tree decl_ultimate_origin (const_tree);
- static tree block_ultimate_origin (const_tree);
  static tree decl_class_context (tree);
  static void add_dwarf_attr (dw_die_ref, dw_attr_ref);
  static inline enum dw_val_class AT_class (dw_attr_ref);
--- 4947,4952 ----
*************** decl_ultimate_origin (const_tree decl)
*** 5772,5822 ****
    return DECL_ABSTRACT_ORIGIN (decl);
  }
  
- /* Determine the "ultimate origin" of a block.  The block may be an inlined
-    instance of an inlined instance of a block which is local to an inline
-    function, so we have to trace all of the way back through the origin chain
-    to find out what sort of node actually served as the original seed for the
-    given block.  */
- 
- static tree
- block_ultimate_origin (const_tree block)
- {
-   tree immediate_origin = BLOCK_ABSTRACT_ORIGIN (block);
- 
-   /* output_inline_function sets BLOCK_ABSTRACT_ORIGIN for all the
-      nodes in the function to point to themselves; ignore that if
-      we're trying to output the abstract instance of this function.  */
-   if (BLOCK_ABSTRACT (block) && immediate_origin == block)
-     return NULL_TREE;
- 
-   if (immediate_origin == NULL_TREE)
-     return NULL_TREE;
-   else
-     {
-       tree ret_val;
-       tree lookahead = immediate_origin;
- 
-       do
- 	{
- 	  ret_val = lookahead;
- 	  lookahead = (TREE_CODE (ret_val) == BLOCK
- 		       ? BLOCK_ABSTRACT_ORIGIN (ret_val) : NULL);
- 	}
-       while (lookahead != NULL && lookahead != ret_val);
- 
-       /* The block's abstract origin chain may not be the *ultimate* origin of
- 	 the block. It could lead to a DECL that has an abstract origin set.
- 	 If so, we want that DECL's abstract origin (which is what DECL_ORIGIN
- 	 will give us if it has one).  Note that DECL's abstract origins are
- 	 supposed to be the most distant ancestor (or so decl_ultimate_origin
- 	 claims), so we don't need to loop following the DECL origins.  */
-       if (DECL_P (ret_val))
- 	return DECL_ORIGIN (ret_val);
- 
-       return ret_val;
-     }
- }
- 
  /* Get the class to which DECL belongs, if any.  In g++, the DECL_CONTEXT
     of a virtual function may refer to a base class, so we check the 'this'
     parameter.  */
--- 5771,5776 ----
Index: tree-ssa-live.c
===================================================================
*** tree-ssa-live.c	(revision 144373)
--- tree-ssa-live.c	(working copy)
*************** remove_unused_scope_block_p (tree scope)
*** 485,494 ****
        next = &TREE_CHAIN (*t);
  
        /* Debug info of nested function refers to the block of the
! 	 function.  */
        if (TREE_CODE (*t) == FUNCTION_DECL)
  	unused = false;
- 
        /* Remove everything we don't generate debug info for.  */
        else if (DECL_IGNORED_P (*t))
  	{
--- 485,497 ----
        next = &TREE_CHAIN (*t);
  
        /* Debug info of nested function refers to the block of the
! 	 function.  We might stil call it even if all statements
! 	 of function it was nested into was elliminated.
! 	 
! 	 TODO: We can actually look into cgraph to see if function
! 	 will be output to file.  */
        if (TREE_CODE (*t) == FUNCTION_DECL)
  	unused = false;
        /* Remove everything we don't generate debug info for.  */
        else if (DECL_IGNORED_P (*t))
  	{
*************** remove_unused_scope_block_p (tree scope)
*** 506,520 ****
  
        /* When we are not doing full debug info, we however can keep around
  	 only the used variables for cfgexpand's memory packing saving quite
! 	 a lot of memory.  */
        else if (debug_info_level == DINFO_LEVEL_NORMAL
  	       || debug_info_level == DINFO_LEVEL_VERBOSE
- 	       /* Removing declarations before inlining is going to affect
- 		  DECL_UID that in turn is going to affect hashtables and
- 		  code generation.  */
  	       || !cfun->after_inlining)
! 	unused = false;
! 
        else
  	{
  	  *t = TREE_CHAIN (*t);
--- 509,529 ----
  
        /* When we are not doing full debug info, we however can keep around
  	 only the used variables for cfgexpand's memory packing saving quite
! 	 a lot of memory.  
! 
! 	 For sake of -g3, we keep around those vars but we don't count this as
! 	 use of block, so innermost block with no used vars and no instructions
! 	 can be considered dead.  We only want to keep around blocks user can
! 	 breakpoint into and ask about value of optimized out variables. 
! 
! 	 Similarly we need to keep around types at least until all variables of
! 	 all nested blocks are gone.  We track no information on whether given
! 	 type is used or not.  */
! 
        else if (debug_info_level == DINFO_LEVEL_NORMAL
  	       || debug_info_level == DINFO_LEVEL_VERBOSE
  	       || !cfun->after_inlining)
! 	;
        else
  	{
  	  *t = TREE_CHAIN (*t);
*************** remove_unused_scope_block_p (tree scope)
*** 537,546 ****
  	    nsubblocks ++;
  	  }
  	else
! 	  {
! 	    gcc_assert (!BLOCK_VARS (*t));
! 	    *t = BLOCK_CHAIN (*t);
! 	  }
        }
      else
        {
--- 546,552 ----
  	    nsubblocks ++;
  	  }
  	else
! 	  *t = BLOCK_CHAIN (*t);
        }
      else
        {
*************** mark_all_vars_used (tree *expr_p, void *
*** 576,581 ****
--- 582,619 ----
    walk_tree (expr_p, mark_all_vars_used_1, data, NULL);
  }
  
+ /* Dump scope blocks.  */
+ 
+ static void
+ dump_scope_block (FILE *file, int indent, tree scope, int flags)
+ {
+   tree var, t;
+ 
+   fprintf (file, "\n%*sScope block #%i %s\n",indent, "" , BLOCK_NUMBER (scope),
+   	   TREE_USED (scope) ? "" : "(unused)");
+   if (BLOCK_ABSTRACT_ORIGIN (scope) && DECL_P (block_ultimate_origin (scope)))
+     {
+       fprintf (file, "\n%*sOriginating from ",indent + 1, "");
+       print_generic_decl (file, block_ultimate_origin (scope), flags);
+       fprintf (file, "\n");
+     }
+   for (var = BLOCK_VARS (scope); var; var = TREE_CHAIN (var))
+     {
+       bool used = false;
+       var_ann_t ann;
+ 
+       if ((ann = var_ann (var))
+ 	  && ann->used)
+ 	used = true;
+ 
+       fprintf (file, "%*s",indent, "");
+       print_generic_decl (file, var, flags);
+       fprintf (file, "%s\n", used ? "" : " (unused)");
+     }
+   for (t = BLOCK_SUBBLOCKS (scope); t ; t = BLOCK_CHAIN (t))
+     dump_scope_block (file, indent + 2, t, flags);
+ }
+ 
  
  /* Remove local variables that are not referenced in the IL.  */
  
*************** remove_unused_locals (void)
*** 588,594 ****
    var_ann_t ann;
    bitmap global_unused_vars = NULL;
  
!   if (optimize)
      mark_scope_block_unused (DECL_INITIAL (current_function_decl));
  
    /* Assume all locals are unused.  */
--- 626,632 ----
    var_ann_t ann;
    bitmap global_unused_vars = NULL;
  
!   /*if (optimize)*/
      mark_scope_block_unused (DECL_INITIAL (current_function_decl));
  
    /* Assume all locals are unused.  */
*************** remove_unused_locals (void)
*** 716,723 ****
  	&& !TREE_ADDRESSABLE (t)
  	&& (optimize || DECL_ARTIFICIAL (t)))
        remove_referenced_var (t);
!   if (optimize)
!     remove_unused_scope_block_p (DECL_INITIAL (current_function_decl));
  }
  
  
--- 754,765 ----
  	&& !TREE_ADDRESSABLE (t)
  	&& (optimize || DECL_ARTIFICIAL (t)))
        remove_referenced_var (t);
!   remove_unused_scope_block_p (DECL_INITIAL (current_function_decl));
!   if (dump_file && (dump_flags & TDF_DETAILS))
!     {
!       fprintf (dump_file, "Scope blocks after cleanups:\n");
!       dump_scope_block (dump_file, 0, DECL_INITIAL (current_function_decl), false);
!     }
  }
  
  
Index: config/i386/i386.c
===================================================================
*** config/i386/i386.c	(revision 144373)
--- config/i386/i386.c	(working copy)
*************** unsigned int
*** 19351,19356 ****
--- 19351,19362 ----
  ix86_local_alignment (tree type, enum machine_mode mode,
  		      unsigned int align)
  {
+   /* We don't want to align DImode to 64bit for compilation with
+      -mpreferred-stack-boundary=2 to not enforce dynamic stack alignment
+      prologue.  */
+   if (mode == DImode && !TARGET_64BIT && ix86_preferred_stack_boundary < 64)
+     align = 32;
+ 
    /* If TYPE is NULL, we are allocating a stack slot for caller-save
       register in MODE.  We will return the largest alignment of XF
       and DF.  */
*************** ix86_local_alignment (tree type, enum ma
*** 19360,19365 ****
--- 19366,19373 ----
  	align = GET_MODE_ALIGNMENT (DFmode);
        return align;
      }
+   if (mode == DImode && !TARGET_64BIT && ix86_preferred_stack_boundary < 64)
+     align = 32;
  
    /* x86-64 ABI requires arrays greater than 16 bytes to be aligned
       to 16byte boundary.  */


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]