JFYI
дизассемблед и фиксед версия турбо паскаля
http://www.cirsovius.de/CPM/Projekte.../TURBO-en.html
там вообще у чувака КУЧА разных рабочих дасмов.
Видимо, оптимизированная компиляция. Другое дело, какой уровень оптимизации приемлем для Спека. В моем компиле точно есть (дописываю на днях):
- свёртка констант;
- упрощение выражений перекидыванием операндов из стека в регистры (удаление лишних push/pop);
- быстрое умножение и деление на числа степени 2, а также быстрое умножение на некоторые часто используемые числа;
- удаление повторных присваиваний и чтений переменных;
- удаление повторных расчетов индексов массива.
Последний раз редактировалось Andrew771; 13.03.2015 в 14:44.
Для меня в этом магическом "разные платформы" главное - переносимость на уровне исходного кода. Язык высокого уровня и есть то, что позволяет писать, не задумываясь о том, на чём это будет запускаться.
Виртуальная машина тоже позволяет абстрагироваться от конкретного процессора. Создать такую виртуальную машину и писать программы на ассемблере для неё я уже пробовал, следующим этапом стал Паскаль. Который в том числе сможет генерировать код для виртуальной машины.
Нет, не пагубна. Практичность/академичность действий понятие относительное. Например, вычисление тройных интегралов и числа Пи до 100-го знака на 8-битных процессорах может использоваться для тестирования процессоров и математических библиотек. Вполне практическое применение.
Мне интересна работа и устройство компиляторов и процессоров, Andrew771 делает инструмент под конкретную платформу, Oleg N. Cher'у нравится Оберон, кто-то запускает ARM Linux на 8-битных процессорах, а кто-то может заняться добавлением функций в дизассемблированную программу или написанием кодогенератора для FPC/GCC/etc.
Это всё на уровне псевдокода? В момент генерации или отдельным проходом? Где и как при этом хранится псевдокод?
Я тоже при разборе исходника генерировал псевдокод, но на пятом или шестом процессоре понял, что оптимизация получится как-то не очень. Проверка типов данных при попытке добавить все эти "массивы указателей на записи, в которых указатели на массивы" тоже зашла в тупик. Но у псевдокода свои плюсы, и сейчас задумываюсь о возвращении к чему-то подобному.
Да.
При первой генерации генерируется псевдокод, а не код ассемблера. А оптимизация происходит при отдельных нескольких проходах.
Псевдокод состоит из команд вида: мнемоника-число-строка. Хранится в массиве записей. Потом после оптимизации при окончательной генерации кода уже генерируется код ассемблера. Каждая команда псевдокода, как правило, состоит из нескольких ассемблерных команд.
На уровне псевдокода проще проводить оптимизацию, чем на окончательном ассемблере. И из него уже можно генерировать не только под Спектрум, но и под другие процы. Просто задать коды конкретного асма для каждой псевдокоманды.
Да, вот именно так у меня и было. Работало. Но таким способом получается хороший код для простых процессоров, а, например, для x86 или ARM с их заковыристыми адресациями такой метод просто не видит операции, они "рассыпаются" в псевдокоде. Или же программу надо писать "простыми словами", а не вот так
Надо что-то изменить в структуре псевдокода, пока не пойму что.Код:if node^.nodeargs[i]^.resulttype<>nil then typ1:=node^.nodeargs[i]^.resulttype^ else begin typ1.flags:=node^.nodeargs[i]^.resulttypeflag; typ1.size:=4; end;
---------- Post added at 00:11 ---------- Previous post was at 00:01 ----------
Кодогенератор FPC вообще жжот, для надёжности проверяет индекс массива два раза и копирует один байт при помощи movsb:
Код:# [210] typ1.flags:=node^.nodeargs[i]^.resulttypeflag; movzbl -860(%ebp),%eax decl %eax cmpl $9,%eax jbe .Lj3685 call FPC_RANGEERROR .Lj3685: movzbl -860(%ebp),%eax movl %eax,%edx decl %eax cmpl $9,%eax jbe .Lj3686 call FPC_RANGEERROR .Lj3686: movl -884(%ebp),%ecx movl 12(%ecx,%edx,4),%eax leal -40(%ebp),%edi leal 69(%eax),%esi cld movsb
Последний раз редактировалось Bolt; 15.03.2015 в 23:13.
Про x86 не знаю, не писал никогда на его асме. Возможно, определенные последовательности псевдокоманд можно объединять в одну команду асма x86.
У меня сейчас в выражениях используется только двухбайтовое представление (через регистровую пару HL), даже если действия производятся над однобайтовыми значениями. Только чтение и запись значений производятся соответственно размерности. Здесь нужно делать еще один проход, чтобы определить максимальный используемый тип в сгенерированном выражении. В первой версии компиля пока не буду это оптимизировать.
И еще индуктивность переменных тоже никак не учитываю. Так что, если встретится например:
то на каждой итерации цикла будет рассчитываться заново адрес в памяти для ячейки a[i], хотя можно было всего лишь прибавить смещение к предыдущей ячейке. Здесь нужно уже анализировать весь поток от начала до конца цикла, а вдруг еще внутри есть другие циклы и ветвления. Пока не стал заморачиваться. А вот если эта же ячейка понадобится еще раз после, то уже возьмется запомненный ее адрес, это я сделал:Код:for i:=1 to 100 do a[i]:=i;
Ячейка a[i] только один раз будет рассчитываться.Код:for i:=1 to 100 do begin a[i]:=i; b[i]:=i+1; if a[i]>b[i] then a[i]:=100; end;
После оптимизации 4 штуки (два сложения, одно умножение и запись).
Последний раз редактировалось Andrew771; 17.03.2015 в 10:53.
Эту тему просматривают: 1 (пользователей: 0 , гостей: 1)