|
Про IAR компилятор С |
|
|
|
Feb 6 2007, 14:45
|
Местный
  
Группа: Свой
Сообщений: 437
Регистрация: 23-04-05
Из: Таганрог
Пользователь №: 4 425

|
Здравствуйте. Раньше никогда на C под железо не писал, только на ассемблере. Но жизнь показывает, что для ARM писать все на asm не актуально. Начал смотреть, какой код генерирует компилятор. Вот для примера две строки на C: Код for(waiting_time = 1999; waiting_time >= 0; waiting_time--);
for(waiting_time = 0; waiting_time <= 2000; waiting_time++); Обе эти строки эквивалентны с точки зрения выполнения программы на С (т.е. будет 2000 шагов). Компилятор генерирует следующий код: \ main: \ ??main_0: \ 00000000 CF00A0E3 MOV R0,#+207 \ 00000004 700E80E3 ORR R0,R0,#0x700 \ 00000008 000000EA B ??main_1 \ ??main_2: \ 0000000C 010040E2 SUB R0,R0,#+1 \ ??main_1: \ 00000010 000050E3 CMP R0,#+0 \ 00000014 FCFFFF5A BPL ??main_2 19 20 //AT91C_BASE_PIOB->PIO_CODR = 1 << 22; 21 for(waiting_time = 0; waiting_time < 2000; waiting_time++) ; \ 00000018 0000A0E3 MOV R0,#+0 \ ??main_3: \ 0000001C 7D0E50E3 CMP R0,#+2000 \ 00000020 F6FFFFAA BGE ??main_0 \ 00000024 010080E2 ADD R0,R0,#+1 \ 00000028 FBFFFFEA B ??main_3 Мне кажется, что выделенная строка явно лишняя, так как флаг нулевого значения выставляется и в предыдущей команде. Во-вторых, при декременте (в первом варианте) есть лишний переход. Таким образом, эквивалентность циклов на С достигнута искуственно. Возможно, это сделано специально (а возможно, человек пока способен генерировать все же лучший код)? Возможно, это где-то описанно или отключается?
|
|
|
|
|
Feb 6 2007, 15:08
|
Участник

Группа: Участник
Сообщений: 71
Регистрация: 2-03-06
Из: Минск
Пользователь №: 14 879

|
Поиграйтесь с настройками оптимизации. При различном уровне - будет различный код.
|
|
|
|
|
Feb 8 2007, 15:26
|
Гуру
     
Группа: Свой
Сообщений: 3 020
Регистрация: 7-02-07
Пользователь №: 25 136

|
Забавно, а у меня комилятор в обоих случаях сгенерил одно и то же: Код for (i=0; i<2000; i++) __no_operation(); for (i=1999; i>=0; i--) __no_operation();
for (i=0; i<2000; i++) 000195C4 E3A00E7D MOV R0, #0x7D0 __no_operation(); 000195C8 E1A00000 NOP for (i=0; i<2000; i++) 000195CC E2500001 SUBS R0, R0, #0x1 for (i=0; i<2000; i++) 000195D0 1AFFFFFC BNE 0x0195C8 for (i=1999; i>=0; i--) 000195D4 E3A00E7D MOV R0, #0x7D0 __no_operation(); 000195D8 E1A00000 NOP for (i=1999; i>=0; i--) 000195DC E2500001 SUBS R0, R0, #0x1 for (i=1999; i>=0; i--) 000195E0 1AFFFFFC BNE 0x0195D8 Это IAR 4.40, С++, максимальная оптимизация на скорость. Надо сказать, этот компилятор оставляет хорошее впечатление. А вообще лучше не лезть в дела компилятора, а заниматься более интересными вещами, то есть написанием программ. Проверять сгенерированный код надо только тогда, когда не хватает памяти или скорости. Иначе не останется времени на отдых :-)
|
|
|
|
|
Feb 8 2007, 16:02
|
Местный
  
Группа: Свой
Сообщений: 437
Регистрация: 23-04-05
Из: Таганрог
Пользователь №: 4 425

|
Цитата(scifi @ Feb 8 2007, 15:26)  Примерно о таком коде я и мечтал, если бы еще и NOP выкинуть... Если убрать пустую операцию, то весь цикл попадает под нож оптимизатора при максимальной оптимизации, во всех других режимах оптимизаци цикл сохраняет первозданное уродство с тремя переходами. Вопрос в том, что при желании сделать например, функцию Код SimpleDelay (long d) { for (;d!=0;d--);
} Этот самый Delay будет прямо зависить от режима оптимизации, и вообще улетит при максимальной. Следующий вопрос, а как-нибудь вообще можно объявить функцию на asm как inline? Или сделать макрос на asm для использования в C-коде?
|
|
|
|
|
Feb 8 2007, 17:28
|

Гуру
     
Группа: Модераторы
Сообщений: 8 455
Регистрация: 15-05-06
Из: Рига, Латвия
Пользователь №: 17 095

|
Цитата(Dopler @ Feb 8 2007, 15:02)  Если убрать пустую операцию, то весь цикл попадает под нож оптимизатора при максимальной оптимизации Если писать правильно, то не попадает. Цитата(Dopler @ Feb 8 2007, 15:02)  Вопрос в том, что при желании сделать например, функцию Код SimpleDelay (long d) { for (;d!=0;d--); } Этот самый Delay будет прямо зависить от режима оптимизации, и вообще улетит при максимальной. А если так: Код SimpleDelay (long volatile d) { for (;d!=0;d--); } При разном уровне действительно возможно различное время выполнения, но можно ведь для этой конкретной функции выставить желаемый уровень оптимизации с помощью #pragma. Цитата(Dopler @ Feb 8 2007, 15:02)  Следующий вопрос, а как-нибудь вообще можно объявить функцию на asm как inline? Или сделать макрос на asm для использования в C-коде? В gcc вроде да, в IAR - точно нет. Про остальные не знаю.
--------------------
На любой вопрос даю любой ответ"Write code that is guaranteed to work, not code that doesn’t seem to break" ( C++ FAQ)
|
|
|
|
|
Feb 8 2007, 22:21
|
Местный
  
Группа: Свой
Сообщений: 437
Регистрация: 23-04-05
Из: Таганрог
Пользователь №: 4 425

|
Цитата(scifi @ Feb 8 2007, 20:49)  Попробуйте так:
#define DELAY(N) __asm("mov R0,#" #N "\nSUBS R0,R0,#1\nBNE .-4"); И при использовании такого макроса компилятор гарантированно не будет использовать R0 в своих целях? Что-то я ничего внятного в документации IAR по поводу INLINE ASSEMBLER не нашел, кроме того, что его лучше избегать.
|
|
|
|
|
Feb 9 2007, 12:36
|
Местный
  
Группа: Свой
Сообщений: 437
Регистрация: 23-04-05
Из: Таганрог
Пользователь №: 4 425

|
Цитата(scifi @ Feb 9 2007, 11:37)  Если я правильно понял, нужно получить малые задержки. Предлагаю для этих целей написать функцию на ассемблере и вызывать её из Си. Просто для совсем маленьких функций накладные расходы по вызову и передаче параметров неприятны. Если бы можно было бы функцию на asm сделать inline, было бы здорово.
|
|
|
|
|
Feb 9 2007, 13:13
|

Гуру
     
Группа: Свой
Сообщений: 13 372
Регистрация: 27-11-04
Из: Riga, Latvia
Пользователь №: 1 244

|
Цитата(scifi @ Feb 9 2007, 10:37)  Время выполнения кода зависит от модели процессора и задержек при доступе к памяти. Для процессора ARM7TDMI времена выполнения инструкций указаны в "ARM7TDMI Technical Reference Manual": И наличия MAM и наличия Кэш и эффективности работы оных а еще DMA захватит шину  . Короче, лучше навсегда выкиньте из головы желание узнать для более-менее современых контроллеров "точное" время исполнения чего-либо. Цитата(Dopler @ Feb 9 2007, 12:02)  Так #pragma optimize не позволяет повысить уровень оптимизации, что это за лажа такая? Изъясняйтесь конкретнее.
--------------------
Feci, quod potui, faciant meliora potentes
|
|
|
|
|
Feb 9 2007, 14:40
|
Местный
  
Группа: Свой
Сообщений: 437
Регистрация: 23-04-05
Из: Таганрог
Пользователь №: 4 425

|
Цитата(zltigo @ Feb 9 2007, 13:13)  Цитата(Dopler @ Feb 9 2007, 12:02)  Так #pragma optimize не позволяет повысить уровень оптимизации, что это за лажа такая?
Изъясняйтесь конкретнее. Я имел в виду, что любимой избранной функции нельзя задать жестко уровень оптимизации. Т.е. нельзя написать какую-нибудь простенькую функцию, определить для нее максимальную оптимизацию и наслаждаться, при условии, что остальной проект выполнен без оптимизации.
|
|
|
|
|
Feb 9 2007, 15:09
|

Гуру
     
Группа: Свой
Сообщений: 13 372
Регистрация: 27-11-04
Из: Riga, Latvia
Пользователь №: 1 244

|
Цитата(Dopler @ Feb 9 2007, 13:40)  Я имел в виду, что любимой избранной функции нельзя задать жестко уровень оптимизации. Т.е. нельзя написать какую-нибудь простенькую функцию, определить для нее максимальную оптимизацию и наслаждаться, при условии, что остальной проект выполнен без оптимизации. 1. Никто не мешает для этого конкретного файла задавать собственные критерии оптимизации ( или вообще не задавать) и все разруливать прагмами. 2. А вообще все "простенькие" функции в отдельный файл и тогда как угодно и как нужно и без прагм. 3. А какого черта проекты вообще без оптимизации собирать - для того что-бы написанный левой ногой код как-то работал? За десятки лет на добром десятке компиляторов никогда не делал ничего без оптимизации. Обычно отдельные куски тупо зажимаются по размеру. Большая часть тупо по максимальной скорости и некоторые критические функции - тонкой индивидуальной подстройкой по скорости. Куски кода с разными требованиями к оптимизации в один файл не сваливаются.
--------------------
Feci, quod potui, faciant meliora potentes
|
|
|
|
|
Feb 9 2007, 23:21
|
Местный
  
Группа: Свой
Сообщений: 437
Регистрация: 23-04-05
Из: Таганрог
Пользователь №: 4 425

|
Вернемся к поиску оптимального кода. Приведенный выше цикл с различными уровнями оптимизации: Код // Исходный цикл for(d = 2000; d !=0; d--) __no_operation(); Код Оптимизации нет 22 for(d = 2000; d !=0; d--) \ 0000000A FA21 MOVS R1,#+250 \ 0000000C C900 LSLS R1,R1,#+3 ;; #+2000 \ 0000000E 0800 MOVS R0,R1 \ ??main_2: \ 00000010 0028 CMP R0,#+0 \ 00000012 02D0 BEQ ??main_3 23 __no_operation(); \ 00000014 C046 Nop \ 00000016 401E SUBS R0,R0,#+1 \ 00000018 FAE7 B ??main_2 Код С оптимизацией 22 for(d = 2000; d !=0; d--) \ 00000010 0C00 MOVS R4,R1 23 __no_operation(); \ ??main_2: \ 00000012 C046 Nop \ 00000014 641E SUBS R4,R4,#+1 \ 00000016 FCD1 BNE ??main_2 Очевидно, что второй код предпочтительнее, причем я на asm написал бы именно так. Единственное, что напрягает - это явно лишний Nop, попробуем от него избавится, сохраняя уровень оптимизации. Код Посто закоментировал Nop, и весь цикл улетел, попав под нож оптимизатора. for(d = 2000; d !=0; d--); // __no_operation(); Пользуемся советом Сергея, делаем d volatile Код 17 int volatile d; 20 for(d = 2000; d !=0; d--); \ 00000012 0091 STR R1,[SP, #+0] \ 00000014 02E0 B ??main_2 \ ??main_3: \ 00000016 009C LDR R4,[SP, #+0] \ 00000018 641E SUBS R4,R4,#+1 \ 0000001A 0094 STR R4,[SP, #+0] \ ??main_2: \ 0000001C 009C LDR R4,[SP, #+0] \ 0000001E 002C CMP R4,#+0 \ 00000020 F9D1 BNE ??main_3 И видим, что весь цикл, где используется d перестает оптимизироваться, более того, d из регистров попадает прямиком в стек, что еще больше раздувает код, отсюда делаю вывод, что без явных причин использовать volatile не стоит. Поэкспериментировав с различными галочками в оптимизаторе, убедился что без Code Motion цикл не пропадает, но все равно получить код как во втором примере, только без Nop не удалось.
|
|
|
|
|
Feb 20 2007, 00:07
|
Знающий
   
Группа: Validating
Сообщений: 838
Регистрация: 31-01-05
Пользователь №: 2 317

|
Вот что у меня получилось IAR 4.41 оптимизция полная по скорости Код void delay(long tmp) { while(--tmp); } результат Код In segment CODE, align 4, keep-with-next void delay(long tmp) { while(--tmp); delay: ??delay_0: 00000000 010050E2 SUBS R0,R0,#+1 00000004 FDFFFF1A BNE ??delay_0 } 00000008 1EFF2FE1 BX LR ;; return при этом он пытается ее инлайнить всегда, но от этого можно легко избавится при желании
|
|
|
|
|
Mar 19 2008, 07:03
|

Местный
  
Группа: Свой
Сообщений: 343
Регистрация: 24-01-07
Из: Новосибирск
Пользователь №: 24 714

|
дабы не открывать новую ветку... Помогите понять, зачем так сложно: (time описана как unsigned long) Код // 80 time++; LDI R30, time LDI R31, 0 LD R16, Z LDD R17, Z+1 LDD R18, Z+2 LDD R19, Z+3 SUBI R16, 255 SBCI R17, 255 SBCI R18, 255 SBCI R19, 255 ST Z, R16 STD Z+1, R17 STD Z+2, R18 STD Z+3, R19
|
|
|
|
|
Mar 19 2008, 08:37
|

Беспросветный оптимист
     
Группа: Свой
Сообщений: 4 640
Регистрация: 26-12-07
Из: Н.Новгород
Пользователь №: 33 646

|
Цитата(Dopler @ Feb 9 2007, 15:36)  Просто для совсем маленьких функций накладные расходы по вызову и передаче параметров неприятны. Если бы можно было бы функцию на asm сделать inline, было бы здорово. А функцию на си можно инлайн объявить? Если да, то что мешает внутри написать asm("something asm text"); Я вот чё-то только __no_inline нашёл, то есть наоборот, запрет инлайна
--------------------
Программирование делится на системное и бессистемное. ©Моё :) — а для кого-то БГ — это Bill Gilbert =)
|
|
|
|
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|