Optimizations
The importance of optimizations
Optimizations are often the reason why compiled code runs so fast. Modern compilers have a wide range of optimizations available, some have significant performance impacts, reduce code size and make things easier for the CPU. Here is a C++ example (godbolt):
int mulByConstant(int x) {
return x * 65599;
}
The instructions generated are exactly what we imagine it to be, an imul
(integer multiplication) of our input with 65599
:
mulByConstant(int):
imul eax, edi, 65599
ret
Now what will happen if we wrote some very bad code that does the same thing (godbolt):
int mulByConstant(int x) {
return (x << 16) + (x << 6) - x;
// ^ ^
// x * 65536 |
// x * 64
// 65536x + 64x - 1x = 65599x
}
In this rather intimidating function we are doing the same thing (multiplying x
with 65599
) however instead of using a multiplication we are using bit-shifts and additions.
mulByConstant(int):
imul eax, edi, 65599
ret
The result that the compiler generated is the same as before, it looked at our arithmetic operations and understood we want to multiply by 65599
. It also knows that a single imul
instruction is cheaper than whatever we wanted to do:
mulByConstant(int): # using bit-shifts with no optimizations
push rbp
mov rbp, rsp
mov dword ptr [rbp - 4], edi
mov eax, dword ptr [rbp - 4]
shl eax, 16
mov ecx, dword ptr [rbp - 4]
shl ecx, 6
add eax, ecx
sub eax, dword ptr [rbp - 4]
pop rbp
ret
Optimizing Papyrus
The CK compiler does not optimizations. It only tries to convert the raw code into a .pex
file, doing only the bare minimum of work required to validate the code and produce an output. This is the reason why the code produces by a decompiler like Champollion is almost identical to the original code.
The next following pages contain information on every optimization done by the Open Papyrus Compiler.