Are common
In your regular compiler, the generated code will most often match, at least if you assume that you are using the regular
csc.exe /optimize+ cl.exe /O2 g++ -O2
and related default optimization modes.
Common mantra: profile, profile, profile (and don't micro-optimize until the profiler tells you). You can always look at the generated code 2 to see if there is room for improvement.
Think of it this way, for example. C # code:
FROM#/. NET
Each of your complex expressions is a call to a de facto function call (call, calli, callvirt opcode 3 ), which requires its arguments to be pushed onto the stack. The return value will be left on the stack instead of the parameters on exit.
Now the CLR, which is a stack-based virtual machine (i.e., without registers), is exactly the same as an anonymous temporary variable on the stack. The only difference is the number of identifiers used in the code.
Now, what the JIT engine does is another matter: the JIT engine will have to transfer these calls to its own assembly and can perform optimization by adjusting register allocation, ordering of commands, branch prediction, etc. 1
<sub>> 1 (although in practice for this sample it will not be allowed to make more interesting optimizations, because complex function calls can have side effects, and the C # specifications are very clear regarding the evaluation order, and so on). Note , however, that the JIT mechanism allows inline function calls to reduce overhead.
Not only when they are not virtual, but (IIRC) also when the runtime type can be known statically at compile time for certain internal .NET components. I need to look for a link for this, but in fact I think that in the .NET Framework 4.0 there are attributes that clearly prevent the embedding of the framework functions; this means that Microsoft can correct library code in service packs / updates, even if the user assemblies were compiled in advance (ngen.exe) into their own images. Sub>
C / C ++
In C / C ++, the memory model is much weaker (that is, at least until C ++ 11), and the code is usually compiled using the built-in instructions during compilation directly. Add that C / C ++ compilers usually do aggressive insertion, the code even in such compilers will usually be the same if you do not compile without optimization.
<sub> 2 I use
monodis or monodis to see generated IL codemono -aot=full,static or mkbundle to create your own modular objects and objdump -CdS to view instructions for this command with annotation.
Please note that this is purely curiosity, because it rarely happens that I find interesting bottlenecks. However, see J in the Skeet blog posts on Noda.NET performance Noda.NET for good examples of surprises that might be hidden in the generated IL code for common classes.
3 Change is inaccurate for statements on built-in compilers, although even they simply leave their result on the stack. Sub>