This is the mail archive of the gcc-bugs@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]

[Bug c/13133] New: Extraneous register-saves triggered by setjmp()


Calling setjmp() causes all kinds of registers to
get saved by GCC:

$ cat t.c
#include <setjmp.h>

jmp_buf j;

void
foo (void)
{
  setjmp (j);
}
$ gcc -v
Reading specs from /opt/gcc-pre3.4/lib/gcc/ia64-hp-linux/3.4/specs
Configured with: ../gcc/configure --enable-shared --with-system-zlib --enable-n\
ls --without-included-gettext --enable-__cxa_atexit --enable-clocale=gnu --enab\
le-java-gc=boehm --enable-objc-gc --enable-languages=c --prefix=/opt/gcc-pre3.4\
 ia64-hp-linux
Thread model: posix
gcc version 3.4 20031113 (experimental)
$ gcc -O2 -S t.c
$ cat t.s
        .file   "t.c"
        .pred.safe_across_calls p1-p5,p16-p63
        .text
        .align 16
        .global foo#
        .proc foo#
foo:
        .prologue
        .mmb
        alloc r16 = ar.pfs, 8, 80, 1, 0
        adds r17 = -424, r12
        nop 0
        .mmi
        adds r18 = -416, r12
        .fframe 448
        adds r12 = -448, r12
        mov r21 = ar.lc
        .mii
        mov r19 = ar.unat
        mov r20 = pr
        addl r120 = @ltoffx(j#), r1
        .mib
        nop 0
        mov r22 = b0
        nop 0
        ;;
        .mmi
        ld8.mov r120 = [r120], j#
        .savesp pr, 24
        st8 [r17] = r20, 16
        mov r23 = b1
        .mii
        nop 0
        mov r24 = b2
        mov r25 = b3
        .mib
        nop 0
        mov r26 = b4
        nop 0
        .mii
        .savesp ar.unat, 32
        st8 [r18] = r19, 16
        mov r27 = b5
        ;;
        nop 0
        .mmb
        .savesp ar.pfs, 40
        st8 [r17] = r16, 16
        .savesp ar.lc, 48
        st8 [r18] = r21, 16
        nop 0
        ;;
        .mmb
        .mem.offset 392, 0
        st8.spill [r17] = r1, 16
        .mem.offset 392, 0
        st8.spill [r17] = r1, 16
        .save.g 0x1
        .mem.offset 384, 0
        st8.spill [r18] = r4, 16
        nop 0
        ;;
        .mmb
        .save.g 0x2
        .mem.offset 376, 0
        st8.spill [r17] = r5, 16
        .save.g 0x4
        .mem.offset 368, 0
        st8.spill [r18] = r6, 16
        nop 0
        ;;
        .mmb
        .save.g 0x8
        .mem.offset 360, 0
        st8.spill [r17] = r7, 16
        .savesp rp, 96
        st8 [r18] = r22, 16
        nop 0
        ;;
        .mmb
        .save.b 0x1
        st8 [r17] = r23, 16
        .save.b 0x2
        st8 [r18] = r24, 16
        nop 0
        ;;
        .mmb
        .save.b 0x4
        st8 [r17] = r25, 16
        .save.b 0x8
        st8 [r18] = r26, 16
        nop 0
        ;;
        .mmb
        .save.b 0x10
        st8 [r17] = r27, 24
        .save.f 0x1
        stf.spill [r18] = f2, 32
        nop 0
        ;;
        .mmb
        .save.f 0x2
        stf.spill [r17] = f3, 32
        .save.f 0x4
        stf.spill [r18] = f4, 32
        nop 0
        ;;
 etc. etc.

Jim Wilson was kind enough to analyze this problem and offer a patch (see
below).  I'd very much appreciate it if this problem could be fixed, since there
are performance-critical paths in libpthread which rely on setjmp().

From: Jim Wilson <wilson@tuliptree.org>
To: David Mosberger <davidm@hpl.hp.com>
Cc: rth@redhat.com, wilson@tuliptree.org
Subject: Re: weird saves triggered by setjmp()
Date: 15 Nov 2003 23:52:24 -0800

On Sat, 2003-11-15 at 11:13, David Mosberger wrote:
> The problem is that setjmp() causes all kinds of registers to
> get saved by GCC.  Example is attached below.

Gcc does this for all targets.  Though it is more noticeable for IA-64
because it has so many registers.

> It appears that GCC is saving every preserved integer/fp register?

Yes.  Every call-saved register is marked as in use if a function
contains a call to setjmp or a related function.

Looking at this now, I see that the code was added between 2.7.2 and
2.8.1, and the intent was that we only did this for builtin setjmp
calls.  This makes some sense, as builtin setjmp is added by the EH
mechanism, not the user, and hence the normal rules of setjmp clobbering
registers don't apply here, so we need to make an effort to save
registers that setjmp won't save.  This code was added by Kenner.

Things got confused after that.  The code originally tested for a
CONST_CALL_P NOTE_INSN_SETJMP.  This was created in
expand_builtin_setjmp, and tested for in reload.  The CONST_CALL_P note
disappeared in 2.95.  It appears that it was deleted by Mike Stump, and
replaced with code to set nonlocal_goto_handler_labels instead.  But the
code testing for the CONST_CALL_P note was still there in reload.

Then Jan Hubicka came along with a patch that replaced NOTE_INSN_SETJMP
with REG_SETJMP.  When this happened, the CONST_CALL_P test was lost,
and now this reload code was enabled for all uses of setjmp.  This
happened in gcc-3.1.

Given this analysis, it does look like it should be possible to just
delete the reload/setjmp code as obsolete.  However, since this affects
setjmp, there is really no good way to test it, and hence we have to be
very careful about this change.  I'd have to propose it, and try to get
some support from others, since we aren't supposed to be adding
destabilizing changes to gcc at this time.

        * reload1.c (reload): Delete special handling for setjmp.

Index: reload1.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/reload1.c,v
retrieving revision 1.408
diff -p -r1.408 reload1.c
*** reload1.c   27 Oct 2003 10:52:46 -0000      1.408
--- reload1.c   16 Nov 2003 07:45:13 -0000
*************** reload (rtx first, int global)
*** 698,706 ****
    /* Look for REG_EQUIV notes; record what each pseudo is equivalent to.
       Also find all paradoxical subregs and find largest such for each pseudo.
       On machines with small register classes, record hard registers that
!      are used for user variables.  These can never be used for spills.
!      Also look for a "constant" REG_SETJMP.  This means that all
!      caller-saved registers must be marked live.  */
  
    num_eliminable_invariants = 0;
    for (insn = first; insn; insn = NEXT_INSN (insn))
--- 698,704 ----
    /* Look for REG_EQUIV notes; record what each pseudo is equivalent to.
       Also find all paradoxical subregs and find largest such for each pseudo.
       On machines with small register classes, record hard registers that
!      are used for user variables.  These can never be used for spills.  */
  
    num_eliminable_invariants = 0;
    for (insn = first; insn; insn = NEXT_INSN (insn))
*************** reload (rtx first, int global)
*** 713,724 ****
        if (INSN_P (insn) && GET_CODE (PATTERN (insn)) == USE
          && GET_MODE (insn) != VOIDmode)
        PUT_MODE (insn, VOIDmode);
- 
-       if (GET_CODE (insn) == CALL_INSN
-         && find_reg_note (insn, REG_SETJMP, NULL))
-       for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
-         if (! call_used_regs[i])
-           regs_ever_live[i] = 1;
  
        if (set != 0 && GET_CODE (SET_DEST (set)) == REG)
        {
--- 711,716 ----

-- 
           Summary: Extraneous register-saves triggered by setjmp()
           Product: gcc
           Version: 3.4
            Status: UNCONFIRMED
          Severity: enhancement
          Priority: P2
         Component: c
        AssignedTo: unassigned at gcc dot gnu dot org
        ReportedBy: davidm at hpl dot hp dot com
                CC: gcc-bugs at gcc dot gnu dot org
  GCC host triplet: ia64-hp-linux


http://gcc.gnu.org/bugzilla/show_bug.cgi?id=13133


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