NOTICE: The Processors Wiki will End-of-Life on January 15, 2021. It is recommended to download any files or other content you may need that are hosted on processors.wiki.ti.com. The site is now set to read only.
C++ Inlining Issues
Contents
Introduction[edit]
This page is about what may go wrong when inlining functions in C++ code. There are some things worth knowing about inlining in plain old C code, but they aren't covered here.
A special welcome goes out to those who come here from the epic length article C++ Template Instantiation Issues. Your long read is near an end! Keep in mind that an inline function which arises from a template has the same issues as any other inline function.
When Inlining Fails[edit]
The most common reason inlining fails is that the code is not built with optimization. Some other, less common, reasons inlining may fail include functions that:
- Have a volatile parameter
- Have a variable length argument list
- Are recursive
- And other similarly unusual situations
When inlining fails, for any reason, the compiler should ideally treat the function as if inlining were never attempted in the first place. A single copy of the function should be generated, which is called just like any other function.
That is not what happens.
Inline functions are different from ordinary functions in an important way. You can supply multiple definitions of an inline function without incurring an error. This is why inline functions can appear in header files. You can't do that with ordinary functions. If you do, the linker issues an error about the function being defined multiple times.
Therefore, when inlining fails, the compiler cannot naively act as if inlining were never attempted. That would cause multiple definition errors. Instead, a static implementation of the function is generated. In the common case of an inline function appearing in a header file, a static copy of the function is generated for every file that includes it. Unfortunately, that increases code size.
Static Variables in Inline Functions[edit]
Things are even more difficult when the inline function contains a static variable. The presence of a static variable does not inhibit inlining. The ANSI standard for C++ requires the compiler to create a single instance of the static local in such a case. The TI compiler does not adhere to this part of the standard. It creates a static copy of the local variable similar to how the function itself is made static. While it rarely occurs in practice, this can cause code to execute incorrectly. Thus the compiler issues a warning when this case occurs.
Here is a simple example.
<syntaxhighlight lang="cpp"> // static_ex1.cpp inline int fxn() {
static int svar; svar++; return svar;
} </syntaxhighlight>
% cl6x static_ex1.cpp "static_ex1.cpp", line 4: warning: static local variables of extern inline function are not resolved to single copy. Not ANSI C++ Compliant
One simple workaround is to make the static variable a global variable. Of course, that's poor form.
A namespace based solution is better. This example has the inline function in a header file, which is more typical of actual practice.
<syntaxhighlight lang=cpp> // hdr.hpp namespace for_static {
int ns_var; inline int fxn() { ns_var++; return ns_var; }
}
using for_static::fxn; </syntaxhighlight>
<syntaxhighlight lang=cpp> // static_ex2.cpp
- include "hdr.hpp"
int test() {
return fxn() + 10;
} </syntaxhighlight>
The using statement means other code that refers to fxn() does not need to change. Though you can still write "for_static::fxn()" if you prefer. Accessing the formerly static variable requires the unlikely step of writing out "for_static::ns_var".
If the inline function is a class member function, then the best workaround is to make the local static variable a static member variable of the class. Consult The C++ Programming Language, 3rd Ed., section 10.2.4 for details. If the inline function is member of a template class, see section C.13.1.
Long Term Solution[edit]
There is a long term solution to all of this. TI compilers for ARM, MSP430, and C6000 devices all support EABI. The handling of inline functions and their possible static local variables is part of the ABI. The details are not worth considering here. The main point is all these inlining issues go away. It just works. The same is true of template instantiation issues.
As of this writing, TI compilers for C2000, C5500, and C5400 do not support EABI.