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

User Tag List

Страница 1 из 10 12345 ... ПоследняяПоследняя
Показано с 1 по 10 из 100

Тема: Кодогенерация SDCC: пожелания об улучшении компилятора

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

Предыдущее сообщение Предыдущее сообщение   Следующее сообщение Следующее сообщение
  1. #1
    Veteran Аватар для Oleg N. Cher
    Регистрация
    24.08.2007
    Адрес
    Днепропетровская обл.
    Сообщений
    1,610
    Спасибо Благодарностей отдано 
    2,182
    Спасибо Благодарностей получено 
    139
    Поблагодарили
    105 сообщений
    Mentioned
    1 Post(s)
    Tagged
    0 Thread(s)

    По умолчанию Кодогенерация SDCC: пожелания об улучшении компилятора

    Начал набрасывать письмо Филиппу Клаусу Краузе (главному мэйнтейнеру кодогенератора Z80 для SDCC).

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

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

  3. #2
    ZEK
    Гость

    По умолчанию

    В pephole логику добавить возможность работать по байтово с компонентами 32/16 битных циферок, можно хорошо подрезать код для библиотек от большого брата,
    а то
    long a = 0x12345678;
    a &= (char)0xFF;
    выливается в 4 операции and вместо одной, не считаю загрузку всех 4х компонент при участии индексного регистра из стека в память и запись обратно, по 5 (или что то около того) инструкций на 1 байт 32 битной циферки, мегатормоз и куча памяти

  4. #3
    Veteran
    Регистрация
    08.05.2007
    Адрес
    Dnepropetrovsk
    Сообщений
    1,058
    Спасибо Благодарностей отдано 
    220
    Спасибо Благодарностей получено 
    47
    Поблагодарили
    31 сообщений
    Mentioned
    3 Post(s)
    Tagged
    0 Thread(s)

    По умолчанию

    Скачал версию от 20 августа. К кодогенератору имеются следующие замечания:

    1) Инициализация данных. Объявив глобальную статическую переменную следующей инструкцией:

    static char s[] = "Hello world!";

    Я получил процедуру инициализации этой переменной вида:
    ld hl, _s
    LD (HL), 'H'
    ld hl, _s+1
    LD (HL),'e'
    Что чрезвычайно неэффективно как по скорости исполнения, так и по занимаемой памяти. Более оптимальное решение - это сохранить исходное значение константы в сегменте инициализированных (константных) данных, а потом копировать с помощью LDIR.

    ---------- Post added at 03:59 ---------- Previous post was at 03:48 ----------

    2) Деление на 2 переменной. Инструкция вида
    k/=2
    где k - стековая 8-битная переменная, привела к генерации кода:
    LD A,(IX+6)
    SRL A
    LD (IX+6),A
    Что лучше заменить на
    SRL (IX+6)

    3) Возведение в квадрат числа. Инструкция вида:
    t*=t
    где t - unsigned short, привела к генерации кода:
    PUSH HL
    LD C,(IX+4)
    LD B,(IX+5)
    PUSH BC
    LD C,(IX+4)
    LD B,(IX+5)
    PUSH BC
    CALL __mulint_rrx_s
    POP AF
    POP AF
    LD D,L
    LD E,H
    POP HL
    LD (IX+4),D
    LD (IX+5),E
    В этом коде, во-первых, нет необходимости загружать BC второй раз, потому что в него загружается одна и та же информация. Обе команды LD между PUSH BC можно выкинуть.
    Во-вторых, после возврата из подпрограммы умножения, результат сначала копируется в регистр DE, а потом сохраняется на фрейм. Вместо этого можно сначала сохранить результат прямо из HL, а потом выполнить POP HL. Экономится две команды LD.

    Вместе с тем отмечаю, что кодогенератор стал существенно лучше, чем был, и в некоторых моментах я был приятно удивлен результатами его работы. Почти как человек написал. Например, вот так получилась функция strlen:


    unsigned short mstrlen(const char* s)
    {
    unsigned short a = 0;
    while(*s++)
    a++;
    return a;
    }

    Сгенерированный код:

    ;test.c:21: unsigned short mstrlen(const char* s)
    ; ---------------------------------
    ; Function mstrlen
    ; ---------------------------------
    ._mstrlen_start
    ._mstrlen
    ;test.c:24: while(*s++)
    ld de,$0000
    pop bc
    pop hl
    push hl
    push bc

    .l_mstrlen00101
    ld a,(hl)
    inc hl
    or a, a
    jp Z,l_mstrlen00103
    ;test.c:25: a++;
    inc de
    jp l_mstrlen00101

    .l_mstrlen00103
    ;test.c:26: return a;
    ex de,hl

    .l_mstrlen00104
    ret
    ._mstrlen_end

    Что не оставляет желать ничего лучшего. Ну разве что можно было бы продублировать заголовок цикла, как это делается в некоторых современных компиляторах, но нельзя требовать всего сразу

  5. #4
    Veteran
    Регистрация
    06.05.2006
    Адрес
    Ливны, Орловская обл
    Сообщений
    1,169
    Спасибо Благодарностей отдано 
    0
    Спасибо Благодарностей получено 
    0
    Поблагодарили
    0 сообщений
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)

    По умолчанию

    На правах "мимопроходил"...
    Цитата Сообщение от Barmaley_m Посмотреть сообщение
    1) Инициализация данных...
    А почему, если у нас static данные в памяти уже лежат, нельзя просто забить на их инициализацию, зачем ещё копировать? Стандарт?
    Цитата Сообщение от Barmaley_m Посмотреть сообщение
    ;test.c:24: while(*s++)
    ld de,$0000
    pop bc
    pop hl
    push hl
    push bc
    Это загрузка параметров функции?
    Если у нас не PIC-код(а на спеке оно наверное так и будет), почему бы вместо push'ей не делать ld sp,#xx?

    ---------- Post added at 10:42 ---------- Previous post was at 09:37 ----------

    Цитата Сообщение от Oleg N. Cher
    ld hl, #2+0
    add hl, sp
    ...
    ret
    А вот в таких конструкциях надо проверять, не лучше ли делать INC/DEC.

  6. #5
    Veteran Аватар для Oleg N. Cher
    Регистрация
    24.08.2007
    Адрес
    Днепропетровская обл.
    Сообщений
    1,610
    Спасибо Благодарностей отдано 
    2,182
    Спасибо Благодарностей получено 
    139
    Поблагодарили
    105 сообщений
    Mentioned
    1 Post(s)
    Tagged
    0 Thread(s)

    По умолчанию

    Цитата Сообщение от Barmaley_m Посмотреть сообщение
    Вместе с тем отмечаю, что кодогенератор стал существенно лучше, чем был, и в некоторых моментах я был приятно удивлен результатами его работы. Почти как человек написал.
    На Дураке выигрыш по размеру кода с версией SDCC 3.2.0 #8008 больше 600 байт! Сами понимаете, что это значит для Z80. Проблема же в том, что он перестал работать... Думаю, приоритетнее будет выловить баги, чем обфичивать. Повторюсь, я не встречал ни одной 100%-корректной по кодогенерации версии SDCC. Это проблема прямо.

    Ещё у меня вопросик к гуру. Я конечно напишу его Филиппу, но позже. Может кто-то раньше ответит. Версия SDCC 3.2.0 в асмовых функциях не генерирует фрейма входа:
    Код:
              PUSH    IX
              LD      IX,#0
              ADD     IX,SP
    И, как я понимаю, это сделано для того, чтобы дать программеру больше свободы в принятии решения, каким способом лучше доставать параметры из стека. Что ж, дело хорошее. Но хотелось бы сохранить работоспособность кода и для старых версий SDCC. Поэтому на ум приходит что-то такое:

    Код:
    void myfunc (int p1, int p2, ...)
    {
    #if SDCC_VER > 3.1.x
      __asm
              PUSH    IX
              LD      IX,#0
              ADD     IX,SP
      __endasm;
    #endif
      ...
    }
    Можете ли подсказать что должно быть вместо #if SDCC_VER > 3.1.x ?
    Т.е. вопрос сводится к тому, с какой версии это дело началось, видимо.

  7. #6
    Veteran Аватар для Oleg N. Cher
    Регистрация
    24.08.2007
    Адрес
    Днепропетровская обл.
    Сообщений
    1,610
    Спасибо Благодарностей отдано 
    2,182
    Спасибо Благодарностей получено 
    139
    Поблагодарили
    105 сообщений
    Mentioned
    1 Post(s)
    Tagged
    0 Thread(s)

    По умолчанию

    По поводу скорости компиляции SDCC. Исходники Дурака у меня собираются SDCC 3.2.0 #8008 (с ключиком --oldralloc) за 15 секунд (бинарник весит 32674 байта), а вот без него! 6 с половиной минут (32895 байт). Сам офигел, старый компилер быстрее компилил. Удивительно, но от нового аллокатора раньше пользы было больше. Не буду утверждать наверняка, но, похоже, принцип работы аллокатора основан на пошаговом выяснении, какие регистры более экономно выделять, простым путём перебора с повторной множественной компиляцией. Идея очень интересная, но хорошо, что он опциональный.

    Если смущает и 15 секунд (ну просто хочется быстрее), вспомним, что SDCC гибридный компилятор, который программу сначала препроцессит, потом парсит, строит деревья, генерит кучу служебной инфы. Наконец целевой код, не код, а асм! Потом пипхольная оптимизация. Вобщем, многоэтапный. Если его ускорять, надо менять всю структуру компилятора, избавляться от лишних звеньев. Даже если от Филиппа это и зависит, полагаю, всё равно не планируется. Выскажу крамольную мысль. На каком-то этапе мы можем получить безбажную версию SDCC. Это может произойти когда Филипп забьёт на SDCC окончательно. Вот тогда желающие и вылижут баги. Но и развиваться перестанет.

    Наконец, Си язык медленно компилируемый. Особенно это было заметно в эпоху старых машин. Но и сейчас со мной согласятся те, кто устанавливал большой софт из исходников или пересобирал ядро Linux. Дело и в препроцессировании, и в многочисленной обработке текстовых заголовков *.h, и в множественных промежуточных представлениях кода с поэтапной оптимизацией.

    Но не расстраивайтесь. Разве бывалого спектрумиста напугаешь 15 секундами? Или можете себе представить более объёмные исходники для Z80? (основнй модуль Дурака весит 2,3 тыс. строк) Наконец, Вы уверяли, что в Си есть модульность. Вот и воспользуйтесь ею. Маленькие модули, раздельная компиляция.
    Цитата Сообщение от Oleg N. Cher Посмотреть сообщение
    я не встречал ни одной 100%-корректной по кодогенерации версии SDCC.
    Песенка со смыслом.
    Sung to Beatles "Let it Be"

    When I find my code in tons of trouble, Friends and colleagues come to me, Speaking words of wisdom: Write in C.
    As the deadline fast approaches, And bugs are all that I can see, Somewhere, someone whispers: Write in C.

    Write in C, write in C, Write in C, oh, write in C. LISP is dead and buried, Write in C.

    I used to write a lot of FORTRAN, For science it worked flawlessly. Try using it for graphics! Write in C.

    If you've just spent nearly 30 hours Debugging some assembly, Soon you will be glad to Write in C.

    Write in C, write in C, Write in C, yeah, write in C. Only wimps use BASIC. Write in C.

    Write in C, write in C Write in C, oh, write in C. Pascal won't quite cut it. Write in C.

    { Guitar Solo }

    Write in C, write in C, Write in C, yeah, write in C. Don't even mention COBOL. Write in C.

    And when the screen is fuzzy, And the editor is bugging me. I'm sick of ones and zeros, Write in C.

    A thousand people swear that T.P. Seven is the one for me. I hate the word PROCEDURE, Write in C.

    Write in C, write in C, Write in C, yeah, write in C. PL1 is 80s, Write in C.

    Write in C, write in C, Write in C, yeah, write in C. The government loves ADA, Write in C.

  8. #7
    Guru Аватар для Дмитрий
    Регистрация
    01.01.2009
    Адрес
    Донецк, Украина
    Сообщений
    3,260
    Спасибо Благодарностей отдано 
    35
    Спасибо Благодарностей получено 
    9
    Поблагодарили
    8 сообщений
    Mentioned
    2 Post(s)
    Tagged
    0 Thread(s)

    По умолчанию

    Цитата Сообщение от NovaStorm Посмотреть сообщение
    А вот в таких конструкциях надо проверять, не лучше ли делать INC/DEC.
    Вообще-то таким образом берется верхушка стека в HL, чтоб не делать что-то типа такого:

    Код:
          ...
          LD (bla+1),sp
    bla: LD HL,0
          ...

  9. #8
    Veteran
    Регистрация
    06.05.2006
    Адрес
    Ливны, Орловская обл
    Сообщений
    1,169
    Спасибо Благодарностей отдано 
    0
    Спасибо Благодарностей получено 
    0
    Поблагодарили
    0 сообщений
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)

    По умолчанию

    Цитата Сообщение от Дмитрий Посмотреть сообщение
    Вообще-то таким образом берется верхушка стека в HL, чтоб не делать что-то типа такого:
    Я думал(так как там дальше ret) тот код восстанавливает стек перед возвратом из функции.

  10. #9
    Vitamin C++ Аватар для Vitamin
    Регистрация
    14.01.2005
    Адрес
    Таганрог, Россия
    Сообщений
    4,258
    Спасибо Благодарностей отдано 
    9
    Спасибо Благодарностей получено 
    84
    Поблагодарили
    36 сообщений
    Mentioned
    7 Post(s)
    Tagged
    0 Thread(s)

    По умолчанию

    Цитата Сообщение от NovaStorm Посмотреть сообщение
    А почему, если у нас static данные в памяти уже лежат, нельзя просто забить на их инициализацию, зачем ещё копировать?
    Потому что это не константная переменная с гарантированным для первого обращения значением. А значит лежит в секции, доступной на чтение-запись. А исходные данные лежат в секции "только на чтение". Хочешь сразу ссылаться на нужную секцию- подскажи компилятору (я вот только не помню, в С можно const писать или только в новом стандарте).

  11. #10
    Veteran
    Регистрация
    08.05.2007
    Адрес
    Dnepropetrovsk
    Сообщений
    1,058
    Спасибо Благодарностей отдано 
    220
    Спасибо Благодарностей получено 
    47
    Поблагодарили
    31 сообщений
    Mentioned
    3 Post(s)
    Tagged
    0 Thread(s)

    По умолчанию

    Цитата Сообщение от Vitamin Посмотреть сообщение
    Потому что это не константная переменная с гарантированным для первого обращения значением. А значит лежит в секции, доступной на чтение-запись. А исходные данные лежат в секции "только на чтение". Хочешь сразу ссылаться на нужную секцию- подскажи компилятору (я вот только не помню, в С можно const писать или только в новом стандарте).
    Совершенно верно. Можно писать const. Если заменить объявление переменной на:
    Код:
    static const char s[] = "Hello world!";
    то компилятор не сгенерирует код, инициализирующий этот массив (строка будет просто храниться в исполняемом образе). Забивание строки в массив, в который разрешена запись - это поначалу была такая ошибка в моей тест-программе, но в связи с тем, что результат компиляции оказался интересным (с той точки зрения, чтобы его улучшить), я решил обратить внимание именно на этот случай.

    На самом деле можно в исполняемом файле иметь сегмент инициализированных данных, доступных на чтение/запись. Тогда даже LDIR не понадобится, но возникнут проблемы, если кто-то захочет скомпоновать файл для размещения в ПЗУ. Тогда придется генерировать как минимум инициализирующие LDIRы, которые бы скопировали исходные значения этих данных из ПЗУ в ОЗУ. Размещение программы в ПЗУ - это далеко не праздная задача. Люди делают прошивки, люди делают на базе Z80 отдельные устройства (как я в 1997); в конце концов, некоторые контроллеры памяти позволяют защитить области ОЗУ от записи. Поэтому генерация кода, работоспособного в ПЗУ - это важное свойство компилятора.
    Последний раз редактировалось Barmaley_m; 22.08.2012 в 23:37.

Страница 1 из 10 12345 ... ПоследняяПоследняя

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

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

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

Похожие темы

  1. SDCC - Small Device C Compiler
    от Valen в разделе Программирование
    Ответов: 52
    Последнее: 06.04.2012, 20:44
  2. Конструктор для компилятора с Си
    от Raydac в разделе Программирование
    Ответов: 0
    Последнее: 21.12.2009, 23:14
  3. Пожелания ваще
    от svofski в разделе Эмуляторы отечественных компьютеров
    Ответов: 7
    Последнее: 01.09.2009, 18:27
  4. SDCC вокруг да около
    от andrews в разделе Программирование
    Ответов: 8
    Последнее: 26.03.2008, 08:16
  5. Пожелания по сервисам форума
    от andrews в разделе Форум
    Ответов: 10
    Последнее: 14.08.2006, 13:47

Ваши права

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