Rev 2325 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | Download
BDS C will simplify constant expressions at compile-time only when the constant expressionsappear 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,DELD A,'\0'LD [HL],ALD HL,[_fn]LD [openwrite.A.],HL# plbl = &plbl[+sizeof(UINT)+1]; //skip string sizeLD HL,[dellbl.plbl]LD DE,2LD BC,1EX DE,HLADD HL,BCEX DE,HLADD HL,DELD [dellbl.plbl],HLкак сделать константное выражение с раскрытием sizeof?#оптимизировать while(+TRUE) - спецкоманду LOOP?сделать continue?СДЕЛАНО переписал бесконечные циклы через goto# добавить операцию POKEINC на размер типа#LD HL,[asmloop.tempvalue.+2]LD DE,[asmloop.tempvalue.]LD A,0x07AND ELD L,0x03LD E,APUSH DELD D,H ;<= из-за того, что regs не знает про ширину, а вообще ex de,hl помог быLD E,LPOP HLCALL _SHLB#LD A,[_waseof.]OR AJP Z,asmloop.agqJP asmloop.agnasmloop.agq:JP asmloop.agmasmloop.agn:#LD BC,1EX DE,HLADD HL,BCEX DE,HLLD BC,_SIZEOF_LONG.EX DE,HLADD HL,BCEX DE,HLLD BC,[addlabel.freestart_index.]LD A,ESUB CLD E,ALD A,DSBC A,BLD D,AADD HL,DELD [_lenlabels.],HL(это была скобка в выражении со сложениями - раскрыл)#POKE *(PUINT)(&_labelN[_LABELPAGEFREESTART]) = _plabel_index + 1/**flag*/ + _SIZEOF_LONG/**value*/;LD HL,[_labelN.]LD DE,_LABELPAGEFREESTART.ADD HL,DELD DE,[_plabel_index.]LD BC,1EX DE,HLADD HL,BCEX DE,HLLD BC,_SIZEOF_LONG.EX DE,HLADD HL,BCEX DE,HLLD [HL],EINC HLLD [HL],D(убрал вычисление справа)# при тайпкасте (long)uintLD HL,[asmloop.scale]LD DE,0LD BC,[asmloop.tempvalue+2]LD IX,[asmloop.tempvalue]PUSH DEPUSH HLPUSH BCPUSH IXPOP IXPOP BCPOP DEPOP HLCALL _MULLONG.LD A,[_token]SUB '0'LD C,ALD B,0LD IX,0EX DE,HLADD HL,BCEX DE,HLLD A,LADC A,LXLD L,ALD A,HADC A,HXLD H,ALD [asmloop.tempvalue],DELD [asmloop.tempvalue+2],HLв regs делать ex de,hl нехорошо#LD HL,[asmloop.tempvalue+2]LD DE,[asmloop.tempvalue]LD A,0x07AND ELD L,0x03LD E,APUSH DELD D,HLD E,LPOP HLCALL _SHLB.LD A,[_base]ADD A,LLD [_base],A#LD [_t.],ALD A,[_t.]LD L,ALD A,[_curfunct.]LD C,_T_RECURSIVE.LD E,ALD A,CCPLAND ESUB LJP NZ,eat_return.avg# было:LD A,[eat_let.t.]LD L,ALD A,[_t.]SUB LLD L,0JR Z,$+2+1DEC LLD A,[eat_let.t.]LD C,_T_POINTER.AND CLD C,0x00SUB CLD E,0JR Z,$+2+1DEC ELD A,[_t.]LD LX,_T_POINTER.AND LXLD LX,0x00SUB LXLD C,0JR Z,$+2+1DEC CLD A,EAND CCPLAND LJP Z,eat_let.ashУБРАНО, а так вообще это всё бы оптимизировалось# можно на верхнем уровне давать подсказку для pushnum - проксить или не проксить, чтобы избежать такого:LD A,0x0bLD L,ALD A,[_reg.]ADD A,LLD [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 EJP Z,asmcompileloop.adbCALL 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,ALD A,[_indblquote.]OR LCPLOR AJP 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,_lblshiftLD A,[_lblhash]LD C,ALD B,0EX DE,HLADD HL,BCEX DE,HLEX DE,HLADD HL,BCEX DE,HLLD A,[DE]INC DEEX AF,AF'LD A,[DE]LD D,AEX AF,AF'LD E,ALD [HL],EINC HLLD [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 объединить с functypeSDCC 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 hlcall _eofвместо него генерит:ld hl,#_finld c, (hl)inc hlld b, (hl)push bccall _eofIAR неоптимальности:\ 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),AIAR выделил интересную процедуру:\ 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