Сделаю.
Сделаю.
Упс. Да, это хак, согласен
а это очень просто, кстатипревратит “ld a,#0x00” в “xor a” (или “sub a”) – (там, где это даст выигрыш). Или найдётся человек, который пропихнёт такие предложения Филиппу Краузе.
подобная замена одного кода на другой легко выполняется через sdcc-шный механизм peep hole optimization. Суть его в том, что после основной компиляции запускается поточный текстовый редактор, заменяющий одни конструкции на другие
надо лишь добавить правило
ЗЫ Запостил Филлипу патч, авось приметКод:replace restart { ld a, #0x00 } by { xor a }
Последний раз редактировалось Eltaron; 18.03.2012 в 01:58.
Граф Дракула наш кумир, патамушта он вомпир!
VKINK 9 : BORDER NOT PI
Только что пощупал SDCC на предмет качества генерации кода. Результат, мягко говоря, не впечатлил. Поэтому, если генератор кода не использует XOR A вместо LD A,0 - то это самая малая из его проблем. Основное падение быстродействия программ будет происходить не из-за этого. Так что, думаю, не стоит заморачиваться с этой отдельно взятой оптимизацией. Снявши голову, по волосам не плачут, как говорится.
Впрочем, генерируется рабочий код Z80 - это тоже результат! Для быстрого написания программ такой компилятор вполне годится. Помнится, я пользовался турбо паскалем под CP/M для некоторых нужд. Результат вполне устраивал, я даже при этом не рассматривал, какой генерируется код. Работает, в память влезает - и хорошо, что не пришлось писать его на ассемблере.
Ну вот например, шлю тестовую программу на си и результат ее компиляции в асм. Программа состоит из двух простых функций: gcd для поиска наибольшего общего делителя; и recupow для возведения в степень с помощью рекурсии (хотел посмотреть, как компилируется рекурсия).
Замечания следующие:
1) Генерируется код для инициализации глобальных переменных (строки 47-65 асм-файла). Вместо этого можно было бы иметь сегмент инициализированных данных, эта концепция поддерживается многими компоновщиками.
2) Код инициализации данных чрезвычайно неэффективный:
LD IY, adr
LD (IY),data
3) Для сравнения двух однобайтовых переменных (строки 84-87 асм-файла) используется команда SUB, а не CP. В результате портится значение аккумулятора, которое далее по тексту программы приходится восстанавливать.
4) Весь цикл функции gcd (строки 84-104 асм-файла) реализован без использования регистров для локальных переменных, все данные сохраняются в памяти посредством индексной адресации. Мне удалось разместить переменные на регистрах только если объявить их локальными, скопировать в них значения аргументов функции, а в цикле работать с локальными переменными. Что ж - спасибо и на этом, хотя с семантической точки зрения разницы быть не должно, и оптимизатор, в идеале, должен генерировать одинаковый код в обоих случаях.
5) Для функции recupow, сравнение одного и того же числа с разными значениями, строки 121, 129 асм-файла. Во-первых, выполнение OR A не портит значение аккумулятора, поэтому восстанавливается он без необходимости. Во-вторых, сравнение с единицей командой SUB 1. Почему не CP? Почему не DEC? Тем более что далее по тексту программы значение аккумулятора снова восстанавливается из памяти (строка 136) и снова уменьшается на единицу, на этот раз командой DEC.
Засылка однобайтового числа на стек обычно выполняется командами PUSH AF / INC SP. Этим экономится 1 байт на стеке за счет потери тактов на команду INC SP и, возможно, DEC SP при удалении со стека аргументов после возврата функции, если их число было нечетным.
Однако в строках 138-140 асм-файла аргумент засылается на стек почему-то посредством LD D,A / PUSH DE / INC SP. Я не нашел этому разумного объяснения.
Путем некоторых шаманских действий с программами - таких как перемена местами операндов при сравнении на неравенство (!) - мне удавалось иногда повысить эффективность генерируемого кода. Но если писать на Си или другом языке высокого уровня, изначально учитывая особенности оптимизатора - то проще уж сразу на ассемблере писать программы.
Добавлю, что в приведенном примере код был сгенерирован еще относительно оптимально. Но это только потому, что я везде использовал тип данных байт (unsigned char). Изначально я применил просто char (знаковый), так тогда компилятор нагенерировал кучу проверок флага знакового переполнения (JP PO) при простых операциях с такими числами, таких как сравнение на равенство/неравенство. Я даже не берусь предполагать, какой код получится при работе с 16-битными знаковыми числами. Хоть стреляйся, наверно. Хотя беззнаковые 16-битные должны обрабатываться неплохо.
Вот еще один пример - подпрограмма быстрого возведения в степень. С ней нареканий совсем немного. Честно говоря, результат компиляции меня даже приятно порадовал. Потому что трудно ожидать, что компилятор мог бы улучшить этот результат хоть сколько-нибудь существенно. Ну так, по мелочи: строки 95-97, пользуется серией команд LD A,(IX+6) / SRL A / LD (IX+6),A и при этом в дальнейшем не использует значение аккумулятора, вместо того, чтобы сделать операцию одной командой SRL (IX+6). При этом команду DEC (IX+6) генератор кода знает. Создается впечатление, что это просто недоработка, может быть авторы не учли наличие у Z80 команд сдвига памяти по IX.
Еще в строках 64-66 проверяется младший бит по адресу IX. Компилятор сгенерировал LD A,(IX+6) / AND 1 / JR Z, хотя то же самое можно было бы сделать через BIT 0,(IX+6) / JR Z.
Поэтому оптимизация XOR A вместо LD A,0 - это капля в море.
Но в целом не поймите неправильно. Код довольно неплохой получается. Даже то, что использована команда DEC (IX+6) - это тоже очень хорошо. Могло ведь быть и хуже: LD A,(IX+6) / SUB 1 / LD (IX+6),A.
Также порадовала в строках 58-62 реализация сравнения с нулем на неравенство посредством OR A (фактически - сравнение на равенство). То есть оптимизатор разобрался, что для беззнакового числа сравнение с нулем на равенство и неравенство - это одно и то же.
Хак - объявить глобальные переменные как const и обращаться к ним через указатель. Тогда они разместятся в кодовом сегменте. Но вообще да, то, что сегмент .data на самом деле функционирует как .bss очень бесит.
---------- Post added at 18:57 ---------- Previous post was at 18:55 ----------
Мой патч для этого, кстати, не приняли. Аргумент разумный - XOR портит флаги, а LD нет. И поэтому в лоб заменить все ld a,0 на xor a нельзя, надо заменять выборочно.
---------- Post added at 20:00 ---------- Previous post was at 19:52 ----------
версия sdcc из транка svn это уже умеет
а еще оно теперь вместоКод:;fastpow.c:16: b >>= 1; srl 6 (ix) jr 00104$
генеритКод:;fastpow.c:8: if(b&1) ld a,6 (ix) and a, #0x01Код:;fastpow.c:8: if(b&1) bit 0, 6 (ix)
Последний раз редактировалось Eltaron; 18.03.2012 в 18:03.
Граф Дракула наш кумир, патамушта он вомпир!
VKINK 9 : BORDER NOT PI
Благодарю Вас.
Видите, Eltaron, я так осторожненько добавил после “превратит “ld a,#0x00” в “xor a” (или “sub a”) ”:
Я могу представить себе ситуацию, где SDCC надеется, сгенерировав “ld a,#0x00”, на неизменность флагов, а такой пипхол опять грозит нам головной болью. Нет, тут надо всё фундаментально делать, а не по-хацкерски, согласны?
Вы запостите Филиппу не идею пипхольной замены, а пусть он научит SDCC генерировать “xor a” там, где не нужно сберегать значение флагов. А заодно пусть и правда подумает о передаче единственного однобайтового параметра через аккумулятор. Идея отличная.
Я тем временем напишу Йозефу Темплу просьбу разрешить мне править код Ofront'а. Беззнаковые типы (байт, слово, двойное слово) - это то, что на очереди к реализации практически в самом начале списка. Сам понимаю, насколько эффективно юзать эти типы на Z80.
Господа, я медленно подвожу вас к тому, чтобы при программировании на Обероне выносить зависимые от платформы вещи в отдельный модуль-конфигуратор Settings. В дальнейшем можно будет даже разработать графический редактор свойств такого модуля (например, похожий на редактор свойств компонентов в Дельфи). Насколько проще, приятнее и нагляднее станет конфигурировать тонкости работы программ. Любой школьник младших классов сможет выбрать из менюшек доступные из свойств и, быстро пересобрав программу, посмотреть, что изменилось. Сравните это с суровым “configure; make; make install”.
Вот ещё одна наша маленькая победа на Оберон-нивах: ссылка на мои Оберон-биндинги к кроссплатформенной библиотеке SDL добавилась на оф.сайт SDL - http://www.libsdl.org/languages.php. Sam Lantinga похвалил качественно проделанную работу, так что я всех нас с этим поздравляю. Это хороший шаг к появлению кроссплатформенного эмулятора Спектрума на Обероне.
После некоторых размышлений я соглашаюсь с модераторами данного форума в том, что использование Оберон-технологий и среды XDev выходит далеко за рамки тем данного форума по ZX, поэтому подумываю о форуме для поддержки нашей среды разработки. А если среди нас соберётся ядро хотя бы 2-3 человека, которые будут активно дорабатывать ZXDev, пропихивать идеи кодогенерации в SDCC-сообщество, взаимодействовать на форумах с заинтересованными людьми на предмет изучения высказываемых идей и предложений, то в итоге выиграют все. Все, кто ещё программируют для Спектрума.
Последний раз редактировалось Oleg N. Cher; 29.03.2014 в 04:14.
Эту тему просматривают: 2 (пользователей: 0 , гостей: 2)