Mandalika's scratchpad [ Work blog @Oracle | Stock Market Notes | My Music Compositions ]

Old Posts: 09.04  10.04  11.04  12.04  01.05  02.05  03.05  04.05  05.05  06.05  07.05  08.05  09.05  10.05  11.05  12.05  01.06  02.06  03.06  04.06  05.06  06.06  07.06  08.06  09.06  10.06  11.06  12.06  01.07  02.07  03.07  04.07  05.07  06.07  08.07  09.07  10.07  11.07  12.07  01.08  02.08  03.08  04.08  05.08  06.08  07.08  08.08  09.08  10.08  11.08  12.08  01.09  02.09  03.09  04.09  05.09  06.09  07.09  08.09  09.09  10.09  11.09  12.09  01.10  02.10  03.10  04.10  05.10  06.10  07.10  08.10  09.10  10.10  11.10  12.10  01.11  02.11  03.11  04.11  05.11  07.11  08.11  09.11  10.11  11.11  12.11  01.12  02.12  03.12  04.12  05.12  06.12  07.12  08.12  09.12  10.12  11.12  12.12  01.13  02.13  03.13  04.13  05.13  06.13  07.13  08.13  09.13  10.13  11.13  12.13  01.14  02.14  03.14 


Friday, April 15, 2005
 
Sun C/C++ compilers: Inlining routines

The C++ compiler has two kinds of inlining: front-end (parser) and back-end (code generator). The C and Fortran compilers have only back-end inlining. The same code generator is used for all compilers on a platform.

Function inlining improves performance by replacing a call to a function with the body of the function itself. This eliminates the overhead of jumping to and returning from a subroutine. An additional advantage is that placing the function code "inline" exposes it to further optimization, enhancing performance even more.

The C++ compiler front end will attempt to expand inline a function declared implicitly or explicitly as inline. If the function is too large, the front end emits a warning when the +w or +w2 ("more warnings") option is used. The +d option prevents the front end from attempting to inline any function. The -g option also turns off front-end inlining. The -O options do not affect front-end inlining. For C++, with -g and -O options, you lose function inlining in the front end of the compiler. This can result is serious loss of performance. To avoid this problem, use -g0 instead of -g. C does not have -g0, use -g instead.

The C++ compiler performs front-end inlining because it can use its knowledge of C++ semantics to eliminate extra copies of objects, among other things that the code generator would not be able to do.

The back-end inlining does not depend on the programming language. With an optimization level of -O4 or higher, the code generator will examine all functions, independent of how they were declared in source code, and replace function calls with inline code where it thinks the replacement will be beneficial. No messages are emitted about back-end inlining (or failure to inline). The +d option does not affect back-end inlining.

Notes:
  1. Don't use "if(0)" in an inline function. Use "#if 0" instead.
  2. Also, don't put a return statement in the "then" part of an if-statement.
    Rearrange the code to put the return in the "else" part, or outside
    the if-else entirely.

Example #1:

% more inline.c
#include <stdio.h>

inline void printmespam() {
printf("print me"); printf("print me");
printf("print me"); printf("print me");
printf("print me"); printf("print me");
printf("print me"); printf("print me");
printf("print me"); printf("print me");
printf("print me"); printf("print me");
printf("print me"); printf("print me");
printf("print me"); printf("print me");
printf("print me");
}

inline void printme() {
printf("print me");
}

int main() {
printme();
printmespam();
return (0);
}

% CC +w2 inline.c
"inline.c", line 17: Warning: "printmespam()" is too large and will not be expanded inline.
1 Warning(s) detected.

In this example, printmespam() was not inlined by the compiler though we requested it to "inline" it. The keyword "inline" is a request, not a guarantee.

How to check if the routine is inlined:
Check the symbol table of the executable. If the routine doesn't showup in the symbol table, it is an indication that the missing routine is inlined. This is because the compiler might have replaced the function call with the body of the function.

% elfdump -CsN.symtab a.out | grep printme
[85] 0x00010e68 0x000000a4 FUNC GLOB D 0 .text void printmespam()

printme is inlined, where as printmespam is not.

The other way is to check the assembly code being generated. To generate the assembly code, compile the code with -S option of Sun Studio compilers.

% more swap.c
void swap (int *a, int *b) {
int t = *a;
*a = *b;
*b = t;
}

int main() {
int x = 5, y = 2;
swap(&x,&y);
return (0);
}

% CC +w2 -S swap.c

% grep call swap.s
call __1cEswap6Fpi0_v_

% dem __1cEswap6Fpi0_v_
__1cEswap6Fpi0_v_ == void swap(int*,int*)

From the above output(s), it is clear that the function is not inlined since an assembly instruction has been generated with a call to routine swap.

% more swap.c
inline void swap (int *a, int *b) {
int t = *a;
*a = *b;
*b = t;
}

int main() {
int x = 5, y = 2;
swap(&x,&y);
return (0);
}
% CC +w2 -S swap.c
% grep call swap.s

Now after instructing the compiler to inline the routine swap, the compiler was able to inline the function in main(), since it was not too big. That's why no assembly instruction has been generated with a call to swap.

Example #2:

%more inline2.c
#include <stdio.h>

int globvar = 0;

inline void setglob () {
globvar= 25;
}

int main(int argc, char *argv[]) {
globvar= 5;
setglob();
printf("Now global variable holds %d\n", globvar);
return (0);
}

%cc -o test inline2.c
Undefined first referenced
symbol in file
setglob inline2.o
ld: fatal: Symbol referencing errors. No output written to test

The above code violates a C rule. An inline definition without an "extern" directive does not create an instance of the function. Calling the function has undefined results.

The fix is to declare setglob with external linkage.

C++ has a different rule for inline functions. The compiler is required to figure out how to generate a defining instance if one is needed, without any special action by the programmer. So, the above example (#2) is valid C++ code, but not valid C code.

Modified code:

% more inline2.c
#include <stdio.h>

int globvar = 0;

extern inline void setglob () {
globvar= 25;
}

int main(int argc, char *argv[]) {
globvar= 5;
setglob();
printf("Now global variable holds %d\n", globvar);
return (0);
}

% cc inline2.c
% ./a.out
Now global variable holds 25

Acknowledgements:
Steve Clamage


Comments: Post a Comment

Links to this post:

Create a Link



<< Home


2004-2014 

This page is powered by Blogger. Isn't yours?