gbadev.org forum archive

This is a read-only mirror of the content originally found on forum.gbadev.org (now offline), salvaged from Wayback machine copies. A new forum can be found here.

C/C++ > C/C++ Optimization trick: Returning two ints from a function

#176998 - Dwedit - Fri Nov 18, 2011 8:15 pm

According to the Arm Procedure Call Standard, there is only one efficient way to return values greater than 32-bits from a function, and that is to use 64-bit integers. A struct that consists of two int values will not work, since it will force the compiler to use the stack.

So here's an example of how to efficiently return two ints from a function:

Code:

typedef unsigned int u32;
typedef unsigned long long u64;

typedef union
{
   u64 doubleword;
   struct
   {
      u32 a;
      u32 b;
   } words;
} doubleword;

#define ReturnTwoInts(a,b) \
   {\
      doubleword dw;\
      dw.words.a = (a);\
      dw.words.b = (b);\
      return dw.doubleword;\
   }

#define AssignToTwoInts(c,a,b) \
   {\
      doubleword dw;\
      dw.doubleword = (c);\
      (a) = dw.words.a;\
      (b) = dw.words.b;\
   }

u64 ExampleFunction(u32 a, u32 b)
{
   a+=4;
   b+=4;
   ReturnTwoInts(a,b);
}


When you want to call ExampleFunction, you can just use something like "AssignToTwoInts(ExampleFunction(a,b),a,b)".

ExampleFunction gives this assembly code:
Code:

ExampleFunction:
   add   r0, r0, #4
   add   r1, r1, #4
   bx   lr


If you look at the assembly code for this example function, you can see that despite creating a temporary union value and assigning variables to it, the compiler simply returns the two ints as r0 and r1. r0 and r1 also happen to be the first two int arguments to a function, so you can make fast functions that taken in two ints, do something, then return the next two ints to use.

Additionally, the compiler is also smart enough to properly handle inlining the function that returns two integers.

Compile this at at least -O1, otherwise you get really bad code.


I also tried other ways to build and separate a 64 bit value, but only the union/struct method seemed to generate good code. Bit shifting didn't work very well.
_________________
"We are merely sprites that dance at the beck and call of our button pressing overlord."

#177009 - Miked0801 - Mon Nov 21, 2011 5:45 pm

Thanks for this. I've been reading the latest ARM docs and it does state that this is completely legal and normal. I just hadn't figured out how to get the compiler to do it regularly.