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

 
 
> Инкремент указателя и оптимизация
Rash
сообщение Oct 1 2015, 13:29
Сообщение #1


Знающий
****

Группа: Свой
Сообщений: 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 конечно не критичен, но костыль. Отключить оптимизацию только для ф-ции не рассматриваю, т.к. подобные записи оформил виде макросов и могут быть в разных участках кода
Go to the top of the page
 
+Quote Post
2 страниц V  < 1 2  
Start new topic
Ответов (15 - 26)
scifi
сообщение Oct 2 2015, 07:27
Сообщение #16


Гуру
******

Группа: Свой
Сообщений: 3 020
Регистрация: 7-02-07
Пользователь №: 25 136



Кстати, безотносительно к тому, есть ли там volatile и в правильных ли местах, важно следующее:
У вас в программе есть прерывания и/или многопоточность (т.н. RTOS)? Потому что volatile только в этом случае имеет значение.
Go to the top of the page
 
+Quote Post
zltigo
сообщение Oct 2 2015, 08:12
Сообщение #17


Гуру
******

Группа: Свой
Сообщений: 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
Go to the top of the page
 
+Quote Post
Valentine Logino...
сообщение Oct 2 2015, 10:27
Сообщение #18


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

Группа: Участник
Сообщений: 78
Регистрация: 7-04-10
Из: Пушкино
Пользователь №: 56 462



Цитата(megajohn @ Oct 2 2015, 10:16) *
я так понимаю: указатель1->указатель2->данные и ваш volatile относится к данным, а не к указателям
Но могу ошибаться

К данным. Читается справа налево. Указатель на волатайл переменную типа бла-бла.
Цитата
volatile uint_setup_addr_t*
Go to the top of the page
 
+Quote Post
Kabdim
сообщение Oct 2 2015, 11:06
Сообщение #19


Знающий
****

Группа: Свой
Сообщений: 558
Регистрация: 26-11-14
Из: Зеленоград
Пользователь №: 83 842



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

Сообщение отредактировал Kabdim - Oct 2 2015, 11:08
Go to the top of the page
 
+Quote Post
Rash
сообщение Oct 2 2015, 11:07
Сообщение #20


Знающий
****

Группа: Свой
Сообщений: 639
Регистрация: 5-09-05
Пользователь №: 8 231



многопоточности нет (RTOS тоже), раньше код был с разделением взятия переменной и инкрементом указателя, работало с оптимизацией и без. решил записать всё в одну строчку, для компактности и чтобы сделать макрос. Нет проблемы записать по другому с доп. переменной и т.п., хотелось записать одной строчкой.

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

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


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

переменные нигде не меняются, меняется (инкрементируется) только указатель на входные буфера
Go to the top of the page
 
+Quote Post
Kabdim
сообщение Oct 2 2015, 11:12
Сообщение #21


Знающий
****

Группа: Свой
Сообщений: 558
Регистрация: 26-11-14
Из: Зеленоград
Пользователь №: 83 842



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

Прошу прощения, проглядел.
Go to the top of the page
 
+Quote Post
scifi
сообщение Oct 2 2015, 11:43
Сообщение #22


Гуру
******

Группа: Свой
Сообщений: 3 020
Регистрация: 7-02-07
Пользователь №: 25 136



Цитата(Rash @ Oct 2 2015, 14:07) *
многопоточности нет (RTOS тоже)

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

Чтобы сделать вывод, что это компилятор виноват, в идеале хорошо бы попытаться получить минимальную программу (легко обозримую), в которой проблема по-прежнему проявляется. Потому что всё-таки гораздо чаще оказывается, что виноват автор кода, а не компилятор.
Go to the top of the page
 
+Quote Post
Rash
сообщение Oct 2 2015, 11:56
Сообщение #23


Знающий
****

Группа: Свой
Сообщений: 639
Регистрация: 5-09-05
Пользователь №: 8 231



компилятор я нигде не обвинял, а только спрашивал, что не так, в расчёте, что укажут на ошибку или я смогу понять где она. С volatile или без результат одинаковый, предполагал, что он относится к указателю, а не к значению. Позже попробую другие вариации попроще.
Go to the top of the page
 
+Quote Post
scifi
сообщение Oct 2 2015, 14:20
Сообщение #24


Гуру
******

Группа: Свой
Сообщений: 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 ничего не изменит.
Go to the top of the page
 
+Quote Post
_Pasha
сообщение Oct 2 2015, 15:51
Сообщение #25


;
******

Группа: Участник
Сообщений: 5 646
Регистрация: 1-08-07
Пользователь №: 29 509



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

???
Go to the top of the page
 
+Quote Post
Rash
сообщение Oct 2 2015, 20:09
Сообщение #26


Знающий
****

Группа: Свой
Сообщений: 639
Регистрация: 5-09-05
Пользователь №: 8 231



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 такой подмены не происходит и анализатор нормально работает.
Естественно, на работоспособность программы это не влияет, но анализатор хорошая штука чего б не использовать.
Go to the top of the page
 
+Quote Post
_Pasha
сообщение Oct 3 2015, 05:48
Сообщение #27


;
******

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

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

вот те на, CSE smile3046.gif
но то sdcc. милость к падшим тсз нада проявлять biggrin.gif
Go to the top of the page
 
+Quote Post

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

 


RSS Текстовая версия Сейчас: 25th July 2025 - 00:53
Рейтинг@Mail.ru


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