This is the mail archive of the
gcc@gcc.gnu.org
mailing list for the GCC project.
SPARC, register renaming, __builtin_return_address
- To: gcc at gcc dot gnu dot org
- Subject: SPARC, register renaming, __builtin_return_address
- From: Mark Mitchell <mark at codesourcery dot com>
- Date: Sun, 13 May 2001 16:50:32 -0700
- Organization: CodeSourcery, LLC
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