|
Инкремент указателя и оптимизация |
|
|
|
Oct 1 2015, 13:29
|
Знающий
   
Группа: Свой
Сообщений: 639
Регистрация: 5-09-05
Пользователь №: 8 231

|
День добрый. Столкнулся с проблемой оптимизации, при инкременте указателя когда 2 строчки подряд. Оптимизация макс. по скорости. IAR ARM 7.40.3. Мк STMF4 Код static void _setup_resp_ready(uint8_t** ppData_rx, bool allow_addr, uint8_t** ppData_tx) { if(allow_addr != false) *(*(volatile uint_setup_addr_t**)&(*ppData_tx))++ = setup_addr; // !!! если NOP нет, то код будет оптимизирован __ASM("NOP"); *((*ppData_tx)++) = *((*ppData_rx)++); return; }
Прим. uint_setup_addr_t - задаётся тип, на данный момент uint16_t скрины ассемблера без оптимизации  макс. оптимизация по скорости  макс. оптимизация по скорости + NOP  Вопрос, возможно ли сделать запись чтобы не оптимизировался инкремент указателя? NOP конечно не критичен, но костыль. Отключить оптимизацию только для ф-ции не рассматриваю, т.к. подобные записи оформил виде макросов и могут быть в разных участках кода
|
|
|
|
|
Oct 1 2015, 16:53
|
Гуру
     
Группа: Свой
Сообщений: 3 020
Регистрация: 7-02-07
Пользователь №: 25 136

|
Цитата(Rash @ Oct 1 2015, 19:50)  А вопрос как написать тоже, но без NOPа? Зачем? Ведь нет жалобы: Цитата(Rash @ Oct 1 2015, 19:50)  Жалобы нет То есть всё нормально. Честно, не понимаю.
|
|
|
|
|
Oct 1 2015, 18:13
|
Гуру
     
Группа: Свой
Сообщений: 3 020
Регистрация: 7-02-07
Пользователь №: 25 136

|
Цитата(Rash @ Oct 1 2015, 20:51)  жалоба на то, что исчез инкремент, который не должен исчезать Ну наконец-то. Дальше надо понять, где у вас ошибка в коде (что очень вероятно) или где глючит компилятор (что весьма маловероятно). Потому что какой-то левый NOP - это не исправление ошибки в коде, а танец с бубном. И без понимания происходящего нежелательный сценарий повторится снова в неожиданном месте. А вот понять, где ошибка, я точно не смогу, потому что приведён мелкий кусочек кода. Ну а если покажете мегапростыню кода, то не обещаю, что буду в ней разбираться  UPDATE: Забыл спросить. Жалоба только на то, что код в окне дизассемблера выглядит не так, как хотелось бы? Или реально программа работает не так, как задумано?
|
|
|
|
|
Oct 2 2015, 06:52
|
Частый гость
 
Группа: Участник
Сообщений: 78
Регистрация: 7-04-10
Из: Пушкино
Пользователь №: 56 462

|
Вам бы не полениться и сделать код читаемым, как например ввести дополнительные переменные. Оптимизация всё уберет, зато сам код и дизасм читать легче станет. Очень очень очень некрасивый код: Цитата *((*ppData_tx)++) = *((*ppData_rx)++);
|
|
|
|
|
Oct 2 2015, 08:12
|

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

|
QUOTE (Rash @ Oct 1 2015, 16:29)  *(*(volatile uint_setup_addr_t**)&(*ppData_tx))++ = setup_addr; Эта строчка есть абсолютный говнокод. Рассуждать, как компилятор должен говнокод компилировать, можно бесконечно. Но без потытки сбить оптимизацию квалификатором volatile, любые инкременты переменной по указателю должны безусловно выбрасываться, как бесполезные. Что и сделано. С volatile оптимизация может быть порушена. Напишите, что надо делать компилятору четко. Но начните с попытки объяснить СЕБЕ.
--------------------
Feci, quod potui, faciant meliora potentes
|
|
|
|
|
Oct 2 2015, 10:27
|
Частый гость
 
Группа: Участник
Сообщений: 78
Регистрация: 7-04-10
Из: Пушкино
Пользователь №: 56 462

|
Цитата(megajohn @ Oct 2 2015, 10:16)  я так понимаю: указатель1->указатель2->данные и ваш volatile относится к данным, а не к указателям Но могу ошибаться К данным. Читается справа налево. Указатель на волатайл переменную типа бла-бла. Цитата volatile uint_setup_addr_t*
|
|
|
|
|
Oct 2 2015, 11:07
|
Знающий
   
Группа: Свой
Сообщений: 639
Регистрация: 5-09-05
Пользователь №: 8 231

|
многопоточности нет (RTOS тоже), раньше код был с разделением взятия переменной и инкрементом указателя, работало с оптимизацией и без. решил записать всё в одну строчку, для компактности и чтобы сделать макрос. Нет проблемы записать по другому с доп. переменной и т.п., хотелось записать одной строчкой. По поводу говнокода, каждому своё, тогда и DSP Lib от ARM тоже говнокод, там такие записи встречаются. Найти ошибку будет сложнее, но эта запись как результат сворачивая из нескольких записей на уже отлаженном коде. Цитата(Kabdim @ Oct 2 2015, 14:06)  *((*ppData_tx)++) = *((*ppData_rx)++); Вообще это изменение одной переменной между двумя точками следования. Это в свою очередь UB. Поэтому компилятор прав, вы - нет. Пишите подобное с временной переменной. Это работает в отладке потому что там компилятор что видит, то и поёт. С нопом это работает по счастливой случайности, из-за особенностей оптимизации конкретным компилятором. переменная тут не меняется, она копируется из _rx в _tx, а адреса буферов меняются переменные нигде не меняются, меняется (инкрементируется) только указатель на входные буфера
|
|
|
|
|
Oct 2 2015, 14:20
|
Гуру
     
Группа: Свой
Сообщений: 3 020
Регистрация: 7-02-07
Пользователь №: 25 136

|
Цитата(Rash @ Oct 2 2015, 14:56)  компилятор я нигде не обвинял А можно было бы. Изредка и он виноват. Я сталкивался не единожды. Цитата(Rash @ Oct 2 2015, 14:56)  спрашивал, что не так, в расчёте, что укажут на ошибку или я смогу понять где она Увы, не получится. Вы привели очень маленький кусок кода, собака легко могла порыться совсем в другом месте программы. Цитата(Rash @ Oct 2 2015, 14:56)  С volatile или без результат одинаковый... А всё-таки, поясните, зачем там volatile? Если нет RTOS, прерываний и аппаратных регистров, то volatile ничего не изменит.
|
|
|
|
|
Oct 2 2015, 15:51
|
;
     
Группа: Участник
Сообщений: 5 646
Регистрация: 1-08-07
Пользователь №: 29 509

|
 я правильно перевел с птичьего языка на норм.? Код static void _setup_resp_ready(uint8_t** ppData_rx, bool allow_addr, uint8_t** ppData_tx) {
uint8_t *ptx = *ppData_tx; uint8_t *prx = *ppData_rx; if(allow_addr != false) *(volatile uint_setup_addr_t *)ptx++ = setup_addr; *ptx++ = *prx++; return; } Цитата(scifi @ Oct 1 2015, 21:41)  То есть уже установлено, что компилятор виноват. А если бы были судьёй, то всех расстреливали бы без следствия? ???
|
|
|
|
|
Oct 2 2015, 20:09
|
Знающий
   
Группа: Свой
Сообщений: 639
Регистрация: 5-09-05
Пользователь №: 8 231

|
scifi, мне интересно, что вас задел этот volatile или слово жалоба? через volatile объявляю только приведение типов по указателю, в книжках читал про это. Прерывание есть, какая реальная программа без прерываний. Ещё на время отладки volatile объявляю float, чтобы watch отображался. _Pasha, ну на птичий язык не совсем тянет, хотя запись с указателями перегружена для непосвящённых По записи вроде всё верно, хотя не проверял, до понедельника не на чем. Но смысл не постоянно писать такими громоздкими записями, а завернуть их в макросы или для противников макросов в inline функции и использовать это макрос один Код *(*(volatile uint_setup_addr_t**)&(*ppData_tx))++ = setup_addr; это второй Код *((*ppData_tx)++) но так получилось, в данной ф-ции, что подряд идущие 2 эти строчки оптимизируется и я вставил NOP между ними. Приводить большие куски кода не вижу смысла т.к. необходимо в любой конструкции работа этих макросов. немного OFFTOP: Другой случай где понадобился NOP, это для анализатора стека. При максимальной оптимизации по скорости (на других не пробовал) в switch вызывались различные ф-ции в зависимости значение case. Все вызовы ф-ций при этом подменялись с CALL на JMP (это на AVR) и анализатор выдавал предупреждение о косвенном вызове и не мог составить дерево вызовов. Причём ни прагмой, ни описанием в файле конфигурации, я так и не смог указать правильное дерево вызовов для данного случая. Но если в конце перед выходом из ф-ции (после switch) поставить NOP такой подмены не происходит и анализатор нормально работает. Естественно, на работоспособность программы это не влияет, но анализатор хорошая штука чего б не использовать.
|
|
|
|
|
Oct 3 2015, 05:48
|
;
     
Группа: Участник
Сообщений: 5 646
Регистрация: 1-08-07
Пользователь №: 29 509

|
Цитата(Rash @ Oct 2 2015, 23:09)  По записи вроде всё верно, хотя не проверял, до понедельника не на чем. Но смысл не постоянно писать такими громоздкими записями, а завернуть их в макросы или для противников макросов в inline функции и использовать 1. Не все там верно, нужно же отразить модификацию собственно указателей, т.е. в конце добавить Код *ppData_tx = ptx; *ppData_rx = prx; 2. Ход мыслей понятен, но имхо такое, что нет смысла бояться локальных переменных даже в таком случае. Т.е. в случае с макросом - обернуть его в do{}while(0) и создавать столько локальных перем. сколько нужно. 3. Не все компиляторы, что существуют, - одинаково хорошие  и если даже такой не сильно тяжелой строкой удалось вогнать его в багу, - повод задуматься, стоит ли так закручивать сюжет. Если создание лишних сущностей отдать на откуп компилю, совсем не факт, что он справится с этим. я недавно написал под SDCC, типа поиграться решил Код crc = (crc >> 1)^((crc & 1)? 0x8C:0); так там вообще неправильный код сгенерировался. пришлось исправить на Код crc = ((crc & 1)? 0x8C:0) ^ (crc >> 1); вот те на, CSE но то sdcc. милость к падшим тсз нада проявлять
|
|
|
|
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|