|
Искусство программирования на Си/си++, Или как правильно объяснить компилятору... |
|
|
|
Jan 17 2012, 02:29
|

Познающий...
     
Группа: Свой
Сообщений: 2 963
Регистрация: 1-09-05
Из: г. Иркутск
Пользователь №: 8 125

|
Здравствуйте, уважаемые коллеги! Вчера глянул в листинг компилятора (arm-kgp за 2009 год) и озадачился. При том, что комплятору дан ключ -Os. Вроде бы из простых функций, получается довольно "пухлый" код на асме. Вот например (вначале исходник на Си, затем листинг) CODE /* This function gets and sends a char IN: nothing
OUT: received char */ char getChar() { char tmp;
while( !( U0LSR & ( 1UL << 0 ) ) ); tmp = U0RBR; putChar( tmp );
return tmp; }
CODE 00000788 <getChar>: 788: e59f202c ldr r2, [pc, #44]; 7bc <getChar+0x34> 78c: e5923014 ldr r3, [r2, #20] 790: e3130001 tst r3, #1; 0x1 794: e59f3020 ldr r3, [pc, #32]; 7bc <getChar+0x34> 798: 0afffffb beq 78c <getChar+0x4> 79c: e5930000 ldr r0, [r3] 7a0: e20000ff and r0, r0, #255; 0xff 7a4: e5932014 ldr r2, [r3, #20] 7a8: e3120020 tst r2, #32; 0x20 7ac: 0afffffc beq 7a4 <getChar+0x1c> 7b0: e59f3004 ldr r3, [pc, #4]; 7bc <getChar+0x34> 7b4: e5830000 str r0, [r3] 7b8: e12fff1e bx lr 7bc: e000c000 .word 0xe000c000 или вот CODE int64_t getNum( F_BOOT_RESULT* flag ) { char c; int64_t result = 0; uint32_t negFlag = 0; uint32_t hexFlag = 0;
*flag = F_BOOT_NO_RESULT;
while( 1 ) { c = getChar();
if( (c == '\r') || (c == '\n')) { break; }
if( c == '-' ) { negFlag = 1; continue; }
if( c == 'x' ) { hexFlag = 1; continue; }
if( hexFlag ) result *= 16; else result *= 10;
if( hexFlag ) result += hexToDec( c ); else result += c - 0x30;
*flag = F_BOOT_OK; }
if( negFlag ) { result *= -1; }
return result; } CODE 00000864 <getNum>: 864: e59f2104 ldr r2, [pc, #260]; 970 <getNum+0x10c> 868: e92d0ff0 push {r4, r5, r6, r7, r8, r9, sl, fp} 86c: e3a03002 mov r3, #2; 0x2 870: e3a05000 mov r5, #0; 0x0 874: e5803000 str r3, [r0] 878: e1a08005 mov r8, r5 87c: e3a03000 mov r3, #0; 0x0 880: e3a04000 mov r4, #0; 0x0 884: e1a09002 mov r9, r2 888: e3a0a00a mov sl, #10; 0xa 88c: e5921014 ldr r1, [r2, #20] 890: e3110001 tst r1, #1; 0x1 894: 0afffffc beq 88c <getNum+0x28> 898: e5921000 ldr r1, [r2] 89c: e1a0600b mov r6, fp 8a0: e20110ff and r1, r1, #255; 0xff 8a4: e1a0700c mov r7, ip 8a8: e592c014 ldr ip, [r2, #20] 8ac: e31c0020 tst ip, #32; 0x20 8b0: 0afffffc beq 8a8 <getNum+0x44> 8b4: e351000d cmp r1, #13; 0xd 8b8: 1351000a cmpne r1, #10; 0xa 8bc: e1a0b006 mov fp, r6 8c0: e1a0c007 mov ip, r7 8c4: e5891000 str r1, [r9] 8c8: 0a000020 beq 950 <getNum+0xec> 8cc: e351002d cmp r1, #45; 0x2d 8d0: 03a08001 moveq r8, #1; 0x1 8d4: 0affffec beq 88c <getNum+0x28> 8d8: e3510078 cmp r1, #120; 0x78 8dc: 03a05001 moveq r5, #1; 0x1 8e0: 0affffe9 beq 88c <getNum+0x28> 8e4: e3550000 cmp r5, #0; 0x0 8e8: 0a000003 beq 8fc <getNum+0x98> 8ec: e3510039 cmp r1, #57; 0x39 8f0: 92411030 subls r1, r1, #48; 0x30 8f4: 9a000009 bls 920 <getNum+0xbc> 8f8: ea000005 b 914 <getNum+0xb0> 8fc: e0876a93 umull r6, r7, r3, sl 900: e027749a mla r7, sl, r4, r7 904: e2411030 sub r1, r1, #48; 0x30 908: e0963001 adds r3, r6, r1 90c: e0a74fc1 adc r4, r7, r1, asr #31 910: ea00000b b 944 <getNum+0xe0> 914: e3510041 cmp r1, #65; 0x41 918: 92411037 subls r1, r1, #55; 0x37 91c: 82411057 subhi r1, r1, #87; 0x57 920: e1a06001 mov r6, r1 924: e1a07fc6 asr r7, r6, #31 928: e1a01204 lsl r1, r4, #4 92c: e1811e23 orr r1, r1, r3, lsr #28 930: e1a0c001 mov ip, r1 934: e1a01203 lsl r1, r3, #4 938: e0963001 adds r3, r6, r1 93c: e1a0b001 mov fp, r1 940: e0a7400c adc r4, r7, ip 944: e3a01000 mov r1, #0; 0x0 948: e5801000 str r1, [r0] 94c: eaffffce b 88c <getNum+0x28> 950: e3580000 cmp r8, #0; 0x0 954: 0a000001 beq 960 <getNum+0xfc> 958: e2733000 rsbs r3, r3, #0; 0x0 95c: e2e44000 rsc r4, r4, #0; 0x0 960: e1a01004 mov r1, r4 964: e1a00003 mov r0, r3 968: e8bd0ff0 pop {r4, r5, r6, r7, r8, r9, sl, fp} 96c: e12fff1e bx lr 970: e000c000 .word 0xe000c000 Я плохо понимаю язык ассемблера для ARM7TDMI-S, но мне кажется, что слишком много кода... Вопрос трудно поставить... Но похоже, что я плохо объясняю, что нужно сделать компилятору. Нет, код работает, есть "косметические" ошибки, но поставленный алгоритм выполняется. Дело в другом. Компялтор раздувает код (или я ошибаюсь?). Вот я и озадачился вопросом, что я делаю не правильно? Может быть не те типы данных использую? Конструкции языка? Или исходный код на Си нужно выбросить, и написать более компактный, более красивый? В общем вопрос пока пространственный... его можно было и не задавать, ведь 512К флеши есть, но, тем не менее... Заранее спасибо за все ответы!
--------------------
Выбор.
|
|
|
|
|
Jan 17 2012, 04:27
|
Частый гость
 
Группа: Свой
Сообщений: 93
Регистрация: 13-01-12
Из: Гатчина
Пользователь №: 69 333

|
Не пытайтесь заменить компилятор, особенно с доступной вам памятью. Вы можете переписать эту функцию более оптимально, но что делать, когда проект разрастется на 10 тыс. строк? PS: Т.к. arm 32 битный, то для скорости, я стараюсь использовать только 32 битные переменные (даже там, где нужен всего байт). PPS: Если интересно, можете почитать эту статью.
|
|
|
|
|
Jan 17 2012, 04:56
|
Частый гость
 
Группа: Участник
Сообщений: 125
Регистрация: 29-05-11
Из: Nizhny Novgorod, Russian Federation
Пользователь №: 65 337

|
Цитата(sparcmaster @ Jan 17 2012, 08:27)  PS: Т.к. arm 32 битный, то для скорости, я стараюсь использовать только 32 битные переменные (даже там, где нужен всего байт). скорость у вас сильно увеличилась ? дело не в том, какие переменные, а как они выравнены в памяти
Сообщение отредактировал am1808 - Jan 17 2012, 04:56
|
|
|
|
|
Jan 17 2012, 05:01
|
Частый гость
 
Группа: Участник
Сообщений: 125
Регистрация: 29-05-11
Из: Nizhny Novgorod, Russian Federation
Пользователь №: 65 337

|
Цитата(demiurg_spb @ Jan 17 2012, 08:59)  Дело и в том и другом. ошибаетесь)
|
|
|
|
|
Jan 17 2012, 05:04
|
Частый гость
 
Группа: Свой
Сообщений: 93
Регистрация: 13-01-12
Из: Гатчина
Пользователь №: 69 333

|
Цитата(am1808 @ Jan 17 2012, 08:56)  скорость у вас сильно увеличилась ?  Для меня достаточно. Цитата(am1808 @ Jan 17 2012, 08:56)  дело не в том, какие переменные, а как они выравнены в памяти Ну да, ну да. Разрядность архитектуры совсем не причем, главное как переменные "выравнены в памяти"...
|
|
|
|
|
Jan 17 2012, 05:08
|
Частый гость
 
Группа: Участник
Сообщений: 125
Регистрация: 29-05-11
Из: Nizhny Novgorod, Russian Federation
Пользователь №: 65 337

|
Цитата(sparcmaster @ Jan 17 2012, 09:04)  Для меня достаточно. камень не подлетает у вас от такой скорости?
|
|
|
|
|
Jan 17 2012, 05:08
|

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

|
Цитата(am1808 @ Jan 17 2012, 08:01)  ошибаетесь) Хорошо. Сейчас проверим на Кейле под cortex-m3: Код uint8_t spi_transfer(uint8_t data) { // for (int i=0; i<8; i++) // Размер программы 18440 for (uint8_t i=0; i<8; i++) // Размер программы 18444 { SPI_SCK(0); SPI_MOSI(data & (1<<7)); // write data at the begin of cycle spi_delay();
SPI_SCK(1); spi_delay(); data = (data<<1) | SPI_MISO(); // read data at the end of cycle }
return data; } Достаточно? Или показать ещё и асм-листинг? А если так: Код uint_fast8_t spi_transfer(uint_fast8_t data) {...} // Размер программы 18336 uint8_t spi_transfer(uint8_t data) {...} // Размер программы 18440 Не спроста?
--------------------
“Будьте внимательны к своим мыслям - они начало поступков” (Лао-Цзы)
|
|
|
|
|
Jan 17 2012, 05:09
|

фанат дивана
     
Группа: Свой
Сообщений: 3 387
Регистрация: 9-08-07
Из: Уфа
Пользователь №: 29 684

|
Цитата(haker_fox @ Jan 17 2012, 08:29)  Вопрос трудно поставить... Но похоже, что я плохо объясняю, что нужно сделать компилятору. Посмотрел, вполне нормальный код (первый пример). Единственное, что приходит в голову - если U0LSR и U0RBR рядом, то можно дать понять это компилятору, объединив их в структуру, и адресуя их указателем на эту структуру. Тогда базовый адрес будет грузиться всего один раз. А в остальном - нормальный код, руками выйдет практически такой же. ЗЫ. Попробуйте -O2, с ним вроде получше получается местами.
--------------------
Если бы я знал, что такое электричество...
|
|
|
|
|
Jan 17 2012, 05:21
|
Частый гость
 
Группа: Участник
Сообщений: 125
Регистрация: 29-05-11
Из: Nizhny Novgorod, Russian Federation
Пользователь №: 65 337

|
Цитата(demiurg_spb @ Jan 17 2012, 09:08)  Хорошо. Сейчас проверим на Кейле под cortex-m3: Код uint8_t spi_transfer(uint8_t data) { // for (int i=0; i<8; i++) // Размер программы 18440 for (uint8_t i=0; i<8; i++) // Размер программы 18444 { SPI_SCK(0); SPI_MOSI(data & (1<<7)); // write data at the begin of cycle spi_delay();
SPI_SCK(1); spi_delay(); data = (data<<1) | SPI_MISO(); // read data at the end of cycle }
return data; } Достаточно? Или показать ещё и асм-листинг? А если так: Код uint_fast8_t spi_transfer(uint_fast8_t data) {...} то размер 18336. Не спроста? и как это на скорость выполнения повлияло? когда уменьшился лишь сегмент данных я не знаком с кейлом, попрошу показать, как затайпдефайнино uint_fast8_t
Сообщение отредактировал am1808 - Jan 17 2012, 05:28
|
|
|
|
|
Jan 17 2012, 05:29
|

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

|
Цитата(am1808 @ Jan 17 2012, 08:21)  и как это на скорость выполнения повлияло? когда уменьшился лишь сегмент данных Прямо пропорционально: Код |L5.8| тело цикла 00000c 1c49 ADDS r1,r1,#1 ;25 00000e 2908 CMP r1,#8 ;25 000010 d3fa BCC |L5.8| Код |L5.8| тело цикла 00000c 1c49 ADDS r1,r1,#1 ;25 00000e b2c9 UXTB r1,r1 ;25 000010 2908 CMP r1,#8 ;25 000012 d3f9 BCC |L5.8| На каждом шаге цикла проигрываем на один такт.
--------------------
“Будьте внимательны к своим мыслям - они начало поступков” (Лао-Цзы)
|
|
|
|
|
Jan 17 2012, 05:33
|
Местный
  
Группа: Участник
Сообщений: 351
Регистрация: 5-04-05
Пользователь №: 3 874

|
Цитата(haker_fox @ Jan 17 2012, 05:29)  что я делаю не правильно? всё правильно, не бери в голову
|
|
|
|
|
Jan 17 2012, 05:36
|

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

|
Цитата(am1808 @ Jan 17 2012, 08:21)  я не знаком с кейлом, попрошу показать, как затайпдефайнино uint_fast8_t Это не важно кейл или gcc или iar. Загляните в stdint.h для любого 32-битного ARM-компилятора и везде будет примерно одно: Код typedef unsigned int uint_fast8_t;
--------------------
“Будьте внимательны к своим мыслям - они начало поступков” (Лао-Цзы)
|
|
|
|
|
Jan 17 2012, 05:36
|
Частый гость
 
Группа: Участник
Сообщений: 125
Регистрация: 29-05-11
Из: Nizhny Novgorod, Russian Federation
Пользователь №: 65 337

|
Цитата(demiurg_spb @ Jan 17 2012, 09:29)  На каждом шаге цикла проигрываем на один такт. оптимизация выключена? какая версия ядра arm?
Сообщение отредактировал am1808 - Jan 17 2012, 05:44
|
|
|
|
|
Jan 17 2012, 05:44
|

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

|
Цитата(am1808 @ Jan 17 2012, 08:36)  оптимизация выключена? Конечно. Чего вы юлите я не пойму? Для всех кроме вас очевидно что разрядность как переменных так и самого таргета влияют на скорость выполнения программ. Точка. Собственно для сглаживания этого эффекта при смене архитектуры и были придуманы типы из stdint... Цитата какая версия ядра arm? Да ведь вроде ясно сказал ещё в сообщении №8 что cortex-m3.
--------------------
“Будьте внимательны к своим мыслям - они начало поступков” (Лао-Цзы)
|
|
|
|
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|