Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Инкремент указателя и оптимизация
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > Cредства разработки для МК > IAR
Rash
День добрый.

Столкнулся с проблемой оптимизации, при инкременте указателя когда 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 конечно не критичен, но костыль. Отключить оптимизацию только для ф-ции не рассматриваю, т.к. подобные записи оформил виде макросов и могут быть в разных участках кода
scifi
Многабукаффниасилил.
Я не пойму, жалоба на некорректный код, так как исчез инкремент, который никак не должен исчезать?
Если так, то такой вопрос: а вы уверены, что у вас исходник корректный? Что там, где надо, написано volatile и так далее? Потому что из приведённых отрывков этого совсем не видно.
Rash
да вроде не так много букв ). Проблема в том, что исчезает инкремент, второй скрин, если между строчками где идёт присваивание по одному и тому же указателю с инкрементом поставить NOP, то всё хорошо, скрин 3 (как и без оптимизации). volatile по типу поставил, хотя он не влияет.

Жалобы нет, т.к. код мой.
А вопрос как написать тоже, но без NOPа?
scifi
Цитата(Rash @ Oct 1 2015, 19:50) *
А вопрос как написать тоже, но без NOPа?

Зачем?
Ведь нет жалобы:
Цитата(Rash @ Oct 1 2015, 19:50) *
Жалобы нет

То есть всё нормально. Честно, не понимаю.
Rash
1. Не нравятся костыли в любом виде, в данном случае NOP.
2. Нет гарантии, что в следующий раз я могу что то не учесть, подобной записью.
scifi
Вы не ответили на важный вопрос: "жалоба на некорректный код, так как исчез инкремент, который никак не должен исчезать?"
Да или нет?
От этого многое зависит.
Rash
жалоба на то, что исчез инкремент, который не должен исчезать
scifi
Цитата(Rash @ Oct 1 2015, 20:51) *
жалоба на то, что исчез инкремент, который не должен исчезать

Ну наконец-то.
Дальше надо понять, где у вас ошибка в коде (что очень вероятно) или где глючит компилятор (что весьма маловероятно). Потому что какой-то левый NOP - это не исправление ошибки в коде, а танец с бубном. И без понимания происходящего нежелательный сценарий повторится снова в неожиданном месте.
А вот понять, где ошибка, я точно не смогу, потому что приведён мелкий кусочек кода.
Ну а если покажете мегапростыню кода, то не обещаю, что буду в ней разбираться laughing.gif

UPDATE:
Забыл спросить. Жалоба только на то, что код в окне дизассемблера выглядит не так, как хотелось бы? Или реально программа работает не так, как задумано?
_Pasha
да там наверное нездоровый упор на CSE.
просто сделать через добавление локальных переменных - попустит дерево синтаксиса и станет код вменяемым
scifi
Цитата(_Pasha @ Oct 1 2015, 21:31) *
да там наверное нездоровый упор на CSE.
просто сделать через добавление локальных переменных - попустит дерево синтаксиса и станет код вменяемым

То есть уже установлено, что компилятор виноват. А если бы были судьёй, то всех расстреливали бы без следствия?
Rash
Цитата(scifi @ Oct 1 2015, 21:13) *
Жалоба только на то, что код в окне дизассемблера выглядит не так, как хотелось бы? Или реально программа работает не так, как задумано?


Программа работает как задумано, без оптимизации или при добавлении NOP.
scifi
Цитата(Rash @ Oct 1 2015, 22:09) *
Программа работает как задумано, без оптимизации или при добавлении NOP.

Обычное дело, если не понимать, что такое volatile, и где его нужно применять.
Rash
естественно, стоит при определении типа на указатель, куда уж не правильней
Valentine Loginov
Вам бы не полениться и сделать код читаемым, как например ввести дополнительные переменные. Оптимизация всё уберет, зато сам код и дизасм читать легче станет.
Очень очень очень некрасивый код:
Цитата
*((*ppData_tx)++) = *((*ppData_rx)++);
megajohn
Цитата(Rash @ Oct 1 2015, 23:23) *
естественно, стоит при определении типа на указатель, куда уж не правильней

я так понимаю: указатель1->указатель2->данные и ваш volatile относится к данным, а не к указателям
Но могу ошибаться
scifi
Кстати, безотносительно к тому, есть ли там volatile и в правильных ли местах, важно следующее:
У вас в программе есть прерывания и/или многопоточность (т.н. RTOS)? Потому что volatile только в этом случае имеет значение.
zltigo
QUOTE (Rash @ Oct 1 2015, 16:29) *
*(*(volatile uint_setup_addr_t**)&(*ppData_tx))++ = setup_addr;

Эта строчка есть абсолютный говнокод. Рассуждать, как компилятор должен говнокод компилировать, можно бесконечно.
Но без потытки сбить оптимизацию квалификатором volatile, любые инкременты переменной по указателю должны безусловно выбрасываться, как бесполезные. Что и сделано.
С volatile оптимизация может быть порушена.
Напишите, что надо делать компилятору четко. Но начните с попытки объяснить СЕБЕ.
Valentine Loginov
Цитата(megajohn @ Oct 2 2015, 10:16) *
я так понимаю: указатель1->указатель2->данные и ваш volatile относится к данным, а не к указателям
Но могу ошибаться

К данным. Читается справа налево. Указатель на волатайл переменную типа бла-бла.
Цитата
volatile uint_setup_addr_t*
Kabdim
*((*ppData_tx)++) = *((*ppData_rx)++);
Вообще это изменение одной переменной между двумя точками следования. Это в свою очередь UB. Поэтому компилятор прав, вы - нет. Пишите подобное с временной переменной. Это работает в отладке потому что там компилятор что видит, то и поёт. С нопом это работает по счастливой случайности, из-за особенностей оптимизации конкретным компилятором.
Rash
многопоточности нет (RTOS тоже), раньше код был с разделением взятия переменной и инкрементом указателя, работало с оптимизацией и без. решил записать всё в одну строчку, для компактности и чтобы сделать макрос. Нет проблемы записать по другому с доп. переменной и т.п., хотелось записать одной строчкой.

По поводу говнокода, каждому своё, тогда и DSP Lib от ARM тоже говнокод, там такие записи встречаются.
Найти ошибку будет сложнее, но эта запись как результат сворачивая из нескольких записей на уже отлаженном коде.

Цитата(Kabdim @ Oct 2 2015, 14:06) *
*((*ppData_tx)++) = *((*ppData_rx)++);
Вообще это изменение одной переменной между двумя точками следования. Это в свою очередь UB. Поэтому компилятор прав, вы - нет. Пишите подобное с временной переменной. Это работает в отладке потому что там компилятор что видит, то и поёт. С нопом это работает по счастливой случайности, из-за особенностей оптимизации конкретным компилятором.


переменная тут не меняется, она копируется из _rx в _tx, а адреса буферов меняются

переменные нигде не меняются, меняется (инкрементируется) только указатель на входные буфера
Kabdim
Цитата(Rash @ Oct 2 2015, 14:07) *
переменная тут не меняется, она копируется из _rx в _tx, а адреса буферов меняются

Прошу прощения, проглядел.
scifi
Цитата(Rash @ Oct 2 2015, 14:07) *
многопоточности нет (RTOS тоже)

Тогда зачем там volatile? Взаимодействие с аппаратными регистрами?

Чтобы сделать вывод, что это компилятор виноват, в идеале хорошо бы попытаться получить минимальную программу (легко обозримую), в которой проблема по-прежнему проявляется. Потому что всё-таки гораздо чаще оказывается, что виноват автор кода, а не компилятор.
Rash
компилятор я нигде не обвинял, а только спрашивал, что не так, в расчёте, что укажут на ошибку или я смогу понять где она. С volatile или без результат одинаковый, предполагал, что он относится к указателю, а не к значению. Позже попробую другие вариации попроще.
scifi
Цитата(Rash @ Oct 2 2015, 14:56) *
компилятор я нигде не обвинял

А можно было бы. Изредка и он виноват. Я сталкивался не единожды.

Цитата(Rash @ Oct 2 2015, 14:56) *
спрашивал, что не так, в расчёте, что укажут на ошибку или я смогу понять где она

Увы, не получится. Вы привели очень маленький кусок кода, собака легко могла порыться совсем в другом месте программы.

Цитата(Rash @ Oct 2 2015, 14:56) *
С volatile или без результат одинаковый...

А всё-таки, поясните, зачем там volatile? Если нет RTOS, прерываний и аппаратных регистров, то volatile ничего не изменит.
_Pasha
rolleyes.gif я правильно перевел с птичьего языка на норм.?
Код
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) *
То есть уже установлено, что компилятор виноват. А если бы были судьёй, то всех расстреливали бы без следствия?

???
Rash
scifi, мне интересно, что вас задел этот volatile или слово жалоба? через volatile объявляю только приведение типов по указателю, в книжках читал про это. Прерывание есть, какая реальная программа без прерываний. Ещё на время отладки volatile объявляю float, чтобы watch отображался.

_Pasha, ну на птичий язык не совсем тянет, хотя запись с указателями перегружена для непосвящённых biggrin.gif
По записи вроде всё верно, хотя не проверял, до понедельника не на чем. Но смысл не постоянно писать такими громоздкими записями, а завернуть их в макросы или для противников макросов в inline функции и использовать
это макрос один
Код
*(*(volatile uint_setup_addr_t**)&(*ppData_tx))++ = setup_addr;

это второй
Код
*((*ppData_tx)++)

но так получилось, в данной ф-ции, что подряд идущие 2 эти строчки оптимизируется и я вставил NOP между ними. Приводить большие куски кода не вижу смысла т.к. необходимо в любой конструкции работа этих макросов.

немного OFFTOP:
Другой случай где понадобился NOP, это для анализатора стека. При максимальной оптимизации по скорости (на других не пробовал) в switch вызывались различные ф-ции в зависимости значение case. Все вызовы ф-ций при этом подменялись с CALL на JMP (это на AVR) и анализатор выдавал предупреждение о косвенном вызове и не мог составить дерево вызовов. Причём ни прагмой, ни описанием в файле конфигурации, я так и не смог указать правильное дерево вызовов для данного случая. Но если в конце перед выходом из ф-ции (после switch) поставить NOP такой подмены не происходит и анализатор нормально работает.
Естественно, на работоспособность программы это не влияет, но анализатор хорошая штука чего б не использовать.
_Pasha
Цитата(Rash @ Oct 2 2015, 23:09) *
По записи вроде всё верно, хотя не проверял, до понедельника не на чем. Но смысл не постоянно писать такими громоздкими записями, а завернуть их в макросы или для противников макросов в inline функции и использовать

1. Не все там верно, нужно же отразить модификацию собственно указателей, т.е. в конце добавить
Код
*ppData_tx = ptx;
*ppData_rx = prx;


2. Ход мыслей понятен, но имхо такое, что нет смысла бояться локальных переменных даже в таком случае.
Т.е. в случае с макросом - обернуть его в do{}while(0) и создавать столько локальных перем. сколько нужно.

3. Не все компиляторы, что существуют, - одинаково хорошие sm.gif и если даже такой не сильно тяжелой строкой удалось вогнать его в багу, - повод задуматься, стоит ли так закручивать сюжет. Если создание лишних сущностей отдать на откуп компилю, совсем не факт, что он справится с этим.
я недавно написал под SDCC, типа поиграться решил
Код
crc = (crc >> 1)^((crc & 1)? 0x8C:0);

так там вообще неправильный код сгенерировался.
пришлось исправить на
Код
crc = ((crc & 1)? 0x8C:0) ^ (crc >> 1);

вот те на, CSE smile3046.gif
но то sdcc. милость к падшим тсз нада проявлять biggrin.gif
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.