Re: Return value on MIPS N64 ABI
Thank you. On Mon, Jun 13, 2016 at 6:19 PM, Matthew Fortunewrote: > Heiher 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 00012c40 <_Z8TestNewAv>: >> 23012c40: 3c030002lui v1,0x2 >> 23112c44: 0079182ddaddu v1,v1,t9 >> 23212c48: 64638400daddiu v1,v1,-31744 >> 23312c4c: dc628050ld v0,-32688(v1) >> 23412c50: 67bdffe0daddiu sp,sp,-32 >> 23512c54: d4400e68ldc1$f0,3688(v0) >> 23612c58: dc628050ld v0,-32688(v1) >> 23712c5c: 67bd0020daddiu sp,sp,32 >> 23812c60: 03e8jr ra >> 23912c64: d4420e70ldc1$f2,3696(v0) >> 240 >> 241 00012c68 <_Z8TestNewBv>: >> 24212c68: 3c0307f9lui v1,0x7f9 >> 24312c6c: 3c0207f7lui v0,0x7f7 >> 24412c70: 3463ori v1,v1,0x >> 24512c74: 3442ori v0,v0,0x >> 24612c78: 00031cb8dsllv1,v1,0x12 >> 24712c7c: 000214b8dsllv0,v0,0x12 >> 24812c80: 3463cccdori v1,v1,0xcccd >> 24912c84: 3442cccdori v0,v0,0xcccd >> 25012c88: 67bdfff0daddiu sp,sp,-16 >> 25112c8c: 00031c78dsllv1,v1,0x11 >> 25212c90: 00021478dsllv0,v0,0x11 >> 25312c94: 6463999adaddiu v1,v1,-26214 >> 25412c98: 6442999adaddiu v0,v0,-26214 >> 25512c9c: 03e8jr ra >> 25612ca0: 67bd0010daddiu sp,sp,16 >> >> // test.cpp >> // gcc -march=mips64r2 -mabi=64 -O3 -o test test.cpp #include >> >> 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; >> } -- Best regards! Heiher http://hev.cc
RE: Return value on MIPS N64 ABI
Heiherwrites: > 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 00012c40 <_Z8TestNewAv>: > 23012c40: 3c030002lui v1,0x2 > 23112c44: 0079182ddaddu v1,v1,t9 > 23212c48: 64638400daddiu v1,v1,-31744 > 23312c4c: dc628050ld v0,-32688(v1) > 23412c50: 67bdffe0daddiu sp,sp,-32 > 23512c54: d4400e68ldc1$f0,3688(v0) > 23612c58: dc628050ld v0,-32688(v1) > 23712c5c: 67bd0020daddiu sp,sp,32 > 23812c60: 03e8jr ra > 23912c64: d4420e70ldc1$f2,3696(v0) > 240 > 241 00012c68 <_Z8TestNewBv>: > 24212c68: 3c0307f9lui v1,0x7f9 > 24312c6c: 3c0207f7lui v0,0x7f7 > 24412c70: 3463ori v1,v1,0x > 24512c74: 3442ori v0,v0,0x > 24612c78: 00031cb8dsllv1,v1,0x12 > 24712c7c: 000214b8dsllv0,v0,0x12 > 24812c80: 3463cccdori v1,v1,0xcccd > 24912c84: 3442cccdori v0,v0,0xcccd > 25012c88: 67bdfff0daddiu sp,sp,-16 > 25112c8c: 00031c78dsllv1,v1,0x11 > 25212c90: 00021478dsllv0,v0,0x11 > 25312c94: 6463999adaddiu v1,v1,-26214 > 25412c98: 6442999adaddiu v0,v0,-26214 > 25512c9c: 03e8jr ra > 25612ca0: 67bd0010daddiu sp,sp,16 > > // test.cpp > // gcc -march=mips64r2 -mabi=64 -O3 -o test test.cpp #include > > 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; > }
Return value on MIPS N64 ABI
Hi, 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? 229 00012c40 <_Z8TestNewAv>: 23012c40: 3c030002lui v1,0x2 23112c44: 0079182ddaddu v1,v1,t9 23212c48: 64638400daddiu v1,v1,-31744 23312c4c: dc628050ld v0,-32688(v1) 23412c50: 67bdffe0daddiu sp,sp,-32 23512c54: d4400e68ldc1$f0,3688(v0) 23612c58: dc628050ld v0,-32688(v1) 23712c5c: 67bd0020daddiu sp,sp,32 23812c60: 03e8jr ra 23912c64: d4420e70ldc1$f2,3696(v0) 240 241 00012c68 <_Z8TestNewBv>: 24212c68: 3c0307f9lui v1,0x7f9 24312c6c: 3c0207f7lui v0,0x7f7 24412c70: 3463ori v1,v1,0x 24512c74: 3442ori v0,v0,0x 24612c78: 00031cb8dsllv1,v1,0x12 24712c7c: 000214b8dsllv0,v0,0x12 24812c80: 3463cccdori v1,v1,0xcccd 24912c84: 3442cccdori v0,v0,0xcccd 25012c88: 67bdfff0daddiu sp,sp,-16 25112c8c: 00031c78dsllv1,v1,0x11 25212c90: 00021478dsllv0,v0,0x11 25312c94: 6463999adaddiu v1,v1,-26214 25412c98: 6442999adaddiu v0,v0,-26214 25512c9c: 03e8jr ra 25612ca0: 67bd0010daddiu sp,sp,16 // test.cpp // gcc -march=mips64r2 -mabi=64 -O3 -o test test.cpp #include 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; }