I’m building interpret, writing in C and using GCC.
I have changed the way I’m generating intermediate code.
But unexpected change happened in interpreting this code.
There is one condition block that is dealing with conditional jumps in intermediate code.
I didn’t change that piece of code.
Using Dissy for disassembly.
Older version assember looks like:
mov 0x10(%r14),%rax
mov 0x50(%rsp),%rcx
mov (%rcx,%rax,8),%r12
mov (%r12),%eax
test $0x4,%al
je 4077ef
cmpb $0x0,0x8(%r12)
je 4077ef
Newer version:
mov 0x10(%r14),%rax
mov (%r12,%rax,8),%rdx
mov (%rdx),%eax
test $0x4,%al
je 4073e0
cmpb $0x0,0x8(%rdx)
je 4073e0
This change caused 4-6% performance regress caused by misspredictions.
Is there a way so suggest GCC to use older version without using assembly sections, for preserving portability?
Thanks.
EDIT
Code in C:
if((M->type & 4 && M->val.boolean)
|| (M->type & 1 && M->val.number != 0.0)
|| (M->type & 2 && M->val.string.length != 0))
// true;
else
// false;
There is and can’t be any difference in branch prediction here.
Rather it seems, that you have modified the original source code from:
to
Because in the latter case the base of myarray is already cached in register r12 — or you have just moved myarray from local stack to be used as a parameter of a function.