stosując następujące dwa pliki:
test.c
:
int main(int argc, char** argv) {
int c, f0, f1, th;
int hold, hold1;
f0 = (int) argv[1];
f1 = (int) argv[2];
th = (int) argv[3];
hold1 = (f0 == 0);
if (!hold1) {
} else {
hold = hold1;
goto done;
}
hold1 = (f1 - f0 > th);
hold = hold1;
done: c = hold;
return c;
}
test2.c
:
int main(int argc, char** argv) {
int c, f0, f1, th;
f0 = (int) argv[1];
f1 = (int) argv[2];
th = (int) argv[3];
c = (f1 == 0) || (f1 - f0 > th);
return c;
}
miałem przypisać f0
, f1
i th
do czegoś tak, że kompilator nie tylko return 1
zgodnie ze specyfikacją C stwierdza, że int
S są inicjowane 0
i f1 == 0
dałoby true
, a tym samym cały logiczna stwierdzenie dałoby true
i zespół może być:
main:
.LFB0:
.cfi_startproc
.L2:
movl $1, %eax
ret
.cfi_endproc
Kompilacja pomocą GCC
z -S -O2
flagi (włączone optymalizacja), zarówno test.s
i test2.s
się :
main:
.LFB0:
.cfi_startproc
movl 8(%rsi), %edx
movq 16(%rsi), %rdi
movl $1, %eax
movq 24(%rsi), %rcx
testl %edx, %edx
je .L2
subl %edx, %edi
xorl %eax, %eax
cmpl %ecx, %edi
setg %al
.L2:
rep
ret
.cfi_endproc
Więc to chyba wyłączyć optymalizacje, w którym jeden z goto
miałby o 50% więcej instrukcji, resul t byłby taki sam.
Powód, dla którego kod wyjściowy C
jest brzydki, wynika z tego, w jaki sposób interpreter odwiedza węzły w AST. Po odwiedzeniu węzła or
, interpreter najpierw ocenia pierwszy parametr, a następnie drugi. Jeśli wyrażenie boolowskie było znacznie bardziej złożone, byłoby znacznie łatwiejsze do przeanalizowania. Wyobraź sobie wywołanie funkcji lambda, która zwraca wartość boolowską (nie jestem pewien, czy Cython ją obsługuje); interpretator musiałby śledzić strukturę:
hold = ... evaluate the lambda expression...
if (hold) {
result = hold;
goto done; // short circuit
}
hold = ... evaluate the second boolean expression...
done:
...
byłoby trudne zadanie, aby zoptymalizować na etapie interpretacji i tym samym Cython nawet nie przeszkadzało.
Wygląda jak 'goto' jest częścią zwarciowego' or'. – hpaulj