История изменений
Исправление wandrien, (текущая версия) :
Но даже так, для цикла можно выделять регистры, а при вызове функций внутри цикла сохранять их в память а при выходе восстанавливать. Это лучше чем постоянно читать/писать память.
Ну это естественный ход улучшения программы:
- Простейший кодогенератор вообще ничего не умеет оптимизировать и тупо использует один регистр для вычислений. Такое написать можно за день.
- Потом мы учим его простейшим вещам, ну хотя бы константы более эффективно обрабатывать.
- Потом учим всё более и более сложным.
В текущем виде функция, которые подбирает оптимальный способ вычисления выражения, учитывая возможность переупорядочивания операндов и содержимого регистров, уже выглядит как адок на 800 строк кода. Но зато творит чудесные вещи, с учётом того, что она вообще не пытается проанализировать программу в глубину, а тупо исходит из сохранённого состояния здесь и сейчас.
Ну и в итоге вот такой кусок исходника:
while P < nDICT do
if Dict[P].Name.Hash != hash then
P = Dict[P].pNext;
continue;
...
Превращается во вполне осмысленный цикл:
@10499:
mov EAX, dword [EBP-8]
cmp EAX, 100000
jae @10500
; #line compiler_dict.qdi:199
imul EAX, 92
mov EDX, dword [@@DATA+EAX+777192]
cmp EDX, dword [EBP-4]
je @10503
; #line compiler_dict.qdi:200
mov ECX, dword [@@DATA+EAX+777204]
mov dword [EBP-8], ECX
jmp @10499
И вот когда мы такое имеем, отсюда уже близко до распределения регистров с учётом более сложного контекста, нежели просто «текущая арифметическая операция». Вот сюда уже проще всунуть преаллокацию регистров по эвристикам анализа кода.
Исходная версия wandrien, :
Но даже так, для цикла можно выделять регистры, а при вызове функций внутри цикла сохранять их в память а при выходе восстанавливать. Это лучше чем постоянно читать/писать память.
Ну это естественный ход улучшения программы:
- Простейший кодогенератор вообще ничего не умеет оптимизировать и тупо использует один регистр для вычислений. Такое написать можно за день.
- Потом мы учим его простейшим вещам, ну хотя бы константы более эффективно обрабатывать.
- Потом учим всё более и более сложным.
В текущем виде функция, которые подбирает оптимальный способ вычисления выражения, учитывая возможность переупорядочивания операндов и содержимого регистров, уже выглядит как адок на 800 строк кода. Но зато творит чудесные вещи, с учётом того, что она вообще не пытается проанализировать программу в глубину, а тупо исходит из сохранённого состояния здесь и сейчас.
Ну и в итоге вот такой кусок исходника:
while P < nDICT do
if Dict[P].Name.Hash != hash then /* optimized for better code layout */
P = Dict[P].pNext;
continue;
...
Превращается во вполне осмысленный цикл:
@10499:
mov EAX, dword [EBP-8]
cmp EAX, 100000
jae @10500
; #line compiler_dict.qdi:199
imul EAX, 92
mov EDX, dword [@@DATA+EAX+777192]
cmp EDX, dword [EBP-4]
je @10503
; #line compiler_dict.qdi:200
mov ECX, dword [@@DATA+EAX+777204]
mov dword [EBP-8], ECX
jmp @10499
И вот когда мы такое имеем, отсюда уже близко до распределения регистров с учётом более сложного контекста, нежели просто «текущая арифметическая операция». Вот сюда уже проще всунуть преаллокацию регистров по эвристикам анализа кода.