Книга: Системное программное обеспечение. Лабораторный практикум
Листинг П3.13. Построение ассемблерного кода по списку триад
Листинг П3.13. Построение ассемблерного кода по списку триад
unit TrdAsm;
{!!! Зависит от целевой вычислительной системы!!! }
interface
{ Модуль распределения регистров и построения ассемблерного
кода по списку триад }
uses Classes, TrdType, Triads;
const { Префикс наименования временных переменных }
TEMP_VARNAME = _Tmp';
NUM_PROCREG = 6; { Количество доступных регистров }
{ Функция распределения регистров и временных переменных
для хранения промежуточных результатов триад }
function MakeRegisters(listTriad: TTriadList): integer;
{ Функция построения ассемблерного кода по списку триад }
function MakeAsmCode(listTriad: TTriadList;
listCode: TStrings;
flagOpt: Boolean): integer;
implementation
uses SysUtils;
function MakeRegisters(listTriad: TTriadList): integer;
{ Функция распределения регистров и временных переменных
для хранения промежуточных результатов триад.
Результат: количество необходимых временных переменных }
var
i,j,iR,iCnt,iNum: integer;{Счетчики и переменные циклов}
{ Динамический массив для запоминания занятых регистров }
listReg: TList;
begin { Создаем массив для хранения занятых регистров }
listReg:= TList.Create;
Result:= 0;
if listReg <> nil then
try { Обнуляем информационное поле у всех триад }
for i:=listTriad.Count-1 downto 0 do
listTriad[i].Info:= 0;
{ Цикл по всем триадам. Обязательно с конца списка! }
for i:=listTriad.Count-1 downto 0 do
for j:=1 to 2 do { Цикл по всем (2) операндам }
{ Если триада – линейная операция, или «IF»
(первый операнд), или присвоение (второй операнд) }
if ((listTriad[i].TrdType in TriadLineSet)
or (listTriad[i].TrdType = TRD_IF) and (j = 1)
or (listTriad[i].TrdType = TRD_ASSIGN) and (j = 2))
{ и операндом является ссылка на другую триаду }
and (listTriad[i][j].OpType = OP_LINK) then
begin { Запоминаем номер триады, на которую направлена ссылка }
iNum:= listTriad[i][j].TriadNum;
{ Если триаде еще не назначен регистр и если это
не предыдущая триада – надо ей назначить регистр }
if (listTriad[iNum].Info = 0) and (iNum <> i-1) then
begin { Количество назначенных регистров }
iCnt:= listReg.Count-1;
for iR:=0 to iCnt do
begin{ Цикл по массиву назначенных регистров }
{ Если область действия регистра за пределами
текущей триады, то его можно использовать }
if longint(listReg[iR]) >= i then
begin { Запоминаем область действия регистра }
listReg[iR]:= TObject(iNum);
{ Назначаем регистр триаде с номером iNum }
listTriad[iNum].Info:= iR+1;
Break; { Прерываем цикл по массиву регистров }
end;
end; { Если ни один из использованных регистров
не был назначен, надо брать новый регистр }
if listTriad[iNum].Info = 0 then
begin { Добавляем запись в массив регистров,
указываем ей область действия iNum }
listReg.Add(TObject(iNum));
{ Назначаем новый регистр триаде с номером iNum }
listTriad[iNum].Info:= listReg.Count;
end;
end;
end;{ Результат функции: количество записей в массиве
регистров -1, за вычетом числа доступных регистров}
Result:= listReg.Count – (NUM_PROCREG-1);
finally listReg.Free;
end;
end;
function GetRegName(iInfo: integer): string;
{ Функция наименования регистров процессора }
begin
case iInfo of
0: Result:= 'eax';
1: Result:= 'ebx';
2: Result:= 'ecx';
3: Result:= 'edx';
4: Result:= 'esi';
5: Result:= 'edi';
{ Если это не один из регистров – значит,
даем имя временной переменной }
else Result:=
Format(%s%d',[TEMP_VARNAME,iInfo-NUM_PROCREG]);
end{case};
end;
function GetOpName(i: integer; listTriad: TTriadList;
iOp: integer): string;
{ Функция наименования операнда триады
i – номер триады в списке;
listTriad – список триад;
iOp – номер операнда триады }
var iNum: integer; {номенр триады по ссылке}
Triad: TTriad; {текущая триада}
begin
Triad:= listTriad[i]; { Запоминаем текущую триаду }
{ Выборка наименования операнда в зависимости от типа }
case Triad[iOp].OpType of
{ Если константа – значение константы }
OP_CONST: Result:= IntToStr(Triad[iOp].ConstVal);
{ Если переменная – ее имя из таблицы идентификаторов }
OP_VAR:
begin
Result:= Triad[iOp].VarLink.VarName;
{ Если имя совпадает с именем функции,
заменяем его на Result функции }
if Result = NAME_FUNCT then Result:= NAME_RESULT;
end; { Иначе – это регистр }
else { для временного хранения результатов триады }
begin { Запоминаем номер триады }
iNum:= Triad[iOp].TriadNum;
{ Если это предыдущая триада, то операнд не нужен }
if iNum = i-1 then Result:=
else
begin {Берем номер регистра, связанного с триадой}
iNum:= listTriad[iNum].Info;
{ Если регистра нет, то операнд не нужен }
if iNum = 0 then Result:=
{ Иначе имя операнда – это имя регистра }
else Result:= GetRegName(iNum);
end;
end;
end{case};
end;
function MakeMove(const sReg,{имя регистра}
sPrev,{предыдущая команда}
sVal{предыдущая величина в eax}: string;
flagOpt: Boolean{флаг оптимизации}): string;
{ Функция, генерящая код занесения значения в регистр eax }
begin { Если операнд был только что выгружен из eax
или необходимое значение уже есть в аккумуляторе,
нет необходимости записывать его туда снова }
if (Pos(Format(#9'mov'#9 %s,eax',[sReg]), sPrev) = 1)
or (sVal = sReg) then
begin
Result:= ; Exit;
end;
if flagOpt then { Если оптимизация команд включена }
begin
if sReg = 0 then { Если требуемое значение = 0, }
begin{его можно получить из –1 и 1 с помощью INC и DEC}
if sVal = -1 then Result:= #9'inc'#9'eax'
else
if sVal = 1 then Result:= #9'dec'#9'eax'
else Result:= #9'xor'#9'eax,eax'
end {иначе – с помощью XOR}
else
if sReg = 1 then { Если требуемое значение = 1, }
begin{его можно получить из –1 и 0 с помощью NEG и INC}
if sVal = -1 then Result:= #9'neg'#9'eax'
else
if sVal = 0 then Result:= #9'inc'#9'eax'
else
Result:= #9'xor'#9'eax,eax'#13#10#9'inc'#9'eax';
end {иначе – двумя командами: XOR и INC }
else
if sReg = -1 then { Если требуемое значение = -1, }
begin{его можно получить из 1 и 0 с помощью NEG и DEC}
if sVal = 1 then Result:= #9'neg'#9'eax'
else
if sVal = 0 then Result:= #9'dec'#9'eax'
else
Result:= #9'xor'#9'eax,eax'#13#10#9'dec'#9'eax';
end {иначе – двумя командами: XOR и DEC }
{ Иначе заполняем eax командой MOV }
else Result:= Format(#9'mov'#9'eax,%s',[sReg]);
end { Если оптимизация команд выключена,
всегда заполняем eax командой MOV }
else Result:= Format(#9'mov'#9'eax,%s',[sReg]);
end;
function MakeOpcode(i: integer;{номер текущей триады}
listTriad: TTriadList;{список триад}
const sOp,sReg,{код операции и операнд}
sPrev,{предыдущая команда}
sVal{предыдущая величина в eax}: string;
flagOpt: Boolean{флаг оптимизации}): string;
{ Функция, генерящая код линейных операций над eax }
var Triad: TTriad;{текущая триада}
begin { Запоминаем текущую триаду }
Triad:= listTriad[i];
if flagOpt then { Если оптимизация команд включена }
begin
if sReg = 0 then { Если операнд = 0 }
begin
case Triad.TrdType of
TRD_AND: { Для команды AND результат всегда = 0 }
Result:= MakeMove(0 ,sPrev,sVal,flagOpt);
{ Для OR, "+" и «-» ничего не надо делать }
TRD_OR,TRD_ADD,TRD_SUB: Result:= #9#9;
{ Иначе генерируем код выполняемой операции }
else Result:= Format(#9 %s'#9'eax,%s',[sOp,sReg]);
end{case};
end
else
if sReg = 1 then { Если операнд = 1 }
begin
case Triad.TrdType of
TRD_OR: { Для команды OR результат всегда = 1 }
Result:= MakeMove(1 ,sPrev,sVal,flagOpt);
{ Для AND ничего не надо делать }
TRD_AND: Result:= #9#9;
{ Для "+" генерируем операцию INC }
TRD_ADD: Result:= #9'inc'#9'eax';
{ Для «-» генерируем операцию DEC }
TRD_SUB: Result:= #9'dec'#9'eax';
{ Иначе генерируем код выполняемой операции }
else Result:= Format(#9 %s'#9'eax,%s',[sOp,sReg]);
end{case};
end
else
if sReg = -1 then { Если операнд = -1 }
begin
case Triad.TrdType of
{ Для "+" генерируем операцию DEC }
TRD_ADD: Result:= #9'dec'#9'eax';
{ Для «-» генерируем операцию INC }
TRD_SUB: Result:= #9'inc'#9'eax';
{ Иначе генерируем код выполняемой операции }
else Result:= Format(#9 %s'#9'eax,%s',[sOp,sReg]);
end{case};
end { Иначе генерируем код выполняемой операции }
else Result:= Format(#9 %s'#9'eax,%s',[sOp,sReg]);
end { Если оптимизация команд выключена,
всегда генерируем код выполняемой операции }
else Result:= Format(#9 %s'#9'eax,%s',[sOp,sReg]);
{ Добавляем к результату информацию о триаде
в качестве комментария }
Result:= Result + Format(#9 { %s },
[Triad.MakeString(i)]);
end;
function MakeAsmCode(
listTriad: TTriadList;{входной список триад}
listCode: TStrings;{список строк результирующего кода}
flagOpt: Boolean{флаг оптимизации}): integer;
{ Функция построения ассемблерного кода по списку триад }
var i,iCnt: integer;{счетчик и переменная цикла}
sR: string;{строка для имени регистра}
sPrev,sVal: string;
{строки для хранения предыдущей команды и значения eax}
procedure TakePrevAsm;
{ Процедура, выделяющая предыдущую команду и значение eax
из списка результирующих команд }
var j: integer;
begin
j:= listCode.Count;
if j > 0 then
begin
sPrev:= listCode[j-1];
sVal:= StrPas(PChar(listCode.Objects[j-1]));
end
else
begin
sPrev:= ; sVal:= ;
end;
end;
procedure MakeOper1(const sOp,{код операции}
sAddOp: string;{код дополнительной операции}
iOp: integer{номер операнда в триаде});
{ Функция генерации кода для унарных операций }
var sReg{строка для имени регистра}: string;
begin
TakePrevAsm; {Берем предыдущую команду и значение из eax}
{ Запоминаем имя операнда }
sReg:= GetOpName(i,listTriad,iOp);
if sReg <> then { Если имя пустое, операнд уже есть в
регистре eax от выполнения предыдущей триады,}
begin { иначе его нужно занести в eax }
{ Вызываем функцию генерации кода занесения операнда }
sReg:= MakeMove(sReg,sPrev,sVal,flagOpt);
if sReg <> then listCode.Add(sReg);
end; { Генерируем непосредственно код операции }
listCode.Add(Format(#9 %s'#9'eax'#9 { %s },
[sOp,listTriad[i].MakeString(i)]));
if sAddOp <> then { Если есть дополнительная операция,
генерируем ее код }
listCode.Add(Format(#9 %s'#9'eax,1,[sAddOp]));
if listTriad[i].Info <> 0 then { Если триада связана с
begin { регистром, запоминаем результат в этом регистре }
sReg:= GetRegName(listTriad[i].Info);
{ При этом запоминаем, что сейчас находится в eax }
listCode.AddObject(Format(#9'mov'#9 %s,eax',[sReg]),
TObject(PChar(sReg)));
end;
end;
procedure MakeOper2(const sOp,{код операции}
sAddOp: string{код дополнительная операции});
{ Функция генерации кода для бинарных арифметических
и логических операций }
var sReg1,sReg2{строки для имен регистров}: string;
begin
TakePrevAsm; {Берем предыдущую команду и значение из eax}
{ Запоминаем имена первого и второго операндов }
sReg1:= GetOpName(i,listTriad,1);
sReg2:= GetOpName(i,listTriad,2);
{ Если имя первого операнда пустое, значит, он уже
есть в регистре eax от выполнения предыдущей триады -
вызываем функцию генерации кода для второго операнда }
if (sReg1 = ) or (sReg1 = sVal) then
listCode.Add(MakeOpCode(i,listTriad,sOp,sReg2,
sPrev,sVal,flagOpt))
else { Если имя второго операнда пустое, значит он уже
есть в регистре eax от выполнения предыдущей триады -
вызываем функцию генерации кода для первого операнда }
if (sReg2 = ) or (sReg2 = sVal) then
begin
listCode.Add(MakeOpCode(i,listTriad,sOp,sReg1,
sPrev,sVal,flagOpt));
{ Если есть дополнительная операция, генерируем ее код
(когда операция несимметричная – например "-") }
if sAddOp <> then
listCode.Add(Format(#9 %s'#9'eax',[sAddOp]));
end
else { Если оба операнда не пустые, то надо:
– сначала загрузить в eax первый операнд;
– сгенерировать код для обработки второго операнда.}
begin
sReg1:= MakeMove(sReg1,sPrev,sVal,flagOpt);
if sReg1 <> then listCode.Add(sReg1);
listCode.Add(MakeOpCode(i,listTriad,sOp,sReg2,
sPrev,sVal,flagOpt));
end;
if listTriad[i].Info <> 0 then { Если триада связана с
begin { регистром, запоминаем результат в этом регистре }
sReg1:= GetRegName(listTriad[i].Info);
{ При этом запоминаем, что сейчас находится в eax }
listCode.AddObject(Format(#9'mov'#9 %s,eax',[sReg1]),
TObject(PChar(sReg1)));
end;
end;
procedure MakeCompare(const sOp: string
{флаг операции сравнения});
{ Функция генерации кода для операций сравнения }
var sReg1,sReg2{строки для имен регистров}: string;
begin
TakePrevAsm; {Берем предыдущую команду и значение из eax}
{ Запоминаем имена первого и второго операндов }
sReg1:= GetOpName(i,listTriad,1);
sReg2:= GetOpName(i,listTriad,2);
{ Если имя первого операнда пустое, значит он уже
есть в регистре eax от выполнения предыдущей триады -
сравниваем eax со вторым операндом }
if sReg1 = then
listCode.Add(Format(#9'cmp'#9'eax,%s'#9 { %s },
[sReg2,listTriad[i].MakeString(i)]))
else { Если имя второго операнда пустое, значит он уже
есть в регистре eax от выполнения предыдущей триады -
сравниваем eax с первым операндом в обратном порядке }
if sReg2 = then
listCode.Add(Format(#9'cmp'#9 %s,eax'#9 { %s },
[sReg1,listTriad[i].MakeString(i)]))
else { Если оба операнда не пустые, то надо:
– сначала загрузить в eax первый операнд;
– сравнить eax со вторым операндом. }
begin
sReg1:= MakeMove(sReg1,sPrev,sVal,flagOpt);
if sReg1 <> then listCode.Add(sReg1);
listCode.Add(Format(#9'cmp'#9'eax,%s'#9 { %s },
[sReg2,listTriad[i].MakeString(i)]));
end; { Загружаем в младший бит eax 1 или 0
в зависимости от флага сравнения }
listCode.Add(Format(#9'set%s'#9'al',[sOp]));
listCode.Add(#9'and'#9'eax,1); {очищаем остальные биты}
if listTriad[i].Info <> 0 then { Если триада связана с
begin { регистром, запоминаем результат в этом регистре }
sReg1:= GetRegName(listTriad[i].Info);
{ При этом запоминаем, что сейчас находится в eax }
listCode.AddObject(Format(#9'mov'#9 %s,eax',[sReg1]),
TObject(PChar(sReg1)));
end;
end;
begin { Тело главной функции }
iCnt:= listTriad.Count-1; { Количество триад в списке }
for i:=0 to iCnt do
begin { Цикл по всем триадам от начала списка }
{ Если триада помечена, создаем локальную метку
в списке команд ассемблера }
if listTriad[i].IsLinked then
listCode.Add(Format(@M%d:,[i+1]));
{ Генерация кода в зависимости от типа триады }
case listTriad[i].TrdType of
{ Код для триады IF }
TRD_IF: { Если операнд – константа, }
begin {(это возможно в результате оптимизации)}
if listTriad[i][1].OpType = OP_CONST then
begin { Условный переход превращается
в безусловный, если константа = 0,}
if listTriad[i][1].ConstVal = 0 then
listCode.Add(Format(#9'jmp'#9 @M%d'#9 { %s },
[listTriad[i][2].TriadNum+1,
listTriad[i].MakeString(i)]));
end { а иначе вообще генерировать код не нужно.}
else { Если операнд – не константа }
begin { Берем имя первого операнда }
sR:= GetOpName(i,listTriad,1);
{ Если имя первого операнда пустое,
значит он уже есть в регистре eax
от выполнения предыдущей триады, }
if sR = then
{ тогда надо выставить флаг «Z», сравнив eax
с ним самим, но учитывая, что предыдущая
триада для IF – это либо сравнение, либо
логическая операция, это можно опустить}
else { иначе надо сравнить eax с операндом }
listCode.Add(Format(#9'cmp'#9 %s,0,[sR]));
{Переход по условию «NOT Z» на ближайшую метку}
listCode.Add(Format(#9'jnz'#9 @F%d'#9 { %s },
[i,listTriad[i].MakeString(i)]));
{ Переход по прямому условию на дальнюю метку }
listCode.Add(Format(#9'jmp'#9 @M%d',
[listTriad[i][2].TriadNum+1]));
{ Метка для ближнего перехода }
listCode.Add(Format(@F%d:,[i]));
end;
end;
{ Код для бинарных логических операций }
TRD_OR: MakeOper2('or', );
TRD_XOR: MakeOper2('xor', );
TRD_AND: MakeOper2('and', );
{ Код для операции NOT (так как NOT(0)=FFFFFFFF,
то нужна еще операция: AND eax,1 }
TRD_NOT: MakeOper1('not','and',1);
{ Код для операций сравнения по их флагам }
TRD_LT: MakeCompare('l');
TRD_GT: MakeCompare('g');
TRD_EQ: MakeCompare('e');
TRD_NEQ: MakeCompare('ne');
{ Код для бинарных арифметических операций }
TRD_ADD: MakeOper2('add', );
TRD_SUB: MakeOper2('sub','neg');
{ Код для унарного минуса }
TRD_UMIN: MakeOper1('neg', ,2);
TRD_ASSIGN: { Код для операции присвоения }
begin {Берем предыдущую команду и значение из eax}
TakePrevAsm;
sR:= GetOpName(i,listTriad,2); {Имя второго операнда}
{ Если имя второго операнда пустое, значит он уже есть
в регистре eax от выполнения предыдущей триады}
if sR <> then
begin {иначе генерируем код загрузки второго операнда}
sVal:= MakeMove(sR,sPrev,sVal,flagOpt);
if sVal <> then listCode.Add(sVal);
end; { Из eax записываем результат в переменную
с именем первого операнда }
sVal:= listTriad[i][1].VarLink.VarName;
if sVal = NAME_FUNCT then sVal:= NAME_RESULT;
sVal:= Format(#9'mov'#9 %s,eax'#9 { %s },
[sVal,listTriad[i].MakeString(i)]);
{ При этом запоминаем, что было в eax }
listCode.AddObject(sVal,TObject(PChar(sR)));
end;
{ Код для операции безусловного перехода }
TRD_JMP: listCode.Add(
Format(#9'jmp'#9 @M%d'#9 { %s },
[listTriad[i][2].TriadNum+1,
listTriad[i].MakeString(i)]));
{ Код для операции NOP }
TRD_NOP: listCode.Add(Format(#9'nop'#9#9 { %s },
[listTriad[i].MakeString(i)]));
end{case};
end{for};
Result:= listCode.Count;
end;
end.
- 3.2.1. Принадлежность к списку
- Листинг 10.1. (simpleid.c) Отображение идентификаторов пользователя и группы
- Глава 5 Агрессивные формы кода и борьба с ними
- Определение целей. Построение цепочек
- 4.2. Создание трехмерной модели и построение горизонтальной проекции детали
- Стиль написания исходного кода
- Построение модели выходов (результатов)
- Листинг 15.11. Код для загрузки файла с Web-сервера
- Глава 9 Построение отказоустойчивых систем
- Анализ CIL-кода
- Листинг 3.1. Конфигурационный файл lilo.conf
- Листинг 3.2. Файл настройки программы inittab