Blame | Last modification | View Log | Download
BDS C will simplify constant expressions at compile-time only when the constant expressions
appear immediately after one of the following keywords:
left square brackets,
the case keyword,
assignment operators,
commas,
left parentheses,
and the return keyword.
Any constant expression that doesnТt follow one of the aforementioned keywords is guaranteed to not be simplified at compile-time.
оптимизации размера бинарника:
# проверка повтора констант (особенно 0)
# передача параметров в регистрах bc,de, они резервируются при генерации процедуры, а если их понадобится занять (при вызове другой процедуры и при работе с лонгами),
то сохранить в спецячейке, которую сгенерить для этой процедуры - и далее ссылаться на неё как на параметр. Проблема с jp!!! при первом же jp надо предсказуемость - то есть надо уже сохранить регистр в спецячейке!
только с hl,ix работать неудобно! сделать только один параметр в регистре bc?
#
LD HL,[_fn]
LD DE,[_lenfn]
ADD HL,DE
LD A,'\0'
LD [HL],A
LD HL,[_fn]
LD [openwrite.A.],HL
# plbl = &plbl[+sizeof(UINT)+1]; //skip string size
LD HL,[dellbl.plbl]
LD DE,2
LD BC,1
EX DE,HL
ADD HL,BC
EX DE,HL
ADD HL,DE
LD [dellbl.plbl],HL
как сделать константное выражение с раскрытием sizeof?
#
оптимизировать while(+TRUE) - спецкоманду LOOP?
сделать continue?
СДЕЛАНО переписал бесконечные циклы через goto
# добавить операцию POKEINC на размер типа
#
LD HL,[asmloop.tempvalue.+2]
LD DE,[asmloop.tempvalue.]
LD A,0x07
AND E
LD L,0x03
LD E,A
PUSH DE
LD D,H ;<= из-за того, что regs не знает про ширину, а вообще ex de,hl помог бы
LD E,L
POP HL
CALL _SHLB
#
LD A,[_waseof.]
OR A
JP Z,asmloop.agq
JP asmloop.agn
asmloop.agq:
JP asmloop.agm
asmloop.agn:
#
LD BC,1
EX DE,HL
ADD HL,BC
EX DE,HL
LD BC,_SIZEOF_LONG.
EX DE,HL
ADD HL,BC
EX DE,HL
LD BC,[addlabel.freestart_index.]
LD A,E
SUB C
LD E,A
LD A,D
SBC A,B
LD D,A
ADD HL,DE
LD [_lenlabels.],HL
(это была скобка в выражении со сложениями - раскрыл)
#
POKE *(PUINT)(&_labelN[_LABELPAGEFREESTART]) = _plabel_index + 1/**flag*/ + _SIZEOF_LONG/**value*/;
LD HL,[_labelN.]
LD DE,_LABELPAGEFREESTART.
ADD HL,DE
LD DE,[_plabel_index.]
LD BC,1
EX DE,HL
ADD HL,BC
EX DE,HL
LD BC,_SIZEOF_LONG.
EX DE,HL
ADD HL,BC
EX DE,HL
LD [HL],E
INC HL
LD [HL],D
(убрал вычисление справа)
# при тайпкасте (long)uint
LD HL,[asmloop.scale]
LD DE,0
LD BC,[asmloop.tempvalue+2]
LD IX,[asmloop.tempvalue]
PUSH DE
PUSH HL
PUSH BC
PUSH IX
POP IX
POP BC
POP DE
POP HL
CALL _MULLONG.
LD A,[_token]
SUB '0'
LD C,A
LD B,0
LD IX,0
EX DE,HL
ADD HL,BC
EX DE,HL
LD A,L
ADC A,LX
LD L,A
LD A,H
ADC A,HX
LD H,A
LD [asmloop.tempvalue],DE
LD [asmloop.tempvalue+2],HL
в regs делать ex de,hl нехорошо
#
LD HL,[asmloop.tempvalue+2]
LD DE,[asmloop.tempvalue]
LD A,0x07
AND E
LD L,0x03
LD E,A
PUSH DE
LD D,H
LD E,L
POP HL
CALL _SHLB.
LD A,[_base]
ADD A,L
LD [_base],A
#
LD [_t.],A
LD A,[_t.]
LD L,A
LD A,[_curfunct.]
LD C,_T_RECURSIVE.
LD E,A
LD A,C
CPL
AND E
SUB L
JP NZ,eat_return.avg
# было:
LD A,[eat_let.t.]
LD L,A
LD A,[_t.]
SUB L
LD L,0
JR Z,$+2+1
DEC L
LD A,[eat_let.t.]
LD C,_T_POINTER.
AND C
LD C,0x00
SUB C
LD E,0
JR Z,$+2+1
DEC E
LD A,[_t.]
LD LX,_T_POINTER.
AND LX
LD LX,0x00
SUB LX
LD C,0
JR Z,$+2+1
DEC C
LD A,E
AND C
CPL
AND L
JP Z,eat_let.ash
УБРАНО, а так вообще это всё бы оптимизировалось
# можно на верхнем уровне давать подсказку для pushnum - проксить или не проксить, чтобы избежать такого:
LD A,0x0b
LD L,A
LD A,[_reg.]
ADD A,L
LD [asmbyte.aaa],A
но при этом всё равно не получится add a,0x0b.
для каждого регистра флаг, что он хранит константу?
проще переставить _reg+0x0b - СДЕЛАНО
# чтобы оптимизировать call-ret, надо перед каждой(!) операцией вызывать gencall, а для ret проверить флаг и вызывать либо genjp, либо genret
# убрать второй jp (от if) в таких случаях:
asmcompileloop.j#_ASMFMT_DIR=$
LD A,[_curdir.]
LD E,_ASMDIR_LABEL.
SUB E
JP Z,asmcompileloop.adb
CALL asmfmt_dir_label.
JP asmcompileloop.loop.
JP asmcompileloop.adc
# если второй аргумент операции константа, но не надо его пихать предварительно в регистр, а вызывать константную версию соответствующего cemit
или делать отложенные ld reg,NNN: генерить только временную метку, а ld делать при использовании или не делать
СДЕЛАНО для +, -
# очень много места занимают обороты типа
IF ( (partype==_T_INT)||(partype==_T_UINT)||((partype&_T_POINTER)!=0x00) )
если делать маски типов, то 8 бит не хватит
надо именно помнить partype в регистре
как???
СДЕЛАНО через длину типа
# как ещё сделать передачу через регистры? для этого процедура должна уметь скидывать регистры в переменные, если регистров не хватает
но не складывать, если они потом не нужны - а это нужен второй проход!
# jr вместо jp, а асм будет расширять jr до jp, если не лезет???
# добавить ifnot, whilenot, untilnot, чтобы исключить такое:
LD A,[_inprime.]
LD L,A
LD A,[_indblquote.]
OR L
CPL
OR A
JP Z,rdch.h
# ??? в строках вместо длины использовать указатель на конец и указатель на предел (число параметров не уменьшается: _endtextword = strjoin(_endtextword, _limittextword, _newword); ), убрать stringclear (_endtextword = _textword), stringclose - инлайном (POKE *(PCHAR)(_endtextword) = '\0';).
# POKE *(PUINT)(plbl) = _lblshift[_lblhash];
LD HL,[addlbl.plbl]
LD DE,_lblshift
LD A,[_lblhash]
LD C,A
LD B,0
EX DE,HL
ADD HL,BC
EX DE,HL
EX DE,HL
ADD HL,BC
EX DE,HL
LD A,[DE]
INC DE
EX AF,AF'
LD A,[DE]
LD D,A
EX AF,AF'
LD E,A
LD [HL],E
INC HL
LD [HL],D
это из-за вычисления правого выражения после вычисления левого, понадобился лишний регистр
как переставить???
но если plbl будет в регистре, то не сэкономить
связки на соседних строчках:
- СДЕЛАНО ld rb,N:sub rb (надо предсказывать вперёд? или вызывать константные примитивы?)
можно запомнить в pushnum, что была константа (вместо того, чтобы её генерить) и её текст
тогда надо во всех примитивах (включая put и return) уметь использовать константу, если возможно
асмопримитивы не могут заказывать регистр - как же они сделают обычный сценарий использования константы (например, в add)?
значит, надо проверять константу в примитивах высокого уровня, а асмопримитивы делать в двух вариантах
на практике нужно в основном sub N с флагом Z (==, !=)
перехват не срабатывает на cstr == +(BYTE)'#' и т.п. Надо писать +(CHAR)cstr=='#'. Но нельзя сравнивать CHAR через > <
- jp:jp (второй можно проверить по номеру строки последнего jp)
- jp nz:jp - пустая ветка if или if()break или if()goto
- ld (),reg:ld reg,() (номер строки последнего popvar (или put) и joined==wasjoined, надо ещё обратимо уничтожать регистр)
- ld (),a:ld a,() (номер строки последнего popvar (или put) и joined==wasjoined, надо ещё обратимо уничтожать регистр и proxy) (или откладывать освобождение регистра и помнить wasput)
- call:ret (тут надо предсказывать вперёд или вызывать генератор call на каждой команде)
- УБРАНО ld l,(hl):ld a,l - таких меньше половины всех ld l,(hl), но если посчитать которые оптимизируются при ld a,(hl), то (по всему compile):
оптимизируются: iiiiiiiiiiiiiiiiiiiiiiiiiiiii
ухудшатся: iiiiii
останутся: iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii (некоторые оптимизируются при cp N, что сейчас невозможно)
- ld a,N:ld rb,a (надо предсказывать вперёд?) (ничего не даст - такие случаи не находятся)
- label:ret (надо предсказывать СИЛЬНО вперёд или смотреть дерево разбора или разрешить return без параметра (как ret, полный return не содержит ret) из середины)
64-битные числа не использовались в FatFS, но в exFAT могли появиться (DimkaM)
в биллиарде тоже нет и не было 64-битных
# SDCC 2.9.0 инициализирует константные массивы вручную. SDCC 3.4.0 нет - всё через ".area _INITIALIZER" (даже нет LDIR и полностью отсутствует код инициализации)
# SDCC 2.9.0 генерирует код stack frame для пустых процедур. SDCC 3.4.0 уже нет. мой кодогенератор тоже нет.
IAR генерирует push-pop регистров в полупустых процедурах непонятно зачем.
SDCC 3.6.0 при opt-size вместо push ix:ld ix,0:add ix,sp пишет call ___sdcc_enter_ix (поэтому надо opt-speed).
ещё при opt-size появляется лишний inc sp:pop af в конце emitinvreg, emitnegreg.
ещё при opt-size (а SDCC 3.4.0 всегда) считает REGNAME[rnew] по одному разу (умеет даже push-pop иногда, при --all-callee-saves чаще). я так не смогу.
никаких других различий в SDCC 3.6.0 между opt-size и opt-speed не замечено (даже остаются inc sp..dec sp для 8-битных параметров).
# в IAR(SDCC?) все выражения с && || считаются арифметически (в IAR нет). самому будет сложно преобразовать
либо надо делать and if, or else, либо кучу веток в условии, либо islalpha... делать на массиве (инициализировать его вручную?)
если разбить на части типа a&&b (это не даёт проигрыша в IAR), то SDCC переводит && в джампы (3.6.0 даже в return a&&b) - как такое повторить?
если разбить || на части типа if (a) else if (b) else if (c) с одинаковой командой, то SDCC её не объединяет (IAR объединяет), но работать должно быстрее (в IAR код вообще не изменился)
если сделать вместо этого if (!a) if (!b) if (!c), то в SDCC код лучше, в IAR почти идеальный (только со странным выбором регистров)
выражения типа (c<='z') в IAR компилируются невыгодно (не как c<('z'+1)). переписать через +1? мой текущий кодогенератор не получит выигрыша, т.к. не умеет CP
# у большинства процедур есть параметр /уже не у большинства?/. IAR передаёт один параметр в регистре (SDCC нет). особенно заметно на печати числа (впрочем, это отладочная процедура).
сделать так же один параметр в регистре? (но для этого надо уметь хранить переменную в регистре!)
иногда можно убрать один параметр, если isfunc объединить с functype
SDCC 3.4.0 достаёт первый параметр через pop:pop:push:push, это выгодно при отсутствии стекфрейма в ix. но лучше через регистр.
# при работе со строками надо одновременно контексты 8 бит и слов
написать весь модуль syscalls на ассемблере?
# при работе со строками (они как массивы) генерируется ужас. ввести указатели? и хранить указатели в регистрах? как определить, где что хранить? слово register?
написать весь модуль syscalls на ассемблере? но строки ещё используются в compiler (обкусывание title, запись/чтение меток)
# SDCC и IAR оптимизируют CALL:RET до JP. как сделать так же?
ленивый CALL? (не получится при CALL в локале - а без локала надо вернуть запись строк в стек!)
SDCC 3.4.0 генерирует jr:ret (getnothingword), раньше был просто jr. В SDCC 3.6.0 исправлено.
# SDCC 3.4.0 (3.6.0 при opt-size) считает REGNAME[rnew] по одному разу (умеет даже push-pop иногда, при --all-callee-saves чаще, других различий не видел). я так не смогу.
todo переписать исходник через переменную (тут надо две, т.к. две буквы, а указателей нет)
# stringappend (бывает только для command и joinwordsresult) надо inline, но #define для инлайнов у меня нет
# read, write надо inline (только syscalls инлайном? или emits инлайном? или оба? в перспективе останется только системный макрос), но #define для инлайнов у меня нет
# SDCC 3.6.0 вместо ld a,()...ld (),a генерирует ld iy:ld a,(iy)...ld (iy),a (readchar_skipdieresis_concat)
--reserve-regs-iy делает через hl, но возвращает стекфреймы, где не надо, и перестаёт уметь такое:
ld hl,(_fin)
push hl
call _eof
вместо него генерит:
ld hl,#_fin
ld c, (hl)
inc hl
ld b, (hl)
push bc
call _eof
IAR неоптимальности:
\ 0E49 3A1600 LD A,(_T_BYTE)
\ 0E4C 47 LD B,A
\ 0E4D DD7D LD A,IXL
\ 0E4F B8 CP B
\ 0E50 2812 JR Z,?0285
\ 0E52 3A1900 LD A,(_T_CHAR)
\ 0E55 47 LD B,A
\ 0E56 DD7D LD A,IXL
\ 0E58 B8 CP B
\ 0E59 2809 JR Z,?0285
\ 0E5B 3A1700 LD A,(_T_BOOL)
\ 0E5E 47 LD B,A
\ 0E5F DD7D LD A,IXL
\ 0E61 B8 CP B
\ 0E62 2012 JR NZ,?0284
\ 0E64 ?0285:
и т.п.
\ 1100 CDDE0E CALL emitasm_regname
\ 1103 C9 RET
и т.п.
\ 438B 3A1E00 LD A,(_T_RECURSIVE)
\ 438E 2F CPL
\ 438F DD45 LD B,IXL
\ 4391 A0 AND B
и т.п.
\ 4167 DD45 LD B,IXL
\ 4169 04 INC B
\ 416A 05 DEC B
\ 416B 2004 JR NZ,?1409
и т.п.
\ 1173 3ACF00 LD A,(_jumpflag)
\ 1176 3D DEC A
\ 1177 3D DEC A
\ 1178 2005 JR NZ,?0333
\ 117A ?0332:
\ 117A 116801 LD DE,?0334
\ 117D 1818 JR ?1697
\ 117F ?0333:
\ 117F 3ACF00 LD A,(_jumpflag)
\ 1182 FE03 CP 3
\ 1184 2005 JR NZ,?0337
\ 1186 ?0336:
\ 1186 116C01 LD DE,?0338
\ 1189 180C JR ?1697
\ 118B ?0337:
\ 118B FE04 CP 4
\ 118D 2005 JR NZ,?0341
\ 4455 56 LD D,(HL)
\ 4456 CBEA SET 5,D
\ 4458 7A LD A,D
\ 4459 321D2F LD (_c1small),A
IAR выделил интересную процедуру:
\ 1354 ?2032:
\ 1354 CD2F0F CALL emitasm_hl
\ 1357 CDC60E CALL emitasm_comma
\ 135A 3AA200 LD A,(_FASTREG)
\ 135D 47 LD B,A
\ 135E 7B LD A,E
\ 135F B8 CP B
\ 1360 C9 RET