tags:

views:

238

answers:

3

Hi,

In the ARM ABI documentation I come across functions defined like:

__value_in_regs struct bar foo(int a, int b) {
    ...
}

but GCC(4.3.3) doesn't allow it and all I could find are references to some RealView compiler. Is there any way of doing this from GCC?

I have tried -freg-struct-return but it doesn't make a difference. As it is an ABI I can't change the original programs, and returning a regular struct mangles the stack.

I would rather not using assembly for this if avoidable as it isn't otherwise necessary.

Thanks!

+1  A: 

In the ARM repertoire, each register is 32 bits wide (minimum). A register can only contain a structure that contains this size or less.

I suggest letting the compiler optimize the code rather than forcing it to use registers for each field in a structure. The compiler may already reserve some register for calling conventions and other issues. This may be a micro-optimization issue.

You can declare N number or register variables, then assign the members of the struct to those variables. There is no guarantee that this will work as the register keyword is only a hint to the compiler.

I highly suggest that you profile the code, if you haven't done so already. If you know this area needs optimizing, print the assembly language listing to get a baseline from the compiler. Try first to optimize using C statements before using inline assembly. Also, try to isolate the functionality into a separate source file or translation unit be using inline assembly. Usually, optimization at this level becomes highly platform specific.

Thomas Matthews
@Thomas, that's not an option for the OP. He has an existing ABI he needs to support. In that ABI, the structures in question are passed in registers.
Carl Norum
A: 

I'm not sure if this will work, but you can try using the pcs function attribute:

struct bar foo(int a, int b) __attribute__((pcs("aapcs")));
struct bar foo(int a, int b) {
    ...
}
Adam Rosenfield
This behaviour isn't specified in the AAPCS; it's a RVCT feature.
Carl Norum
+1  A: 

Posting as an answer by request:

If you have to generate a binary that will work with an ABI your compiler doesn't support, you're in for some trouble. There's nothing you can do in C. In this case, you'll need to fall back on assembly language programming and thunk the necessary calls. There are two possibilities:

  1. Calls from your binary into the other binary's ABI.
  2. Calls from the other binary into your binary's ABI.

Both of these problems are solved similarly. To call out from your code, you'll need to make shim functions in assembly that swizzle around the calling convention to match the external ABI, and then call the external functions from there. The difference to your C code is that now to make external calls, you call your internal assembly routine, and it does whatever it needs to to call out externally, then puts the return value back in a format your C code will understand, and returns.

To support calls from the external binary into your code, you do the same thing, but in reverse. The entry points to your binary will be little assembly routines that swizzle the external ABI into a format your C code can understand, call your internal function, then put the return values back into a format the external code understands, and return.

Sometimes there's just no good solution, I'm afraid.

Carl Norum