Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Инлайновая функция
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > Cредства разработки для МК > IAR
Страницы: 1, 2
aiwa
Цитата(Kabdim @ Jul 10 2018, 13:29) *
Нет волатайл объекта - нет ограничений. Вот так уже работает.


В одном случае работает, во втором не работает:
Код
void main()
{
    fptr ftemp = (fptr)&func;
    (*ftemp)();                      // работает. есть вызов.  
    ((fptr)func)();                  // не работает. происходит inline подстановка.   тут rvalue  
}

VladislavS
Господа, вы научно-технические извращенцы sm.gif Скомпилируйте функцию в отдельном модуле и никто её встраивать не будет. Про мультифайл компилэйшин знаю, но это легко не включается.
scifi
Цитата(aiwa @ Jul 10 2018, 14:32) *
В одном случае работает, во втором не работает:

А не надо делать так, чтобы не работало. Очевидно же! biggrin.gif
jcxz
Цитата(VladislavS @ Jul 10 2018, 14:41) *
Скомпилируйте функцию в отдельном модуле и никто её встраивать не будет.

Ну-ну. А чекбокс "Inline small routines" в IAR в свойствах компоновщика не замечали? rolleyes.gif
А значит инлайнить может не только компилятор, но и компоновщик. Конечно косвенных вызовов это не касается.
VladislavS
Блин, секта отрицателей инлайна, оказывается, ещё крепче sm.gif
demiurg_spb
Тут ещё extern inline не обсосали)))

Помню что в стандарте это описывается.
С ходу нашёл лишь

https://www.ibm.com/support/knowledgecenter...ine_linkage.htm
http://m68hc11.serveftp.org/inline-1.php
aiwa
Цитата(VladislavS @ Jul 10 2018, 15:01) *
Блин, секта отрицателей инлайна, оказывается, ещё крепче sm.gif

Та мелочи. Скоро придет Лесник.
Kabdim
Цитата(aiwa @ Jul 10 2018, 14:32) *
В одном случае работает, во втором не работает:
Код
void main()
{
    fptr ftemp = (fptr)&func;
    (*ftemp)();                      // работает. есть вызов.  
    ((fptr)func)();                  // не работает. происходит inline подстановка.   тут rvalue  
}

К чему вы это? Второй вариант снова попытка извернутся и не создавать указателя, которая закономерно заканчивается своершенно предсказуемым итогом. Если нужно гарантировать отсутствие инлайна никуда вы не отвертитись от указателя в памяти в явном виде.
VladislavS
Придумал. Если функцию разместить в другой секции, то нет той силы которая её встроит. Двойное ИМХО.
aiwa
Цитата(Kabdim @ Jul 10 2018, 16:49) *
К чему вы это? Второй вариант снова попытка извернутся и не создавать указателя, которая закономерно заканчивается своершенно предсказуемым итогом. Если нужно гарантировать отсутствие инлайна никуда вы не отвертитись от указателя в памяти в явном виде.


К тому, что в Вашем конкретном примере наличие волатайл-указателя добавляет лишь заполнение его ячеек в стеке.
Если его объявление заменить просто вызовом функции ничего не поменяется.
Kabdim
Почему ничего не меняется? По-моему меняется инлайн или нет инлайна. Возможно вы захватили ссылку на годболт в котором я описался в тайпдефе и постарался быстро это исправить, посмотрите это место внимательно.

ЗЫ Вообще я как-то притомился от этой дискуссии. Была озвучена задача "как избежать инлайна", было озвучено решение, попросили аргументы почему оно должно работать, ссылки были приведены. Но почему-то когда оппоненты декларируют что что-то не работает или может работать по другому своё мнение ссылками не подтверждают. В общем я пас продолжать в том же духе. Приводите ссылки на стандарт которые по вашем мнению его подтверждают, тогда поговорим.

УПД Поправил ссылку на годболт с вариантом lvalue без volatile. Если обратить внимание оно поняло что вызывается конкретная функция и происходит сразу джамп куда надо, да оно не захотело инлайнить, но по стандарту компилятор имеет на это полное право. Ваша надежда на lvalue без volatile и есть тот самый "тонкий лёд" который сейчас работает, а потом может и перестать.

УПД2: Вот кстати шланг замечательно заинлайнил ваш lvalue.
aiwa
Цитата(Kabdim @ Jul 10 2018, 18:26) *

Это был не lvalue, а xvalue. Чтобы получить lvalue надо "fptrnv ftnv = (fptrnv)&func;" вынести за пределы функции и тогда происходит вызов.
По поводу lvalue у меня лишь предположение в надежде что кто-то знающий стандарт или подтвердит или опровергнет.
Насчет модификатора "volatile" у меня возражений изначально не было, просто хотелось найти объяснение почему не работает ((fptr)func)();.
Отличия лишь только в том, что c указателем - xvalue, с преобразованием - rvalue.
jcxz
Цитата(aiwa @ Jul 10 2018, 17:36) *
Если его объявление заменить просто вызовом функции ничего не поменяется.

Точнее - заменить команду BLX Rx. Чтение указателя из памяти должно остаться так как он volatile.
А вот заменить BLX Rx на тело функции - это нисколько не противоречит концепции volatile, так как volatile (судя по её определению), должна сохранять неизменным только порядок доступов к памяти (чтений/записи). А не всю последовательность команд подряд. Но пара команд BLX Rx/BX LR - не осуществляет доступов к памяти. Так что - даже если современные версии компиляторов не инлайнят, то ничто не мешает инлайнить последующим версиям.
scifi
Цитата(jcxz @ Jul 11 2018, 09:57) *
ничто не мешает инлайнить последующим версиям.

У вас какая-то избирательная манера читать. Напоминаю:
Цитата(scifi @ Jul 10 2018, 09:23) *
Причина, по которой этого не случится: указатель объявлен как volatile, поэтому компилятор не знает, что в нём, поэтому не знает, какой код туда можно заинлайнить вместо вызова функции по указателю. Следовательно, вызовет функцию.

Возражения есть? Возражений нет.
jcxz
Цитата(Kabdim @ Jul 10 2018, 18:26) *
попросили аргументы почему оно должно работать, ссылки были приведены.

Где??? Пролистал только что весь топик - ни одной ссылки по теме не увидел.
Ваши ссылки тут вообще ни к селу ни к городу. Это как если бы доказывать, что вот, раз сейчас у меня компилятор компилит функцию с переменной расположенной в регистре R4, то значит и всегда все компиляторы должны компилить эту функцию с данной переменной расположенной в R4. Надеюсь достаточно доходчиво объяснил бесполезность ваших ссылок? 01.gif
А я придерживаюсь строгого правила: пока не доказано обратное, может быть и так и сяк - гарантий нет.
scifi
Цитата(jcxz @ Jul 11 2018, 10:10) *
А я придерживаюсь строгого правила: пока не доказано обратное, может быть и так и сяк - гарантий нет.

Вы электрон видели? Вот и я не видел. Существует ли он в природе? "Может быть и так и сяк - гарантий нет" laughing.gif
Есть ещё такой анекдот: "- Какая вероятность встретить на улице динозавра? - 50/50: либо встретишь, либо нет" biggrin.gif
jcxz
Цитата(scifi @ Jul 11 2018, 10:04) *
Возражения есть? Возражений нет.

Возражения есть. Я Вам эту отвечал на подобный аргумент - см. выше.
Что значит "не знает"? Если эта volatile-переменная - именно переменная и изменяется по ходу выполнения программы, то да - не знает.
А если она константа? Или переменная с начальной инициализацией, но неизменная в процессе выполнения? Или инициализируемая всегда одним значением? Все эти случаи для обычных data-переменных современные оптимизаторы определяют на раз, узнавая в них просто константы. Так что для всех этих случаев такие указатели будут - константы (void (* volatile const pf)()). И вот в таком случае уже могут и заинлайнить. Даже если сейчас этого не делают.
scifi
Код уже приводили:
Код
void f(void)
{
  do_something();
}

void foobar(void)
{
  void (*volatile fptr)(void);
  fptr = f;
  fptr();
}

Цитата(jcxz @ Jul 11 2018, 10:40) *
Все эти случаи для обычных data-переменных современные оптимизаторы определяют на раз, узнавая в них просто константы.

Для этого и существует слово volatile: "Оптимизатор, не твоё пи-пи дело, какой адрес хранится в указателе fptr. Может, святой дух там изменил значение. Вызывай функцию по адресу и не выпендривайся."
Вот: "An object that has volatile-qualified type may be modified in ways unknown to the implementation or have other unknown side effects." Собственно, отсюда и следует.
jcxz
Цитата(jcxz @ Jul 11 2018, 09:57) *
так как volatile (судя по её определению), должна сохранять неизменным только порядок доступов к памяти (чтений/записи).

Да, похоже что и даже это не так. Только что проверил: указание volatile даже не гарантирует сохранение порядка доступов к памяти. По крайней мере в IAR 7.80:
Код
static int DteTstInline1(char const *str, uint, uint)
{
  return 0x3871;
}
static int DteTstInline0(char const *str, uint c, uint n)
{
  static int (* volatile const pf)(char const *, uint, uint) = DteTstInline1;
  ...
  return (*pf)(str, c, __CLZ(n));
}

Код
        ...
        LDR.W    R3,??DataTable647_10  
        LDR      R3,[R3, #+0]          
        CLZ      R2,R6                  
        MOV      R1,R5                  
        MOV      R0,R4                  
        ADD      SP,SP,#+4              
        POP      {R4-R9,LR}            
        BX       R3

??DataTable647_10:                                                                                  
        DC32     `...::pf`

??_Z13DteTstInline1PKcjj:    
        MOVW     R0,#+14449  
        BX       LR

Как видно - компилятор разорвал выражение (*pf)(str, c, __CLZ(n)) и вставил между чтением volatile-константы и вызовом функции другой доступ к памяти: POP {R4-R9,LR}. Что странно, так как в пределах volatile он не должен вроде менять порядок доступов к памяти.... wacko.gif
scifi
Цитата(jcxz @ Jul 11 2018, 10:59) *
Как видно - компилятор разорвал выражение (*pf)(str, c, __CLZ(n)) и вставил между чтением volatile-константы и вызовом функции другой доступ к памяти: POP {R4-R9,LR}. Что странно, так как в пределах volatile он не должен вроде менять порядок доступов к памяти.... wacko.gif

Гарантируется порядок доступа к volatile-объектам. У вас в примере только один такой объект, поэтому говорить о порядке доступа не приходится.
Вы откровенно плохо знаете стандарт. При этом риторика огого. Почаще туда заглядывайте.
jcxz
Цитата(scifi @ Jul 11 2018, 11:03) *
Гарантируется порядок доступа к volatile-объектам. У вас в примере только один такой объект, поэтому говорить о порядке доступа не приходится.

Возможно. Но и никто из "хорошо знающих" не смог привести конкретных ссылок, а только на словах. laughing.gif
Ладно - разговор пошёл по 3-му кругу. Больше не участвую.
scifi
Цитата(jcxz @ Jul 11 2018, 11:08) *
Ладно - разговор пошёл по 3-му кругу. Больше не участвую.

И это правильно. В этом топике стандарт знают 2-3 человека, остальные просто пришли поболтать, обменяться мнениями. Демократический процесс привёл к закономерному результату: мнение настоящих специалистов никому не интересно laughing.gif
jcxz
Цитата(scifi @ Jul 11 2018, 11:11) *
И это правильно. В этом топике стандарт знают 2-3 человека, остальные просто пришли поболтать,

Ну-ну.... знают и молчат biggrin.gif
scifi
Цитата(jcxz @ Jul 11 2018, 11:12) *
Ну-ну.... знают и молчат biggrin.gif

Ну, я свой аргумент приводил раз 5. Скорее, не слушают laughing.gif
Kabdim
Цитата(jcxz @ Jul 11 2018, 10:10) *
Где??? Пролистал только что весь топик - ни одной ссылки по теме не увидел.

#50
Цитата(jcxz @ Jul 11 2018, 10:10) *
Ваши ссылки тут вообще ни к селу ни к городу. Это как если бы доказывать, что вот, раз сейчас у меня компилятор компилит функцию с переменной расположенной в регистре R4, то значит и всегда все компиляторы должны компилить эту функцию с данной переменной расположенной в R4. Надеюсь достаточно доходчиво объяснил бесполезность ваших ссылок? 01.gif

Нет, просто упорствуете в своем очевидном всем остальным невежестве. :D
Цитата(aiwa @ Jul 11 2018, 08:55) *
Это был не lvalue, а xvalue. Чтобы получить lvalue надо "fptrnv ftnv = (fptrnv)&func;" вынести за пределы функции и тогда происходит вызов.

Под конкретный оптимизатор всегда можно найти танец с бубном который выключит ту или иную оптимизацию. В предложеном варианте вы просто разносите присваивание и использование за границу глубины анализа. Но лет через 10 она поменяется, компилятор сново увидит в конкретном месте что значение переменной - конкретное им вычисленное и заоптимизирует так как заохочет. Единственная гарантированная защита которая возможна по стандарту это volatile.
aiwa
Цитата(jcxz @ Jul 11 2018, 09:57) *
Так что - даже если современные версии компиляторов не инлайнят, то ничто не мешает инлайнить последующим версиям.

Имхо все идет именно к этому. Стандарт отдает работу с volatile на усмотрение компилятору.
Цитата
What constitutes an access to an object that has volatile-qualified type is implementation-defined.
scifi
Цитата(aiwa @ Jul 11 2018, 13:01) *
Стандарт отдает работу с volatile на усмотрение компилятору.

Нет, не отдаёт. И вот эта цитата из стандарта - это вовсе не про то.
aiwa
Насколько я понимаю, под реализацией имеется ввиду компилятор+платформа.
Но по поводу доступа к volatile говорится
Цитата
Note: volatile is a hint to the implementation to avoid aggressive optimization involving the object because the value of the object might be changed by means undetectable by an implementation.

Что это всего лишь подсказка компилятору, что объект может быть изменен незамеченным для компилятора способом.
Однако в случае локального указателя с последующим вызовом, компилятор гарантированно может быть уверен какое значение содержится в нем.
Инлайн-вставка никак не противоречит стандарту.
scifi
Цитата(aiwa @ Jul 11 2018, 13:17) *
Однако в случае локального указателя с последующим вызовом, компилятор гарантированно может быть уверен какое значение содержится в нем.

Нет, не может. Стандарт запрещает: "An object that has volatile-qualified type may be modified in ways unknown to the implementation". По-моему, это фразу нельзя толковать никак иначе. Если компилятор на это забил - что же, можно подумать, мы не видели глючных компиляторов.
Кстати, я цитирую C99. Вы цитируете C++. Там есть некоторая разница. Сам предпочитаю в C++ не вникать, да и не использую я его.
Kabdim
Цитата(aiwa @ Jul 11 2018, 13:01) *
Стандарт отдает работу с volatile на усмотрение компилятору.

Приведенная строка говорит лишь о том что обращение к волайл объектам может отличаться от простого доступа на аппаратном уровне. И если бы вы прочитали следующую фразу то увидели бы что там дополнительно предупреждается что если будешь обращаться к волатайл объекту через указатель в котором этот волатайл открутили, то это ЮБ.

А так все правила для волатайла которые записаны в стандарте должна выполнять любая реализация. Независимо от того как она их имплементирует.
scifi
Цитата(Kabdim @ Jul 11 2018, 13:24) *
предупреждается что если будешь обращаться к волатайл объекту через указатель в котором этот волатайл открутили, то это ЮБ.

Значит ли это, что копирование волатайл объектов при помощи memcpy - это UB? Как страшно жЫть!
Мы-то понимаем, что memcpy может читать и писать в произвольном порядке, и даже повторно. Но зачем пугать этими страшными буквами UB?
aiwa
Цитата(scifi @ Jul 11 2018, 13:20) *
Стандарт запрещает: "An object that has volatile-qualified type may be modified in ways unknown to the implementation". По-моему, это фразу нельзя толковать никак иначе.

В английском не силен, правильно толковать не берусь, но, имхо, "мау be" - это предупреждение ни к чему строго не обязывающее.
Kabdim
Цитата(scifi @ Jul 11 2018, 13:28) *
Значит ли это, что копирование волатайл объектов при помощи memcpy - это UB? Как страшно жЫть!
Мы-то понимаем, что memcpy может читать и писать в произвольном порядке, и даже повторно. Но зачем пугать этими страшными буквами UB?

Если вы пишете абсолютно переносимый код - да. Представьте что у вас регистровый файл с байтовым доступом на 32битной машине (да, извращение). Компилятор про это извращение знает и волатайл доступ делает правильно. А теперь представьте что вы делаете memcpy в этот регистровый файл.
Стандарт такой, его задача формализовать язык которой возможно имплементировать на самой извращенской платформе, вкупе с максимальными возможностями для оптимизации.
Хотя сейчас наметилась тенденция по вычищению самых упоротых ЮБ, но комитет как всегда быстр (чуть быстрее улитки).
scifi
Цитата(aiwa @ Jul 11 2018, 13:30) *
В английском не силен, правильно толковать не берусь, но, имхо, "мау be" - это предупреждение ни к чему строго не обязывающее.

Там есть продолжение, которое именно обязывает:
Цитата
An object that has volatile-qualified type may be modified in ways unknown to the implementation or have other unknown side effects. Therefore any expression referring to such an object shall be evaluated strictly according to the rules of the abstract machine...

"Shall" - это как раз "обязательно". Как Гэндальф со своим "you shall not pass" biggrin.gif
Kabdim
Кстати с волатайл буферами (если не хочется быть платформозависимым) стоит использовать std::copy, который вроде как правильно воспринимает волатайл. Но сам указатель-итератор не должен быть выхолощен от волатайл-квалификатора.
aiwa
Цитата(scifi @ Jul 11 2018, 13:20) *
Нет, не может. Стандарт запрещает: "An object that has volatile-qualified type may be modified in ways unknown to the implementation". По-моему, это фразу нельзя толковать никак иначе. Если компилятор на это забил - что же, можно подумать, мы не видели глючных компиляторов.

А разве в таком случае компилятор к оператору ((void (*volatile)())func)(); не равным образом?
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.