6

C/C++ compilers optimize single layer functions with constant parameters (known at compile time) only when using -Os, -O1 and -O2. They do not optimize all the layers. Only -O3 can do that. gcc is WinAVR 4.3.3 which does not support attribute "optimize".

void inner(double value)
{
    //operations using value
    //...
}

void outer(double value)
{
    //few operations using value
    //...
    inner(value);
}

int main()
{
    inner(1); //optimize
    outer(1); //only optimize by using -O3
}

What are the possible solutions other than the followings?

  1. -O3 hold program or file (misuse will blow up the size)
  2. attribute optimize -O3 for the functions (4.3.3 does not support)
  3. macro (error prone)

Update:

//inner function
static inline void _delay_us(double __us) __attribute__((always_inline));
//outer function
void f(double);
inline f1(double);
static inline f2(double);
static f3(double);

f1 is optimized but give warning '_delay_us' is static but used in inline function 'f1' which is not static due to static function problem. Others are not optimized.


Solution:

static inline void outer(double) __attribute__((always_inline));

Inline is the key. My outer function is too large for inline. The attribute always_inline forces the function to be inline. This allows the compiler to optimize the function with less compilation cost than trying to figure out the optimization. -O3 is smart enough to do the optimization but not -Os. -Os may need some compiler options. (The keyword static is required because the inner function is also static inline.)

keithyip
  • 985
  • 7
  • 21
  • Hm, I am not sure to understand why this is a concern. If you want the compiler to optimize, tell him. If you fear that `-O3` (or whatever level) blows up your code size, `-Os` is just the way to go. – Jens Gustedt Jan 31 '11 at 08:56
  • The code is used in 8-bit microcontrollers which do not have hardware floating point ALU. -O3 in fact give smaller code size than -Os in this function, 4k vs 400 – keithyip Jan 31 '11 at 09:21

4 Answers4

3

Somewhat similar to the macro option (3), but without the disadvantages of a macro, you can make specific functions inline, which will typically result in the desired constant optimizations. Of course this only helps if you're calling the relevant functions from one place (or from a few places), otherwise code bloat becomes an issue.

Note that gcc has a provision for forcing specific inline functions to always be inlined (rather than leaving this to the compiler's discretion): __attribute__ ((always_inline)). Other compilers will typically have a similar mechanism, although it may be a command line switch or a pragma.

Paul R
  • 208,748
  • 37
  • 389
  • 560
  • Note that (standard C++) `inline` is only a hint to the compiler. The compiler may ignore such hints if the compiler determines that inlining is not worth it or is not necessary. How this decision is made is dependent on the implementation. – In silico Jan 31 '11 at 08:53
  • @In silico: true, but gcc allows you to force inline functions to be inlined: `__atttribute__ ((always_inline))` – Paul R Jan 31 '11 at 08:55
  • @Paul R GCC will still hold the upper hand when using always_inline. it will reject it for several reasons, the typical cases include: recursion and instruction count. it's a very useful option where size and speed matter, but not quite always. it also has the nsty side-effect of popping other simple stuff out of line. `-finline-limit` is useful if you monitor all this closely and know what you're doing. – justin Jan 31 '11 at 09:29
  • The inner function use static inline. If the outer function also use static inline, there is no such optimizations. The functions are updated at the ended of the original post. – keithyip Jan 31 '11 at 12:07
  • Finally, adding __attribute__ ((always_inline)) to outer function do the job! the keyword inline is not sufficient. – keithyip Jan 31 '11 at 14:21
1

In GCC at least, the -O flags just turn on a whole load of other flags, see e.g. http://gcc.gnu.org/onlinedocs/gcc/Optimize-Options.html. You could just enable the ones you're interested in, although that's generally discouraged.

Note that I'm not sure that the behaviour of e.g. GCC at -O2 and -O3 is necessarily any indicator of what a completely different compiler will do.

Oliver Charlesworth
  • 267,707
  • 33
  • 569
  • 680
1

As a general point, if you increase the information that you supply to the compiler then it might be able to perform a better optimisation.

For instance, assuming those are the only calls to inner and outer then you could declare them as static to limit their scope and allow the compiler more flexibility in how it optimises them.

Depending on the actual content of the functions you could might also declare their parameters as const which lets the compiler know immediately that they cannot be changed without it having to analyse the code

static void inner(const double value)
{
    //operations using value
}

static void outer(const double value)
{
    //few operations using value
    //...
    inner(value);
}
GrahamS
  • 9,980
  • 9
  • 49
  • 63
  • const parameters does not help much. My outer function is too compile time costly to auto optimize without forcing inline. – keithyip Jan 31 '11 at 14:16
0

How about introducing a function 'outerFast', defined in it's own cpp, including the definitions of inner and outer, and compiling only that file with -O3?

It has its own disadvantages, though.

Jan
  • 1,807
  • 13
  • 26
  • I am writing some libraries. Complexed setup is not user friendly for users but the fine optimization control for individual files is very useful in production. – keithyip Jan 31 '11 at 14:20