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

SPARC, register renaming, __builtin_return_address



I've just travelled down a fascinating rathole.

On SPARC, 20010122-1.c has regressed from GCC 2.95.2.

This test is one that uses __builtin_return_address (1) in several
places, and that's not working correctly.  The problem is that we emit
the following code:

  test10a:
	  !#PROLOGUE# 0
	  save	%sp, -112, %sp
	  !#PROLOGUE# 1
	  ta	3
	  ld	[%sp+60], %o0
	  sethi	%hi(ret_addr), %g1
	  st	%o0, [%g1+%lo(ret_addr)]
	  ret
	  restore

For:

  void test10a (char * p)
  {
    ret_addr = __builtin_return_address (1);
    return;
  }

when compiling with -O3.

Here, [%sp + 60] is the return value for this function, not for its
caller.  In other words, we've done:

  ret_addr = __builtin_return_address(0)

instead of 

  ret_addr = __builtin_return_address(1)

Why did that happen?

Because until register renaming, we didn't think we were going to have
a stack frame.  We thought this function was a leaf, and so we thought
%sp would be our callers %sp, not our own.

Before register renaming we had:

  (insn 27 13 28 (set (reg:SI 25 %i1 [107])
	  (mem:SI (plus:SI (reg/f:SI 14 %sp)
		  (const_int 60 [0x3c])) 0)) 51 {*movsi_insn} (nil)
      (expr_list:REG_EQUIV (mem:SI (plus:SI (reg/f:SI 14 %sp)
		  (const_int 60 [0x3c])) 0)
	  (nil)))

  (insn 28 27 16 (set (reg/f:SI 24 %i0 [109])
	  (high:SI (symbol_ref:SI ("ret_addr")))) 53 {*movsi_high} (nil)
      (expr_list:REG_EQUIV (high:SI (symbol_ref:SI ("ret_addr")))
	  (nil)))

  (insn 16 28 26 (set (mem/f:SI (lo_sum:SI (reg/f:SI 24 %i0 [109])
		  (symbol_ref:SI ("ret_addr"))) 2)
	  (reg:SI 25 %i1 [107])) 51 {*movsi_insn} (insn_list 27 (insn_list 28 (insn_list 12 (insn_list 13 (insn_list:REG_DEP_ANTI 10 (nil))))))
      (expr_list:REG_DEAD (reg:SI 25 %i1 [107])
	  (expr_list:REG_DEAD (reg/f:SI 24 %i0 [109])
	      (nil))))

Register renaming for some reason decides to rename %i1 to %o0 and %i0
to %g1.  

(It's wasn't clear what *good* this was supposed to do, so I looked at
the register renaming code.  The comment on regrename_optimize is the
none-too-illuminating:

  /* Perform register renaming on the current function.  */

Hmm.  Lucky I already knew what this optimization was about.)

Anyhow, ignoring the goodness of the optimization, why does this cause
a problem?  Because now we're using %o0, and %o0 isn't a leaf
register, and so we now decide to introduce a `save' instruction in
the prologue.  But, that means we're adding a frame where we didn't
have one before, and everything goes to heck.

(You have to think hard to figure out why GCC doesn't think %o0 is a
leaf register.  That's because since this is a leaf function, we're
going to come along and remap registers later, so %i0 *is* a leaf
register.  %i0 will get remapped to %o0.)

There are multiple issues here:

  - Register renaming probably shouldn't be using non-leaf registers
    when we have a function that only uses leaf registers up until
    this point.

    I will fix this, unless anyone objects.
	
  - The manual explicitly documents __builtin_return_address 
    being guaranteed to return the correct value only when 
    the index is 0.

    Therefore, the test-case is semi-bogus.
	
  - The documentation for regrename.c is, shall we say, minimal.
    There is not even a basic description of the optimization being
    performed.  There is no mention of this pass in the `passes'
    section in the manual.

    The best overall description actually shows up with the
    -frename-registers documentation in the manual.

    Whoever originally wrote this code should write some
    documentation for it.  In addition to the lack of global 
    description, there are no comments on many of the functions
    and variables in regrename.c.

  - The name and documentation for current_function_uses_only_leaf_regs
    is less-than-complete.  This variable actually means that
    this function *is* a leaf function, without a normal prologue
    and epilogue.  In particular, this variable isn't set
    when we're not optimizing (independent of the registers in use),
    and everything assumes that leaf register renaming will be done
    if this variable is true.

  - Why are we renaming registers that aren't being used more
    than once in the function?  It doesn't hurt, but is it 
    expected to help?

--
Mark Mitchell                   mark@codesourcery.com
CodeSourcery, LLC               http://www.codesourcery.com


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