Bitten by inlining (again)

So this relatively straight-forward looking code fails to compile without optimisation:

#include <stdio.h>

inline void f1()
{
  printf("In f1\\n");
}

inline void f2()
{
  printf("In f2\\n");
  f1();
}

void main()
{
  printf("In main\\n");
  f2();
}

Here's the linker error when compiled without optimisation:

% cc inline.c
Undefined                       first referenced
 symbol                             in file
f2                                  inline.o
ld: fatal: Symbol referencing errors. No output written to a.out

At low optimisation levels the compiler does not inline these functions, but because they are declared as inline functions the compiler does not generate function bodies for them - hence the linker error. To make the compiler generate the function bodies it is necessary to also declare them to be extern (this places them in every compilation unit, but the linker drops the duplicates). This can either be done by declaring them to be extern inline or by adding a second prototype. Both approaches are shown below:

#include <stdio.h>

extern inline void f1()
{
  printf("In f1\\n");
}

inline void f2()
{
  printf("In f2\\n");
  f1();
}
extern void f2();

void main()
{
  printf("In main\\n");
  f2();
}

It might be tempting to copy the entire function body into a support file:

#include <stdio.h>

void f1()
{
  printf("In duplicate f1\\n");
}

void f2()
{
  printf("In duplicate f2\\n");
  f1();
}

This is a bad idea, as you might gather from the deliberate difference I've made to the source code. Now you get different code depending on whether the compiler chooses to inline the functions or not. You can demonstrate this by compiling with and without optimisation, but this only forces the issue to appear. The compiler is free to choose whether to honour the inline directive or not, so the functions selected for inlining could vary from build to build. Here's a demonstration of the issue:

% cc -O inline.c inline2.c
inline.c:
inline2.c:
% ./a.out
In main
In f2
In f1

% cc inline.c inline2.c
inline.c:
inline2.c:
% ./a.out
In main
In duplicate f2
In duplicate f1

Douglas Walls goes into plenty of detail on the situation with inlining on his blog.

Comments:

Note that using inline with sunpro is asking for trouble.

http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6878135

http://gmplib.org/list-archives/gmp-discuss/2010-February/004041.html

(not sure the second one is caused by inline as I don't have the means to reproduce it, but it is my first guess)

Posted by Marc on February 15, 2010 at 08:56 PM PST #

Thanks, Marc.

I don't agree with your conclusion that using inlining always causes trouble. However, you do seem to have hit some issues!

The first issue is a bug.

The second issue is a problem of some kind, but there's not sufficient information to be able to figure out where the problem is. It looks like non-inlined versions of the functions get included multiple times.

Yeah, cg dying is always a bug.

Posted by Darryl Gove on February 16, 2010 at 02:31 AM PST #

Post a Comment:
Comments are closed for this entry.
About

Darryl Gove is a senior engineer in the Solaris Studio team, working on optimising applications and benchmarks for current and future processors. He is also the author of the books:
Multicore Application Programming
Solaris Application Programming
The Developer's Edge

Search

Categories
Archives
« April 2014
SunMonTueWedThuFriSat
  
1
2
5
6
8
9
10
12
13
14
15
18
19
20
21
22
23
24
25
26
27
28
29
30
   
       
Today
Bookmarks
The Developer's Edge
Solaris Application Programming
Publications
Webcasts
Presentations
OpenSPARC Book
Multicore Application Programming
Docs