реклама на сайте
подробности

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


Познающий...
******

Группа: Свой
Сообщений: 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К флеши есть, но, тем не менее...
Заранее спасибо за все ответы!


--------------------
Выбор.
Go to the top of the page
 
+Quote Post
 
Start new topic
Ответов
sparcmaster
сообщение Jan 17 2012, 04:27
Сообщение #2


Частый гость
**

Группа: Свой
Сообщений: 93
Регистрация: 13-01-12
Из: Гатчина
Пользователь №: 69 333



Не пытайтесь заменить компилятор, особенно с доступной вам памятью. Вы можете переписать эту функцию более оптимально, но что делать, когда проект разрастется на 10 тыс. строк?

PS: Т.к. arm 32 битный, то для скорости, я стараюсь использовать только 32 битные переменные (даже там, где нужен всего байт).
PPS: Если интересно, можете почитать эту статью.
Go to the top of the page
 
+Quote Post
am1808
сообщение Jan 17 2012, 04:56
Сообщение #3


Частый гость
**

Группа: Участник
Сообщений: 125
Регистрация: 29-05-11
Из: Nizhny Novgorod, Russian Federation
Пользователь №: 65 337



Цитата(sparcmaster @ Jan 17 2012, 08:27) *
PS: Т.к. arm 32 битный, то для скорости, я стараюсь использовать только 32 битные переменные (даже там, где нужен всего байт).

скорость у вас сильно увеличилась ? biggrin.gif

дело не в том, какие переменные, а как они выравнены в памяти

Сообщение отредактировал am1808 - Jan 17 2012, 04:56
Go to the top of the page
 
+Quote Post
demiurg_spb
сообщение Jan 17 2012, 04:59
Сообщение #4


неотягощённый злом
******

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



Цитата(am1808 @ Jan 17 2012, 07:56) *
дело не в том, какие переменные, а как они выравнены в памяти
Дело и в том и другом.


--------------------
“Будьте внимательны к своим мыслям - они начало поступков” (Лао-Цзы)
Go to the top of the page
 
+Quote Post
am1808
сообщение Jan 17 2012, 05:01
Сообщение #5


Частый гость
**

Группа: Участник
Сообщений: 125
Регистрация: 29-05-11
Из: Nizhny Novgorod, Russian Federation
Пользователь №: 65 337



Цитата(demiurg_spb @ Jan 17 2012, 08:59) *
Дело и в том и другом.

ошибаетесь)
Go to the top of the page
 
+Quote Post
demiurg_spb
сообщение Jan 17 2012, 05:08
Сообщение #6


неотягощённый злом
******

Группа: Свой
Сообщений: 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
Не спроста?


--------------------
“Будьте внимательны к своим мыслям - они начало поступков” (Лао-Цзы)
Go to the top of the page
 
+Quote Post
am1808
сообщение Jan 17 2012, 05:21
Сообщение #7


Частый гость
**

Группа: Участник
Сообщений: 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
Go to the top of the page
 
+Quote Post
demiurg_spb
сообщение Jan 17 2012, 05:29
Сообщение #8


неотягощённый злом
******

Группа: Свой
Сообщений: 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|

На каждом шаге цикла проигрываем на один такт.


--------------------
“Будьте внимательны к своим мыслям - они начало поступков” (Лао-Цзы)
Go to the top of the page
 
+Quote Post
am1808
сообщение Jan 17 2012, 05:36
Сообщение #9


Частый гость
**

Группа: Участник
Сообщений: 125
Регистрация: 29-05-11
Из: Nizhny Novgorod, Russian Federation
Пользователь №: 65 337



Цитата(demiurg_spb @ Jan 17 2012, 09:29) *
На каждом шаге цикла проигрываем на один такт.

оптимизация выключена?
какая версия ядра arm?


Сообщение отредактировал am1808 - Jan 17 2012, 05:44
Go to the top of the page
 
+Quote Post
demiurg_spb
сообщение Jan 17 2012, 05:44
Сообщение #10


неотягощённый злом
******

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



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


--------------------
“Будьте внимательны к своим мыслям - они начало поступков” (Лао-Цзы)
Go to the top of the page
 
+Quote Post
am1808
сообщение Jan 17 2012, 05:51
Сообщение #11


Частый гость
**

Группа: Участник
Сообщений: 125
Регистрация: 29-05-11
Из: Nizhny Novgorod, Russian Federation
Пользователь №: 65 337



Цитата(demiurg_spb @ Jan 17 2012, 09:44) *
Конечно. Чего вы юлите я не пойму?
Для всех кроме вас очевидно что разрядность переменных влияет на скорость выполнения программ. Точка.

разрядность используемых в вашем примере выше никак не влияет,
влияет unsigned или signed переменная.
компилятор явно приводит в случае uint_fast8_t к unsigned, что и приводит к лишней операции, за счет цикла кол-во операций увеличивается в вашем примере на 8 тактов.
это просто конкретная фича компилятора, и в принципе, другой компилятор может явно не делать
Код
UXTB     r1,r1


так что зря вы так, в приведенном вашем примере не влияет РАЗРЯДНОСТЬ, выше я объяснил почему.
так что ваш пример плох и не подтверждает ваше высказывание выше
Go to the top of the page
 
+Quote Post
sasamy
сообщение Jan 17 2012, 08:07
Сообщение #12


Знающий
****

Группа: Участник
Сообщений: 783
Регистрация: 22-11-08
Пользователь №: 41 858



Цитата(am1808 @ Jan 17 2012, 09:51) *
так что ваш пример плох и не подтверждает ваше высказывание выше


У современных ARM нет 8/16 битных регистров и компилятору приходится эмулировать их, в частности переполнение. В некоторых случаях компилятор сглаживает этот факт и не генерирует лишнего кода - но все равно рекомендуется локальные переменные, передаваемые и возвращаемые данные в ф-ции делать соразмерными с регистрами, кроме тех случаев когда нужно именно такое поведение - 8 или 16 битная переменная или когда переменные глобальные (для экономии памяти).
Go to the top of the page
 
+Quote Post
am1808
сообщение Jan 17 2012, 08:26
Сообщение #13


Частый гость
**

Группа: Участник
Сообщений: 125
Регистрация: 29-05-11
Из: Nizhny Novgorod, Russian Federation
Пользователь №: 65 337



Цитата(sasamy @ Jan 17 2012, 12:07) *
У современных ARM нет 8/16 битных регистров и компилятору приходится эмулировать их, в частности переполнение. В некоторых случаях компилятор сглаживает этот факт и не генерирует лишнего кода - но все равно рекомендуется локальные переменные, передаваемые и возвращаемые данные в ф-ции делать соразмерными с регистрами, кроме тех случаев когда нужно именно такое поведение - 8 или 16 битная переменная или когда переменные глобальные (для экономии памяти).

на сколько мне известно, все локальные переменные в отличии от 32b, выравниваются по word, т.е. 4 байта.
то, что кейл в вышеприведенном примере добавляет инструкцию, это причиндалы самого компилятора, который таким образом пытается занулить память, которая выделилась по причине выравнивания. т.е. получается, что кейл лишний раз себя как бы страхует
Go to the top of the page
 
+Quote Post
ViKo
сообщение Jan 17 2012, 08:30
Сообщение #14


Универсальный солдатик
******

Группа: Модераторы
Сообщений: 8 634
Регистрация: 1-11-05
Из: Минск
Пользователь №: 10 362



Цитата(am1808 @ Jan 17 2012, 10:26) *
на сколько мне известно, все локальные переменные в отличии от 32b, выравниваются по word, т.е. 4 байта.
то, что кейл в вышеприведенном примере добавляет инструкцию, это причиндалы самого компилятора, который таким образом пытается занулить память, которая выделилась по причине выравнивания. т.е. получается, что кейл лишний раз себя как бы страхует

локальные переменные в регистрах хранятся, пока место есть
Go to the top of the page
 
+Quote Post

Сообщений в этой теме
- haker_fox   Искусство программирования на Си/си++   Jan 17 2012, 02:29
|||- - demiurg_spb   Вам что в лоб что по лбу. Честное слово! Прове...   Jan 17 2012, 05:55
||||- - sparcmaster   Цитата(demiurg_spb @ Jan 17 2012, 09:55) ...   Jan 17 2012, 06:02
||||- - am1808   Цитата(demiurg_spb @ Jan 17 2012, 09:55) ...   Jan 17 2012, 06:03
||||- - demiurg_spb   И снова здравствуйте! Все варианты исчерпали? ...   Jan 17 2012, 06:12
||||- - am1808   Цитата(ViKo @ Jan 17 2012, 12:30) локальн...   Jan 17 2012, 08:39
|||- - sasamy   Цитата(am1808 @ Jan 17 2012, 12:26) то, ч...   Jan 17 2012, 10:17
||- - demiurg_spb   Цитата(am1808 @ Jan 17 2012, 08:21) я не ...   Jan 17 2012, 05:36
|- - sparcmaster   Цитата(am1808 @ Jan 17 2012, 08:56) скоро...   Jan 17 2012, 05:04
|- - am1808   Цитата(sparcmaster @ Jan 17 2012, 09:04) ...   Jan 17 2012, 05:08
- - AHTOXA   Цитата(haker_fox @ Jan 17 2012, 08:29) Во...   Jan 17 2012, 05:09
- - Idle   Цитата(haker_fox @ Jan 17 2012, 05:29) чт...   Jan 17 2012, 05:33
- - haker_fox   QUOTE (sparcmaster @ Jan 17 2012, 12:27) ...   Jan 17 2012, 05:56
- - ViKo   В закромах была книжка Arm System Developer's ...   Jan 17 2012, 08:21
- - haker_fox   Скачал материалы, рекомендованные к прочтению. Спа...   Jan 18 2012, 11:31


Reply to this topicStart new topic
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0

 


RSS Текстовая версия Сейчас: 31st July 2025 - 17:51
Рейтинг@Mail.ru


Страница сгенерированна за 0.02105 секунд с 7
ELECTRONIX ©2004-2016