AVR C -- они все издеваются что ли?!.

▐┤E╚°' All!
Существуют в природе хоть какие-нибудь нормальные компиляторы C для AVR?
Посмотрел пока что CodeVisionAVR, который (без Automatic Register Allocation)
делает такое:
; 40 led_status<<=1;
LDS R30,_led_status
LSL R30
STS _led_status,R30
; 41 led_status|=1;
ORI R30,1
STS _led_status,R30
И avr-gcc, который со всякими ключами оптимизациями делает вообще такое:
5a: 80 91 60 00 lds r24, 0x0060
5e: 99 27 eor r25, r25
60: 00 97 sbiw r24, 0x00 ; 0
62: 19 f0 breq .+6 ; 0x6a
6a: 80 91 61 00 lds r24, 0x0061
6e: 90 91 62 00 lds r25, 0x0062
72: 01 96 adiw r24, 0x01 ; 1
74: 90 93 62 00 sts 0x0062, r25
78: 80 93 61 00 sts 0x0061, r24
7c: 80 91 61 00 lds r24, 0x0061
80: 90 91 62 00 lds r25, 0x0062
84: 8f 5f subi r24, 0xFF ; 255
86: 93 40 sbci r25, 0x03 ; 3
88: a9 f4 brne .+42 ; 0xb4
Создаётся впечатление, что даже самая наипримитивнейшая чистка кода отсутствует
полностью -- что транслятор наделал, то и нате!
Hеужели всё действительно настолько плохо?.. :-(
|V|uxau/\
Reply to
Michael Ryazanov
Loading thread data ...
Всем привет!
Michael Ryazanov писал к All 28.01.2005:
MR> Существуют в природе хоть какие-нибудь нормальные компиляторы C для MR> AVR?
Да - IAR
Reply to
Askold Volkov
Hello, Michael! You wrote to All on Thu, 27 Jan 2005 22:35:00 +0300:
MR> И avr-gcc, который со всякими ключами оптимизациями делает вообще MR> такое:
MR> 5a: 80 91 60 00 lds r24, 0x0060 MR> 5e: 99 27 eor r25, r25 <...>
И как ты этого добился? Вот мой пример: === Cut === #include <inttypes.h> uint8_t led_status = 0; int main() { led_status <<= 1; led_status |= 1; return led_status; } === Cut ===
$ avr-gcc -g -Wall -mmcu=atmega8 -Os -o proba.elf proba.c $ avr-objdump -h -S proba.elf > proba.listing $ less proba.listing <...> led_status <<= 1; 64: 80 91 60 00 lds r24, 0x0060 68: 88 0f add r24, r24 led_status |= 1; 6a: 81 60 ori r24, 0x01 ; 1 6c: 80 93 60 00 sts 0x0060, r24 return led_status; } <...>
При добавлении "volatile" к "led_status", делает так:
led_status <<= 1; 64: 80 91 60 00 lds r24, 0x0060 68: 88 0f add r24, r24 6a: 80 93 60 00 sts 0x0060, r24 led_status |= 1; 6e: 80 91 60 00 lds r24, 0x0060 72: 81 60 ori r24, 0x01 ; 1 74: 80 93 60 00 sts 0x0060, r24 return led_status; 78: 80 91 60 00 lds r24, 0x0060 }
Вот ещё такой пример: === Cut === #include <inttypes.h> #include <avr/io.h> int main() { uint8_t led_status = PINB; led_status <<= 1; led_status |= 1; return led_status; }
=== Cut ===
Компилится в это:
uint8_t led_status = PINB; 64: 86 b3 in r24, 0x16 ; 22 led_status <<= 1; 66: 88 0f add r24, r24 led_status |= 1; 68: 81 60 ori r24, 0x01 ; 1 return led_status; }
И что не так? avr-gcc версии 3.4.1 под винду.
With best regards, Serg.
Reply to
Sergey Mudry
Очень рад вас видеть, Michael!
27 Янв 05 в 22:35, Michael Ryazanov писал All следующее:
MR> Существуют в природе хоть какие-нибудь нормальные компиляторы C MR> для MR> AVR? Посмотрел пока что CodeVisionAVR, который (без Automatic Register MR> Allocation) делает такое:
MR> ; 40 led_status<<=1; MR> LDS R30,_led_status MR> LSL R30 MR> STS _led_status,R30 MR> ; 41 led_status|=1; MR> ORI R30,1 MR> STS _led_status,R30
MR> И avr-gcc, который со всякими ключами оптимизациями делает вообще такое:
MR> 5a: 80 91 60 00 lds r24, 0x0060 MR> 5e: 99 27 eor r25, r25 MR> 60: 00 97 sbiw r24, 0x00 ; 0 MR> 62: 19 f0 breq .+6 ; 0x6a
MR> 6a: 80 91 61 00 lds r24, 0x0061 MR> 6e: 90 91 62 00 lds r25, 0x0062 MR> 72: 01 96 adiw r24, 0x01 ; 1 MR> 74: 90 93 62 00 sts 0x0062, r25 MR> 78: 80 93 61 00 sts 0x0061, r24 MR> 7c: 80 91 61 00 lds r24, 0x0061 MR> 80: 90 91 62 00 lds r25, 0x0062 MR> 84: 8f 5f subi r24, 0xFF ; 255 MR> 86: 93 40 sbci r25, 0x03 ; 3 MR> 88: a9 f4 brne .+42 ; 0xb4
MR> Создаётся впечатление, что даже самая наипримитивнейшая чистка кода MR> отсутствует полностью -- что транслятор наделал, то и нате! MR> Hеужели всё действительно настолько плохо?.. :-(
надо указывать, что результат ожидаешь восьмибитный, чуть лучше будет...
а сильно напрягает? флеша жалко? я просто внимания не обращаю... правда подобного ужаса сам не видел, пользуюсь гцц под виндой (винавр) на грабли с неявным преобразованием типов наступал, но как подобный код получился - не понимаю.
AVL
Reply to
Vasiliy Andreev
Hello, Michael!
Четверг Январь 27 2005 22:35, Michael Ryazanov wrote to All: MR> И avr-gcc, который со всякими ключами оптимизациями делает вообще MR> такое: хмю вот попробовал:
void inline set_bit(volatile unsigned char& port, unsigned char bit) { port |= _BV(bit); }
set_bit(DDRD, CONV); set_bit(PORTD, CONV); Транслируется в c6: 8c 9a sbi 0x11, 4 ; 17 c8: 94 9a sbi 0x12, 4 ; 18
Оптимизация -O2 avr-c++.exe (GCC) 3.3.1
Best regards и все такое... Sergey. [Death/Black/Power Metal]
Reply to
Sergey Shopin
27-Jan-05 22:35 Michael Ryazanov wrote to All:
MR> Существуют в природе хоть какие-нибудь нормальные компиляторы C для MR> AVR? MR> Посмотрел пока что CodeVisionAVR, который (без Automatic Register MR> Allocation) MR> делает такое:
MR> ; 40 led_status<<=1; MR> LDS R30,_led_status MR> LSL R30 MR> STS _led_status,R30 MR> ; 41 led_status|=1; MR> ORI R30,1 MR> STS _led_status,R30
MR> И avr-gcc, который со всякими ключами оптимизациями делает вообще такое:
MR> 5a: 80 91 60 00 lds r24, 0x0060 MR> 5e: 99 27 eor r25, r25 MR> 60: 00 97 sbiw r24, 0x00 ; 0 MR> 62: 19 f0 breq .+6 ; 0x6a
MR> 6a: 80 91 61 00 lds r24, 0x0061 MR> 6e: 90 91 62 00 lds r25, 0x0062 MR> 72: 01 96 adiw r24, 0x01 ; 1 MR> 74: 90 93 62 00 sts 0x0062, r25 MR> 78: 80 93 61 00 sts 0x0061, r24 MR> 7c: 80 91 61 00 lds r24, 0x0061 MR> 80: 90 91 62 00 lds r25, 0x0062 MR> 84: 8f 5f subi r24, 0xFF ; 255 MR> 86: 93 40 sbci r25, 0x03 ; 3 MR> 88: a9 f4 brne .+42 ; 0xb4
Нельзя ли привести C-шный исходник, из которого gcc сделал приведенный код? Это ведь совершенно другое, чем то, что компилировалось CodeVision. Я не говорю, что gcc во всём хорош, он иногда слишком увлекается соблюдением integer promotion rules из стандарта C и недочищает посл еэтого явно ненужные хвосты. Но что касается куска с led_status: #include <inttypes.h>
extern uint8_t led_status;
void foo(void) { led_status <<= 1; led_status |= 1; }
С оптимизацией -O2
5:foo.c **** void foo(void) { 53 .LM1: 54 /* prologue: frame size=0 */ 55 /* prologue end (size=0) */ 6:foo.c **** led_status <<= 1; 57 .LM2: 58 0000 8091 0000 lds r24,led_status 59 0004 880F lsl r24 7:foo.c **** led_status |= 1; 61 .LM3: 62 0006 8160 ori r24,lo8(1) 63 0008 8093 0000 sts led_status,r24 64 /* epilogue: frame size=0 */ 65 000c 0895 ret
Без оптимизации функция выходит больше, но только за счёт ненужных пролога и эпилога, а именно эти две строки с led_status компилируются точно так же. Худшего кода я смог *добиться* только комбинацией знаковой переменной с квалификатором volatile: volatile int8_t led_status; Тогда перед выполнением сдвига остаётся преобразование со знаком к знаковому 16-битному значению и сдвиг 16-битного значения. И несмотря на ненужность старшего байта оптимизатор этот хвост не подчистил: 5:foo.c **** void foo(void) { 53 .LM1: 54 /* prologue: frame size=0 */ 55 /* prologue end (size=0) */ 6:foo.c **** led_status <<= 1; 57 .LM2: 58 0000 8091 0000 lds r24,led_status 59 0004 9927 clr r25 60 0006 87FD sbrc r24,7 61 0008 9095 com r25 62 000a 880F lsl r24 63 000c 991F rol r25 64 000e 8093 0000 sts led_status,r24 7:foo.c **** led_status |= 1; 66 .LM3: 67 0012 8091 0000 lds r24,led_status 68 0016 8160 ori r24,lo8(1) 69 0018 8093 0000 sts led_status,r24 70 /* epilogue: frame size=0 */ 71 001c 0895 ret
В любом случае приведенный тобой код соответствует совсем другому исходнику.
wbr,
Reply to
Oleksandr Redchuk
Hello, Askold!
MR>> Существуют в природе хоть какие-нибудь нормальные компиляторы C для AVR? AV> Да - IAR
Честно говоря, качать 58 Мб не очень хочется, тем более, что он совсем не бесплатный. Хотя, если он действительно нормальный, и к нему есть лекарство от жадности... ?
|V|uxau/\
Reply to
Michael Ryazanov
Hello, Oleksandr!
MR>> Существуют в природе хоть какие-нибудь нормальные компиляторы C для AVR? MR>> Посмотрел пока что CodeVisionAVR, который (без Automatic Register MR>> Allocation) делает такое:
MR>> ; 40 led_status<<=1; MR>> LDS R30,_led_status MR>> LSL R30 MR>> STS _led_status,R30 MR>> ; 41 led_status|=1; MR>> ORI R30,1 MR>> STS _led_status,R30
MR>> И avr-gcc, который со всякими ключами оптимизациями делает вообще такое:
MR>> 5a: 80 91 60 00 lds r24, 0x0060 MR>> 5e: 99 27 eor r25, r25 MR>> 60: 00 97 sbiw r24, 0x00 ; 0 MR>> 62: 19 f0 breq .+6 ; 0x6a
MR>> 6a: 80 91 61 00 lds r24, 0x0061 MR>> 6e: 90 91 62 00 lds r25, 0x0062 MR>> 72: 01 96 adiw r24, 0x01 ; 1 MR>> 74: 90 93 62 00 sts 0x0062, r25 MR>> 78: 80 93 61 00 sts 0x0061, r24 MR>> 7c: 80 91 61 00 lds r24, 0x0061 MR>> 80: 90 91 62 00 lds r25, 0x0062 MR>> 84: 8f 5f subi r24, 0xFF ; 255 MR>> 86: 93 40 sbci r25, 0x03 ; 3 MR>> 88: a9 f4 brne .+42 ; 0xb4
OR> Hельзя ли привести C-шный исходник, из которого gcc сделал приведенный OR> код? Это ведь совершенно другое, чем то, что компилировалось CodeVision.
Вы таки будете смеяться, но приведённые отрывки -- это примеры, поставляемые с самими компиляторами... :-/ Для CodeVisionAVR -- проект из каталога EXAMPLES\LED\, собранный сразу после установки (без изменения каких-либо настроек). Для avr-gcc -- результат команды make в каталоге examples\demo\ после установки только что скачанного с SourceForge WinAVR (20040720, gcc version 3.4.1).
OR> Я не говорю, что gcc во всём хорош, он иногда слишком увлекается OR> соблюдением integer promotion rules из стандарта C и недочищает после OR> этого явно ненужные хвосты. <...> OR> Худшего кода я смог *добиться* только комбинацией знаковой переменной OR> с квалификатором volatile: OR> volatile int8_t led_status; OR> Тогда перед выполнением сдвига остаётся преобразование со знаком OR> к знаковому 16-битному значению и сдвиг 16-битного значения. И несмотря OR> на ненужность старшего байта оптимизатор этот хвост не подчистил: <...> OR> 6:foo.c **** led_status <<= 1; OR> 57 .LM2: OR> 58 0000 8091 0000 lds r24,led_status OR> 59 0004 9927 clr r25 OR> 60 0006 87FD sbrc r24,7 OR> 61 0008 9095 com r25 OR> 62 000a 880F lsl r24 OR> 63 000c 991F rol r25 OR> 64 000e 8093 0000 sts led_status,r24
Тоже стыд и срам. Hо тут он хоть как-то объясним, как и в моём первом куске (5a-62). А вот что его заставило сгенерировать такой код для второго куска (6a-88)?
OR> В любом случае приведенный тобой код соответствует совсем другому OR> исходнику.
Откуда взят тот исходник, я уже сказал, а маленький пример, демонстрирующий такое поведение, сейчас вот сделал:
#include <inttypes.h>
volatile uint16_t pwm;
void f(void) { if (++pwm == 1023) pwm = 0; }
|V|uxau/\
Reply to
Michael Ryazanov
Hello, Sergey!
MR>> И avr-gcc, который со всякими ключами оптимизациями делает вообще MR>> такое:
MR>> 5a: 80 91 60 00 lds r24, 0x0060 MR>> 5e: 99 27 eor r25, r25 SM> <...>
SM> И как ты этого добился?
Извиняюсь, что не совсем понятно написал. Это были просто примеры плохого кода, генерируемого данными компиляторами. Все они получены из разных исходных текстов.
SM> Вот мой пример: SM> === Cut === SM> #include <inttypes.h> SM> uint8_t led_status = 0; SM> int main() { SM> led_status <<= 1; SM> led_status |= 1; SM> return led_status; SM> } SM> === Cut === <...> SM> При добавлении "volatile" к "led_status", делает так:
SM> led_status <<= 1; SM> 64: 80 91 60 00 lds r24, 0x0060 SM> 68: 88 0f add r24, r24 SM> 6a: 80 93 60 00 sts 0x0060, r24 SM> led_status |= 1; SM> 6e: 80 91 60 00 lds r24, 0x0060 SM> 72: 81 60 ori r24, 0x01 ; 1 SM> 74: 80 93 60 00 sts 0x0060, r24 SM> return led_status; SM> 78: 80 91 60 00 lds r24, 0x0060 SM> }
Кто может пояснить тайный смысл этого ритуала -- сохраненять и тут же загружать значение переменной посреди вычислений? Особенно в том куске:
if (++pwm == 1023) // объявлено как volatile uint16_t pwm; 6a: 80 91 61 00 lds r24, 0x0061 6e: 90 91 62 00 lds r25, 0x0062 72: 01 96 adiw r24, 0x01 ; 1 74: 90 93 62 00 sts 0x0062, r25 78: 80 93 61 00 sts 0x0061, r24 7c: 80 91 61 00 lds r24, 0x0061 80: 90 91 62 00 lds r25, 0x0062 84: 8f 5f subi r24, 0xFF ; 255 86: 93 40 sbci r25, 0x03 ; 3 88: a9 f4 brne .+42 ; 0xb4
Hеужели они делают столь смелое предположение, что прерывание может произойти только перед 7c, но ни в каком другом месте? (Учитывая, что этот кусок, вообще-то, сам взят из обработчика прерывания... :-) ) И из каких-таких соображений они вообще решили, что нужно заниматься синхронизацией промежуточных результатов при вычислении выражения?
|V|uxau/\
Reply to
Michael Ryazanov
Sat Jan 29 2005 18:38, Michael Ryazanov wrote to Sergey Mudry:
SM>> При добавлении "volatile" к "led_status", делает так:
SM>> led_status <<= 1; SM>> 64: 80 91 60 00 lds r24, 0x0060 SM>> 68: 88 0f add r24, r24 SM>> 6a: 80 93 60 00 sts 0x0060, r24 SM>> led_status |= 1; SM>> 6e: 80 91 60 00 lds r24, 0x0060 SM>> 72: 81 60 ori r24, 0x01 ; 1 SM>> 74: 80 93 60 00 sts 0x0060, r24 SM>> return led_status; SM>> 78: 80 91 60 00 lds r24, 0x0060 SM>> }
MR> Кто может пояснить тайный смысл этого ритуала -- сохраненять и тут же MR> загружать значение переменной посреди вычислений?
RTFM volatile.
MR> Особенно в том куске: MR> if (++pwm == 1023) // объявлено как volatile uint16_t pwm;
RTFM volatile.
MR> И из MR> каких-таких соображений они вообще решили, что нужно заниматься MR> синхронизацией промежуточных результатов при вычислении выражения?
RTFM volatile.
WBR, Yuriy
Reply to
Yuriy K
Всем привет!
Michael Ryazanov писал к Askold Volkov Sat, 29 Jan 2005 17:32:00 +0300:
MR>>> Существуют в природе хоть какие-нибудь нормальные компиляторы C для MR>>> AVR? AV>> Да - IAR
MR> Честно говоря, качать 58 Мб не очень хочется,
Ну не хочется, так не качай. Мы-то тут при чем? Ты спросил, я ответил, а уж что с этим ответом делать - дело твое.
MR> Хотя, если он действительно нормальный, и к нему есть лекарство от жадности... ?
Лекарство, разумеется, есть:
formatting link
ru_embedded00 pass: sobaka
Что касается нормальности, то у каждого свои критерии, однако то, что этот компилятор для AVR лучший из существующих - это точно.
Reply to
Askold Volkov
Привет Michael!
29 Jan 05 17:32, Michael Ryazanov писал Askold Volkov:
MR>>> Существуют в природе хоть какие-нибудь нормальные компиляторы C MR>>> для AVR? AV>> Да - IAR MR> Честно говоря, качать 58 Мб не очень хочется, тем более, что он MR> совсем не бесплатный.
Бесплатный - avr-gcc.
Всего наилучшего, [Team PCAD 2000] Алексей М. ... Смотрю куда глаза глядят...
Reply to
Alex Mogilnikov
Привет Michael!
29 Jan 05 18:24, Michael Ryazanov писал Oleksandr Redchuk:
MR> Откуда взят тот исходник, я уже сказал, а маленький пример, MR> демонстрирующий такое поведение, сейчас вот сделал:
MR> #include <inttypes.h>
MR> volatile uint16_t pwm;
MR> void f(void) { MR> if (++pwm == 1023) MR> pwm = 0; MR> }
avr-gcc -O3: f: lds r26,pwm lds r27,(pwm)+1 adiw r26,1 sts (pwm)+1,r27 sts pwm,r26 lds r24,pwm lds r25,(pwm)+1 subi r24,lo8(1023) sbci r25,hi8(1023) breq .L4 ret .L4: sts (pwm)+1,__zero_reg__ sts pwm,__zero_reg__ ret
Кроме уже упоминавшегося тут пристрастия к lds/sts вместо обращения через указатель, придраться по-моему не к чему.
Всего наилучшего, [Team PCAD 2000] Алексей М. ... Крыскас. Потому что крыса вам доверяет.
Reply to
Alex Mogilnikov
Привет Michael!
29 Jan 05 18:38, Michael Ryazanov писал Sergey Mudry:
MR> Кто может пояснить тайный смысл этого ритуала -- сохраненять и тут MR> же загружать значение переменной посреди вычислений? Особенно в том MR> куске:
MR> if (++pwm == 1023) // объявлено как volatile uint16_t pwm; MR> 6a: 80 91 61 00 lds r24, 0x0061 MR> 6e: 90 91 62 00 lds r25, 0x0062 MR> 72: 01 96 adiw r24, 0x01 ; 1 MR> 74: 90 93 62 00 sts 0x0062, r25 MR> 78: 80 93 61 00 sts 0x0061, r24 MR> 7c: 80 91 61 00 lds r24, 0x0061 MR> 80: 90 91 62 00 lds r25, 0x0062 MR> 84: 8f 5f subi r24, 0xFF ; 255 MR> 86: 93 40 sbci r25, 0x03 ; 3 MR> 88: a9 f4 brne .+42 ; 0xb4
Тайный смысл должен знать программист, объявивший переменную pwm как volatile. Этим он именно указал компилятору, что тот должен каждый раз заново вычитывать ее из памяти. И при каждой модификации записывать. Если еще точнее, volatile запрещает оптимизатору исключать "ненужные" обращения к переменной. И компилятор эти указания безропотно выполняет.
MR> Hеужели они делают столь смелое предположение, что прерывание может MR> произойти только перед 7c, но ни в каком другом месте? (Учитывая, что MR> этот кусок, вообще-то, сам взят из обработчика прерывания... :-) ) И MR> из каких-таких соображений они вообще решили, что нужно заниматься MR> синхронизацией промежуточных результатов при вычислении выражения?
Что ты здесь называешь промежуточными результатами и почему?
А если эта переменная - на самом деле регистр какого-то устройства? Считываемые данные могут не иметь никакого отношения к записываемым. Hе факт, что прочитав, например, 55 и записав туда 56, это же 56 оттуда в следующий раз и считается. Из этого регистра вполне может читаться какая-то последовательность данных. А записываться другая последовательность. Исключив любое из обращений, компилятор эту последовательность нарушит. Hе его дело делать предположения о назначении переменной - ни смелые, ни трусливые. :)
Всего наилучшего, [Team PCAD 2000] Алексей М. ... Слепой Пью, Глухой Ем...
Reply to
Alex Mogilnikov
Hello, Yuriy!
SM>>> При добавлении "volatile" к "led_status", делает так:
SM>>> led_status <<= 1; SM>>> 64: 80 91 60 00 lds r24, 0x0060 SM>>> 68: 88 0f add r24, r24 SM>>> 6a: 80 93 60 00 sts 0x0060, r24 SM>>> led_status |= 1; SM>>> 6e: 80 91 60 00 lds r24, 0x0060 SM>>> 72: 81 60 ori r24, 0x01 ; 1 SM>>> 74: 80 93 60 00 sts 0x0060, r24 SM>>> return led_status; SM>>> 78: 80 91 60 00 lds r24, 0x0060
MR>> Кто может пояснить тайный смысл этого ритуала -- сохраненять и тут же MR>> загружать значение переменной посреди вычислений?
YK> RTFM volatile.
MR>> Особенно в том куске: MR>> if (++pwm == 1023) // объявлено как volatile uint16_t pwm;
YK> RTFM volatile.
MR>> И из каких-таких соображений они вообще решили, что нужно заниматься MR>> синхронизацией промежуточных результатов при вычислении выражения?
YK> RTFM volatile.
Точные ссылки давайте, вежливый вы наш.
|V|uxau/\
Reply to
Michael Ryazanov
Hello, Askold!
MR>>>> Существуют в природе хоть какие-нибудь нормальные компиляторы C для MR>>>> AVR? AV>>> Да - IAR MR>> Честно говоря, качать 58 Мб не очень хочется, AV> Hу не хочется, так не качай. Мы-то тут при чем? AV> Ты спросил, я ответил,
Спасибо.
AV> а уж что с этим ответом делать - дело твое. MR>> Хотя, если он действительно нормальный, и к нему есть лекарство от MR>> жадности... ? AV> Лекарство, разумеется, есть: AV>
formatting link
AV> id: ru_embedded00 AV> pass: sobaka AV> Что касается нормальности, то у каждого свои критерии, однако то, что AV> этот компилятор для AVR лучший из существующих - это точно.
Тогда буду качать...
|V|uxau/\
Reply to
Michael Ryazanov
Mon Jan 31 2005 21:23, Michael Ryazanov wrote to Yuriy K:
SM>>>> При добавлении "volatile" к "led_status", делает так: MR>>> И из каких-таких соображений они вообще решили, что нужно заниматься MR>>> синхронизацией промежуточных результатов при вычислении выражения?
YK>> RTFM volatile.
MR> Точные ссылки давайте, вежливый вы наш.
Любая книжка по С.
WBR, Yuriy.
Reply to
Yuriy K
31-Jan-05 21:27 Michael Ryazanov wrote to Askold Volkov:
AV>> Что касается нормальности, то у каждого свои критерии, однако то, что AV>> этот компилятор для AVR лучший из существующих - это точно.
MR> Тогда буду качать...
Качай, он пожалуй действительно самый лучший. Только предупреждаю, что он тоже в полном соответствии со стандартом С и в полной противоположности с твоим мнением считает, что квалифицированную как volatile переменную надо перезачитывать даже если в него писали "только что":
extern volatile unsigned uu; unsigned foo(unsigned u) { uu = u; return uu; }
3 unsigned foo(unsigned u) { 4 uu = u; \ __nearfunc unsigned int foo(unsigned int); \ foo: \ 00000000 .... LDI R30,uu \ 00000002 8300 ST Z,R16 \ 00000004 8311 STD Z+1,R17 5 return uu; \ 00000006 8100 LD R16,Z \ 00000008 8111 LDD R17,Z+1 \ 0000000A 9508 RET 6 }
wbr, p.s. поищи всё-таки нормальную книжку по C, если стандарт читать неохота, чтобы понимать что означают всякие volatile и почему, скажем, на такое:
extern const volatile unsigned uu;
unsigned foo(void) { return uu + uu; }
тем же IAR-ом генерится такой код:
3 unsigned foo(void) { 4 return uu + uu; \ __nearfunc unsigned int foo(); \ foo: \ 00000000 .... LDI R30,uu \ 00000002 8120 LD R18,Z \ 00000004 8131 LDD R19,Z+1 \ 00000006 8100 LD R16,Z \ 00000008 8111 LDD R17,Z+1 \ 0000000A 0F02 ADD R16,R18 \ 0000000C 1F13 ADC R17,R19 \ 0000000E 9508 RET 5 }
Reply to
Oleksandr Redchuk
Hello, Oleksandr!
AV>>> Что касается нормальности, то у каждого свои критерии, однако то, что AV>>> этот компилятор для AVR лучший из существующих - это точно. MR>> Тогда буду качать... OR> Качай, он пожалуй действительно самый лучший.
Скачал. Hо пока ещё не смотрел.
OR> Только предупреждаю, что он тоже в полном соответствии со стандартом С и OR> в полной противоположности с твоим мнением считает, что квалифицированную OR> как volatile переменную надо перезачитывать даже если в него писали OR> "только что": <...> OR> p.s. поищи всё-таки нормальную книжку по C, если стандарт читать неохота,
Я бы лучше стандарт почитал (или его разбор/комментарии к нему), потому что в книжках бывает не написано или написано не то. (Примечание, добавленное после написания всего письма: стандарт всё-таки совершенно невменяемо написан. Hадо что-нибудь более правильное читать. Что именно?)
OR> чтобы понимать что означают всякие volatile и почему, скажем, на такое:
OR> extern const volatile unsigned uu;
OR> unsigned foo(void) { OR> return uu + uu; OR> }
OR> тем же IAR-ом генерится такой код:
OR> 3 unsigned foo(void) { OR> 4 return uu + uu; OR> \ __nearfunc unsigned int foo(); OR> \ foo: OR> \ 00000000 .... LDI R30,uu OR> \ 00000002 8120 LD R18,Z OR> \ 00000004 8131 LDD R19,Z+1 OR> \ 00000006 8100 LD R16,Z OR> \ 00000008 8111 LDD R17,Z+1 OR> \ 0000000A 0F02 ADD R16,R18 OR> \ 0000000C 1F13 ADC R17,R19 OR> \ 0000000E 9508 RET OR> 5 }
В данном случае в исходном тексте к переменной обращаются два раза. Если считать, что по стандарту положено "читать каждый раз", то в коде всё правильно. В моём же случае (++pwm == 1023) в тексте всего одно обращение к переменной. Вообще, в стандарте C++, что у меня есть (файл ansi_iso_iec_14882_1998.pdf), по делу нашёл следующее:
*1.9 Program execution* <...> 5 A conforming implementation executing a wellformed program shall produce the same observable behavior as one of the possible execution sequences of the corresponding instance of the abstract machine with the same program and the same input. However, if any such execution sequence contains an undefined operation, this International Standard places no requirement on the implementation executing that program rule,<...> <...> 6 The observable behavior of the abstract machine is its sequence of reads and writes to volatile data and calls to library I/O functions.
Из этого вроде как следует, что последовательности чтения и записи volatile-объектов должны количественно совпадать для любого компилятора и любой машины. Больше никакого внятного упоминания о том, каковы же эти последовательности должны быть, найти не удалось.
<...> 11 The least requirements on a conforming implementation are: - At sequence points, volatile objects are stable in the sense that previous evaluations are complete and subsequent evaluations have not yet occurred.
Только то, что между точками следованя volatile-объекты должны принять состояние, соответствующее уже выполненным вычислениям, т.е. их значения нужно записать. Определение точки следования почему-то найти не удалось, но операция сравнения, вроде как, ей не является.
*5 Expressions* <...> 4 Except where noted, the order of evaluation of operands of individual operators and subexpressions of individual expressions, and the order in which side effects take place, is unspecified. Between the previous and next sequence point a scalar object shall have its stored value modified at most once by the evaluation of an expression. Furthermore, the prior value shall be accessed only to determine the value to be stored. The requirements of this paragraph shall be met for each allowable ordering of the subexpressions of a full expression; otherwise the behavior is undefined. [Example: i = v[i++]; // the behavior is unspecified i = 7, i++, i++; // i becomes 9 i = ++i + 1; // the behavior is unspecified i = i + 1; // the value of i is incremented -end example]
Тут у меня какие-то проблемы с пониманием около первого слова stored. Если кто-нибудь с хорошим знанием этого языка :-) переведёт, буду благодарен. Зато тут есть важное слово only. Его трактовка, конечно, зависит от того, что считать точкой следования, и что они подразумевают под "прежним значением", но на определённые мысли это наводит.
*7.1.5.1 The cv-qualifiers* <...> 8 [Note: volatile is a hint to the implementation to avoid aggressive optimization involving the object because the value of the object might be changed by means undetectable by an implementation. See 1.9 for detailed semantics. In general, the semantics of volatile are intended to be the same in C++ as they are in C. ]
Вот тут вот прошу обратить внимание на слово hint. Т.е. это всего лишь намёк избегать "агрессивной" оптимизации. Что считать "агрессивной", и насколько важно её избегать, найти, опять же, не удалось. По моему мнению, в первоначальном моём примере компилятор достоверно знал, что ничего с этой переменной случиться не может, и вполне мог исключить повторное чтение. Более того, он мог бы вообще разместить её в регистрах.
А вот, кстати, между прочим. Программа
#include <stdio.h>
int i = 0;
int& f(void) { puts("f()"); return i; }
int main(void) { int j = -1; printf("i = %d, j = %d\n", i, j); j = ++f(); printf("i = %d, j = %d\n", i, j); j = f()++; printf("i = %d, j = %d\n", i, j);
return 0; }
выдаёт следующее:
i = 0, j = -1 f() i = 1, j = 1 f() i = 2, j = 1
От добавления volatile результат не меняется, хотя в любом случае тут уж явно не до оптимизации -- вызов функции может повлечь побочные эффекты, поэтому не должен пропускаться.
В RU.C_CPP что ли спросить?..
|V|uxau/\
Reply to
Michael Ryazanov
3-Feb-05 01:19 Michael Ryazanov wrote to Oleksandr Redchuk:
MR> стандарт всё-таки совершенно невменяемо написан. MR> Hадо что-нибудь более правильное читать. Что именно?) Не знаю, я когда-то читал K&R, потом в стандарт только заглядывал. Написан он так же, как любой стандарт :-)
OR>> return uu + uu; MR> В данном случае в исходном тексте к переменной обращаются два раза. MR> Если считать, что по стандарту положено "читать каждый раз", то в коде всё MR> правильно. В моём же случае (++pwm == 1023) в тексте всего одно обращение А почему не два (плюс ещё одно на запись)? Один раз в тексте написано - ещё не означает одно обращение. По стандарту ++pwm эквивалентно pwm+=1, что в свою очередь эквивалентно pwm = pwm + 1. Дальше, (pwm=pwm+1) это "присваивающее выражение". ISO/IEC 9899:1999 aka C99, 6.5.16: "An assignment expression has the value of the left operand after the assignment" а не "value to be assigned to the left operand" Т.е. значением всего выражения является не "то, что будет присвоено", а "то, что содержится после присваивания", в лучшем случае "нечто, равное тому, что будет лежать в левом операнде после присваивания". В случае не-volatile переменной pwm её значение после присваивания равно значению правой части выражения, приведённое к типу левой части. И оптимизатор имеет право не зачитывать заново то, что "и так известно". А вот в случае volatile оно "неизвестно", после записи в volatile-объект чего бы то ни было в нём лежит всё, что угодно.
Но тут действительно есть один противный момент. Собственно присваивание является побочным явлением выражения (pwm=pwm+1) и это побочное явление обязано завершиться не позже следующей точки следования. А тут это - закрывающая круглая скобка if( ). До этого значение pwm+1 может быть не записано назад в pwm. Но что тогда сравнивать с 1023 ? Только что вычисленное значение pwm+1 вроде бы нельзя, так как оно не есть значением выражения (pwm=pwm+1) при volatile pwm. Мрак.
MR> At sequence MR> points, volatile objects are stable in the sense that previous evaluations MR> are complete and subsequent evaluations have not yet occurred.
MR> Только то, что между точками следованя volatile-объекты должны принять MR> состояние, соответствующее уже выполненным вычислениям, т.е. их значения MR> нужно записать. Нет, *это* требование - "записать всё" - работает для любых переменных. Для volatile должно закончиться всё, включая "закешированное" в регистрах или в памяти компилятора значение - предыдущие оценки закончились, следующие ещё не начались ( a = 5; if( a == 5) {} )
MR> Определение точки следования почему-то найти не удалось ";" "," конец выражения перед оператором && || и перед ? из ?: момент между вычислением аргументов функции и собственно её вызовом момент перед возвратом из функции ")" в if() switch() while() все три выражения в for(;;) разделены точками следования между собой и от кода до/после.
MR> операция сравнения, вроде как, ей не является. Вот в том-то и дело, что нет... Дурдом.
MR> *7.1.5.1 The cv-qualifiers* MR> <...> MR> 8 [Note: volatile is a hint to the implementation to avoid aggressive MR> optimization involving the object because the value of the object might MR> be MR> changed by means undetectable by an implementation. See 1.9 for detailed MR> semantics. In general, the semantics of volatile are intended to be the MR> same in MR> C++ as they are in C. ]
MR> Вот тут вот прошу обратить внимание на слово hint. Т.е. это всего лишь MR> намёк MR> избегать "агрессивной" оптимизации. Что считать "агрессивной", и насколько MR> важно её избегать, найти, опять же, не удалось. По моему мнению, в MR> первоначальном моём примере компилятор достоверно знал, что ничего с MR> этой переменной случиться не может, и вполне мог исключить повторное чтение. MR> Более того, он мог бы вообще разместить её в регистрах. Разве он имеет на это право для нелокальной переменной (не auto)?
В стандарте С сформулировано несколько не так. Там
An object that has volatile-qualified type may be modified in ways unknown to the implementation or have other unknown side effects. Therefore any expression referring to such an object shall be evaluated strictly according to the rules of the abstract machine, as described in 5.1.2.3. Furthermore, at every sequence point the value last stored in the object shall agree with that prescribed by the abstract machine, except as modified by the unknown factors mentioned previously.114) What constitutes an access to an object that has volatile-qualified type is implementation-defined.
114) A volatile declaration may be used to describe an object corresponding to a memory-mapped input/output port or an object accessed by an asynchronously interrupting function. Actions on objects so declared shall not be ''optimized out'' by an implementation or reordered except as permitted by the rules for evaluating expressions.
Т.е. в конечном итоге volatile-объект может измениться в любой момент по неизвестной причине. В конкретном случае, когда pwm - это точно не аппаратный регистр процессора (для уверенности компилятора в этом она должна лежать в том же файле, так как extern может после линковки оказаться аппаратным регистром), когда компилируемый код выполняется при запрещённых прерываниях (даже если это в обработчике прерывания e AVR - надо проверить, не выполнится ли раньше по дороге sei()), в этом конкретном случае компилятор может и "ссобразить", что volatile можно рассматривать как non-volatile, но не слишком ли многого хочется от компилятора?
MR> В RU.C_CPP что ли спросить?.. Да наверное. Нехорошее какое-то вышло сочетание проверки значения volatile-объекта с отсутствием точки следования.
wbr,
Reply to
Oleksandr Redchuk

ElectronDepot website is not affiliated with any of the manufacturers or service providers discussed here. All logos and trade names are the property of their respective owners.