Patchwork Tiny .eh_frame size optimization

login
register
mail settings
Submitter Jakub Jelinek
Date Sept. 20, 2010, 12:14 p.m.
Message ID <20100920121452.GL1269@tyan-ft48-01.lab.bos.redhat.com>
Download mbox | patch
Permalink /patch/65199/
State New
Headers show

Comments

Jakub Jelinek - Sept. 20, 2010, 12:14 p.m.
Hi!

Ulrich recently pointed out that with -gdwarf2-cfi-asm (the default with
not too obsolete binutils) the unwind info is unnecessarily large.
E.g.
        .cfi_startproc
        pushq   %rbx
        .cfi_def_cfa_offset 16
        movq    %rdi, %rbx
        .cfi_offset 3, -16
        /* asm using %rbx */
        popq    %rbx
        .cfi_def_cfa_offset 8
        ret
        .cfi_endproc
there is an unnecessary DW_CFA_advance_loc* - the pushq insn both adjusts
CFA and saves the %rbx register.  When emitting .eh_frame by hand, we emit
the queued register saves at last_reg_save_label instead of current spot,
but when emitting .cfi_* directives we don't have that luxury when this
processing is done during insn output.

The patch below flushes all queued register saves not just on
jumps/calls/barriers or insns that clobber any of the registers that
have register saves queued, but any time we already had to emit some
directives at the current spot.

On i686-linux cc1plus, the .eh_frame size went down from
771220 to 757260.
readelf -wf ../objbefore/gcc/cc1plus | grep DW_CFA_ | egrep -v DW_CFA_nop | wc -l
317205
readelf -wf ../objafter/gcc/cc1plus | grep DW_CFA_ | egrep -v DW_CFA_nop | wc -l
308218
readelf -wf ../objbefore/gcc/cc1plus | grep DW_CFA_ | egrep -v DW_CFA_'(nop|advance)' | wc -l
197091
readelf -wf ../objafter/gcc/cc1plus | grep DW_CFA_ | egrep -v DW_CFA_'(nop|advance)' | wc -l
197102
The 11 non-advance/nop ops addition is due to the changes in dwarf2out.c,
on dwarf2out.o only.
Similarly on x86_64-linux cc1plus, size went down from
766028 to 754532.
readelf -wf ../objbefore/gcc/cc1plus | grep DW_CFA | egrep -v DW_CFA_nop | wc -l
270890
readelf -wf ../objafter/gcc/cc1plus | grep DW_CFA | egrep -v DW_CFA_nop | wc -l
255556
readelf -wf ../objbefore/gcc/cc1plus | grep DW_CFA | egrep -v DW_CFA_'(nop|advance)' | wc -l
152807
readelf -wf ../objafter/gcc/cc1plus | grep DW_CFA | egrep -v DW_CFA_'(nop|advance)' | wc -l
152816

Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk?

2010-09-20  Jakub Jelinek  <jakub@redhat.com>

	* dwarf2out.c (any_cfis_emitted): New static variable.
	(add_fde_cfi): Set it.
	(dwarf2out_frame_debug): Clear it before processing,
	if it is set afterwards, flush any queued reg saves.


	Jakub
Jason Merrill - Sept. 20, 2010, 3:08 p.m.
OK.

Jason
Richard Henderson - Sept. 20, 2010, 3:30 p.m.
On 09/20/2010 05:14 AM, Jakub Jelinek wrote:
> 	* dwarf2out.c (any_cfis_emitted): New static variable.
> 	(add_fde_cfi): Set it.
> 	(dwarf2out_frame_debug): Clear it before processing,
> 	if it is set afterwards, flush any queued reg saves.

Ok.


r~

Patch

--- gcc/dwarf2out.c.jj	2010-09-17 09:58:23.000000000 +0200
+++ gcc/dwarf2out.c	2010-09-20 09:54:00.000000000 +0200
@@ -800,6 +800,9 @@  dwarf2out_cfi_label (bool force)
 /* True if remember_state should be emitted before following CFI directive.  */
 static bool emit_cfa_remember;
 
+/* True if any CFI directives were emitted at the current insn.  */
+static bool any_cfis_emitted;
+
 /* Add CFI to the current fde at the PC value indicated by LABEL if specified,
    or to the CIE if LABEL is NULL.  */
 
@@ -879,6 +882,7 @@  add_fde_cfi (const char *label, dw_cfi_r
 	  output_cfi_directive (cfi);
 
 	  list_head = &fde->dw_fde_cfi;
+	  any_cfis_emitted = true;
 	}
       /* ??? If this is a CFI for the CIE, we don't emit.  This
 	 assumes that the standard CIE contents that the assembler
@@ -916,6 +920,7 @@  add_fde_cfi (const char *label, dw_cfi_r
 	}
 
       list_head = &fde->dw_fde_cfi;
+      any_cfis_emitted = true;
     }
 
   add_cfi (list_head, cfi);
@@ -2745,6 +2750,7 @@  dwarf2out_frame_debug (rtx insn, bool af
     }
 
   label = dwarf2out_cfi_label (false);
+  any_cfis_emitted = false;
 
   for (note = REG_NOTES (insn); note; note = XEXP (note, 1))
     switch (REG_NOTE_KIND (note))
@@ -2830,7 +2836,11 @@  dwarf2out_frame_debug (rtx insn, bool af
 	break;
       }
   if (handled_one)
-    return;
+    {
+      if (any_cfis_emitted)
+	dwarf2out_flush_queued_reg_saves ();
+      return;
+    }
 
   insn = PATTERN (insn);
  found:
@@ -2839,7 +2849,7 @@  dwarf2out_frame_debug (rtx insn, bool af
   /* Check again.  A parallel can save and update the same register.
      We could probably check just once, here, but this is safer than
      removing the check above.  */
-  if (clobbers_queued_reg_save (insn))
+  if (any_cfis_emitted || clobbers_queued_reg_save (insn))
     dwarf2out_flush_queued_reg_saves ();
 }