Pracuję nad technikami optymalizacji wykonywanymi przez .NET Native Compiler. I utworzeniu pętli próbki:Dlaczego .Net Native kompiluje pętlę w odwrotnej kolejności?
for (int i = 0; i < 100; i++)
{
Function();
}
I została skompilowana go z rodzimymi. Następnie zdemontowałem plik wyniku .dll
z kodem maszynowym wewnątrz IDA. W rezultacie mam:
(Usunąłem kilka niepotrzebnych linii, więc nie martw się, że linie są inconsistant adres)
Rozumiem, że add esi, 0FFFFFFFFh
oznacza naprawdę subtract one from esi and alter Zero Flag if needed
, więc możemy przeskoczyć na początek, jeśli jeszcze nie osiągnięto zera.
Czego nie rozumiem, dlaczego kompilator powrócił do pętli?
doszedłem do wniosku, że
LOOP:
add esi, 0FFFFFFFFh
jnz LOOP
jest po prostu szybsze niż na przykład
LOOP:
inc esi
cmp esi, 064h
jl LOOP
Ale to jest naprawdę z tego powodu i jest naprawdę znacząca różnica prędkości?
ADD o wartości bezpośredniej jest szybsze niż INC i pomijane jest CMP ... wszystkie z nich w 3 wierszach kodu. Wtedy tak, różnica jest NAPRAWDĘ znacząca (zarówno pod względem wielkości, jak i prędkości). Wyobraź sobie, że możesz to zrobić w ~ 30000 miejscach w rzeczywistym programie ... –
Tak, jest to szybsze, a generalnie optymalizatorzy zastosują dowolną optymalizację, dzięki której twój kod będzie szybszy bez zmiany semantyki twojego programu. –
Jeśli chodzi o odwrócony kierunek, to być może porównanie do zera jest szybsze niż porównanie z określoną wartością? – user5226582