- Код: Выделить всё
push A
push B
mov reg, C
sub [sp], reg
pop reg
add [sp], reg
push D
mov ax, E
mul [sp]
mov [sp], ax
pop reg
add [sp], reg
Хотелось бы "оптимизировать" его так, чтобы все промежуточные значения в вычислениях хранились в регистрах, а не на стеке.
* Прежде всего, нужно решить, что делать с регистрами reg: можно просто нумеровать их, вести до самого конца в виде таких "логических регистров", и только в самом конце подставлять на их место "физические регистры". (Будем в рамках этой задачи считать, что у x86 есть 4 доступных нам регистра общего назначения: ax, bx, cx, dx.) Преимущество здесь в потенциальной переносимости: может оказаться, что код с такими "логическими регистрами" легко превратить в машинный код нескольких реальных процессоров. Но возникает риск "переиспользования" регистров: что, если в конце генерации кода окажутся одновременно используемыми 5 регистров? придётся откатываться на использование стека?
Другой подход -- расставить "физические регистры" сразу же, и тащить их до конца. Потом, если возникнет конфликт (двум "логическим регистрам" поставлен в соответствие один "физический", и оба этих регистра должны использоваться одновременно), то придётся каким-то образом их переименовывать, возможно, даже каскадом. Зато худшее, что может произойти -- лишние промежуточные значения останутся на стеке, а это не смертельно.
Последнее замечание про регистры -- то, что некоторые инструкции x86 навязывают использование конкретных регистров: например, инструкции mul и div всегда сохраняет результат в паре dx:ax, поэтому во время выполнения этих инструкций ни в dx, ни в ax не должно храниться промежуточных значений. Поэтому в нашем примере я расставляю "физические регистры" так, чтобы вокруг инструкции mul не было поблизости ни dx, ни ax.
* Наконец, чтобы отслеживать использование регистров, напротив каждой инструкции я напишу, значения каких регистров она использует, каких получает и каких производит. Для простоты мы будем считать, что каждое значение ровно по разу производится и получается. Кроме того, использоваться может стек.
- Код: Выделить всё
use prod cons
push A st
push B st
mov dx, C dx
sub [sp], dx st dx
pop bx st bx
add [sp], bx st bx
push D st
mov ax, E ax
mul [sp] st,ax dx dx
mov [sp], ax st ax
pop cx st cx
add [sp], cx st cx
Здесь правая часть до неприличия простая, в связи с тем, что слева очень ограниченный набор инструкций. Но мы увидим, что она будет оказываться в дальнейшем более сложной, и более полезной.