Сергей Борщ 119 17 ноября, 2012 Опубликовано 17 ноября, 2012 · Жалоба могу сделать на асме и сделаю, здесь проблем нет, хотя инлайновый асм в винавре это нечто.Но желание потроллить не дает покоя. То, что в качестве вброса использовался компилятор почти трехлетней давности автора не смущает, а то, что при грамотном использовании инлайн-асм gcc позволяет сделать практичеки чудеса - это для слабых... Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
=GM= 0 17 ноября, 2012 Опубликовано 17 ноября, 2012 · Жалоба Борщ, уймитесь. Мне этот топик был полезен, уже скачал avr-gcc-4.7.2-mingw32, спасибо неозабоченным коллегам. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
ReAl 0 17 ноября, 2012 Опубликовано 17 ноября, 2012 · Жалоба А нельзя ли уточнить, какая именно версия avr-gcc/WinAVR сгенерировала код из первого сообщения :blink: ? И с какими ключами :blink: ? А то я вот поднял виртуалку, в которой я виндовые компиляторы на scmRTOS гоняю, у меня там подборка анитквариата есть. Полез вглубь. WinAVR-20100110 (avr-gcc 4.3.3) testfn: ldi r30,lo8(ph-4) ldi r31,hi8(ph-4) rjmp .L2 .L3: ld r24,Z com r24 std Z+4,r24 adiw r30,1 .L2: ldi r24,hi8(ph+4) cpi r30,lo8(ph+4) cpc r31,r24 brne .L3 ret WinAVR-20081205 (avr-gcc 4.3.2) testfn: ldi r30,lo8(ph-4) ldi r31,hi8(ph-4) rjmp .L2 .L3: ld r24,Z com r24 std Z+4,r24 adiw r30,1 .L2: ldi r24,hi8(ph+4) cpi r30,lo8(ph+4) cpc r31,r24 brne .L3 ret WinAVR-20070525 (avr-gcc 4.1.2) testfn: ldi r30,lo8(ph-4) ldi r31,hi8(ph-4) .L2: ld r24,Z com r24 std Z+4,r24 adiw r30,1 ldi r24,hi8(ph+4) cpi r30,lo8(ph+4) cpc r31,r24 brne .L2 ret WinAVR-20060421 (avr-gcc 3.4.6) testfn: ldi r30,lo8(ph) ldi r31,hi8(ph) .L4: sbiw r30,4 ld r24,Z adiw r30,4 com r24 st Z+,r24 ldi r24,hi8(ph+8) cpi r30,lo8(ph+8) cpc r31,r24 brne .L4 ret Это все с -Os, для пары версий глянул с -O2 -- то же самое. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
=GM= 0 17 ноября, 2012 Опубликовано 17 ноября, 2012 · Жалоба WinAVR-20100110 (AVR-Studio, vers.4.18, build 684, GUI vers.4.18,0,680) Ключ -Os Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
ReAl 0 18 ноября, 2012 Опубликовано 18 ноября, 2012 · Жалоба Да студия по барабану, если ключ оптимизации известен. Ну 20100110 я ж первой проверил. Практически от 3.4.6 до 4.7.1 на этом тесте результат одинаков по объёму, разница в деталях реализации. Возможно, там вокруг что-то было, что поломало потмизацию, но всё равно непонятно. Можно больший по размеру фрагмент кода, внутри которого этот цикл? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Petka 0 18 ноября, 2012 Опубликовано 18 ноября, 2012 · Жалоба .... Возможно, там вокруг что-то было, что поломало потмизацию, но всё равно непонятно. Можно больший по размеру фрагмент кода, внутри которого этот цикл? Наверняка там всё volatile. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
demiurg_spb 0 19 ноября, 2012 Опубликовано 19 ноября, 2012 · Жалоба Мне вообще представленная ТС строка не нравится *(pph++)=~(*(pph-4)); приходится напрягать мозг чтобы понять что произойдёт тут и вспоминать точки следования:( ИМХО так значительно прозрачнее pph[0] = ~pph[-4]; pph++; ну или даже так *pph++ = ~pph[-4] не, так плохо, прогнал, и на компиляции получил предупреждение о возможном неопределённом поведении. {дополнено позже} при грамотном использовании инлайн-асм gcc позволяет сделать практичеки чудесаЭто наверно так, но у меня к примеру почему-то простейшая конструкция не выходит (правда я нашёл другой способ решить мою задачу) #define makeword16(b0,b1) \ (__extension__({ \ uint8_t __b0 = (uint8_t)(b0); \ uint8_t __b1 = (uint8_t)(b1); \ uint16_t __result; \ __asm__ __volatile__ \ ( \ "\n\t" \ "mov %A0,%A1" "\n\t" \ "mov %B0,%A2" "\n\t" \ : "=r" (__result) /* output operands */ \ : "r" (__b0), /* input operands */ \ "r" (__b1) \ ); \ __result; \ })) uint8_t b[n]; uint16_t x = makeword16(b[1],b[0]); //read big-endian value ... получаем 582: 81 81 ldd r24, Z+1; 0x01 584: 90 81 ld r25, Z 586: 88 2f mov r24, r24 // я плакал:( 588: 99 2f mov r25, r25 // дважды:( Если вы сможете мне помочь буду очень благодарен за развитие кругозора. Спасибо! Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
GenaSPB 11 20 ноября, 2012 Опубликовано 20 ноября, 2012 · Жалоба понять что произойдёт тут и вспоминать точки следования А неопределённый результат произойдёт. Я в данном случае не присматирвался к коду, а компилятор ругнулся как раз про это. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Сергей Борщ 119 20 ноября, 2012 Опубликовано 20 ноября, 2012 · Жалоба // я плакал:(Вы сами написали mov в своей вставке, вы его получили. Компилятор не виноват, что входные и выходные параметры были в одних и тех же регистрах. Как ему это объяснить - я пока не знаю. Эта ваша задача решается через union. Будет так же непортируемо, как и с асм-вставкой. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
demiurg_spb 0 20 ноября, 2012 Опубликовано 20 ноября, 2012 · Жалоба Эта ваша задача решается через union. Будет так же непортируемо, как и с асм-вставкой.Так и сделано (с union наиоптимальнейший результат). Но хотелось бы понять как сие и на асме изобразить. Сейчас не до портируемости, ибо размер сильно важен, а со сдвигами сильно плохо оптимизирует... uint16_t x = b0<<8 | b1; никак не меньше 4 инструкций выходит:( Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Сергей Борщ 119 20 ноября, 2012 Опубликовано 20 ноября, 2012 · Жалоба Но хотелось бы понять как сие и на асме изобразить.Знаю, как убрать один из mov: __asm__ __volatile__ \ ( \ "\n\t" \ "mov %B0,%2" "\n\t" \ : "=r" (__result) /* output operands */ \ : "0" (__b0), /* input operands */ \ "r" (__b1) \ ); \ Как объяснить насчет второго - пока не придумал. а со сдвигами сильно плохо оптимизирует...Увы, пока да. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
demiurg_spb 0 20 ноября, 2012 Опубликовано 20 ноября, 2012 · Жалоба Знаю, как убрать один из mov:Остроумно. Я около этого варианта тоже крутился, но не додумался до такого. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
=GM= 0 20 ноября, 2012 Опубликовано 20 ноября, 2012 · Жалоба 1) Мне вообще представленная ТС строка не нравится *(pph++)=~(*(pph-4)); приходится напрягать мозг чтобы понять что произойдёт тут и вспоминать точки следования:( 2) ИМХО так значительно прозрачнее pph[0] = ~pph[-4]; pph++; Моя версия компилятора даёт один и тот же ассемблерный код для обоих вариантов 1 и 2. while(pph!=&ph[8]) { *(pph++)=~(*(pph-4)); 98: 80 91 70 00 lds r24, 0x0070 9c: 80 95 com r24 9e: 80 93 74 00 sts 0x0074, r24 a2: 80 91 71 00 lds r24, 0x0071 a6: 80 95 com r24 a8: 80 93 75 00 sts 0x0075, r24 ac: 80 91 72 00 lds r24, 0x0072 b0: 80 95 com r24 b2: 80 93 76 00 sts 0x0076, r24 b6: 80 91 73 00 lds r24, 0x0073 ba: 80 95 com r24 bc: 80 93 77 00 sts 0x0077, r24 И сначала мне больше понравилась ваша версия 2, поскольку никаких предупреждений не было, а в моём варианте было предупреждение: operation on pph may be undefined - операция с pph может быть неопределенной. Но присмотревшись к коду, я понял к чему относится предупреждение. По си коду указатель pph в процессе исполнения кода увеличивается на 4, а в листинге указатель кода никак не участвует, поскольку там цикл развернут и применена прямая адресация! Поэтому компилятор предупреждает, что если вы будете использовать pph дальше, то содержимое указателя может быть отлично от того, на что вы рассчитывали. Я считаю, что лучше пусть будет предупреждение просто как напоминание, что может произойти в дальнейшем. А чудеса с оптимизацией продолжаются. Из такого си кода, больше ничего нет int main(void) //LCD test { unsigned char *pph; unsigned char *pdg; while(1) { pdg=&dig[0]; pph=&ph[4]; while(pph!=&ph[8]) { *(pph++)=~(*(pph-4)); } } } получается такой ассемблерный листинг int main(void) //LCD test { 5e: e4 e7 ldi r30, 0x74 ; 116 60: f0 e0 ldi r31, 0x00 ; 0 pph=&ph[4]; while(pph!=&ph[8]) { *(pph++)=~(*(pph-4)); 62: 34 97 sbiw r30, 0x04 ; 4 64: 80 81 ld r24, Z 66: 34 96 adiw r30, 0x04 ; 4 68: 80 95 com r24 6a: 81 93 st Z+, r24 } while((pdg)!=&dig[4]); pph=&ph[4]; while(pph!=&ph[8]) 6c: 80 e0 ldi r24, 0x00 ; 0 6e: e8 37 cpi r30, 0x78 ; 120 70: f8 07 cpc r31, r24 72: b9 f7 brne .-18 ; 0x62 <main+0x4> 74: 34 97 sbiw r30, 0x04 ; 4 76: f5 cf rjmp .-22 ; 0x62 <main+0x4> Умереть-не встать: теперь компилятор решил не разворачивать цикл while. Не могу понять, по какой причине меняется генерируемый код - по воле левой ноги компилятора или я делаю что-то не так? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
_Pasha 0 20 ноября, 2012 Опубликовано 20 ноября, 2012 · Жалоба Умереть-не встать: теперь компилятор решил не разворачивать цикл while. Не могу понять, по какой причине меняется генерируемый код - по воле левой ноги компилятора или я делаю что-то не так? Имхо, на таких мизерных фрагментах, смеяться над компилятором не нужно. Побеждает то один вариант, то другой. Я думаю, если у Вас флеш будет заканчиваться, в программу войдет кусок наименьшего объема. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
ReAl 0 20 ноября, 2012 Опубликовано 20 ноября, 2012 · Жалоба И сначала мне больше понравилась ваша версия 2, поскольку никаких предупреждений не было, а в моём варианте было предупреждение: operation on pph may be undefined - операция с pph может быть неопределенной. Но присмотревшись к коду, я понял к чему относится предупреждение. По си коду указатель pph в процессе исполнения кода увеличивается на 4, а в листинге указатель кода никак не участвует, поскольку там цикл развернут и применена прямая адресация! Поэтому компилятор предупреждает, что если вы будете использовать pph дальше, то содержимое указателя может быть отлично от того, на что вы рассчитывали. Я считаю, что лучше пусть будет предупреждение просто как напоминание, что может произойти в дальнейшем. Нет, не так. Перепишите цикл следующим образом while(pph!=&ph[8]) { *pph=~(*(pph-4)); ++pph; // Ну или pph++ } и убедитесь, что сообщение пропало, хотя указатель так же меняется. Дело тут в том, что эффект от операции pph++ может быть сделан где угодно между уже упомянутыми точками следования. И строка { *pph++=~(*(pph-4)); } имеет одинаковое право быть скомпилированной и как вышло, и так: { temp_ptr1 = pph pph = pph + 1 <- эта строка имеет право стоять где угодно в пределах от { до; temp_ptr2 = pph - 4 temp_var1 = *temp_ptr2 temp_var1 = ~temp_var1 *temp_ptr1 = temp_var1 ; и на какой-то другой архитектуре это может оказаться выгоднее, например, по скорости исполнения. С-шная строка та же, а результат разный. Стандарт такие места обозначил как undefined behaviour, так как попытка задать что-то жесткое может ухудшить оптимизацию в других местах. Классика. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться