Please note as of Wednesday, August 15th, 2018 this wiki has been set to read only. If you are a TI Employee and require Edit ability please contact x0211426 from the company directory.

C++ Inlining Issues

From Texas Instruments Wiki
Jump to: navigation, search

Introduction

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

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

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.

// static_ex1.cpp
inline int fxn()
{
   static int svar;
   svar++;
   return svar;
}
% 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.

// hdr.hpp
namespace for_static {
   int ns_var;
   inline int fxn()
   {
      ns_var++;
      return ns_var;
   }
}
 
using for_static::fxn;
// static_ex2.cpp
#include "hdr.hpp"
 
int test()
{
   return fxn() + 10;
}

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

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.