|
Несимметрия конечного результата vinavr компилятора |
|
|
|
Nov 16 2012, 21:46
|

Ambidexter
    
Группа: Свой
Сообщений: 1 589
Регистрация: 22-06-06
Из: Oxford, UK
Пользователь №: 18 282

|
Всем привет. Такой вопрос. Почему код Код while(pph!=&ph[8]) { *(pph++)=~(*(pph-4)); }, в котором берётся часть массива, инвертируется и записывается в другое место, компилируется в такой несимметричный код? Код while(pph!=&ph[8]) { *(pph++)=~(*(pph-4)); 94: fd 01 movw r30, r26 96: 34 97 sbiw r30, 0x04; 4 98: 80 81 ld r24, Z 9a: 80 95 com r24 9c: 8c 93 st X, r24 9e: 80 91 71 00 lds r24, 0x0071 a2: 80 95 com r24 a4: 11 96 adiw r26, 0x01; 1 a6: 8c 93 st X, r24 a8: 11 97 sbiw r26, 0x01; 1 aa: 90 91 72 00 lds r25, 0x0072 ae: 89 2f mov r24, r25 b0: 80 95 com r24 b2: 12 96 adiw r26, 0x02; 2 b4: 8c 93 st X, r24 b6: 12 97 sbiw r26, 0x02; 2 b8: 80 91 73 00 lds r24, 0x0073 bc: 80 95 com r24 be: 13 96 adiw r26, 0x03; 3 c0: 8c 93 st X, r24 } Казалось бы чего проще, для всех 4-х байт сделать одно и тоже действие: загрузить байт в регистр, а лучше бы воспользоваться регистровой парой Z, инвертировать и записать в новое место, указываемое парой Х. Дальше, почему бы не использовать постинкремент Х+ вместо двух команд adiw и st? Может, кто-то знает, как переделать си-код в нечто подобное?
--------------------
Делай сразу хорошо, плохо само получится
|
|
|
|
|
 |
Ответов
|
Nov 19 2012, 06:52
|

неотягощённый злом
     
Группа: Свой
Сообщений: 2 746
Регистрация: 31-01-08
Из: Санкт-Петербург
Пользователь №: 34 643

|
Мне вообще представленная ТС строка не нравится Цитата(=GM= @ Nov 17 2012, 01:46)  *(pph++)=~(*(pph-4)); приходится напрягать мозг чтобы понять что произойдёт тут и вспоминать точки следования  ИМХО так значительно прозрачнее Код pph[0] = ~pph[-4]; pph++; ну или даже так Код *pph++ = ~pph[-4] не, так плохо, прогнал, и на компиляции получил предупреждение о возможном неопределённом поведении. {дополнено позже} Цитата(Сергей Борщ @ Nov 17 2012, 21:42)  при грамотном использовании инлайн-асм 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 // дважды:( Если вы сможете мне помочь буду очень благодарен за развитие кругозора. Спасибо!
--------------------
“Будьте внимательны к своим мыслям - они начало поступков” (Лао-Цзы)
|
|
|
|
|
Nov 20 2012, 15:37
|

Ambidexter
    
Группа: Свой
Сообщений: 1 589
Регистрация: 22-06-06
Из: Oxford, UK
Пользователь №: 18 282

|
Цитата(demiurg_spb @ Nov 19 2012, 06:52)  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. Не могу понять, по какой причине меняется генерируемый код - по воле левой ноги компилятора или я делаю что-то не так?
--------------------
Делай сразу хорошо, плохо само получится
|
|
|
|
|
Nov 20 2012, 20:51
|

Нечётный пользователь.
     
Группа: Свой
Сообщений: 2 033
Регистрация: 26-05-05
Из: Бровари, Україна
Пользователь №: 5 417

|
Цитата(=GM= @ Nov 20 2012, 17:37)  И сначала мне больше понравилась ваша версия 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, так как попытка задать что-то жесткое может ухудшить оптимизацию в других местах. Классика.
--------------------
Ну, я пошёл… Если что – звоните…
|
|
|
|
|
Nov 22 2012, 04:15
|

Ambidexter
    
Группа: Свой
Сообщений: 1 589
Регистрация: 22-06-06
Из: Oxford, UK
Пользователь №: 18 282

|
Цитата(HHIMERA @ Nov 21 2012, 20:44)  2 =GM= А вопрос применения МК с хадварной поддержкой LCD рассматривался??? Ну там... PIC какой... или STM8L ...Или всё это только "мазохизма ради" ??? Всё началось отсюда, там на основе сломанного электронного термометра был сделан пробник-минивольтметр. Что касается других МК. На STM32F100 discovery писал программку вывода на ЛСД, который стоит на плате, вот там просто исплевался! Не знаю, кто придумал такое аппаратное двухмерное представление сегментов, возможно индусы, тогда я думал о них гораздо лучше, чем они есть на самом деле, но ХУЖЕ просто невозможно придумать, это даже не мазохизм, а примерно как ржавой тупой пилой самому пилить зажатые в тисках гениталии. Цитата(ReAl @ Nov 21 2012, 07:22)  { temp_ptr1 = pph pph = pph + 1 <- эта строка имеет право стоять где угодно в пределах от { до; temp_ptr2 = pph - 4 temp_var1 = *temp_ptr2 temp_var1 = ~temp_var1 *temp_ptr1 = temp_var1 ; Извините, Александр, с ходу не углядел, но третью строку вы неправильно представляете. Должно быть "temp_ptr2 = temp_ptr1-4", а не " temp_ptr2 = pph-4". Кстати, порядок для операции присваивания вполне определённый - справа налево.
--------------------
Делай сразу хорошо, плохо само получится
|
|
|
|
|
Nov 22 2012, 06:58
|

Нечётный пользователь.
     
Группа: Свой
Сообщений: 2 033
Регистрация: 26-05-05
Из: Бровари, Україна
Пользователь №: 5 417

|
Цитата(=GM= @ Nov 22 2012, 06:15)  Извините, Александр, с ходу не углядел, но третью строку вы неправильно представляете. Должно быть "temp_ptr2 = temp_ptr1-4", а не " temp_ptr2 = pph-4". Я всё написал правильно. Именно temp_ptr2 = pph-4. И именно потому, что это один из допустимых вариантов, компилятор и выдаёт предупреждение udefined operation. Цитата(=GM= @ Nov 22 2012, 06:15)  Кстати, порядок для операции присваивания вполне определённый - справа налево. Ага, щас™ Код unsigned char A; unsigned char foo() { unsigned char temp; temp = A = 3; // Сначала присвоили A, а потом temp ? return temp; } Код foo: ldi r24,lo8(3); таки сначала temp sts A,r24 ; потом A ret Определён не порядок присавиваний, а порядок вычисления присваивающих выражений. Как видите, это несколько разные вещи, как и пара высказываний «имя массива есть указатель на его первый элемент» (почти правда, работающая в большинстве случаев, как и «порядок присваиваний», но иногда приводящая к недоумению) и «имя массива автоматически приводится к указателю на его первый элемент во всех случаях кроме...». Благодаря определённому порядку во все переменные заносятся величины, полученные вычислениями справа налево, но порядок занесения величин (между двумя точками следования) неопределён. В корректной программе всё нормально. В некорректной, как в Вашем случае с указателями или как в той цепочке a ^= b ^= a ^= b; компилятор выдаёт предупреждение, что операции над той или иной переменной неопределены.
--------------------
Ну, я пошёл… Если что – звоните…
|
|
|
|
|
Nov 22 2012, 20:01
|

Нечётный пользователь.
     
Группа: Свой
Сообщений: 2 033
Регистрация: 26-05-05
Из: Бровари, Україна
Пользователь №: 5 417

|
Цитата(ReAl @ Nov 22 2012, 08:58)  но порядок занесения величин (между двумя точками следования) неопределён. Да, чтобы два раза не вставать... В качестве упреждения разных «фи, какой он этот С, вот в ассемблере всё однозначно» предлагаю любителям PDP-11 сказать, что будет результатом операций Код MOV (R0)+, R0; как бы p = *p++; MOV R0, -(R0); как бы *--p = p; и при этом сказать, для какой модели PDP-11/версии микрокода такой результат будет :-) Я уже точно не помню (оно мне и не нужно было, просто когда-то как казус запомнилось, но потом в понимании сути UB помогло), возможно, какая-то из этих строк одинаково выполнялась на любой PDP-11, но одна из них точно выполнялась по разному. Цитата(ReAl @ Nov 22 2012, 08:58)  В корректной программе В стандарте есть такое понятие «well-formed», «корректная» может и не самый лучший перевод, но у меня лучше не вышло. Ещё там есть слова sequence point (точка следования), assignment expression (присваивающее выражение) и side effect (побочный эффект -- в частности, запись в левый операнд присваивающего выражения является побочным эффектом вычисления присваивающего выражения). Там всё можно найти. А я, пожалуй, на пару с Сергеем тоже на какое-то время уймусь. Есть более интересные занятия, чем чтение стандарта вслух.
--------------------
Ну, я пошёл… Если что – звоните…
|
|
|
|
Сообщений в этой теме
=GM= Несимметрия конечного результата vinavr компилятора Nov 16 2012, 21:46 Genadi Zawidowski -Os, gcc 4.7.2
Код000066a2 <testfn>:
... Nov 16 2012, 23:19 zombi Писать на CИ и надеятся что какие то "дяди... Nov 16 2012, 23:44 С_Ч Цитата(zombi @ Nov 17 2012, 02:44) Писать... Nov 17 2012, 06:57  =GM= Да, слова золотые, целиком и полностью поддерживаю... Nov 17 2012, 07:30 _Pasha Текст, взятый у Геннадия, дает
CODEstatic unsigned... Nov 17 2012, 06:14 _Pasha Возьмите Клёновскую сборку, не обязательно крайнюю... Nov 17 2012, 07:57 ReAl Цитата(_Pasha @ Nov 17 2012, 09:57) Возьм... Nov 17 2012, 09:02  demiurg_spb Цитата(ReAl @ Nov 17 2012, 13:02) Или её,... Nov 17 2012, 12:47 polyname ЦитатаНа ассемблере писать!не, лучше прямо в б... Nov 17 2012, 12:31 С_Ч Цитата(polyname @ Nov 17 2012, 15:31) не,... Nov 17 2012, 13:27  =GM= Это я всё могу сделать на асме и сделаю, здесь про... Nov 17 2012, 15:28   _Pasha Цитата(=GM= @ Nov 17 2012, 18:28) Ну, над... Nov 17 2012, 15:43   Сергей Борщ QUOTE (=GM= @ Nov 17 2012, 17:28) могу сд... Nov 17 2012, 17:42    =GM= Борщ, уймитесь. Мне этот топик был полезен, уже ск... Nov 17 2012, 19:42 ILYAUL Код*(pph++)=~(*(pph-4));
... Nov 17 2012, 12:51 ILYAUL ЦитатаА то я чего-то отстал от жизни. нет , прост... Nov 17 2012, 14:11 ReAl А нельзя ли уточнить, какая именно версия avr-gcc/... Nov 17 2012, 20:37 =GM= WinAVR-20100110 (AVR-Studio, vers.4.18, build 684,... Nov 17 2012, 21:58 ReAl Да студия по барабану, если ключ оптимизации извес... Nov 18 2012, 09:35 Petka Цитата(ReAl @ Nov 18 2012, 13:35) ....
Во... Nov 18 2012, 10:33 Сергей Борщ QUOTE (demiurg_spb @ Nov 19 2012, 08:52) ... Nov 20 2012, 07:35  demiurg_spb Цитата(Сергей Борщ @ Nov 20 2012, 11:35) ... Nov 20 2012, 07:40   Сергей Борщ QUOTE (demiurg_spb @ Nov 20 2012, 09:40) ... Nov 20 2012, 10:25    demiurg_spb Цитата(Сергей Борщ @ Nov 20 2012, 14:25) ... Nov 20 2012, 12:39  _Pasha Цитата(=GM= @ Nov 20 2012, 19:37) Умереть... Nov 20 2012, 16:31      HHIMERA Цитата(=GM= @ Nov 22 2012, 08:15) Не знаю... Nov 22 2012, 05:38       demiurg_spb В продолжение темы:КодPORTA=PORTB=PORTC=0;может бы... Nov 22 2012, 09:38    ReAl Цитата(=GM= @ Nov 21 2012, 09:22) Эта стр... Nov 21 2012, 21:32 Genadi Zawidowski Цитатапонять что произойдёт тут и вспоминать точки... Nov 20 2012, 01:29
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|