Heiher <ad...@heiher.info> writes:
> Looks the return value of TestNewA is passed on $f0/$f2 from disassembly
> code.  I don't known why the return value of TestNewB is passed on
> $v0/$v1? a bug?

I believe this is an area where GNU strays from the N64 ABI definition but
is defacto standard. TestA is a struct of two floating point fields which
is passed and returned in FP registers. TestB is a struct of a struct of
two floating point fields (or at least I think that is the interpretation).

The ABI does say that this should be flattened and be seen as simply two
floating point fields but GCC does not and passes it in integer registers
instead. Or at least the ABI says this for arguments but not results.

The relevant bit of the ABI we are not adhering to is 'Structs,unions' on
page 7 which covers arguments, however the corresponding text for results
does not include the part about ignoring the struct field structure
when determining between floating point and integer chunks.

https://dmz-portal.ba.imgtec.org/mw/images/6/6f/007-2816-005-1.pdf

FWIW: Clang/LLVM ABI implementation matches GCC in this regard as we run
cross linking tests and use GCC as 'correct'.

Thanks,
Matthew

> 229 0000000120000c40 <_Z8TestNewAv>:
> 230    120000c40:   3c030002        lui     v1,0x2
> 231    120000c44:   0079182d        daddu   v1,v1,t9
> 232    120000c48:   64638400        daddiu  v1,v1,-31744
> 233    120000c4c:   dc628050        ld      v0,-32688(v1)
> 234    120000c50:   67bdffe0        daddiu  sp,sp,-32
> 235    120000c54:   d4400e68        ldc1    $f0,3688(v0)
> 236    120000c58:   dc628050        ld      v0,-32688(v1)
> 237    120000c5c:   67bd0020        daddiu  sp,sp,32
> 238    120000c60:   03e00008        jr      ra
> 239    120000c64:   d4420e70        ldc1    $f2,3696(v0)
> 240
> 241 0000000120000c68 <_Z8TestNewBv>:
> 242    120000c68:   3c0307f9        lui     v1,0x7f9
> 243    120000c6c:   3c0207f7        lui     v0,0x7f7
> 244    120000c70:   34633333        ori     v1,v1,0x3333
> 245    120000c74:   34423333        ori     v0,v0,0x3333
> 246    120000c78:   00031cb8        dsll    v1,v1,0x12
> 247    120000c7c:   000214b8        dsll    v0,v0,0x12
> 248    120000c80:   3463cccd        ori     v1,v1,0xcccd
> 249    120000c84:   3442cccd        ori     v0,v0,0xcccd
> 250    120000c88:   67bdfff0        daddiu  sp,sp,-16
> 251    120000c8c:   00031c78        dsll    v1,v1,0x11
> 252    120000c90:   00021478        dsll    v0,v0,0x11
> 253    120000c94:   6463999a        daddiu  v1,v1,-26214
> 254    120000c98:   6442999a        daddiu  v0,v0,-26214
> 255    120000c9c:   03e00008        jr      ra
> 256    120000ca0:   67bd0010        daddiu  sp,sp,16
> 
> // test.cpp
> // gcc -march=mips64r2 -mabi=64 -O3 -o test test.cpp #include <stdio.h>
> 
> class TestA
> {
> public:
>         double l;
>         double h;
> 
>         TestA(double l, double h) : l(l), h(h) {} };
> 
> class TestB : public TestA
> {
> public:
>         TestB(const TestA& a) : TestA(a) {} };
> 
> TestA
> TestNewA(void)
> {
>         return TestA(0.1, 0.2);
> }
> 
> TestB
> TestNewB(void)
> {
>         return TestA(0.1, 0.2);
> }
> 
> int
> main(int argch, char *argv[])
> {
>         TestA a = TestNewA();
>         printf("%lf, %lf\n", a.l, a.h);
> 
>         TestB b = TestNewB();
>         printf("%lf, %lf\n", b.l, b.h);
> 
>         return 0;
> }

Reply via email to