How can I force the inlining of a function, but define it in a C++ file ?
This is a question that's been asked in the past, for example here: Moving inline methods from a header file to a .cpp files
The answers there, in short, go as follows: "inline used to mean [remove function call overhead at the expense of .text size], now it means [relax ODR], so don't use inline for anything that's not ODR related, the compiler knows better".
I'm aware of that, however in my somewhat exotic case, I don't care about performance.
I'm programming an embedded device and, should someone break through the other layers of security, I want to make it as obnoxious as possible to reverse engineer this part of the code, and one thing this implies is that I don't want function calls (that aren't called numerous times anyway) to expose the function boundaries, which are natural delimitations of pieces of code that achieve something on their own.
However, I would also like to keep my code orderly and not have code in my header files.
I see that I can use __attribute((force_inline)) to force inlining, but then I get warnings if those functions don't have an inline attribute too: warning: always_inline function might not be inlinable [-Wattributes]
Suppressing the attributes warning is an option, but I'd rather only take it once I'm sure there are no clean way to do this.
Hence the question: how can I have a forcibly inlined function whose declaration is in a header, but definition is in a source file, without suppressing all attributes warnings ? Is that impossible ?
Inlining can only be asked. Sometimes a bit forcefully. But you can never guarantee that the function WILL be inlined finally - because reasons, sometimes quite obscure ones.
Here what's MSVC documentation says (I've highlighted the important parts):
The compiler treats the inline expansion options and keywords as suggestions. There's no guarantee that functions will be inlined. You can't force the compiler to inline a particular function, even with the __forceinline keyword. When compiling with /clr, the compiler won't inline a function if there are security attributes applied to the function.
C++ standard says:
No matter how you designate a function as inline, it is a request that the compiler is allowed to ignore: the compiler might inline-expand some, all, or none of the places where you call a function designated as inline.
GCC documentation is a bit less crystal-clear about non-inlinable functions, but cases exists anyway.
The only "real" way to force inlining is quite ugly, since it rely on inlining it before compilation... Yeah, old-style preprocessor macros. The Evil Itself. Or by using a dirty hack with a #include replacing the function call (and inserting C++ code instead)... It may be a bit safer than a macro, regarding double evaluations, but other side-effects can be even worse since it must rely on "global" variables to work.
Does it worth the pain? Probably not. In particular for "obfuscation", because it won't be as "secure" as you think it will be. Yes, an explicit function call is easier to trace. But it won't change anything: reverse engineering don't rely on that to be done. In fact, obfuscation is near never a good (or even working...) solution. I used to think that... a long, very long time ago. I proved to myself that it was near useless. On my own "secured" code. Breaking the code took me much less time than it took me to "protect" it...
Related
I was reviewing a colleague's code recently and noticed he had put the "inline" keyword in in front of a bunch of Getter functions that were defined in a class declaration.
eg
class Foo
{
public:
inline bool GetBar() const { return m_Bar; }
private:
bool m_Bar;
};
I suggested in the code review that he remove the inline keywords, as I've read in a number of different places that defining a function in the class declaration is interpreted by the compiler (MSVC in this case, but apparently part of the C++ standard) as an indication that the author wants the functions inlined. My feeling is that if the extra text doesn't serve any purpose, it's just unnecessary clutter and should be removed.
His response was as follows:
The inline keyword makes it clear to other programmers interacting with this code that these functions are/should be inlined.
Many compilers still take the inline keyword into account in this case and use it to affect (read: increase) some kind of weighting that is used to decide whether or not said function would in fact be inlined.
Having the inline keyword there means that "warn if not inlined" warnings will be triggered (if enabled) if said functions are not inlined for whatever reason.
Personally, I disagree with the first reason altogether. To me, having the functions defined in the class declaration is enough to show the intention.
I'm skeptical about the last two reasons. I can't find any information that either confirms or denies the the point about the inline keyword affecting some sort of weighting. I'm also having trouble triggering the "warn if not inlined" warning for a function defined in a class declaration.
If you've read this far, I was wondering if you might have any insight into any of the above points? Additionally, if you could point me to any relevant articles/documentation, I'd really appreciate it.
Thanks!
Edit 1: Added LLVM (in other words "clang") inlining code
Edit 2: Add clarification as to how to "resolve" this.
The actual correct
Point 1 is of course self-explanatory.
Point 2 is nonsense - all modern compilers (at least MS, GCC and Clang [aka XCode]) completely ignore inline keywords and decides purely based on frequency/size critera (determining "code-bloat factor" based on size * number times, so small functions or functions called only a few times are more likely to be inlined - of course a getter would be a perfect choice for inlining always by the compiler, since it will be only two or three instructions, and most likely shorter than loading up this, then calling the getter function.
The inline keyword doesn't make ANY difference at all [and the C++ standard states that a definition inside the class is inline anyway].
Point 3 is another plausible scenario, but I would have thought that the fact that it is implicitly inline by it's defintion should give the same result. There was discussion about the inline keyword and its meaning on Clang mailing list a while back, with the conclusion that "the compiler usually knows best".
It is also typically completely useless to use inline together with virtual functions, as they will nearly always be called through a vtable entry, and can't be inlined.
Edit 1:
Code taken from LLVM's "InlineCost.cpp":
InlineCost InlineCostAnalysis::getInlineCost(CallSite CS, Function *Callee,
int Threshold) {
// Cannot inline indirect calls.
if (!Callee)
return llvm::InlineCost::getNever();
// Calls to functions with always-inline attributes should be inlined
// whenever possible.
if (CS.hasFnAttr(Attribute::AlwaysInline)) {
if (isInlineViable(*Callee))
return llvm::InlineCost::getAlways();
return llvm::InlineCost::getNever();
}
// Never inline functions with conflicting attributes (unless callee has
// always-inline attribute).
if (!functionsHaveCompatibleAttributes(CS.getCaller(), Callee,
TTIWP->getTTI(*Callee)))
return llvm::InlineCost::getNever();
// Don't inline this call if the caller has the optnone attribute.
if (CS.getCaller()->hasFnAttribute(Attribute::OptimizeNone))
return llvm::InlineCost::getNever();
// Don't inline functions which can be redefined at link-time to mean
// something else. Don't inline functions marked noinline or call sites
// marked noinline.
if (Callee->mayBeOverridden() ||
Callee->hasFnAttribute(Attribute::NoInline) || CS.isNoInline())
return llvm::InlineCost::getNever();
DEBUG(llvm::dbgs() << " Analyzing call of " << Callee->getName()
<< "...\n");
CallAnalyzer CA(TTIWP->getTTI(*Callee), ACT, *Callee, Threshold, CS);
bool ShouldInline = CA.analyzeCall(CS);
DEBUG(CA.dump());
// Check if there was a reason to force inlining or no inlining.
if (!ShouldInline && CA.getCost() < CA.getThreshold())
return InlineCost::getNever();
if (ShouldInline && CA.getCost() >= CA.getThreshold())
return InlineCost::getAlways();
return llvm::InlineCost::get(CA.getCost(), CA.getThreshold());
}
As can be seen (with some digging around in the rest of the code), there is only checks for the "always" and "never" inline options. None for the inline keyword itself.
[Note that this is the inliner code for clang and clang++ - clang itself does not do anything particularly clever when it generates code, it's "just" (upsetting hundreds of programmers who have spent hundreds of manyears on that project!) a parser for C and C++ that translates to LLVM IR, all the good, clever stuff is done at the LLVM layer - this is really a good way to provide a "multilanguage" compiler framework. I have written a Pascal compiler, and despite being a complete novice on compiler work, my compiler (which uses LLVM to generate actual machine code) is better in benchmarks (of the generated code) than Free Pascal - all thanks to LLVM, nearly none of that is my work - except for some code to inline a few commonly called functions in one particular benchmark]
I don't have access sources for MS compiler (doh!), and I can't be bothered to download gcc just to check this. I know, from experience, that all three will inline functions without the inline keyword, and gcc will aggressively inline functions that it can determine has only one caller (e.g. large static helper functions)
Edit 2:
The right way to resolve this sort of issue is to have a coding standard that says, clearly, when and where inline [and functions defined inside the class] should be used, and when this shouldn't be done. If currently, none of the other small getter functions in other classes have inline on them, then it would be strange and stand out that this function does. If all except some have inline, that probably should be fixed too.
Another anectdote: I personally like to write if-statements as
if (some stuff goes here)
(space between if and parenthesis, but not around the thing inside)
but the coding standard at work says:
if( some stuff goes here )
(no space between if and parenthesis, but space around the thing inside)
I had accidentally got something like this:
if ( some stuff goes here )
in some code that was up for review. I fixed that line, but decided to ALSO fix the 175 other if-statements with a space after if - in total there were less than 350 if-statements in that file, so MORE than half of them were incorrect...
For the particular example you mentioned, GetBar is implicitly inlined, which makes the inline keyword redundant. Section 7.1.2 P3 from the C++ standard says:
A function defined within a class definition is an inline function.
Also the VC++ documentation states the same:
A class's member functions can be declared inline either by using the
inline keyword or by placing the function definition within the class
definition.
In general, you don't need to use the inline keyword. A C/C++ expert once said back in 2002:
the inline keyword allows the programmer to tell the compiler
something it might have a hard time figuring out automatically.
However, in the future, compilers may be able to do a better job of
making inline decisions than programmers. When that happens, the
inline keyword might be regarded as a quaint reminder of when
programmers were forced to worry about details of code generation.
You can find the complete article here. You should read the whole article to understand why the keyword was added to C99. Also the article discusses extern inline functions.
Now we are in the future and indeed, modern compilers are very sophisticated and don't require this keyword anymore. The only exception is when using extern inline functions.
Does the inline keyword have any affect whatsoever on the compiler's
decision to inline the function?
In MSVC, the inline keyword might affect the compiler's decision, although the compiler may choose to ignore this hint if inlining would be a net loss.
The inline keyword makes it clear to other programmers interacting
with this code that these functions are/should be inlined.
This is an invalid reason. The programmer is a human being. It's generally very hard for a human to make a better decision than MSVC regarding whether to inline a function or not. Second, what is a programmer supposed to do when you tell him/her that a function should be inlined? The compiler is the one that is doing the inlining. The warning by itself does not tell you whether you have to do anything about it and, in if that was the case, what to do.
Many compilers still take the inline keyword into account in this case
and use it to affect (read: increase) some kind of weighting that is
used to decide whether or not said function would in fact be inlined.
This is true in MSVC. But the modern MSVC doesn't need this hint anymore. If it's beneficial to inline the function, the compiler will know and will inline it. If it's not, it will ignore the inline keyword which was inserted by a human.
Having the inline keyword there means that "warn if not inlined"
warnings will be triggered (if enabled) if said functions are not
inlined for whatever reason.
The MSVC compiler issues warning C4710 when a function that is selected for inlining was not inlined. This warning is disabled by default because most developers don't (and shouldn't) care about this warning. You can enable this warning, however. Unless you're a compiler optimizations researcher and want to understand the inlining algorithm used by MSVC, you shouldn't enable these warnings.
I'm ignoring the C++-specific part of the question and focusing just on ordinary inline functions (C or C++) per your #2 bullet:
I'm skeptical about the last two reasons. I can't find any information that either confirms or denies the the point about the inline keyword affecting some sort of weighting.
https://blog.tartanllama.xyz/inline-hints/ provides some detail, dated January 2018. In short: Clang+LLVM and GCC both take the keyword into account when deciding whether or not to inline a function. It isn't the only consideration, but it does affect the decision.
I know compiler may or may not perform inline expansion of a function whether requested by the programmer or not.
I was just curious to know, is there any way by which programmer can know for sure that compiler has inlined a particular function?
Other than by looking at the generated code, no. Some implementations may provide that information but it's not required by the standard.
Things like inline or register (shudder) are suggestions to the compiler and it's free to accept them, ignore them or even lie to you that it's done it while secretly going behind your back and not doing it :-)
I tend not to use features like that since I suspect the compiler often knows better than I do how to wring the most performance out of my code.
You can profile your code and see if the function of interest shows up in the call stack. Although, I suppose there is no guarantee if your stack sampling rate is not high enough.
But it may prove that it is inlined: if you know A calls B, which calls C, and A never calls C directly, if you see A calling C on the call stack, you know B was inlined for that call.
Set your compiler to generate assembler code and check there.
Read the disassembly of the object file.
There is no way to know except to look at the output assembler.
Compilers these days are 'smart' and they decide what functions to inline and in what cases.
Just like the register keyword, compilers do the picking these days and really ignore your requests.
I don't think there is a way to find out what you want,
But you can increase the possibilites of the function being an inline function by,
Making the definition of the function visible to the translation unit in which it is called. i.e you always have to put the definition of an inline function in header file.
I have to check whether a function is being inlined by the compiler. Is there any way to do this without looking at assembly (which I don't read). I have no choice in figuring this out, so I would prefer if we could not discuss the wisdom of doing this. Thanks!
If you enable warnings C4714, C4710, and C4711, it should give you fairly detailed information about which functions are and aren't inlined.
Each call site may potentially be different.
The compiler may decide for certain parent methods it is worth inlining and for other parent methods that it is not worth inlining. Thus you can not actually determine the real answer without examing the assembley at each call site.
As a result any tools you use would potentially give you a misleading answer. If you use a tool that checks for the existance of symbol (it may be there because some call sites need it, but potentially it may be inlined at others). Conversely the lack of the symbol does not mean the method/function is not inlined it may be static (as in file static) and thus the compiler does not need to keep the symbol around (yet it was not inlined).
Using the /FAs compiler option to dump the asm with source code is the only way that I know of to be sure.
Note: if you want to force a function to be inline, just use __forceinline.
Generate a "MAP" file. This gives you the addresses of all non-inlined functions. If your function appears in this list, it's not inlined, otherwise it's either inlined or optimized out entirely (e.g. when it's not called at all).
If you really don't want to jump into assembly, declare the function as __forceinline, and if the executable gets larger, you know it wasn't being inlined.
I have a method like the one shown below.
Will the for loop always make the compiler for go the "inline request" ?
inline void getImsiGsmMapFrmImsi
(
const string& imsiForUEDir,
struct ImsiGsmMap& imsiGsmMap
)
{
for (int i = 0 ; (unsigned)i < imsiForUEDir.length() - 1 ; i++)
{
imsiGsmMap.value[i] = imsiForUEDir[i] - '0' ;
}
imsiGsmMap.length = imsiForUEDir.length() - 1 ;
}
You can specify "inline" and the compiler can ignore it if it feels like that.
Simply, no.
"inline" is just a hint to the compiler.
There are ways to force a compiler to inline something, but these ways are compiler-specific. Your code looks mobile to me, so here's some ways on some C++ compilers used on various mobile phone platforms:
Windows CE/ Windows Mobile VC++ ARM compiler uses the __forceinline keyword instead of the hint 'inline'.
A better compiler (i.e. makes faster output) for Windows CE/ Windows Mobile is cegcc, which uses the very latest GCC 4.4. In GCC, you write __attribute__((always_inline)) after the function name and before the body.
The bigger thing is if it's a good idea to inline this loop. I program mobile phones for a living, and they don't have much CPU budget generally. But I'd be really surprised if this loop is a bottleneck. Strip your program of all the 'inline' decorations and when you're approaching shipping, if the program is slow, profile it!
Some compilers allow 'profile guided optimisation' where they can make an instrumented binary that you run in a realistic way, and then they use the data so gathered to make a production binary where they make informed decisions about code speed vs code size in the various parts of your program to give the very best mix of both.
"No inlining for functions with loops" is probably a bit of some inline heuristic from some particular compiler. It doesn't apply universally.
Every compiler uses some heuristics to determine whether the function should be inlined or not, but normally every compiler uses its own ones. So, to say that a loop will have some universal effect on inlining is not correct. It won't. There's absolutely nothing in your function that would somehow fundamentally preclude inlining. Most modern compilers can easily inline this function, if they deem it reasonable or if you force them to do it.
Yes, some compilers offer non-standard declaration specifiers (or compiler options) that will actually force the inlining, i.e. override the heuristic analysis, except for a number of situation when the inlining is truly beyond the capabilities of the compiler. For example, many modern C/C++ compilers normally can't inline functions with variable number of parameters (variadic functions).
It also commonly believed that recursive function can't be inlined. In reality, in many compilers recursive functions can be inlined to certain fixed recursion depth, thus "compressing" the recursion.
I wonder if the inline keyword is even necessary anymore. Don't modern compilers mostly just ignore it and do whatever they think is best, anyway?
Most likely compilers will not inline a function with a loop, since what would be the point? If the code is looping, generally the cost of a function call will be unmeasurable noise compared to the looping.
But if a compiler wants to inline it (maybe the compiler is sophisticated enough to determine the loop bounds and can even unroll the loop), it's certainly allowed to.
But I wouldn't bet on it.
To summarize a previous answer I gave to this, the things you should watch out for when choosing a function for inlining are:
* local static variables
* loop constructs
* switch statements
* try/catch
* goto
* recursion
* and of course too much complexity (whatever that means)
Having said that as the other answers here point out, it's basically unspecified if the compiler inlines the function or not. 7.1.2/2 has:
A function declaration (8.3.5, 9.3, 11.4) with an inline specifier declares an inline function. The inline specifier indicates to the implementation that inline substitution of the function body at the point of call is to be preferred to the usual function call mechanism. An implementation is not required to perform this inline substitution at the point of call; however, even if this inline substitution is omitted, the other rules for inline functions defined by 7.1.2 shall still be respected.
An interesting detail on this, is that the compiler would normally label the kind of behaviour that's involved here. For example: "it is unspecified" or "the behaviour is undefined" etc.
While it would be very convenient to use inline functions at some situations,
Are there any drawbacks with inline functions?
Conclusion:
Apparently, There is nothing wrong with using inline functions.
But it is worth noting the following points!
Overuse of inlining can actually make programs slower. Depending on a function's size, inlining it can cause the code size to increase or decrease. Inlining a very small accessor function will usually decrease code size while inlining a very large function can dramatically increase code size. On modern processors smaller code usually runs faster due to better use of the instruction cache. - Google Guidelines
The speed benefits of inline functions tend to diminish as the function grows in size. At some point the overhead of the function call becomes small compared to the execution of the function body, and the benefit is lost - Source
There are few situations where an inline function may not work:
For a function returning values; if a return statement exists.
For a function not returning any values; if a loop, switch or goto statement exists.
If a function is recursive. -Source
The __inline keyword causes a function to be inlined only if you specify the optimize option. If optimize is specified, whether or not __inline is honored depends on the setting of the inline optimizer option. By default, the inline option is in effect whenever the optimizer is run. If you specify optimize , you must also specify the noinline option if you want the __inline keyword to be ignored. -Source
It worth pointing out that the inline keyword is actually just a hint to the compiler. The compiler may ignore the inline and simply generate code for the function someplace.
The main drawback to inline functions is that it can increase the size of your executable (depending on the number of instantiations). This can be a problem on some platforms (eg. embedded systems), especially if the function itself is recursive.
I'd also recommend making inline'd functions very small - The speed benefits of inline functions tend to diminish as the function grows in size. At some point the overhead of the function call becomes small compared to the execution of the function body, and the benefit is lost.
It could increase the size of the
executable, and I don't think
compilers will always actually make
them inline even though you used the
inline keyword. (Or is it the other
way around, like what Vaibhav
said?...)
I think it's usually OK if the
function has only 1 or 2 statements.
Edit: Here's what the linux CodingStyle document says about it:
Chapter 15: The inline disease
There appears to be a common
misperception that gcc has a magic
"make me faster" speedup option called
"inline". While the use of inlines can
be appropriate (for example as a means
of replacing macros, see Chapter 12),
it very often is not. Abundant use of
the inline keyword leads to a much
bigger kernel, which in turn slows the
system as a whole down, due to a
bigger icache footprint for the CPU
and simply because there is less
memory available for the pagecache.
Just think about it; a pagecache miss
causes a disk seek, which easily takes
5 miliseconds. There are a LOT of cpu
cycles that can go into these 5
miliseconds.
A reasonable rule of thumb is to not
put inline at functions that have more
than 3 lines of code in them. An
exception to this rule are the cases
where a parameter is known to be a
compiletime constant, and as a result
of this constantness you know the
compiler will be able to optimize most
of your function away at compile time.
For a good example of this later case,
see the kmalloc() inline function.
Often people argue that adding inline
to functions that are static and used
only once is always a win since there
is no space tradeoff. While this is
technically correct, gcc is capable of
inlining these automatically without
help, and the maintenance issue of
removing the inline when a second user
appears outweighs the potential value
of the hint that tells gcc to do
something it would have done anyway.
There is a problem with inline - once you defined a function in a header file (which implies inline, either explicit or implicit by defining a body of a member function inside class) there is no simple way to change it without forcing your users to recompile (as opposed to relink). Often this causes problems, especially if the function in question is defined in a library and header is part of its interface.
I agree with the other posts:
inline may be superfluous because the compiler will do it
inline may bloat your code
A third point is it may force you to expose implementation details in your headers, .e.g.,
class OtherObject;
class Object {
public:
void someFunc(OtherObject& otherObj) {
otherObj.doIt(); // Yikes requires OtherObj declaration!
}
};
Without the inline a forward declaration of OtherObject was all you needed. With the inline your
header needs the definition for OtherObject.
As others have mentioned, the inline keyword is only a hint to the compiler. In actual fact, most modern compilers will completely ignore this hint. The compiler has its own heuristics to decide whether to inline a function, and quite frankly doesn't want your advice, thank you very much.
If you really, really want to make something inline, if you've actually profiled it and looked at the disassembly to ensure that overriding the compiler heuristic actually makes sense, then it is possible:
In VC++, use the __forceinline keyword
In GCC, use __attribute__((always_inline))
The inline keyword does have a second, valid purpose however - declaring functions in header files but not inside a class definition. The inline keyword is needed to tell the compiler not to generate multiple definitions of the function.
I doubt it. Even the compiler automatically inlines some functions for optimization.
I don't know if my answer's related to the question but:
Be very careful about inline virtual methods! Some buggy compilers (previous versions of Visual C++ for example) would generate inline code for virtual methods where the standard behaviour was to do nothing but go down the inheritance tree and call the appropriate method.
You should also note that the inline keyword is only a request. The compiler may choose not to inline it, likewise the compiler may choose to make a function inline that you did not define as inline if it thinks the speed/size tradeoff is worth it.
This decision is generaly made based on a number of things, such as the setting between optimise for speed(avoids the function call) and optimise for size (inlining can cause code bloat, so isn't great for large repeatedly used functions).
with the VC++ compiler you can overide this decision by using __forceinline
SO in general:
Use inline if you really want to have a function in a header, but elsewhere theres little point because if your going to gain anything from it, a good compiler will be making it inline for you anyway.
Inlining larger functions can make the program larger, resulting in more instruction cache misses and making it slower.
Deciding when a function is small enough that inlining will increase performance is quite tricky. Google's C++ Style Guide recommends only inlining functions of 10 lines or less.
(Simplified) Example:
Imagine a simple program that just calls function "X" 5 times.
If X is small and all calls are inlined: Potentially all instructions will be prefetched into the instruction cache with a single main memory access - great!
If X is large, let's say approaching the capacity of the instruction cache:
Inlining X will potentially result in fetching instructions from memory once for each inline instance of X.
If X isn't inlined, instructions may be fetched from memory on the first call to X, but could potentially remain in the cache for subsequent calls.
Excessive inlining of functions can increase size of compiled executable which can have negative impact on cache performance, but nowadays compiler decide about function inlining on their own (depending on many criterias) and ignore inline keyword.
Among other issues with inline functions, which I've seen heavily overused (I've seen inline functions of 500 lines), what you have to be aware of are:
build instability
Changing the source of an inline function causes all the users of the header to recompile
#includes leak into the client. This can be very nasty if you rework an inlined function and remove a no-longer used header which some client has relied on.
executable size
Every time an inline is inlined instead of a call instruction the compiler has to generate the whole code of the inline. This is OK if the code of the function is short (one or two lines), not so good if the function is long
Some functions can produce a lot more code than at first appears. I case in point is a 'trivial' destructor of a class that has a lot of non-pod member variables (or two or 3 member variables with rather messy destructors). A call has to be generated for each destructor.
execution time
this is very dependent on your CPU cache and shared libraries, but locality of reference is important. If the code you might be inlining happens to be held in cpu cache in one place, a number of clients can find the code an not suffer from a cache miss and the subsequent memory fetch (and worse, should it happen, a disk fetch). Sadly this is one of those cases where you really need to do performance analysis.
The coding standard where I work limit inline functions to simple setters/getters, and specifically say destructors should not be inline, unless you have performance measurements to show the inlining confers a noticeable advantage.
In addition to other great answers, at least once I saw a case where forced inlining actually slowed down the affected code by 1.5x. There was a nested loop inside (pretty small one) and when this function was compiled as a separate unit, compiler managed to efficiently unroll and optimize it. But when same function was inlined into much bigger outer function, compiler (MSVC 2017) failed to optimize this loop.
As other people said that inline function can create a problem if the the code is large.As each instruction is stored in a specific memory location ,so overloading of inline function make a code to take more time to get exicuted.
there are few other situations where inline may not work
does not work in case of recursive function.
It may also not work with static variable.
it also not work in case there is use of a loop,switch etc.or we can say that with multiple statements.
And the function main cannot work as inline function.