x86128: (Default)
x86128 ([personal profile] x86128) wrote2021-10-20 04:16 pm

Кодоген здорового человека

Рассмотрим теперь простой алгоритм преобразования арифметических (или логических) выражений в машинный код БЭСМ-6.

Допустим есть вот эта программа:
MODULE arith;

var
	a : integer;

begin
	a := 5  - 3 * 8 div 6;
	writeint(a);
	writeln
END arith.


После прохода парсера и построения промежуточного вида в кодах виртуальной машины имеем такой код:
 ('LABEL', 'arith_main'),
 ('ALLOC', 1),
Вычисление выражения (без оптимизации) 
('CLOAD', 0),
 ('CLOAD', 1),
 ('CLOAD', 2),
 ('BINOP', '*'),
 ('CLOAD', 3),
 ('BINOP', 'DIV'),
 ('BINOP', '-'),
Сохранение в переменную А
 ('VSTOR', -1, 'a'),

Загрузка на стэк значения А
 ('VLOAD', -1, 'a'),
 ('SYSCALL', 'writeint'),
 ('DEALLOC', 1),

 ('SYSCALL', 'writeln'),
 ('STOP', '12345'),

 ('LABEL', 'const_table'),
 ('WORD', 5),
 ('WORD', 3),
 ('WORD', 8),
 ('WORD', 6),
 ('WORD', 0),
 ('LABEL', 'locals_base'),
 ('LABEL', 'stack_base')]


Суть алгоритма заключается в том, что мы рассматриваем аккумулятор как вершину стека, соотв. линейно просматриваем код первой машины и начинаем заменять команды манипуляции со стеком на команды манипуляции с аккумулятором.
Загрузка значения на аккумулятор взводит флаг того что он занят.
Если два раза подряд попалась команда загрузки на аккумулятор, мы выталкиваем значение в стэк БЭСМ-6. Если же за командой выталкивания следует арифметическая операция, то операция выталкивания заменяется на арифметическую команду БЭСМ с указанием адреса аргумента. Таким образом отбрасывание вершины стека сводится к сбросу флага занятости аккумулятора. Операции вызова процедуры при занятом аккумуляторе автоматически сбрасывают его значение в стэк.

TEXT:
00000:        	VTM  	21    	,M1
00001:        	VTM  	21    	,M15
00002:        	VTM  	16    	,M2
00003:        	UJ   	4    	 

00004: arith_main UTM  	1     	,M15

Вычисление a := 5  - 3 * 8 div 6;
00005:        	XTA  	0     	,M2
00006:        	XTS  	1     	,M2
00007:        	A*X  	2     	,M2
00008:        	A/X  	3     	,M2
00009:        	X-A  	0     	,M15
Запись в А
00010:        	ATX  	-1    	,M1
Вызов процедуры. Аргумент на стэк (т.к. XTA -1, M1 соотв. предыдущей команде, она удаляется)
00011:        	ATX  	0     	,M15
00012:        	*77  	0    	 
Корректировка стэка после вызова
00013:        	UTM  	-1    	,M15
00014:        	*77  	2    	 
00015:        	STOP 	12345	 
Константы
00016:        	WORD 	5    	 
00017:        	WORD 	3    	 
00018:        	WORD 	8    	 
00019:        	WORD 	6    	 
00020:        	WORD 	0    	 

CONSTANT TABLE:
00000:    	5    	5
00001:    	3    	3
00002:    	8    	8
00003:    	6    	6

PROCEDURE TABLE
  arith_main: 4

1
STOP at PC=15 code=12345 ir=0


Итого:
00005:        	XTA  	0     	,M2
00006:        	XTS  	1     	,M2
00007:        	A*X  	2     	,M2
00008:        	A/X  	3     	,M2
00009:        	X-A  	0     	,M15

Против метода курильщика:
00005:       	XTA  	0     	,M2
00006:       	ATX  	0     	,M15
00007:       	XTA  	1     	,M2
00008:       	ATX  	0     	,M15
00009:       	XTA  	2     	,M2
00010:       	ATX  	0     	,M15
00011:       	XTA  	-2    	,M15
00012:       	A*X  	-1    	,M15
00013:       	ATX  	-2    	,M15
00014:       	UTM  	-1    	,M15
00015:       	XTA  	3     	,M2
00016:       	ATX  	0     	,M15
00017:       	XTA  	-2    	,M15
00018:       	A/X  	-1    	,M15
00019:       	ATX  	-2    	,M15
00020:       	UTM  	-1    	,M15
00021:       	XTA  	-2    	,M15
00022:       	A-X  	-1    	,M15
00023:       	ATX  	-2    	,M15
00024:       	UTM  	-1    	,M15
00025:       	XTA  	0     	,M15


Как говорится, почувствуйте разницу 😅️

Дальше необходимо разобраться со ссылочными VAR-аргументами доступ к которым осуществляется по адресу значения и починить вычисление константных выражений.
vak: (Default)

[personal profile] vak 2021-10-20 09:28 am (UTC)(link)
Ага, уже похоже на правду. :)