|
|
  |
Рассуждения о _regvar и register, Вынесено из темы "Глюки компилятора.." |
|
|
|
Jan 26 2008, 21:17
|
Местный
  
Группа: Свой
Сообщений: 462
Регистрация: 26-06-07
Пользователь №: 28 723

|
Цитата(Qwertty @ Jan 27 2008, 00:06)  Это просто я тогда не понял, о чем идет речь. Вот и спросил о register и IAR. Я тоже сижу на ГЦЦ, и проблем с размещением в регистрах не испытывал. Правда номер регистра жестко не задаю. В документации к avr-libs указывается, что компилятор не контролирует конфликты в случае жесткого указания номера регистра. Документированные грабли и не грабли вовсе, а так, особенности реализации  Вообще говоря, не понимаю, зачем вообще при написании кода самим создавать себе проблемы - жестко указывать номера регистров для размещения переменных компилятору ? Выгоды практически никакой, а переносимость и надежность могут конкретно пострадать. Можно понять, если регистр особенный и с этой переменной надо что-то специфичное делать, но такой кусочек кода надо бы оформлять маленькой препроцессорной вставочкой/подпрограммкой, и подробно комментить.
|
|
|
|
|
Jan 26 2008, 21:19
|
дятел
    
Группа: Свой
Сообщений: 1 681
Регистрация: 13-05-06
Из: Питер
Пользователь №: 17 065

|
Цитата(Qwertty @ Jan 27 2008, 00:06)  Правда номер регистра жестко не задаю. В документации к avr-libs указывается, что компилятор не контролирует конфликты в случае жесткого указания номера регистра. Скажем так(насколько я ничего не понимаю...), R2-R8 можно почти всегда безболезненно, R9-R15 с контролем листинга, регистр без указания месторасположения почти не имеет смысла... по последнему пункту не уверен точно, тк в своих прогах предпочитаю месторасположение указывать явно... ЗЫ. конечно R2-R7 и R8-R15 ...
|
|
|
|
|
Jan 26 2008, 21:22
|
Знающий
   
Группа: Участник
Сообщений: 596
Регистрация: 26-05-06
Из: Москва
Пользователь №: 17 484

|
Используя модификатор register вы просите компилятор разместить переменную в регистрах процессора, предполагая что таким образом получите более оптимальный код, но компилятор вправе игнорировать вашу просьбу, если сочтет генерируемый что код в результате будет хуже. Используя код: Код register unsigned char counter asm("r3"); Вы заставляете компилятор разместить переменную counter в регистре r3 контроллера. И всю ответственность за этот поступок берете на себя. В GCC полностью безопасно использовать регистры r2..r7 для объявления переменных. (С точки зрения компилятора, если только Вы сами не будете их изменять в ассемблерных вставках.) Возможно использование r8..r15, но эти регистры могут использоваться компилятором для передачи аргументов функций. Тоесть если все функции в проекте не передают в аргументах больше 10 байт, то регистры r8..r15 в вашем распоряжении. Если 12 байт то регистры r8-r9 будут использоваться компилятором, и переменная расположенная в них исказиться. avr-libc-user-manual FAQ#3:How to permanently bind a variable to a register? и FAQ#13 What registers are used by the C compiler? Не используйте модификатор volatile с регистровыми переменными, его работа не гарантируется. К сожалению GCC не дает предупреждения, но это факт. Анатолий.
|
|
|
|
|
Jan 26 2008, 21:34
|
дятел
    
Группа: Свой
Сообщений: 1 681
Регистрация: 13-05-06
Из: Питер
Пользователь №: 17 065

|
Цитата(SIA @ Jan 27 2008, 00:17)  Вообще говоря, не понимаю, зачем вообще при написании кода самим создавать себе проблемы - жестко указывать номера регистров для размещения переменных компилятору ? Выгоды практически никакой, а переносимость и надежность могут конкретно пострадать. Выгода может быть в разы, в 2-3 раза легко... О переносимости такого кода речи нет, это используется только на самом низком уровне и только при условии что ты знаешь что делаешь. Цитата Можно понять, если регистр особенный и с этой переменной надо что-то специфичное делать, но такой кусочек кода надо бы оформлять маленькой препроцессорной вставочкой/подпрограммкой, и подробно комментить. Вот пример моих коментариев из реального проекта: Код //------------------------------------------------------------------- // Прерывание системного таймера // используются только регистровые переменные // никакие регистры не сохраняются // SREG не сохраняется // ОБЯЗАТЕЛЬНО ПРОВЕРИТЬ СГЕНЕРИРОВАННЫЙ КОД !!!!!!!!!!!!!!!!!!!!! //------------------------------------------------------------------- там всего 8 команд + reti Но я точно знаю что я делаю. Вы можете спросить почему это не написано на асм. Потому что в качестве бонуса я получаю возможность обращаться к регистровым переменным как к обычным С переменным в обычном С коде...
|
|
|
|
|
Jan 26 2008, 21:38
|
Местный
  
Группа: Свой
Сообщений: 408
Регистрация: 21-10-06
Из: Санкт-Петербург
Пользователь №: 21 527

|
Цитата(singlskv @ Jan 27 2008, 00:19)  регистр без указания месторасположения почти не имеет смысла...
по последнему пункту не уверен точно, тк в своих прогах предпочитаю месторасположение указывать явно... Имеет, хотя ГЦЦ и сам достаточно умный и может разместить переменную в регистре даже без указания. Правда к глобальным это не относится, во всяком случае я такого не видел ни разу. А насчет смысла - например указатель выгодно хранить в регистре, тогда его изменении (++ или --) проходят гораздо быстрее. А так как такие операции обычно происходят в циклах, которые являются узким местом в программе, то использование регистров дает возможность сильно уменьшить время. При этом мне совсем не важно, в каких конкретно регистрах находится указатель. Правда оптимизатор и так обычно такой указатель разместит в регистрах  А вот явное месторасположение имеет смысл в основном для встроенного ассемблера.
|
|
|
|
|
Jan 26 2008, 21:48
|
дятел
    
Группа: Свой
Сообщений: 1 681
Регистрация: 13-05-06
Из: Питер
Пользователь №: 17 065

|
Цитата(Qwertty @ Jan 27 2008, 00:38)  А насчет смысла - например указатель выгодно хранить в регистре, тогда его изменении (++ или --) проходят гораздо быстрее. А так как такие операции обычно происходят в циклах, которые являются узким местом в программе, то использование регистров дает возможность сильно уменьшить время. Вот как раз для такой оптимизации использование register абслоютно беcсмысленно и может даже(в принципе) помешать компилятору.... Для таких кусков кода нужно грамотно использовать локальные переменные. Если хотите примеров, покажите кусок кода где register дал выигрыш, и я покажу как нужно было написать просто с локальными переменными.
|
|
|
|
|
Jan 26 2008, 21:55
|
Местный
  
Группа: Свой
Сообщений: 408
Регистрация: 21-10-06
Из: Санкт-Петербург
Пользователь №: 21 527

|
Цитата(singlskv @ Jan 27 2008, 00:34)  Вы можете спросить почему это не написано на асм. Потому что в качестве бонуса я получаю возможность обращаться к регистровым переменным как к обычным С переменным в обычном С коде... В свете того, что выше написал aesok о регистровых переменных и квалификаторе volatile, возможность обращаться к регистровым переменным, модифицируемым в прерывании, из С кода весьма сомнительна. Цитата(singlskv @ Jan 27 2008, 00:48)  Вот как раз для такой оптимизации использование register абслоютно беcсмысленно и может даже(в принципе) помешать компилятору.... Для таких кусков кода нужно грамотно использовать локальные переменные. Если хотите примеров, покажите кусок кода где register дал выигрыш, и я покажу как нужно было написать просто с локальными переменными. Это и есть локальная переменная. Я выше писал, что не объявляю глобальных переменных регистровыми. Сам по себе register даст выигрыщ только если локальных переменных много, тогда это будет подсказка оптимизатору о том, какие размещать в регистрах в первую очередь. Если локальная переменная одна, то она станет регистровой сама по себе  И перестанет показывать свое значение в студии  А вот помешать компилятору вряд-ли удастся, он просто молча проигнорирует register и все, даже варнинга не даст.
|
|
|
|
|
Jan 26 2008, 22:00
|
Местный
  
Группа: Свой
Сообщений: 462
Регистрация: 26-06-07
Пользователь №: 28 723

|
Код //------------------------------------------------------------------- // Прерывание системного таймера // используются только регистровые переменные // никакие регистры не сохраняются // SREG не сохраняется // ОБЯЗАТЕЛЬНО ПРОВЕРИТЬ СГЕНЕРИРОВАННЫЙ КОД !!!!!!!!!!!!!!!!!!!!! //------------------------------------------------------------------- там всего 8 команд + reti Но я точно знаю что я делаю. Так нельзя делать даже из самых лучших побуждений. Код, работающий по прерыванию и при этом портящий регистры и статус процессора - нонсенс, т.к. его исполнение может оказаться прервано другим таким же с большим приоритетом - с соответствующей порчей данных. Не говоря уже о том, что уменьшение числа регистров, доступных компилятору, ухудшает оптимизацию, и дополнительные загрузки-выгрузки легко съедят весь эффект, полученный в частной подпрограмме. Я однажды еще на ассемблере делал системный таймер в регистре процессора для системы быстрой регистрации, но код отработки прерывания не изменял в процессоре НИЧЕГО, кроме регистра таймера. Если хочется сэкономить такты - практичнее подумать над алгоритмом в целом или поменять МК, если экономится память - это вообще нонсенс, т.к. цена версий МК с разной памятью не сильно отличается. Чтобы окупить затраты на отладку такого "кода", потребуются многотысячные тиражи, и то не факт, что это рационально - резервов для апгрейда не останется. Еще для ускорения при отработке прерываний можно использовать теневой банк регистров (дополнительные банки есть у многих МК, от 8051 и Z80 до PIC32).
|
|
|
|
|
Jan 26 2008, 22:03
|
Местный
  
Группа: Свой
Сообщений: 408
Регистрация: 21-10-06
Из: Санкт-Петербург
Пользователь №: 21 527

|
Цитата(SIA @ Jan 27 2008, 01:00)  т.к. его исполнение может оказаться прервано другим таким же с большим приоритетом - с соответствующей порчей данных. У AVR этого никогда не произойдет  Я видел один раз похожий прием, правда на ассемблере - на Телесисах лежит проект генератора Л.И. Ридико. Там обработчик вообще начинается с адреса вектора и самая короткая ветка не сохраняет SREG. Но это сделано для того, чтобы выжать из контроллера все что можно и видимо такие задачи крайне редки. Хотя тоже имеют право на жизнь.
Сообщение отредактировал Qwertty - Jan 26 2008, 22:10
|
|
|
|
|
Jan 26 2008, 22:07
|
дятел
    
Группа: Свой
Сообщений: 1 681
Регистрация: 13-05-06
Из: Питер
Пользователь №: 17 065

|
Цитата(Qwertty @ Jan 27 2008, 00:55)  В свете того, что выше написал aesok о регистровых переменных и квалификаторе volatile, возможность обращаться к регистровым переменным, модифицируемым в прерывании, из С кода весьма сомнительна. По большому счету, квалификаторы register и volatile одновременно не применимы. При "жестком" расположении переменной в регистре volatile просто теряет смысл... Я не знаю примеров в которых "жестко" заданная регистровая переменная может портиться. Цитата Это и есть локальная переменная. Я выше писал, что не объявляю глобальных переменных регистровыми. Сам по себе register даст выигрыщ только если локальных переменных много, тогда это будет подсказка оптимизатору о том, какие размещать в регистрах в первую очередь. Если локальная переменная одна, то она станет регистровой сама по себе  И перестанет показывать свое значение в студии  А вот помешать компилятору вряд-ли удастся, он просто молча проигнорирует register и все, даже варнинга не даст. В таком варианте, согласен.
|
|
|
|
|
Jan 26 2008, 22:13
|
Знающий
   
Группа: Участник
Сообщений: 596
Регистрация: 26-05-06
Из: Москва
Пользователь №: 17 484

|
Цитата(singlskv @ Jan 27 2008, 01:07)  По большому счету, квалификаторы register и volatile одновременно не применимы. При "жестком" расположении переменной в регистре volatile просто теряет смысл... Я не знаю примеров в которых "жестко" заданная регистровая переменная может портиться. В таком варианте, согласен. Почитайте пост, там описана проблема: http://electronix.ru/forum/index.php?showtopic=42140GCC ведет себя также. До веррсии 4.1 он выдавал предупреждение, потом перестал. Есть ключик чтобы его включть. Анатолий.
|
|
|
|
|
Jan 26 2008, 22:29
|
дятел
    
Группа: Свой
Сообщений: 1 681
Регистрация: 13-05-06
Из: Питер
Пользователь №: 17 065

|
Цитата(SIA @ Jan 27 2008, 01:00)  Так нельзя делать даже из самых лучших побуждений. Код, работающий по прерыванию и при этом портящий регистры и статус процессора - нонсенс, т.к. его исполнение может оказаться прервано другим таким же с большим приоритетом - с соответствующей порчей данных. Может конечно и нельзя .... Но я точно знаю что я делаю.используются только зарезервированные регистры и регистры переферии, код написан таким образом что SREG просто не меняется, напоминание "ПРОВЕРИТЬ КОД" именно про то, чтобы проверить что компилятор не начудил и не вставил инструкции меняющие SREG. Цитата(aesok @ Jan 27 2008, 01:13)  Почитайте пост, там описана проблема: http://electronix.ru/forum/index.php?showtopic=42140GCC ведет себя также. До веррсии 4.1 он выдавал предупреждение, потом перестал. Есть ключик чтобы его включть. Я не только читал но и писал в той ветке... Про проблемы с повтором констант я знаю, более того примерно с год назад я поднимал этот вопрос на форуме (ссылку лень искать сейчас, что то типа"Проблемы оптимизации WinAVR"). У меня все проблемы сводились к тому что код оказывался просто очень не оптимальным. У Вас есть пример кода для GCC который будет в такой ситуации некорректным ?
|
|
|
|
|
Jan 26 2008, 22:31
|
Местный
  
Группа: Свой
Сообщений: 462
Регистрация: 26-06-07
Пользователь №: 28 723

|
Цитата(singlskv @ Jan 27 2008, 01:17)  Может конечно и нельзя .... Но я точно знаю что я делаю.используются только зарезервированные регистры и регистры переферии, код написан таким образом что SREG просто не меняется, напоминание "ПРОВЕРИТЬ КОД" именно про то, чтобы проверить что компилятор не начудил и не вставил инструкции меняющие SREG. IMHO, это приемлемо только для очень маленького проекта, строк на 300-500. Более крупный при использовании таких методов становится слишком непрактичным. p.s. Эпоху, когда экономили каждый такт, я еще застал. Но не думаю, что сейчас это правильно - проще взять более мощный процессор, они сейчас недороги.
|
|
|
|
|
Jan 26 2008, 23:39
|
Знающий
   
Группа: Участник
Сообщений: 596
Регистрация: 26-05-06
Из: Москва
Пользователь №: 17 484

|
Цитата(singlskv @ Jan 27 2008, 01:29)  Цитата Почитайте пост, там описана проблема: http://electronix.ru/forum/index.php?showtopic=42140GCC ведет себя также. До веррсии 4.1 он выдавал предупреждение, потом перестал. Есть ключик чтобы его включть. У Вас есть пример кода для GCC который будет в такой ситуации некорректным ? Да нашел на www.avrfreaks.net. Код volatile register uint16_t s1 asm("r2"); ISR(INT0_vect) {
if(bit_is_set(PINC,0)) s1++; else s1--; }
int main{ //... sei(); OCR0+=10; while(s1<10); //... } Регистровая переменная объявлена как volatile, код на уровне оптимизации -Os: Код 205: sei(); SEI 208: OCR0+=10; IN R24,0x31 SUBI R24,0xF6 OUT 0x31,R24 MOVW R24,R2 //!!! 209: while(s3<10); CPI R24,0x0A CPC R25,R1 BRCS PC-0x02 Происходит копирование R2:R3 в R24:R25, и в цикле анализируеться копия переменой s1 в R24:R25, а не она сама в R2:R3. Так что не используйте в GCC 'volatile register' переменые и добавте в свои макефайлы ключик '-Wvolatile-register-var'. Если интересно почему GCC так работает то, можно почитать здесь: http://gcc.gnu.org/ml/gcc-patches/2005-11/msg00657.htmlАнатолий.
|
|
|
|
|
  |
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|