Важная информация

User Tag List

Страница 1 из 4 1234 ПоследняяПоследняя
Показано с 1 по 10 из 53

Тема: к вопросу о разумности использования компиляторов C на спеке

Комбинированный просмотр

Предыдущее сообщение Предыдущее сообщение   Следующее сообщение Следующее сообщение
  1. #1
    Sinclair User Аватар для Eltaron
    Регистрация
    16.01.2005
    Адрес
    Ekaterinburg
    Сообщений
    2,045
    Записей в дневнике
    7
    Спасибо Благодарностей отдано 
    144
    Спасибо Благодарностей получено 
    463
    Поблагодарили
    326 сообщений
    Mentioned
    4 Post(s)
    Tagged
    0 Thread(s)

    По умолчанию к вопросу о разумности использования компиляторов C на спеке

    давно занимает эта тема
    вот, решил потестировать все компиляторы, до которых дотянулись руки
    проверял на банальнейшей штуке - заливке всего экрана черным цветом, вот такой вот код:
    Код:
    int main()
    {
      unsigned char* t;
      t = 16384;
      while (t<16384+6144)
      {
        *t = 255;
        t++;
      }
      return 0;
    }
    специально не использовал никаких библиотек, если что, их всегда можно написать самому, да и не нужна на спеке добрая половина их возможностей.
    первым попался под руку z88dk
    вот что он мне выдал
    Код:
    ._main
    	ld	hl,16384	;const
    	push	hl
    .i_3
    	pop	hl
    	push	hl
    	ld	de,22528	;const
    	ex	de,hl
    	call	l_ult
    	jp	nc,i_4
    	pop	hl
    	push	hl
    	ld	(hl),#(255 % 256 % 256)
    	pop	hl
    	inc	hl
    	push	hl
    	dec	hl
    	jp	i_3
    .i_4
    	ld	hl,0	;const
    	pop	bc
    	ret
    то есть даже в таком примитивном коде наворочено по максимуму
    причем, это только асмовый исходник, после линковки он добавляет еще мусора
    пытаться скомпилировать этот код руками не стал, нервы дороже
    в общем, барахло, а не компилятор

    Дальше был sdcc
    им уже вполне можно пользоваться, судите сами:
    Код:
    	org #9c40
    _main_start::
    _main:
    	ld	bc,#4000
    _l00101: 
    	ld	e,c
    	ld	d,b
    	ld	a,e
    	sub	a,#00
    	ld	a,d
    	sbc	a,#58
    	jp	p, _l00103
    	ld	a,#FF
    	ld	(bc),a
    	inc	bc
    	jp	 _l00101
    _l00103: 
    	ld	hl,#0000
    _l00104: 
    	ret
    слишком много явно лишних операций(типа вычитания нуля из аккумулятора), но это уже что-то
    но хотелось лучшего и я полез в инет
    нашел еще компилятор от Softools, но он слишком хотел денег и у меня запуститься отказался наотрез
    и, в конце-концов наткнулся на компилятор от IAR. Плох он тем, что нет command-line утилит, все встроено в IDE, и писать приходится в нем, неудобно, все же FAR роднее
    вот такое вот чудо он нагенерировал:
    Код:
    	org #9c40
    main:
            PUSH    BC
            PUSH    IX
            LD      IX,0
            ADD     IX,SP
            PUSH    AF
            LD      (IX-2),0
            LD      (IX-1),64
    l0001:
            LD      BC,22528
            LD      L,(IX-2)
            LD      H,(IX-1)
            AND     A
            SBC     HL,BC
            JR      NC,l0000
    l0002:
            LD      L,(IX-2)
            LD      H,(IX-1)
            LD      (HL),255
            INC     (IX-2)
            JR      NZ,l0003
            INC     (IX-1)
    l0003:
            JR      l0001
    l0000:
            LD      SP,IX
            POP     IX
            POP     BC
            RET
    оно, конечно, работает, но не радует, блин
    и тут меня как ударило - что-то слишком активно с памятью он работает, и я полез искать в опциях настройки компиляции
    и вот оно! оптимизация - Default/Size/Speed
    ну, поставил Speed на максимум
    вот что выдал:
    Код:
    	org #9c40
    main:
            PUSH    BC
            PUSH    DE
            LD      DE,16384
    l0001:
            LD      BC,22528
            LD      H,D
            LD      L,E
            AND     A
            SBC     HL,BC
            JR      NC,l0000
    l0002:
            LD      H,D
            LD      L,E
            LD      (HL),255
            INC     DE
            JR      l0001
    l0000:
            POP     DE
            POP     BC
            RET
    довольно непривычно глазу(я б не так написал :-)), но работает
    а, главное, действительно оптимизировано, лень такты подсчитывать, но, думаю, это самый быстрый вариант

    к чему я это все? да ни к чему, просто хотелось радостью поделиться, нашел хоть один нормальный компилятор :-)
    вообще, неудивительно, что он дает такой неплохой код, все-таки коммерческая разработка для промышленного применения
    если кто заинтересовался - компилер можно бесплатно скачать с www.iar.com(4 мега). Там написано, что это демо-версия, но никаких ограничений пока не заметил

    ЗЫ везде из сгенеренного компилером кода вычищен весь мусор и сам код переделан для нормального ассемблирования сторонним спектрумским ассемблером(я юзал sjasm)
    Граф Дракула наш кумир, патамушта он вомпир!
    VKINK 9 : BORDER NOT PI

  2. #1
    С любовью к вам, Yandex.Direct
    Размещение рекламы на форуме способствует его дальнейшему развитию

  3. #2
    Veteran Аватар для lvd
    Регистрация
    23.01.2005
    Сообщений
    1,113
    Спасибо Благодарностей отдано 
    0
    Спасибо Благодарностей получено 
    3
    Поблагодарили
    3 сообщений
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)

    По умолчанию

    Цитата Сообщение от Eltaron
    Дальше был sdcc
    ld a,e
    sub a,#00
    ld a,d
    sbc a,#58
    jp p, _l00103
    Ошибка. Должно быть jp c/nc, потому что #ff00 -#5800 - будет флаг N стоять.

    довольно непривычно глазу(я б не так написал :-)), но работает
    а, главное, действительно оптимизировано, лень такты подсчитывать, но, думаю, это самый быстрый вариант
    Посчитай и убедись, что сдцц всё же в данном случае дал наиболее оптимальный код - без коматозных 16-битных конструкций и тд. Вот ещё бы и правильный был бы =)
    --- Кто съел всю уху?

  4. #3
    Guru Аватар для breeze
    Регистрация
    11.02.2005
    Адрес
    【RB】
    Сообщений
    3,694
    Спасибо Благодарностей отдано 
    29
    Спасибо Благодарностей получено 
    42
    Поблагодарили
    30 сообщений
    Mentioned
    2 Post(s)
    Tagged
    0 Thread(s)

    Question

    Цитата Сообщение от Eltaron
    если кто заинтересовался - компилер можно бесплатно скачать с www.iar.com(4 мега). Там написано, что это демо-версия, но никаких ограничений пока не заметил
    это этот линк ? http://supp.iar.com/FilesPublic/EWDE...560/ewz80d.zip
    (๑•̀ㅂ•́)و✧ Doors UI → https://t.me/doorsui | https://t.me/atari_xl_xe ← Atari XL/XE (●´ω`●)ゞ

  5. #4
    Sinclair User Аватар для Eltaron
    Регистрация
    16.01.2005
    Адрес
    Ekaterinburg
    Сообщений
    2,045
    Записей в дневнике
    7
    Спасибо Благодарностей отдано 
    144
    Спасибо Благодарностей получено 
    463
    Поблагодарили
    326 сообщений
    Mentioned
    4 Post(s)
    Tagged
    0 Thread(s)

    По умолчанию

    Цитата Сообщение от breeze
    он самый

    Посчитай и убедись, что сдцц всё же в данном случае дал наиболее оптимальный код - без коматозных 16-битных конструкций и тд. Вот ещё бы и правильный был бы =)
    ну не знаю, один коматозный sbc идет 15 тактов, а у sdcc два некоматозных, но по 7, почти то же самое
    но эт я так, навскидку, внимательно потом посчитаю
    Граф Дракула наш кумир, патамушта он вомпир!
    VKINK 9 : BORDER NOT PI

  6. #5
    Sinclair User Аватар для Eltaron
    Регистрация
    16.01.2005
    Адрес
    Ekaterinburg
    Сообщений
    2,045
    Записей в дневнике
    7
    Спасибо Благодарностей отдано 
    144
    Спасибо Благодарностей получено 
    463
    Поблагодарили
    326 сообщений
    Mentioned
    4 Post(s)
    Tagged
    0 Thread(s)

    По умолчанию

    ладно, соглашусь, что если бы sdcc не делал ошибок и умел бы выкидывать ненужные инструкции, то цены бы ему не было :-))
    но это в том примере
    а счас для сравнения вот такое:
    main.c:
    Код:
    #include "main.h"
    
    void main(void)
    {
      gotoXY(10,10);
      printf("Hello, world!");
    }
    main.h:
    Код:
    void gotoXY(char x, char y);
    void printf(char* data);
    естественно, линковщик будет ругаться, ибо тел продекларированных функций нет, но черт с ним, с линковщиком, все равно у него на выходе что-то непотребное, проще обычным ассемблером ассемблировать

    вот sdcc:
    Код:
    _main_start::
    _main:
    	ld	hl,#0x0A0A
    	push	hl
    	call	_gotoXY
    	pop	af
    	ld	hl,#__str_0
    	push	hl
    	call	_printf
    	pop	af
    00101$:
    	ret
    _main_end::
    __str_0:
    	.ascii "Hello, world!"
    а вот iar ewz80:
    Код:
    main:
            PUSH    BC
            PUSH    DE
            LD      C,10
            LD      E,C
            CALL    gotoXY
            LD      DE,?0000   ; вот это место мне не нравится, к божескому виду приводится только встроенным линкером
            CALL    printf
            POP     DE
            POP     BC
            RET
    комментарии, думаю, излишни
    один ld e,c чего стоит
    да и sdcc передает аргументы через стек, как принято на pc, а iar если аргументов мало, заполняет ими регистры
    еще sdcc чуть что, начинает воротить огород вокруг индексных регистров, ewz80 тоже, но реже и код у него выглядит лучше(может, конечно, работает хуже , не тестировал)
    в общем, мне определенно нравится iar'овский компайлер
    но нашел у него большую проблему - он не вставляет в ассемблерный листинг строковые(а может и не только) константы, счас думаю, как это обходить...
    Граф Дракула наш кумир, патамушта он вомпир!
    VKINK 9 : BORDER NOT PI

  7. #6
    Veteran Аватар для lvd
    Регистрация
    23.01.2005
    Сообщений
    1,113
    Спасибо Благодарностей отдано 
    0
    Спасибо Благодарностей получено 
    3
    Поблагодарили
    3 сообщений
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)

    По умолчанию

    Цитата Сообщение от Eltaron
    комментарии, думаю, излишни
    один ld e,c чего стоит :)
    да и sdcc передает аргументы через стек, как принято на pc, а iar если аргументов мало, заполняет ими регистры
    еще sdcc чуть что, начинает воротить огород вокруг индексных регистров, ewz80 тоже, но реже и код у него выглядит лучше(может, конечно, работает хуже :), не тестировал)
    в общем, мне определенно нравится iar'овский компайлер :)
    но нашел у него большую проблему - он не вставляет в ассемблерный листинг строковые(а может и не только) константы, счас думаю, как это обходить...
    Одним словом, любой компюлер цэ для з80 можно заставить бред нагенерить. О чём и речь - на з80 нормально можно только на асме прогать. Ни один компайлер не догадается на for(i=0;i<256;i++) a[i]=0; нагенерить ld sp,:ld de,0:push de:push de:...:push de. А кодер в маинлупе или в инте где критично время исполнения - такое автоматом влепит.
    --- Кто съел всю уху?

  8. #7
    Activist Аватар для Raider
    Регистрация
    24.06.2005
    Адрес
    novosibirsk
    Сообщений
    266
    Записей в дневнике
    5
    Спасибо Благодарностей отдано 
    0
    Спасибо Благодарностей получено 
    1
    Поблагодарили
    1 сообщение
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)

    По умолчанию

    Отпишу мысли..

    Цитата Сообщение от Eltaron
    давно занимает эта тема
    вот, решил потестировать все компиляторы, до которых дотянулись руки
    проверял на банальнейшей штуке - заливке всего экрана черным цветом, вот такой вот код:
    Код:
    int main()
    {
      unsigned char* t;
      t = 16384;
      while (t<16384+6144)
      {
        *t = 255;
        t++;
      }
      return 0;
    }

    Еще есть некий Avocet compiler - доступен в edonkey network (правда лучше пользовать emule клиента).

    Еще есть GCC. И к нему есть патч (текстовая заплатка на исходники чтобы получить кодогенерацию для z80).

    Еще должны быть ссылки на сайте Zilog (если zilog еще живой, не был там лет 5-6 уже наверное).


    Ты неправильно сделал то что поместил пример прямо внутрь int main()
    это чревато. Всегда тестируй в отдельной функции:

    Код:
    void test() {
    
    }
    main - системный вход и мало ли что туда может попадать. Непредсказуемо
    туда по-идее должна попадать argc и argv и возвращаться результат.


    хорошо, если компилятор додумается посчитать инвариантные константы. в (t<16384+6144) Но он не обязан.

    Указатели в любом компиляторе оптимизируются плохо, и лучше всего их заменять адресацией t[x] - может выйти эффективнее.

    Указатель t - 16-битный. А это форсирует компилятор применять 16-битную арифметику, т.к. ты ему написал операцию сравнения (t<16384+6144) которые явно 16-битные, так что эффективного кода для z80 не жди. Эффективнее может оказаться следущее:

    Код:
    unsigned char *t = 0x4000;
    register i; // или unsigned short
    
    for(i=0x1800; i != 0; i--)  *t++ = (unsigned char)0xFF;
    А вообще, должно было быть
    Код:
    memset( 0x4000, 0x00, 0x1800)
    - компилятор должен позвать либо библиотечную функцию, либо заменить ее на встроенный intrinsic в виде LDIR'а.

    Мое мнение - писать на компайлерах наверное можно, но нужно четко понимать что за чем стоит там внутри. В основном, писать логику программы, и из нее дергать функции на асме.

    p.s.
    Из компиляторов самый перспективный будет GCC (в теории), особенно, если довести его кодогенерацию для z80 до ума. Вполне вероятно, что какая-то из фирм так и сделала, это обычный путь, пройденый уже не раз.
    Alex Raider, Flash inc. 1992-1997 Новосибирск

  9. #8
    Sinclair User Аватар для Eltaron
    Регистрация
    16.01.2005
    Адрес
    Ekaterinburg
    Сообщений
    2,045
    Записей в дневнике
    7
    Спасибо Благодарностей отдано 
    144
    Спасибо Благодарностей получено 
    463
    Поблагодарили
    326 сообщений
    Mentioned
    4 Post(s)
    Tagged
    0 Thread(s)

    По умолчанию

    Цитата Сообщение от Raider
    main - системный вход и мало ли что туда может попадать. Непредсказуемо
    я и не смотрел на код до и после моего цикла
    а внутри него никаких последствий от main'а быть уже не должно
    туда по-идее должна попадать argc и argv и возвращаться результат.
    ну, это понятно, не первый раз замужем :-)
    просто плох тот компилятор, который при отсутствии argv и argc будет городить код для их обработки, а компайлер, не могущий посчитать константу вообще можно сразу на свалку

    Цитата Сообщение от Raider
    т.к. ты ему написал операцию сравнения (t<16384+6144) которые явно 16-битные
    это да, конечно же надо цикл обратно к нулю крутить, но я же не задавался мыслью написать оптимально, чтоб компилер выдал красотищу, я писал примитив и смотрел, что скажут разные компилеры

    а gcc для z80 - это очень интересно, надо поискать... Avocet поставил на закачку, качнется, потестю
    Граф Дракула наш кумир, патамушта он вомпир!
    VKINK 9 : BORDER NOT PI

  10. #9
    Guru Аватар для jerri
    Регистрация
    01.03.2005
    Адрес
    Samara
    Сообщений
    4,753
    Спасибо Благодарностей отдано 
    273
    Спасибо Благодарностей получено 
    286
    Поблагодарили
    214 сообщений
    Mentioned
    12 Post(s)
    Tagged
    0 Thread(s)

    По умолчанию

    Я бы рекомендовaл пoсмотреть изнутри игрушку Mr Whimpy & Shi Vampires

    Очень интересный результат применения компиляторов
    С уважением,
    Jerri / Red Triangle.

  11. #10
    Activist Аватар для Raider
    Регистрация
    24.06.2005
    Адрес
    novosibirsk
    Сообщений
    266
    Записей в дневнике
    5
    Спасибо Благодарностей отдано 
    0
    Спасибо Благодарностей получено 
    1
    Поблагодарили
    1 сообщение
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)

    По умолчанию

    Цитата Сообщение от Eltaron
    я и не смотрел на код до и после моего цикла
    а внутри него никаких последствий от main'а быть уже не должно
    Не совсем так. Как повезет. Могут быть side effects.

    Оптимизирующий компилятор (мы же проверяем оптимизацию) занимается распределением процессорных ресурсов, таких как регистры процессора, ячейки во фрейме стека, формы команд, предпочтение коротких форм адресации, итд итп. (ну это как бы по-идее, на самом деле не стоит ожидать всего такого от примитивных компиляторов типа z88, zcc, smallc и им подобных).

    Простенький компилятор обязан следовать всему что ты напишешь. И сигнатуре функции в том числе.

    И между

    void foo() {}

    и

    void foo(int variable) {}

    может быть разница.

    во втором случае при вызове функции уже существует фрейм стека. А это предполагает то, что раз фрейм есть, в каком-то регистре нужно держать его адрес. Компилятор "настораживается" и перестает например использовать внутри функции этот регистр. Такое может быть запросто.

    Либо может быть такой вариант - параметр поступает в функцию в регистре. Компилятор не смог разобраться что параметр так и не использован внутри функции, и продолжает его там держать, "забивая" тем самым регистр. Возможно не на всю функцию. Возможно только в самом ее начале. Но это может привести к неприятным перестановкам команд и иногда вообще может сломать код. Поэтому все-таки желательно чтобы было все "чистенько".

    Для z80 компиляторов можно попробовать избегать использования фреймов стека и локальных переменных, обращаясь к глобальным переменным модуля (их можно объявить как static и они будут видны только этому модулю). Это может построить более эффективный, быстрый код, так как обращение к глобальной переменной это будет прямой

    LD A,(...)
    или LD HL,(...)

    а вот обращение к автоматической переменной на фрейме стека это для z80 уже "корячение", т.к. минимально нужно обеспечить механизм обращения к переменным стека, а это возможно только через какой-то регистр.


    ну, это понятно, не первый раз замужем :-)
    просто плох тот компилятор, который при отсутствии argv и argc будет городить код для их обработки, а компайлер, не могущий посчитать константу вообще можно сразу на свалку
    выше я сказал, что ждать волшебства от простеньких компиляторо не нужно. Они вполне могут иметь side-effects.

    это да, конечно же надо цикл обратно к нулю крутить, но я же не задавался мыслью написать оптимально, чтоб компилер выдал красотищу, я писал примитив и смотрел, что скажут разные компилеры
    Но для меня полезнее знать следущее. Когда я пишу УЖЕ эффективный код, насколько компилятор помогает мне в этом, насколько эффективный он строит код согласно моим замыслам.
    Alex Raider, Flash inc. 1992-1997 Новосибирск

Страница 1 из 4 1234 ПоследняяПоследняя

Информация о теме

Пользователи, просматривающие эту тему

Эту тему просматривают: 1 (пользователей: 0 , гостей: 1)

Ваши права

  • Вы не можете создавать новые темы
  • Вы не можете отвечать в темах
  • Вы не можете прикреплять вложения
  • Вы не можете редактировать свои сообщения
  •