This is the mail archive of the
gdb@sources.redhat.com
mailing list for the GDB project.
Re: MIPS o32 ABI spec, $fp1 valid?
- From: Andrew Cagney <ac131313 at redhat dot com>
- To: David Anderson <davea at quasar dot engr dot sgi dot com>,Kevin Buettner <kevinb at redhat dot com>
- Cc: cgd at broadcom dot com, gdb at sources dot redhat dot com, drow at mvista dot com
- Date: Wed, 18 Jun 2003 12:11:52 -0400
- Subject: Re: MIPS o32 ABI spec, $fp1 valid?
- References: <200306172012.NAA26452@quasar.engr.sgi.com>
Andrew Cagney <ac131313@redhat.com> writes:
Does the o32 ABI specify how to spill a loating point register (a spill
is different to a double store of a parameter as a spilt register is
recovered by the unwind code. mdebug might, for instance, specify
something.
No, mdebug says nothing about how spills are done (it says nothing
about how exactly float/double are stored, AFAICT).
Sigh. However, this code is finally starting to make [partial] sense.
The hardware requires mentioning the odd regs to get the entire
64 bits stored. In MIPS1.
Here is some mips1 o32 disassembly output, IRIX, so big-endian:
Given
double x1(double d)
{
double d2 = d + 3.0;
d2 += x2(5.0);
return d2/4.5;
}
The param
[ 11] 0x 58: e7 ad 00 38 swc1 $f13,56($sp)
[ 11] 0x 5c: e7 ac 00 3c swc1 $f12,60($sp)
The spill
[ 11] 0x 90: e7 b5 00 18 swc1 $f21,24($sp)
[ 11] 0x 94: e7 b4 00 1c swc1 $f20,28($sp)
[ 12] 0x 98: e7 a8 00 34 swc1 $f8,52($sp)
[ 13] 0x 9c: 03 20 f8 09 jalr $25
[ 12] 0x a0: e7 a9 00 30 swc1 $f9,48($sp)
# 9 }
# 10 double x1(double d)
# 11 {
.ent x1 2
x1:
.option O1
.set noreorder
.cpload $25
.set reorder
subu $sp, 56
sw $31, 36($sp)
.cprestore 32
s.d $f12, 56($sp)
s.d $f20, 24($sp)
.mask 0x90000000, -20
.fmask 0x00300000, -32
.frame $sp, 56, $31
.loc 2 11
...
Now I must admit I am using a modern compiler, not an original
old mips1 compiler. So while the spill would be the same,
(and same as reg saves) I don't recall precisely how it would
really look in IRIX mips1 assembler.
Ref: mips_find_saved_regs /float_mask/ at the end of the function.
I believe that the debug info indicates that $f20/$f21 were both saved.
The code comes with the comment:
/* Apparently, the freg_offset gives the offset to the first 64
bit saved.
When the ABI specifies 64 bit saved registers, the FREG_OFFSET
designates the first saved 64 bit register.
When the ABI specifies 32 bit saved registers, the ``64 bit
saved DOUBLE'' consists of two adjacent 32 bit registers, Hence
FREG_OFFSET, designates the address of the lower register of
the register pair. Adjust the offset so that it designates the
upper register of the pair -- i.e., the address of the first
saved 32 bit register. */
Now, from the thread so far, it is clear that the comment is only
partially correct. It should indicate that:
On a big endian 32 bit ABI, the compiler spills floating-point registers
as a pair and as a floating-point double. Because the target is
big-endian, this leads to the register pair being stored in reverse
order vis: $fN ||| $fN+1 are stored as $fN+1 and then $fN.
The code doesn't do that, it gets the address of $fN correct, but $fN+1
is 8 bytes out. Outch!
Given o32, GDB needs to track the location of the individual 32 bit
floating point registers and not 64 bit FP pairs. By doing that, the
code (mips_register_to_value):
frame_read_register (frame, regnum + 0, (char *) to + 4);
frame_read_register (frame, regnum + 1, (char *) to + 0);
is able to correctly construct a double value for any frame.
Andrew
(dave, one last favour, can you check -o32 -mips>1 to see if the fmask
remains the same. I'd expect it to).