, GCC ifadelerin doğru olacaktır eğer koşul olduğunu varsayar bağlamsal.
extern int t(int*);
int g(int* ip) {
if (!ip)
return 0;
return t(ip);
}
üretir
f(int):
testl %edi, %edi
jne .L4
movl $1, %eax
ret
.L4:
jmp s(int)
ise
extern int s(int);
int f(int i) {
if (i == 0)
return 1;
return s(i);
}
üretir:
g(int*):
testq %rdi, %rdi
je .L6
jmp t(int*)
.L6:
xorl %eax, %eax
ret
(
godbolt bakınız)
Şubenin f
şubesinin jne
(koşulun doğru olduğunu varsayalım) şeklini not edin; g
ise koşulun yanlış olduğu varsayılır. o karar GCC onu yeniden kullanımını ki burada L2
lekeli, bu yüzden:
Burada bağlam faktörlerden biri bkz
x(int, int*):
testq %rsi, %rsi
je .L3 # first branch: assumed unlikely
movl $2, %eax
testl %edi, %edi
jne .L12 # second branch: assumed likely
ret
.L12:
pushq %rbx
movq %rsi, %rbx
call s(int)
movl %eax, %edx
movl $3, %eax
testl %edx, %edx
je .L13 # third branch: assumed likely
.L2:
popq %rbx
ret
.L3:
movl $1, %eax
ret
.L13:
movq %rbx, %rdi
call t(int*)
movl %eax, %edx
movl $4, %eax
testl %edx, %edx
jne .L2 # fourth branch: assumed unlikely!
movq %rbx, %rdi
call t(int*)
popq %rbx
movl %eax, %edi
jmp s(int)
üretir
extern int s(int);
extern int t(int*);
int x(int i, int* ip) {
if (!ip)
return 1;
if (!i)
return 2;
if (s(i))
return 3;
if (t(ip))
return 4;
return s(t(ip));
}
: Aşağıdaki ile Şimdi
karşılaştırmak Daha az kod yayabilmesi için son şartsız ihtimalleri dikkate alın. ! Oluşturulan kod dalları Z doğrudur, zaten sanki işlevi gördüğünden
f(int, int, int):
movl $1, %eax
testl %edi, %edi
jne .L9
movl $2, %eax
testl %esi, %esi
je .L11
.L9:
ret
.L11:
testl %edx, %edx
je .L12 # branch if !Z
movl $3, %eax
ret
.L12:
subq $8, %rsp
call raiseError()
movl $-1, %eax
addq $8, %rsp
ret
Not:
#define likely(x) __builtin_expect((x),1)
#define unlikely(x) __builtin_expect((x),0)
extern void raiseError();
int f(int A, int B, int Z)
{
if (A)
return 1;
else if (B)
return 2;
else if (Z)
return 3;
raiseError();
return -1;
}
montaj looks like this:
Verdiğin örnek montajı inceleyelim Z muhtemeldir. Z'nin muhtemel olduğunu söylersek ne olur?
#define likely(x) __builtin_expect((x),1)
#define unlikely(x) __builtin_expect((x),0)
extern void raiseError();
int f(int A, int B, int Z)
{
if (A)
return 1;
else if (B)
return 2;
else if (likely(Z))
return 3;
raiseError();
return -1;
}
şimdi we get
f(int, int, int):
movl $1, %eax
testl %edi, %edi
jne .L9
movl $2, %eax
testl %esi, %esi
je .L11
.L9:
ret
.L11:
movl $3, %eax # assume Z
testl %edx, %edx
jne .L9 # but branch if Z
subq $8, %rsp
call raiseError()
movl $-1, %eax
addq $8, %rsp
ret
burada nokta dikkatli olmanız bu makroları kullanırken ve daha önce kodu incelemek ve dikkatli sonra emin Beklediğiniz sonuç almak ve kıyaslama yapmak gerektiğidir (örneğin, perf ile) işlemcinin, oluşturduğunuz kodla uyumlu tahminler yaptığını doğrulamak için.
Kesin olanı öğrenmenin tek yolu (en iyileştirmeler etkinleştirilmiş) oluşturmak ve oluşturulan kodu kontrol etmektir. Kullanılma olasılığı olan ve olmayan kodları karşılaştırın. –
Neden diğer tüm koşulların yanında “olası” değil? –
@KerrekSB Bunu önlemek istediğim şey. Hiçbir koşulun doğru olmadığı durumlar hariç tüm şartlar eşit derecede muhtemeldir. – Leo