Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I inline a function from another translation unit?

Consider the two translation units below. My goal is to inline the function add both in file1.c and main.c.

file1.c:

extern inline int add(int x, int y)
{
 return x + y;
}

void g(void)
{
  add(1, 1);     // this will probably be inlined
}

main.c:

extern int add(int, int);

void f(void)
{
  add(2, 4);    // this doesn't appear to be inlined
}

int main(void)
{
  f();
  return 0;
}

The generated assembly indicates that add(2, 4) is not inlined. Why? Or is it the rule that, for a function to be inlined in a translation unit, it must be declared inline in the translation unit and therefore its definition must be seen?

like image 831
cmutex Avatar asked Feb 09 '20 05:02

cmutex


People also ask

How do you inline a function?

To inline a function, place the keyword inline before the function name and define the function before any calls are made to the function. The compiler can ignore the inline qualifier in case defined function is more than a line.

What is extern inline?

extern inline will not generate an out-of-line version, but might call one (which you therefore must define in some other compilation unit. The one-definition rule applies, though; the out-of-line version must have the same code as the inline offered here, in case the compiler calls that instead.

Can inline functions extern?

An extern inline function is declared by a file scope declaration with the extern storage-class-specifier (that is, the function definition and/or prototype). For an extern inline function the compiler will provide a global definition of the function in the resulting object file.

What is AC inline function?

An inline function is one for which the compiler copies the code from the function definition directly into the code of the calling function rather than creating a separate set of instructions in memory. This eliminates call-linkage overhead and can expose significant optimization opportunities.


1 Answers

Traditionally, the compiler processes every translation unit separately and therefore optimizations such as function inlining are performed for every translation unit separately. In such a setup, it is not possible for function calls to different translation units to be inlined.

However, most modern compilers have a feature called "Whole Program Optimization" or "Link Time Optimization" which is able to perform interprocedural optimization (including inlining) even if both functions reside in different translation units. But in some compilers, this feature is disabled by default and must be explicitly activated in the compiler/linker options.

The inline keyword merely provides a hint to the compiler suggesting that a function be inlined. Whether it is actually inlined or not is for the compiler's optimizer to decide. Many compilers ignore the hint and judge for themselves whether the function should be inlined, based on the size of the function and how often it is called.

However, most compilers will only perform function inlining if compiler optimizations are activated. If not, then even functions declared as inline are unlikely to be inlined.

My goal is to inline the function add both in file1.c and main.c

In order to achieve that goal, I recommend that you either

  • activate the Whole Program Optimization/Link Time Optimization feature of your compiler described above and hope that the compiler's optimizer takes care of inlining the appropriate functions automatically, or

  • define the function in both translation units, but make it static inline, or

  • define the function as extern inline in exactly one translation unit (in order to not violate the one definition rule), and simply as inline (without any 'extern' or 'static' modifier keywords) in all other translation units, making these so-called "inline definitions" pursuant to §6.7.4 ¶7 of the C11 standard, which leaves it up to the compiler whether it takes the external definition or the definition in the same translation unit.

If you use static inline in all translation units, then you run the risk of unnecessary code duplication in the executable file. In the case of all function calls being inlined by the compiler's optimizer, this code duplication would have occured anyway, so in that case it wouldn't matter. However, in the case of the compiler deciding not to inline the functions, the compiler will generate one function for every translation unit, duplicating code in the executable file. This can likely be prevented by using extern inline in one file translation unit and simply inline (see "inline definitions" described above) in all other translation units.

However, functions declared as extern inline or simply inline (not static inline) have the disadvantage that, according to §6.7.4 ¶3 of the C11 standard, they may not use any variables with internal linkage, only variables with external linkage or no linkage (such as local automatic variables or global variables with external linkage). Also, they may not call any functions with internal linkage (functions with the keyword static), only functions with external linkage.

Because of the mentioned disadvantages of using static inline, extern inline and inline, I recommend that you don't use them at all. Instead, I recommend that you simply make sure that the appropriate optimization settings on your compiler and linker (see above) are set properly and that you let these two programs decide for themselves which functions should be inlined.

Please note that this answer only applies to the language C, not C++, because you tagged the question with "C". The inline keyword in C++ has a slightly different meaning and you can use extern inline in all translation units without violating the C++ one definition rule.

like image 90
Andreas Wenzel Avatar answered Sep 19 '22 13:09

Andreas Wenzel