Handmade Hero»Forums»Code
Andrew Reece
51 posts / 4 projects
Maker of things
Why does "inline" obviate the need for "internal" ("static")?
Edited by Andrew Reece on Reason: Long link title was elided
So I understand that internal/static removes the need for functions to be put into a symbol table (useful for unity builds), reducing overhead and lowering compile time. During HMH, when Casey marks a function as "inline", he removes the "internal" label, but I'm not 100% sure why.

I presume that when functions are inlined they don't need to be put into a symbol table. I've heard that "inline" is just a hint to the compiler, but the compiler has the last word. In the cases when the function is not inlined, what happens to it? Does the compiler assume that it is static or does it put it into a symbol table (or something else...)?

Thanks,
Andrew
Mārtiņš Možeiko
2559 posts / 2 projects
Why does "inline" obviate the need for "internal" ("static")?
Edited by Mārtiņš Možeiko on
For optimization purposes "inline" keyword really doesn't matter. Modern compilers don't use "inline" keyword as indication whether to do inlining or not. They will perform inlining regardless is function marked with "inline", "static" or even without any keyword. It will try to inline anything that makes sense.

Inline is more a keyword for how to link program.

Because compiler can decide to not inline some functions, it must have these functions in object file. If function is just "inline" and not "static inline" then this means function has external linkage. And because it is inline function compiler marks this function as weak symbol.

Simplified explanation about what weak symbol means is that if linker founds multiple symbols with same name and all have weak linkages it can take any of them. This means that all symbols (functions) with same name are required to do exactly same thing. In standard this is referred as "one definition rule". Violating this rule means undefined behavior.

So in summary - inline generates entry in symbol table for linker. Static does not.
Only big difference from static is that you are not allowed to have in two or more translation units inline function with same name but different code. Basically don't do this:
In a.c have "inline int f() { return 1; }"
In b.c have "inline int f() { return 2; }"
If compiler in code calling these functions doesn't inline f into caller, then linker can decide to use only one of them in all places. Which is probably not what you would expect.
Jay Waggle
10 posts
insobot++
Why does "inline" obviate the need for "internal" ("static")?
Edited by Jay Waggle on
Some follow-up questions I have on this topic:

What kind of benefit is there for choosing to mark a function "inline", especially if the compiler does what it wants to anyway?

What does Casey intend for his code when he marks a function "inline"?

Is there merit in using "__forceinline" for, as an example, one line functions that calculate and return a value?
Casey Muratori
801 posts / 1 project
Casey Muratori is a programmer at Molly Rocket on the game 1935 and is the host of the educational programming series Handmade Hero.
Why does "inline" obviate the need for "internal" ("static")?
At this point I mostly just use "inline" as a force of habit to notate a function I presume to be inlined. Probably I could just mark everything static and it would be fine! But I haven't recently done any testing to make sure that that works well, so I haven't switched to it.

- Casey
Mārtiņš Možeiko
2559 posts / 2 projects
Why does "inline" obviate the need for "internal" ("static")?
From compiler perspective there is very little benefit. Especially if you are using unity build. For "normal" code organization with headers and c/cpp files inline sometimes makes sense in header files. You want same function in header file be present in one copy in binary. Static will compile functions independently. Although you can eliminating identical functions in linker. For MSVC that is done with /Gy for cl.exe and /OPT:ICF for link.exe arguments, and for gcc with -ffunction-sections -Wl,--gc-sections arguments.

In my opinion inline is just for reader. You are stating your intention to yourself or other readers of code.

__forceinline for MSVC and __attribute__((always_inline) for gcc/clang will always perform inlining regardless of what compiler thinks.

Should you use this instead of inline? No, not really. Compiler most of the times knows better when to inline or not. Too much inlining can actually harm performance for multiple reasons. One example would be increased register pressure, compiler may be not able to optimize code so well and will start spilling temporary values to stack. Another reason is CPU cache, by too much inlining of the same function you are using more space than for calls to one function.

Only if by profiling you can determine that yes this call is the spot where a lot of time is spent and it is not inlined, then you should put force inline directive for one or few functions.

One line simple functions (like abs, lerp, clamp, etc) will be pretty much always inlined, so you shouldn't worry about forcing them to inline.
Caleb
12 posts
None
Why does "inline" obviate the need for "internal" ("static")?
mmozeiko
Should you use this instead of inline? No, not really. Compiler most of the times knows better when to inline or not. Too much inlining can actually harm performance for multiple reasons. One example would be increased register pressure, compiler may be not able to optimize code so well and will start spilling temporary values to stack. Another reason is CPU cache, by too much inlining of the same function you are using more space than for calls to one function.
Oddly enough EA found that manually inlining the functions in their own STL implementation instead of writing and reusing private 2 liners all over the place resulted in better performance overall.
Mārtiņš Možeiko
2559 posts / 2 projects
Why does "inline" obviate the need for "internal" ("static")?
Edited by Mārtiņš Možeiko on
Afaik EASTL was made at least 9 years ago. C/C++ compilers improved a lot since then.