As said in the previous post, some ABI specs are a little confusing, and sometimes there are so many (15 different variations for mips), that you just don’t remember where that rule came from. For the more interested ones there’s a whole history about mips ABIs and why there are some many. I’ll devote my time in the next posts, writing about implementations issues in o32 and eabi ones. llvm mips backend is walking toward full support for both (I already implemented the basic calling convention mechanism for o32 and eabi) I’ll approach some issues giving some llvm view of things.
o32
o32 is the mips old 32 bit ABI specified by Sysv4. It’s easy to find o32 on a linux box or in embedded mips applications, worth having support on a compiler. o32 is known for its bad register usage (it’s very inefficient when compared to eabi for example) and messy spec. So, since it is the most comom llvm should have it.
eabi
As all the other used ABIs, the eabi is implemented in GCC. There is no official documentation about it and the only resource available is a post on binutils mailing list and gcc mips backend sources. Although this is the only doc available, it is very direct and a thousand times better than the sysV one. This ABI is used to generate mips assembly for the psp allegrex core (the pspdev gcc patches from uses eabi by default). Since I’m giving support for the allegrex core, this abi must be implemented in llvm.
Structure return
If a pointer to a struct is returned, then it is considered a normal pointer and nothing special has to be done. But if a function returns the whole aggregate, the space must be allocated on the caller and the aggregate address must be passed as the first argument ($4) to the callee. The callee must fulfill this memory space with the returned value before exiting and must also return the pointer in $2. This mechanism is called sret in llvm, where we use a argument with a pointer to the memory space reserved for the aggregate. To be more specific, if we consider this C function:
1 2 3 4 5 6 7 8 9 |
struct sret0 { int a; }; struct sret0 test0(int dummy) { struct sret0 s; s.a = dummy; return s; } |
The following asm output for function test0 is:
1 2 3 |
move $2,$4 sw $5,0($4) j $31 |
As the code highlights the pointer argument comes in $4, is copied to the return value register $2, and the struct is fulfilled by storing the 2nd argument ($5) into the memory pointed by $4. The eabi has almost the same behavior when dealing with struct passing, the only difference is that it directly returns single element structs and aggregates <= 64 bits, and only uses the shadow mechanism otherwise (eabi always uses registers when it’s possible, that’s why it’s so fast, someday I’ll deserve it a post).