Ну только не поэтому... Для х86х gcc тоже код генерит, хотя там такой же разнобой с регистрами, что на Z80...Цитата:
Сообщение от yoko_ono
Да и в AVRке регистры r0, r1-r15, r16-r25 и r26-r31 далеко не равноправны...
Вид для печати
Ну только не поэтому... Для х86х gcc тоже код генерит, хотя там такой же разнобой с регистрами, что на Z80...Цитата:
Сообщение от yoko_ono
Да и в AVRке регистры r0, r1-r15, r16-r25 и r26-r31 далеко не равноправны...
Вы работаете с армом и поэтому решили, что gcc точился под арм? Браво, вашей логике позавидуют даже блондинки...Цитата:
Сообщение от Vitamin
Да что вы.Цитата:
ЗЫ. За вами должок! ;)
По крайней мере в ia32 можно говорить, что имеющиеся 7 регистров более-менее равноправны, за редкими исключениями вроде 8-битных загрузок и умножений-делений.Цитата:
Сообщение от SfS
И что? Их же 32, и со всеми (абсолютно со всеми) возможны 2-адресные логические и арифметические операции. Неравноправность только в операциях с константами и 16-битными указателями в память.Цитата:
Да и в AVRке регистры r0, r1-r15, r16-r25 и r26-r31 далеко не равноправны...
Почемуто вы опустили предыдущую фразу тов. NovaStorm, где он сказал, что gcc заточен под х86. Почему-то она вопросов не вызвала. А вот мое возражение, в котором в качестве аргумента я привел АРМ, сразу "обидело державу". Вы кроме х86 больше ни на чем не работали?Цитата:
Сообщение от yoko_ono
Официально разрешаю завидовать даже вам.Цитата:
Сообщение от yoko_ono
Да. Вы меня обвинили в недостаточном знании возможностей ALASM'а (с чем, собственно согласен), но никак не доказали свою состоятельность в этом вопросе. Вместо этого довольно топорно увильнули от беседы. Так что...Цитата:
Сообщение от yoko_ono
а мой транслятор PC110 Си->Z80 Asm у когонить сохранился? а то че то меня ностальжи мучать начала, не моглиб прислать на rrg<собака>forth.org.ru
Потому, что это никому не нужно. В новых разработках Z80 никто не использует, поэтому и порт для gcc не делают. gcc например поддерживает 68hc11, 68hc12 и т.п., хотя поддержка этих контроллеров сложнее чем поддержка Z80.Цитата:
Сообщение от SfS
(оффтоп) А у хваленого недориск-проца 6502 ваще полный мрак с ЯВУ, особенно компиляторами :p (/оффтоп)Цитата:
Сообщение от andrews
Скачал компилятор IAR и решил протестить. Весьма серьезная штука. Имеется довольно развитая среда разработки, куча библиотек.
Компилятор был протестирован в двух режимах работы- с максимальной оптимизацией по скорости и по размеру.
Из влияющих на кодогенерацию настроек:
Large model, enable undocumented instructions, use alternate register set, use rst-functions, static allocation of 'autos', language extensions, 'char' is 'signed char'.
Для начала быстрая версия кода:
0. Пролог. Ничего особого
1. Размножение констант и копийКод:PUSH BC
PUSH DE
2. Свертка константКод:;j4 = 2;
LD HL,2
LD (j4),HL
;if( i2 < j4 && i4 < j4 )
; i2 = 2;
;Весьма и весьма странная конструкция!
;Для правильного знакового сравнения кажется
;Размножение константы только на первом сравнении
LD BC,32770
LD HL,(i2)
LD A,B
XOR H
LD H,A
SBC HL,BC
JR NC,?0011
LD BC,(j4)
LD HL,(i4)
;почему не AND A?..
OR 128
SBC HL,BC
JP PO,?0088
XOR H
?0088:
JP P,?0011
?0013:
?0012:
?0010:
LD HL,2
LD (i2),HL
?0011:
;j4 = k5;
;if( i2 < j4 && i4 < j4 )
; i5 = 3;
;а здесь имеет просто достаточно качественные регистровые переменные
LD HL,(k5)
LD (j4),HL
LD C,L
LD B,H
LD HL,(i2)
OR 128
SBC HL,BC
JP PO,?0089
XOR H
?0089:
JP P,?0015
LD HL,(i4)
OR 128
SBC HL,BC
JP PO,?0090
XOR H
?0090:
JP P,?0015
?0017:
?0016:
?0014:
LD HL,3
LD (i5),HL
?0015:
Деление на 0 было определено на этапе компиляции. Пришлось объявить NO_ZERO_DIVIDEКод:;i3 = 1 + 2;
LD HL,3
LD (i3),HL
;flt_1 = 2.4 + 6.3;
LD BC,16651
LD HL,13107
LD (flt_1),HL
LD (flt_1+2),BC
;i2 = 5;
LD HL,5
LD (i2),HL
;j2 = i + 0;
;k2 = i / 1;
;i4 = i * 1;
;Красавец!
LD HL,(i)
LD (j2),HL
LD (k2),HL
LD (i4),HL
;i5 = i * 0;
LD HL,0
LD (i5),HL
3. Лишнее присваиваниеКод:;flt_3 = 2.4 / 1.0;
LD BC,16409
LD HL,39322
LD (flt_3),HL
LD (flt_3+2),BC
;flt_4 = 1.0 + 0.0000001;
LD BC,16256
LD HL,1
LD (flt_4),HL
LD (flt_4+2),BC
;flt_5 = flt_6 * 0.0;
;умножение на 0 он благополучно распознал
;но как выкрутился с загрузкой!!!
LD C,H
LD B,H
DEC HL
LD (flt_5),HL
LD (flt_5+2),BC
;flt_6 = flt_2 * flt_3;
;4 байта через стек, 4 в регистрах иначе никак...
LD HL,16409
PUSH HL
LD HL,39322
PUSH HL
LD BC,(flt_2+2)
LD HL,(flt_2)
CALL ?F_MUL_L04
LD (flt_6),HL
LD (flt_6+2),BC
4. Снижение мощностиКод:;k3 = 1;
;k3 = 1;
;в Багдаде все спокойно...
LD HL,1
LD (k3),HL
5. Простой циклКод:;k2 = 4 * j5;
;нормально...
LD HL,(j5)
ADD HL,HL
ADD HL,HL
LD (k2),HL
;for( i = 0; i <= 5; i++ )
; ivector4[ i ] = i * 2;
LD HL,0
?0095:
LD (i),HL
?0020:
;опять эти интересные сравнения...
;судя по всему, там где не требуются знаковые вычисления,
;лучше честно писать unsigned вместо int
LD C,L
LD B,H
LD HL,5
OR 128
SBC HL,BC
JP PO,?0091
XOR H
?0091:
JP M,?0019
?0021:
LD L,C
LD H,B
ADD HL,HL
;снижения мощности нет, но цикл в целом весьма достойный
LD BC,ivector4
ADD HL,BC
PUSH HL
LD HL,(i)
ADD HL,HL
LD C,L
LD B,H
POP HL
LD (HL),C
INC HL
LD (HL),B
LD HL,(i)
INC HL
JR ?0095
?0019:
6. Управление переменной индукции циклаКод:;j5 = 0;
LD HL,0
LD (j5),HL
;k5 = 10000;
LD HL,10000
LD (k5),HL
;do {
; k5 = k5 - 1;
;много лишнего... подозреваю что дело опять в знаковости
?0025:
LD HL,65535
LD BC,(k5)
ADD HL,BC
LD (k5),HL
; j5 = j5 + 1;
LD HL,1
LD BC,(j5)
ADD HL,BC
LD (j5),HL
; i5 = (k5 * 3) / (j5 * constant5);
;на 3 умножил достойно
LD HL,(k5)
LD C,L
LD B,H
ADD HL,HL
ADD HL,BC
EX DE,HL
;и на 5 тоже
LD HL,(j5)
LD C,L
LD B,H
ADD HL,HL
ADD HL,HL
ADD HL,BC
LD C,L
LD B,H
CALL ?SS_DIV_L02
LD (i5),DE
;} while ( k5 > 0 );
;опять эти интересные игры с флагами....
LD BC,(k5)
LD HL,0
OR 128
SBC HL,BC
JP PO,?0092
XOR H
?0092:
JP M,?0025
?0023:
7. Глубокие подвыраженияКод:;for( i = 0; i < 100; i++ )
; ivector5[ i * 2 + 3 ] = 5;
; хороший добротный пролог цикла
?0023:
LD HL,0
?0096:
LD (i),HL
?0027:
LD BC,32868
LD A,B
XOR H
LD H,A
SBC HL,BC
JR NC,?0026
?0028:
;ну просто замечательно сделано!!! лучше не придумаешь
LD HL,(i)
ADD HL,HL
ADD HL,HL
LD BC,ivector5+6
ADD HL,BC
LD (HL),5
INC HL
LD (HL),0
LD HL,(i)
INC HL
JR ?0096
?0026:
8. Генерация адреса переменной с константным индексомКод:;if( i < 10 )
; j5 = i5 + i2;
;else
; k5 = i5 + i2;
;не совсем, но имеется- загрузка вынесена за скобки
LD BC,32778
LD HL,(i)
LD A,B
XOR H
LD H,A
SBC HL,BC
LD HL,(i2)
LD BC,(i5)
JR NC,?0031
?0030:
ADD HL,BC
LD (j5),HL
JR ?0032
?0031:
ADD HL,BC
LD (k5),HL
?0032:
9. Удаление общих подвыраженийКод:;ivector[ 0 ] = 1; /* генерация константного адреса */
LD HL,1
LD (ivector),HL
;ivector[ i2 ] = 2; /* значение i2 должно быть скопировано*/
LD HL,(i2)
ADD HL,HL
LD BC,ivector
ADD HL,BC
LD (HL),2
INC HL
LD (HL),0
;ivector[ i2 ] = 2; /* копирование регистров */
;нет копирования... только база остается
LD HL,(i2)
ADD HL,HL
ADD HL,BC
LD (HL),2
INC HL
LD (HL),0
;ivector[ 2 ] = 3; /* генарация константного адреса */
LD HL,3
LD (ivector+4),HL
Код:;if(( h3 + k3 ) < 0 || ( h3 + k3 ) > 5 )
;нет выделения. зато одна переменная прописалась в регистрах
LD HL,(k3)
LD BC,(h3)
AND A
ADC HL,BC
BIT 7,H
JR NZ,?0035
LD HL,(k3)
ADD HL,BC
LD C,L
LD B,H
LD HL,5
OR 128
SBC HL,BC
JP PO,?0093
XOR H
?0093:
JP P,?0034
; printf("Common subexpression elimination\n");
;gcc например, printf без параметров сокращает до puts. но пойдет и так
?0033:
LD HL,?0037
PUSH HL
CALL printf
POP AF
JR ?0038
;else {
; m3 = ( h3 + k3 ) / i3;
;нет выделения...
?0034:
LD HL,(k3)
LD BC,(h3)
ADD HL,BC
EX DE,HL
LD BC,(i3)
CALL ?SS_DIV_L02
LD (m3),DE
; g3 = i3 + (h3 + k3);
LD HL,(k3)
LD DE,(h3)
ADD HL,DE
ADD HL,BC
LD (g3),HL
?0038:
;}
10. Вынесение инвариантного кода
11. Вызов функции с аргументамиКод:;for( i4 = 0; i4 <= max_vector; i4++)
; ivector2[ i4 ] = j * k;
LD HL,0
?0097:
LD (i4),HL
?0040:
LD C,L
LD B,H
LD HL,2
OR 128
SBC HL,BC
JP PO,?0094
XOR H
?0094:
JP M,?0039
?0041:
;нет вынесения, умножение на каждом цикле
LD HL,ivector2
ADD HL,BC
LD A,(j)
PUSH AF
LD A,(k)
LD B,A
POP AF
CALL ?C_MUL_L01
LD (HL),A
LD HL,(i4)
INC HL
JR ?0097
?0039:
12. Вызов функции без аргументов, эпилогКод:;dead_code( 1, "This line should not be printed" );
;все чин-чином: справа налево, в регистрах
LD BC,?0043
LD DE,1
CALL dead_code
13. Проверка недостижимого кода и лишних присваиванийКод:;unnecessary_loop();
;ничего особого. в конце очистка стека и возврат по дну(!)
CALL unnecessary_loop
POP HL
POP HL
RET
14.Ненужный циклКод:;void dead_code(int a, char *b )
;{
;int idead_store;
;idead_store = a;
dead_code:
PUSH BC
PUSH DE
LD HL,0
ADD HL,SP
LD D,E
INC HL
LD H,(HL)
LD L,D
LD (?0044),HL
;if( 0 )
; printf( "%s\n", b );
;нет проверки....
XOR A
JR Z,?0046
?0045:
PUSH BC
LD HL,?0047
PUSH HL
CALL printf
POP AF
POP AF
?0046:
;} /* Конец dead_code */
POP HL
POP HL
RET
15. Слияние цикловКод:;void unnecessary_loop()
;{
;int x;
;x = 0;
PUSH BC
LD HL,0
LD (?0044+2),HL
;for( i = 0; i < 5; i++ )
?0098:
LD (i),HL
?0049:
LD BC,32773
LD A,B
XOR H
LD H,A
SBC HL,BC
JR NC,?0048
?0050:
; k5 = x + j5;
;нет проверки... вычисления каждую итерацию
LD HL,(j5)
LD BC,(?0044+2)
ADD HL,BC
LD (k5),HL
LD HL,(i)
INC HL
JR ?0098
?0048:
;} /* Конец unnecessary_loop */
?0048:
POP BC
RET
16. Разворот цикловКод:;void loop_jamming(int x )
;{
;интересный пролог...
;x=IX, другого регистра чтоли не нашли...
PUSH BC
PUSH IX
PUSH DE
POP IX
;for( i = 0; i < 5; i++ )
LD HL,0
?0101:
LD (i),HL
?0053:
LD BC,32773
LD A,B
XOR H
LD H,A
SBC HL,BC
JR NC,?0052
?0054:
; k5 = x + j5 * i;
LD BC,(i)
LD DE,(j5)
CALL ?S_MUL_L02
PUSH IX
POP HL
ADD HL,DE
LD (k5),HL
LD L,C
LD H,B
INC HL
JR ?0101
?0052:
;for( i = 0; i < 5; i++ )
;нет слияния- видать слишком сложно было бы, будь такая возможность
LD HL,0
?0102:
LD (i),HL
?0057:
LD BC,32773
LD A,B
XOR H
LD H,A
SBC HL,BC
JR NC,?0056
?0058:
; i5 = x * k5 * i;
LD BC,(k5)
PUSH IX
POP DE
CALL ?S_MUL_L02
LD BC,(i)
CALL ?S_MUL_L02
LD (i5),DE
LD L,C
LD H,B
INC HL
JR ?0102
;} /* Конец loop_jamming */
POP IX
POP BC
RET
17. Сжатие цепочки переходовКод:;void loop_unrolling(int x )
;{
;нет сжатия, просто обычный цикл
PUSH BC
PUSH DE
;for( i = 0; i < 6; i++ )
LD HL,0
?0104:
LD (i),HL
?0061:
LD BC,32774
LD A,B
XOR H
LD H,A
SBC HL,BC
JR NC,?0060
?0062:
; ivector4[ i ] = 0;
LD HL,(i)
ADD HL,HL
LD BC,ivector4
ADD HL,BC
XOR A
LD (HL),A
INC HL
LD (HL),A
LD HL,(i)
INC HL
JR ?0104
?0060:
;} /* Конец loop_unrolling */
POP HL
POP BC
RET
Версия с оптимизацией по размеру отличается в основном операциями сравнения, кой-какой оптимизацией загрузки регистров а также вызовом рестартов в прологах (rst 8) и эпилогах (rst 20h) функций, принимающих параметры (кроме jump_compression)Код:;int jump_compression(int i,int j,int k,int l,int m )
;{
;просто страшный пролог, уж проще было через индексные регистры...
PUSH IY
PUSH IX
EXX
PUSH BC
PUSH DE
EXX
PUSH BC
POP IX
PUSH DE
EXX
POP BC
EXX
LD HL,12
ADD HL,SP
LD A,(HL)
LD IYL,A
INC HL
LD A,(HL)
LD IYH,A
DEC HL
DEC HL
DEC HL
PUSH HL
EXX
POP HL
LD E,(HL)
INC HL
LD D,(HL)
EXX
?0105:
;beg_1:
; if( i < j )
;далее можно заплутать в регистрах и проверках...
PUSH IX
POP BC
EXX
PUSH BC
EXX
POP HL
OR 128
SBC HL,BC
JP PO,?0111
XOR H
?0111:
JP P,?0066
?0065:
; if( j < k )
EXX
PUSH DE
EXX
POP BC
PUSH IX
POP HL
OR 128
SBC HL,BC
JP PO,?0112
XOR H
?0112:
JP P,?0068
?0067:
; if( k < l )
PUSH IY
POP BC
EXX
PUSH DE
EXX
POP HL
OR 128
SBC HL,BC
JP PO,?0113
XOR H
?0113:
JP P,?0070
?0069:
; if( l < m )
LD HL,14
ADD HL,SP
LD C,(HL)
INC HL
LD B,(HL)
PUSH IY
POP HL
OR 128
SBC HL,BC
JP PO,?0114
XOR H
?0114:
;есть сжатие! иначе был бы переход на ?0074
JP P,?0105
?0071:
; l += m;
ADD IY,BC
JR ?0077
?0072:
; else
; goto end_1;
; else
; k += l;
?0073:
?0070:
PUSH IY
EXX
POP HL
ADD HL,DE
EX DE,HL
JR ?0115
?0075:
; else {
; j += k;
;end_1:
; goto beg_1;
; }
; else
; i += j;
?0068:
ADD IX,BC
?0074:
JR ?0105
?0076:
; return( i + j + k + l + m );
?0066:
PUSH IX
EXX
POP HL
ADD HL,BC
LD C,L
LD B,H
?0115:
EXX
?0077:
PUSH IX
POP HL
EXX
PUSH BC
EXX
POP BC
ADD HL,BC
EXX
PUSH DE
EXX
POP BC
ADD HL,BC
PUSH IY
POP BC
ADD HL,BC
PUSH HL
LD HL,16
ADD HL,SP
LD C,(HL)
INC HL
LD B,(HL)
POP HL
ADD HL,BC
;} /* Конец jump_compression */
EXX
POP DE
POP BC
EXX
POP IX
POP IY
RET
Резюме: 9/10. Компилятор оставил крайне приятное впечатление практически полным отсутствием неоправданных наворотов (иногда даже в ущерб...) и грамотным использованием регистров.
Для практического применения следует выработать ряд рекомендаций, направленных на улучшение качества кода (что, впрочем, является обычным явлением для всех ЯВУ для встроенных систем).
ЗЫ. Если все переменные, где не нужна знаковость, принудительно объявить как unsigned, а также снять опцию "static allocation of 'autos'" (в данном случае), то можно получить достаточно весомый выигрыш по оптимизации! В частности, первая рекомендация весьма и весьма упрощает операции сравнения, а вторая облегчает функции с маленьким числом локальных переменных и оптимизирует использование регистров как переменных
Кажется в IAR можно управлять вычислением указателей, не сталкивался? А то вот интересно, можно ли это применить для того, чтобы дать проге побольше памяти как при стандарном 7FFD, так и при более навороченном (4x16k)MMU? Сорцы uzi(x) как глотает? А то, я так понял, оно довольно старомодно писано...