Open MrOctopus opened 2 years ago
The C++ inline
specifier is just a "suggestion" to the compiler and with every C++ compiler doing something different you are not guaranteed that the function will be inlined. However there are ways a C++ programmer can "force" a compiler to inline a function: GCC has __attribute__((always_inline))
and MVSC has __forceinline
(It's still not guaranteed).
It's important to have a distinction between the following when talking about inlining:
1) automatic inlining done by the compiler as part of an optimization (eg using cost-benefit analysis) 2) forced inlining specified by the programmer
For the Papyrus compiler I plan on adding automatic inlining as part of the optimization process however I'm unsure about forced inlining as it would require a language addition, probably an extra function flag.
I am aware that the C++ inline specifier is just a suggestion to the compiler to enforce inlining (though it most most often follows this suggestion). As for the distinction you mention between automatic inlining and forced inlining, I find the latter one to be the most useful. I am aware that this will require a new function flag (as I pointed out in the original comment), but I feel that this added control is important for controlling the program flow. For example, automatically inlining functions inside of the OnPlayerLoadGame() ReferenceAlias event can prove problematic for script updates; which is why you most commonly want to defer the actual load game logic to a separate function call.
Automatic inlining by the optimizer will of course require a lot of fine tuning, however it is one of the most impactful optimization in any compiler regardless of language. The only times where you want to force an inline is when you can't be sure if optimizer is inlining the function (maybe it's a little too long) and the function is trivial enough and/or called on the hot path or some tight loop to warrant this optimization.
What I'm trying to say is that modern compilers are very good at this and sometimes manually forcing an inline will not result in better performance. As for the compiler I'm building, it won't be able to compete with LLVM optimizations but I'm trying to make the automatic inlining "good enough". If "good enough" is not enough, you can then look at manually forcing an inline.
I especially want to discourage new programmers and new users of the compiler to over-use manually forcing an inline.
That's understandable, but I would argue that inlining is more important for Papyrus to stay performant because of the function call overheads; which do add up, believe me on that. As for being afraid of the potential for over-use with manual inlining:
Most probably, if you're planning to use an alternative compiler to the one provided with the CK, you're already at an intermediate level of understanding Papyrus. Additionally, since the inlining feature would be unique to this compiler, reading the documentation is a must to even garner the possibility of using it. That's why I personally prefer to downplay its potential for abuse. Papyrus scripts are already written badly enough as is, with a buttload of race conditions in virtually every mod out there.
I think a big fat warning in the docs on manually forcing an inline and a warning/info when compiling should be enough to make sure people understand to use it sparingly.
Also the main goal of the compiler is analysis and optimization in general. The CK compiler doesn't do any of that, it just has a lexer+parser (using ANTLR), a middle for lowering to an intermediate representation (.pas
) and finally a backend/code generator to .pex
. While modern compilers can't fix bad code, the cleanup and canonicalization steps are often enough to fix common "bad practices".
On that note, if you have any other suggestions please open more issues.
I agree with you that a big fat warning in the docs will probably be enough. If I have any other suggestions/resources I'll be sure to provide them.
Since function calls can be very costly in Papyrus, it would be helpful if an inline flag for function definitions could be added to the compiler. This feature would speed up the use of small proxy functions in framework APIs whilst retaining their readability and usability. It would also serve to avoid dependencies on long functions that have to be pre-inlined because they are time and resource critical.
For more information on inlining, see: https://en.cppreference.com/w/cpp/language/inline