Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Скачиваний:
30
Добавлен:
02.05.2014
Размер:
20.59 Кб
Скачать
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
Result := 0;
{ Создаем массив для хранения занятых регистров }
listReg := TList.Create;
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
{ Цикл по всем (2) операндам }
for j:=1 to 2 do
{ Если триада - линейная операция, или "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
{ Запоминаем новую область действия регистра
(iNum) }
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
{ Если значение = 0, то заносим его с помощью XOR }
if sReg = '0' then
begin
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
else
{ Если = 1 - двумя командами: XOR и INC }
if sReg = '1' then
begin
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
else
{ Если = -1 - двумя командами: XOR и DEC }
if sReg = '-1' then
begin
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
{ Иначе заполняем 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
{ Если операнд = 0 }
if sReg = '0' then
begin
case Triad.TrdType of
{ Для команды AND результат всегда = 0 }
TRD_AND:
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
{ Если операнд = 1 }
if sReg = '1' then
begin
case Triad.TrdType of
{ Для команды OR результат всегда = 1 }
TRD_OR:
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
{ Если операнд = -1 }
if sReg = '-1' then
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
{ Берем предыдущую команду и значение из eax }
TakePrevAsm;
{ Запоминаем имя операнда }
sReg := GetOpName(i,listTriad,iOp);
{ Если имя пустое, операнд уже есть в регистре EAX
от выполнения предыдущей триады, иначе его нужно
занести в EAX - вызываем функцию генерации кода }
if sReg <> '' then
begin
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
{ Берем предыдущую команду и значение из eax }
TakePrevAsm;
{ Запоминаем имя 1 операнда }
sReg1 := GetOpName(i,listTriad,1);
{ Запоминаем имя 2 операнда }
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
{ Берем предыдущую команду и значение из eax }
TakePrevAsm;
{ Запоминаем имя 1 операнда }
sReg1 := GetOpName(i,listTriad,1);
{ Запоминаем имя 2 операнда }
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]));
(* Один из вариантов кода:
{ Преобразуем 8 младших бит в 16 бит }
listCode.Add(#9'cbw');
{ Преобразуем 16 младших бит в 32 бита }
listCode.Add(#9'cwde'); *)
(* Другой вариант: *)
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 - это либо сравнение, либо
логическая операция, это можно опустить}
(* listCode.Add(#9'test'#9'eax,eax') *)
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
{ иначе генерим код загрузки операнда в EAX }
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.
Соседние файлы в папке Cursov