Версия для печати темы

Нажмите сюда для просмотра этой темы в обычном формате

Форум разработчиков электроники ELECTRONIX.ru _ IAR _ Инлайновая функция

Автор: Jenya7 Jul 5 2018, 08:57

Если я определяю функцию как инлайн

Код
файл .h
inline uint32_t SYSTIME_GetSystemTime(void);
файл .с
inline uint32_t SYSTIME_GetSystemTime(void)
{  
    //do something
}
то при вызове функции IAR ругается Error[Li005]: no definition for "SYSTIME_GetSystemTime"
то есть функцию надо разместить в .h файле по другому никак?

Автор: aaarrr Jul 5 2018, 09:13

Цитата(Jenya7 @ Jul 5 2018, 11:57) *
то есть функцию надо разместить в .h файле по другому никак?

А как иначе компилятор получит тело функции для встраивания?

Автор: scifi Jul 5 2018, 09:16

Зачем вам этот инлайн? Включайте в яре "multifile compilation" и оптимизацию, он сам заинлайнит получше любых вот этих потуг.

Автор: Jenya7 Jul 5 2018, 10:37

Цитата(scifi @ Jul 5 2018, 14:16) *
Зачем вам этот инлайн? Включайте в яре "multifile compilation" и оптимизацию, он сам заинлайнит получше любых вот этих потуг.


так он заинлайнит все функции. а мне нужно несколько.

Цитата(aaarrr @ Jul 5 2018, 14:13) *
А как иначе компилятор получит тело функции для встраивания?

я думал как и обычные функции - из .h файла

Автор: scifi Jul 5 2018, 10:49

Цитата(Jenya7 @ Jul 5 2018, 13:37) *
так он заинлайнит все функции

Ну это вряд ли, зависит от настроек оптимизации и характера кода. А даже если и все, что за печаль?

Цитата(Jenya7 @ Jul 5 2018, 13:37) *
а мне нужно несколько.

Интересно, зачем? Нет, правда интересно.

Автор: VladislavS Jul 5 2018, 11:05

Свидетели секты пресвятого инлайна. excl.gif

Автор: Jenya7 Jul 5 2018, 11:09

Цитата(scifi @ Jul 5 2018, 15:49) *
Ну это вряд ли, зависит от настроек оптимизации и характера кода. А даже если и все, что за печаль?


Интересно, зачем? Нет, правда интересно.

ну если все то размер кода вырастит в 10 раз. а это довольно печально.я конечно обеими руками за скорость исполнения но раздувать код до немыслимых пределов я не могу. поэтому и существует трейдофф.


Цитата(VladislavS @ Jul 5 2018, 16:05) *
Свидетели секты пресвятого инлайна. excl.gif

если вам не нужен инлайн то наверно вам можно только позавидовать.

Автор: Arlleex Jul 5 2018, 11:13

Цитата(Jenya7 @ Jul 5 2018, 15:09) *
если вам не нужен инлайн то наверно вам можно только позавидовать.

Я Вас уверяю, компилятор может посчитать, что и Вам inline, собственно, не нужен, и не станет вставлять тело функции, а вызовет ее.

Автор: jcxz Jul 5 2018, 11:15

Цитата(Jenya7 @ Jul 5 2018, 14:09) *
если вам не нужен инлайн то наверно вам можно только позавидовать.

Вы как бы даже не задумались, что подобные проблемы здесь на форуме возникают только у Вас? Совсем ни о чём не говорит? biggrin.gif

Автор: VladislavS Jul 5 2018, 11:31

Среди программистов ходит байка, что некоторые компиляторы, видя в коде больше N инлайнов, решают что юзер дурак и забивают на них.

Цитата(jcxz @ Jul 5 2018, 14:15) *
Вы как бы даже не задумались, что подобные проблемы здесь на форуме возникают только у Вас? Совсем ни о чём не говорит? biggrin.gif

Неправда ваша, последователи этой секты появляются с регулярной периодичностью.

Цитата(Jenya7 @ Jul 5 2018, 14:09) *
ну если все то размер кода вырастит в 10 раз.

Где такую забористую @$# берёте? В IAR поставьте оптимизацию Balanced и забудьте раз и навсегда.

Автор: scifi Jul 5 2018, 11:42

Цитата(VladislavS @ Jul 5 2018, 14:31) *
Где такую забористую @$# берёте? В IAR поставьте оптимизацию Balanced и забудьте раз и навсегда.

Вот-вот, я в эту же сторону намекаю beer.gif
Этот инлайн - тяжёлое наследие кровавого прошлого, когда сердобольные кодеры читали листинг дизассемблера и рыдали от горя.

Автор: demiurg_spb Jul 5 2018, 13:20

Код
файл .h
static inline uint32_t SYSTIME_GetSystemTime(void)
{  
    //do something
}
и всё

Автор: Kabdim Jul 5 2018, 13:25

Четкие пацаны, которым нужен четкий инлайн пишут не функции, а макросы. Ну а потом уже разбираются с этим счастьем.

Автор: jcxz Jul 5 2018, 14:38

Цитата(Kabdim @ Jul 5 2018, 16:25) *
Четкие пацаны, которым нужен четкий инлайн пишут не функции, а макросы. Ну а потом уже разбираются с этим счастьем.

Поддерживаю. rolleyes.gif

Автор: Arlleex Jul 5 2018, 14:53

Цитата(Kabdim @ Jul 5 2018, 17:25) *
Четкие пацаны, которым нужен четкий инлайн пишут не функции, а макросы. Ну а потом уже разбираются с этим счастьем.

Отладить сложно неудобно в макросах, плюс проверка на соответствие типов в макросах отсутствует... ИМХО, не очень удобно. Хотя сам пользуюсь biggrin.gif

Автор: scifi Jul 5 2018, 14:59

Цитата(Kabdim @ Jul 5 2018, 16:25) *
Четкие пацаны, которым нужен четкий инлайн пишут не функции, а макросы. Ну а потом уже разбираются с этим счастьем.

В основном потому, что инлайн - нестандартное расширение.
Но дело даже не в этом. Вот не могу себе представить, где это реально может понадобиться. Вернее, могу, но это будет оч. экзотический случай. В 99% случаев это можно отдать на откуп современному компилятору. Он умеет инлайнить сам без подсказок, причём функции из разных файлов без тела функции в хедере.

Автор: technik-1017 Jul 5 2018, 15:19

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

использование inline ещё не говорит о том, что функция будет сто процентов инлайниться. Для принудительного инланинга необходимо использования директиву
#pragma inline = forced

Автор: esaulenka Jul 5 2018, 19:49

Цитата(scifi @ Jul 5 2018, 17:59) *
инлайн - нестандартное расширение.

Можно пользоваться языком, у которого ключевое слово "инлайн" прописано в стандарте.

Цитата(scifi @ Jul 5 2018, 17:59) *
Но дело даже не в этом. Вот не могу себе представить, где это реально может понадобиться.

Например, какой-то макросозаменитель, вычисление которого быстрее, чем перекладывание параметров в нужном порядке по регистрам. Да, скорее всего компилятор проявит интеллект и сам заинлайнит. А может и нет. Проще подсказать.

Автор: jcxz Jul 5 2018, 20:07

Цитата(scifi @ Jul 5 2018, 17:59) *
Но дело даже не в этом. Вот не могу себе представить, где это реально может понадобиться.

Результат компиляции функции-макроса, часто порождает более оптимальный код, чем результат оптимизации даже хорошего компилятора - оптимизаторы пока не идеальны.
Да и иногда полезно при отладке (без оптимизации) иметь обязательный инлайнинг. А inline в си к сожалению вещь опциональная - на усмотрение компилятора. По-крайней мере в IAR.
А ещё бывает нужно в качестве аргумента передать несуществующее значение, которое внутри макроса, конкатенируясь, даст реальные переменные/константы. Такой финт с inline-функцией не провернёшь.
А ещё бывает желательно проверять валидность аргументов функции. В обычной функции (или inline) можно сделать такую проверку только с порождением кода и работающую в run-time. В макросе можно сделать проверку в build-time, не порождающую лишнего кода.

Автор: Сергей Борщ Jul 5 2018, 23:19

QUOTE (esaulenka @ Jul 5 2018, 22:49) *
Можно пользоваться языком, у которого ключевое слово "инлайн" прописано в стандарте.
Кстати, да. Оно есть в голых Сях уже лет семь.

Автор: VladislavS Jul 6 2018, 03:48

Начиная с C++11 в каждой новой спецификации добавляются всё новые возможности выполнения кода на этапе компиляции. Это сейчас модно, а не инлайны, с которыми компиляторы уже давным-давно научились сами разбираться. Попереключайте настройки оптимизатора и посмотрите результаты компиляции. Адептам секты пресвятого инлайна смотреть результат оптимизации с ключом Size на максимуме не рекомендую , чтобы при виде сплошного антиинлайна не возникли суицидалные мысли.

Сейчас мэинстрим чтобы программа вообще не порождала run-time кода sm.gif Модно написать программу на несколько страниц и получить пару ассемблерных команд. Даже соревнования проходят кто больше кода на этапе компиляции выполнит.

И тут очередной такой ТС с давно уже неактуальным инлайном на белом коне въезжает. Совет ТС - если у вас есть место где не проходите по скорости, а иначе зачем гнаться за инлайном, то лучше перепишите этот кусок более оптимально наблюдая за результатом компиляции. Может даже с уходом в ASM. Но надеяться на инлайн не стоит. Даже если вы директиву принудительного инлайна поставите, компилятор может её проигнорировать. Не из вредности, а из-за продвинутости оптимизатора.

Кстати, приёмов оптимизации в арсенале компилятора очень много, но почему-то только инлайн так волнует души неокрепших программистов sm.gif Почему вас раскручивание циклов вообще не волнует, а? wink.gif

Автор: scifi Jul 6 2018, 06:53

Цитата(VladislavS @ Jul 6 2018, 06:48) *
Модно написать программу на несколько страниц и получить пару ассемблерных команд. Даже соревнования проходят кто больше кода на этапе компиляции выполнит.

Это же легко: Евгения Онегина в комментарий скопипастить - и дело в шляпе biggrin.gif
Есть ещё соревнования по созданию самых непонятным программам: http://electronix.ru/redirect.php?https://www.ioccc.org/.

Автор: jcxz Jul 6 2018, 07:27

Цитата(VladislavS @ Jul 6 2018, 06:48) *
Почему вас раскручивание циклов вообще не волнует, а? wink.gif

Это точно sm.gif
Мне здесь на форуме один товарищ недавно рассказывал и пытался убеждать, что копирование через memcpy() в любом случае быстрее, чем написать это копирование простым циклом на си. Сколько я ему не намекал, что оптимизирующий компилятор может и этот цикл и даже саму memcpy(!) раскрутить в несколько ассемблерных инструкций (в зависимости от размера пересылки, выравниваний и известности параметров пересылки на этапе компиляции), а может и то и другое заменить просто оптимальным циклом с копированием внутри - так и не убедил его. Он только обиделся. Он приводил в доказательство какие-то частные случаи, в определённых созданных им условиях.
Так он и не понял, что при включении максимальной оптимизации и чем лучше и продвинутее компилятор, тем результат будет больше зависеть от реализуемого действия (алгоритма), а не от способа его реализации (цикл-ли, инлайн или даже memcpy).
Так и ТС здесь - уверен что что-то зависит от того, с inline он напишет функцию или без. wink.gif
Так что как я неоднократно убеждался - понимание принципов работы оптимизаторов ускользает от основной массы программистов, сколько не описывай это в мануалах. Ну и в результирующий ассемблерный код тоже как видно мало кто смотрит и понимает его. Иначе бы даже без мануалов всё было понятно.

PS: Кстати - вдогонку, в тему: Иногда возникает желание сказать компилятору (IAR в частности), чтобы он не inline-ил функцию. Так это сделать посложнее чем сказать inline.
А вот сделать функцию жёстко "не inline" вне зависимости от работы оптимизатора - это имхо гораздо полезнее чем сделать её inline.

Автор: scifi Jul 6 2018, 07:36

Цитата(jcxz @ Jul 6 2018, 10:27) *
Мне здесь на форуме один товарищ недавно рассказывал и пытался убеждать, что копирование через memcpy() в любом случае быстрее, чем написать это копирование простым циклом на си. Сколько я ему не намекал, что оптимизирующий компилятор может и этот цикл и даже саму memcpy(!) раскрутить в несколько ассемблерных инструкций (в зависимости от размера пересылки, выравниваний и известности параметров пересылки на этапе компиляции), а может и то и другое заменить просто оптимальным циклом с копированием внутри - так и не убедил его. Он только обиделся. Он приводил в доказательство какие-то частные случаи, в определённых созданных им условиях.

Был случай, когда хотелось, чтобы memcpy был маленький и медленный. Скорость не нужна, а байтов жалко. Библиотечный memcpy шибко умный, видимо. Ускоренный настолько, что весит сотни байт :-( Хоть заменяй своим.

Цитата(jcxz @ Jul 6 2018, 10:27) *
PS: Кстати - вдогонку, в тему: Иногда возникает желание сказать компилятору (IAR в частности), чтобы он не inline-ил функцию. Так это сделать посложнее чем сказать inline.
А вот сделать функцию жёстко "не inline" вне зависимости от работы оптимизатора - это имхо гораздо полезнее чем сделать её inline.

Очевидно же: взять адрес функции, загнать его в указатель volatile, не? И вызывать через этот указатель для верности.

Автор: jcxz Jul 6 2018, 07:51

Цитата(scifi @ Jul 6 2018, 10:36) *
Был случай, когда хотелось, чтобы memcpy был маленький и медленный. Скорость не нужна, а байтов жалко. Библиотечный memcpy шибко умный, видимо. Ускоренный настолько, что весит сотни байт :-( Хоть заменяй своим.

Когда хочется иметь определённый ассемблерный результат, вне зависимости от умности компилятора, то есть только один надёжный выход - ассемблер. И не нужно его бояться.

Цитата(scifi @ Jul 6 2018, 10:36) *
Очевидно же: взять адрес функции, загнать его в указатель volatile, не? И вызывать через этот указатель для верности.

Не уверен что это прокатит с любым компилятором. Да, указатель он создаст, и пожалуй даже поставит команду LDR Rx, указатель. Но кто дальше ему мешает просто вставить код функции? Ведь все условия volatile указателя он уже выполнил: создал его, и чтение его выполнил.

PS: Про #pragma inline=never знаю и его сейчас и использую в IAR. Но это компиляторо-зависимо.

Автор: demiurg_spb Jul 6 2018, 11:13

Цитата(jcxz @ Jul 6 2018, 10:51) *
А в IAR разве нет атрибутов наподобие gcc и keil?
У меня написан compiler.h в котором все нюансы компиляторов запрятаны. Типа
Код
#if defined(__GNUC__)
#      define __is_always_inline   __inline__ __attribute__((__always_inline__))
#endif

А пользовательский код никаких специфических вещей компиляторов не использует - только свою прослойку.
Код
static __is_always_inline void foo(void)
{
    // do something
}
ИМХО прагмы в коде последнее дело...

Автор: jcxz Jul 6 2018, 11:23

Цитата(demiurg_spb @ Jul 6 2018, 14:13) *
А в IAR разве нет атрибутов наподобие gcc и keil?

Атрибутов не знаю, знаю только прагмы. И тогда Ваш compiler.h - неверный.

Цитата(demiurg_spb @ Jul 6 2018, 14:13) *
ИМХО прагмы в коде последнее дело...

Согласен. Но я не знаю другого способа явно указать IAR-у - инлайнить или нет. sad.gif

Автор: scifi Jul 6 2018, 11:25

Цитата(jcxz @ Jul 6 2018, 10:51) *
Но кто дальше ему мешает просто вставить код функции?

Как кто? Вызов функции по указателю volatile. Он же не знает, что там в этом указателе (он же volatile!), поэтому именно вызовет функцию по указателю без всяких инлайнов. И заметьте, это чистый Си, без всяких прагм и атрибутов.

Автор: VladislavS Jul 6 2018, 11:26

Цитата(jcxz @ Jul 6 2018, 14:23) *
Но я не знаю другого способа явно указать IAR-у - инлайнить или нет. sad.gif

Не знаю с какой версии, но
Цитата
In extended language mode, the IAR C/C++ Compiler also supports a limited selection
of GCC-style attributes. Use the __attribute__ ((attribute-list)) syntax for
these attributes.
The following attributes are supported in part or in whole. For more information, see the
GCC documentation.
● alias
● aligned
● always_inline
● cmse_nonsecure_call
● cmse_nonsecure_entry
● constructor
● deprecated
● noinline
● noreturn
● packed
● pcs (for IAR type attributes used on functions)
● section
● target (for IAR object attributes used on functions)
● transparent_union
● unused
● used
● volatile
● weak

Автор: demiurg_spb Jul 6 2018, 11:30

Немного погуглив нашёл _Pragma(...)

Код
#ifdef IAR
        #define NO_OPT _Pragma ("optimize=none")
#endif

NO_OPT void some_func(void)
{

}

Автор: jcxz Jul 6 2018, 11:44

Цитата(scifi @ Jul 6 2018, 14:25) *
Как кто? Вызов функции по указателю volatile. Он же не знает, что там в этом указателе (он же volatile!), поэтому именно вызовет функцию по указателю без всяких инлайнов. И заметьте, это чистый Си, без всяких прагм и атрибутов.

Да, в текущей версии IAR это работает, но нет уверенности, что будет также работать и в последующих.
В доках насчёт volatile говорится только применительно к данным, про код ничего не упоминается.

Цитата(demiurg_spb @ Jul 6 2018, 14:30) *
Немного погуглив нашёл _Pragma(...)
Код
#ifdef IAR
        #define NO_OPT _Pragma ("optimize=none")
#endif

Ну так это совсем не то. Это как бороться с перхотью при помощи топора biggrin.gif
Тогда уж так: #define NO_OPT _Pragma("inline=never")

Автор: demiurg_spb Jul 6 2018, 11:47

Цитата(jcxz @ Jul 6 2018, 14:44) *
Ну так это совсем не то.
То, то.
ИМХО внутри _Pragma(...) можно всё что угодно написать (даже "inline = forced") и задефайнить...

Автор: scifi Jul 6 2018, 12:54

Цитата(jcxz @ Jul 6 2018, 14:44) *
Да, в текущей версии IAR это работает, но нет уверенности, что будет также работать и в последующих.
В доках насчёт volatile говорится только применительно к данным, про код ничего не упоминается.

Это уже паранойа какая-то. Так можно в чём угодно усомниться laughing.gif
Впрочем, я не настаиваю, куйте своё счастье самостоятельно rolleyes.gif

Автор: jcxz Jul 6 2018, 15:24

Цитата(scifi @ Jul 6 2018, 15:54) *
Это уже паранойа какая-то. Так можно в чём угодно усомниться laughing.gif
Впрочем, я не настаиваю, куйте своё счастье самостоятельно rolleyes.gif

В мануале на IAR нет ничего про volatile для указателей на функции. Судя по контексту описания, там везде подразумевается его использование для описания данных. Поэтому и осторожничаю.
Всё-таки про прагму чётко там написано: не будет инлайнится и всё тут.
А как поведёт себя в последующих версия IAR с void (* volatile)() - я не уверен.
Но всё равно - спасибо Вам что указали на такую возможность запрета inline. Мне самому не пришло в голову в своё время. rolleyes.gif

Автор: Kabdim Jul 6 2018, 15:36

Цитата(Arlleex @ Jul 5 2018, 17:53) *
Отладить сложно неудобно в макросах, плюс проверка на соответствие типов в макросах отсутствует... ИМХО, не очень удобно. Хотя сам пользуюсь biggrin.gif

Не только лишь все умеют иронию. sm.gif
Цитата(jcxz @ Jul 6 2018, 14:44) *
Да, в текущей версии IAR это работает, но нет уверенности, что будет также работать и в последующих.
В доках насчёт volatile говорится только применительно к данным, про код ничего не упоминается.

Ну так у компилятора нет гарантий что волотайл указывает на тот код который он думает, поэтому оптимизировать инлайном он не имеет права.

Автор: jcxz Jul 6 2018, 16:32

Цитата(Kabdim @ Jul 6 2018, 18:36) *
Ну так у компилятора нет гарантий что волотайл указывает на тот код который он думает, поэтому оптимизировать инлайном он не имеет права.

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

Автор: Jenya7 Jul 7 2018, 05:45

вобщем вдруг осенило. вспомнил

Код
#define Foo() do{ } while (0);
вот тебе бабушка и юрьев день инлайн

а впринципе я тут посчитал - что мы экономим на инлайне - 8-10 инструкций - 100-200 наносекунд - наверно это не существенно. разве это спасет отца русской демократии?

Автор: Kabdim Jul 8 2018, 15:52

Цитата(jcxz @ Jul 6 2018, 19:32) *
Вы полагаете, что способ предложенный scifi, не только сделает функцию явно не-инлайновой, но и запретит оптимизацию её кода? хмм.... если это так, то тогда этот способ некошерный...

Почему оптимизацию-то запретит? Внутри всё заоптимизирует и снаружи тоже, а вот функцию как единицу вызова оставит. Единственное что вызывать её нужно всё таки по указателю, если быть педантичным.

Автор: jcxz Jul 8 2018, 23:47

Цитата(Kabdim @ Jul 8 2018, 18:52) *
Почему оптимизацию-то запретит? Внутри всё заоптимизирует и снаружи тоже, а вот функцию как единицу вызова оставит.

И на каком основании Вы делаете такой вывод? Перечитал в мануале на IAR всё что касается volatile - там ни слова об указателях на функции.

Автор: Kabdim Jul 9 2018, 01:10

Сильно удивляете. Стандарт на язык читать надо, а не иаровский мануал.

Автор: Arlleex Jul 9 2018, 18:49

Цитата(Jenya7 @ Jul 7 2018, 08:45) *
вобщем вдруг осенило. вспомнил
Код
#define Foo() do{ } while (0);
вот тебе бабушка и юрьев день инлайн

а впринципе я тут посчитал - что мы экономим на инлайне - 8-10 инструкций - 100-200 наносекунд - наверно это не существенно. разве это спасет отца русской демократии?

Только без точки с запятой в конце.

Автор: aiwa Jul 9 2018, 20:12

Цитата(Kabdim @ Jul 9 2018, 04:10) *
Сильно удивляете. Стандарт на язык читать надо, а не иаровский мануал.

Похоже на то, что стандарт не в курсе дела.

Автор: jcxz Jul 10 2018, 06:17

Цитата(Kabdim @ Jul 9 2018, 04:10) *
Сильно удивляете. Стандарт на язык читать надо, а не иаровский мануал.

Можете привести выдержку из стандартна касательно этого?

Автор: scifi Jul 10 2018, 06:23

Цитата(jcxz @ Jul 10 2018, 09:17) *
Можете привести выдержку из стандартна касательно этого?

Стандарт не обязан разжёвывать каждую ситуацию. Кое-что следует логически из того, что там написано.
У вас опасение, что при вызове функции по указателю компилятор заинлайнит код. Причина, по которой этого не случится: указатель объявлен как volatile, поэтому компилятор не знает, что в нём, поэтому не знает, какой код туда можно заинлайнить вместо вызова функции по указателю. Следовательно, вызовет функцию.

Автор: jcxz Jul 10 2018, 06:45

Цитата(scifi @ Jul 10 2018, 09:23) *
Кое-что следует логически из того, что там написано.

Из описание действия volatile на переменные, следует что компилятор не должен оптимизировать никакие операции с данными через эти указатели.
Соответственно - для указателей на функции можно ожидать, что он не будет оптимизировать и сами функции? Или даже - на всю цепочку функций, вызываемых из данной функции? А это меня не устраивает.

Цитата(scifi @ Jul 10 2018, 09:23) *
У вас опасение, что при вызове функции по указателю компилятор заинлайнит код.

Нет, скорее у меня опасение, что раз это явно не описано в стандарте, то может трактоваться строителями компиляторов так, как они считают правильным.
Это называется "undefined behaviour".

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

Что значит "не знает"? Для функции есть объявление.
И если подходить логически, то что значит volatile для переменных? Он собственно означает, что порядок и количество операций доступа к данным при использовании volatile в оптимизированном коде должны быть точно такими же как в неоптимизированном. Раз в неоптимизированном коде сперва следует чтение указателя из памяти, значит компилятор при оптимизации не должен удалять такое чтение. Но вот что нельзя удалить пару инструкций BLX Rx/BX LR - это из описания volatile для данных никак не следует. Так как они не выполнят операций с памятью.
volatile накладывает ограничение на выполнение операций с объектом, а не на расположение объекта. Так что ничто не мешает ему расположить этот объект сразу после точки вызова, убрав инструкции передачи управления. Имхо.

Автор: aiwa Jul 10 2018, 06:55

Имхо, в случае с указателем на функцию играет роль является ли этот указатель lvalue или нет.

lvalue нельзя инлайнить, а xvalue и rvalue - можно.

Автор: scifi Jul 10 2018, 06:55

Я устал объяснять. Просто скажу, что вы заблуждаетесь.

Автор: VladislavS Jul 10 2018, 07:10

Цитата(jcxz @ Jul 10 2018, 09:45) *
Соответственно - для указателей на функции можно ожидать, что он не будет оптимизировать и сами функции?

Не совсем понятно почему такое может быть. Функция на момент компиляции ничего не знает о существовании указателей на неё. Она даже где-то в другом модуле может быть скомпилирована и лежит себе ждёт своего часа. Остаётся взять её адрес и вызвать пока тёпленькая.

Автор: aiwa Jul 10 2018, 07:11

{
((void (* volatile)())func)(); // оптимизирует несмотря на volatile. наверное потому, что получаемый указатель rvalue;
}

Автор: Kabdim Jul 10 2018, 10:29

N3690

Цитата
146p 7.1.6.1 The cv-qualifiers
7 [ 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. Furthermore,
for some implementations, volatile might indicate that special hardware instructions are required to access
the object. See 1.9 for detailed semantics. In general, the semantics of volatile are intended to be the
same in C++ as they are in C. — end note ]

8p 1.9 Program execution
8 The least requirements on a conforming implementation are:
Access to volatile objects are evaluated strictly according to the rules of the abstract machine

Т.е. оно не заоптимизирует указатель даже если не видит переприсваиваний ему, а в нужном участке кода считает его значение и выполнит вызов функции по нему.

Отчего у вас в голове родилась странная идея что внутри тела фукнции будет отключена оптимизация я не знаю. Она неверна.

Цитата(aiwa @ Jul 10 2018, 10:11) *
{
((void (* volatile)())func)(); // оптимизирует несмотря на volatile. наверное потому, что получаемый указатель rvalue;
}

Нет волатайл объекта - нет ограничений. http://electronix.ru/redirect.php?https://godbolt.org/g/oVfR1M.

Автор: aiwa Jul 10 2018, 11:32

Цитата(Kabdim @ Jul 10 2018, 13:29) *
Нет волатайл объекта - нет ограничений. http://electronix.ru/redirect.php?https://godbolt.org/g/oVfR1M.


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


Автор: VladislavS Jul 10 2018, 11:41

Господа, вы научно-технические извращенцы sm.gif Скомпилируйте функцию в отдельном модуле и никто её встраивать не будет. Про мультифайл компилэйшин знаю, но это легко не включается.

Автор: scifi Jul 10 2018, 11:51

Цитата(aiwa @ Jul 10 2018, 14:32) *
В одном случае работает, во втором не работает:

А не надо делать так, чтобы не работало. Очевидно же! biggrin.gif

Автор: jcxz Jul 10 2018, 11:56

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

Ну-ну. А чекбокс "Inline small routines" в IAR в свойствах компоновщика не замечали? rolleyes.gif
А значит инлайнить может не только компилятор, но и компоновщик. Конечно косвенных вызовов это не касается.

Автор: VladislavS Jul 10 2018, 12:01

Блин, секта отрицателей инлайна, оказывается, ещё крепче sm.gif

Автор: demiurg_spb Jul 10 2018, 12:26

Тут ещё extern inline не обсосали)))

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

http://electronix.ru/redirect.php?https://www.ibm.com/support/knowledgecenter/en/ssw_ibm_i_71/rzarg/inline_linkage.htm
http://electronix.ru/redirect.php?http://m68hc11.serveftp.org/inline-1.php

Автор: aiwa Jul 10 2018, 13:41

Цитата(VladislavS @ Jul 10 2018, 15:01) *
Блин, секта отрицателей инлайна, оказывается, ещё крепче sm.gif

Та мелочи. Скоро придет Лесник.

Автор: Kabdim Jul 10 2018, 13:49

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

К чему вы это? Второй вариант снова попытка извернутся и не создавать указателя, которая закономерно заканчивается своершенно предсказуемым итогом. Если нужно гарантировать отсутствие инлайна никуда вы не отвертитись от указателя в памяти в явном виде.

Автор: VladislavS Jul 10 2018, 14:33

Придумал. Если функцию разместить в другой секции, то нет той силы которая её встроит. Двойное ИМХО.

Автор: aiwa Jul 10 2018, 14:36

Цитата(Kabdim @ Jul 10 2018, 16:49) *
К чему вы это? Второй вариант снова попытка извернутся и не создавать указателя, которая закономерно заканчивается своершенно предсказуемым итогом. Если нужно гарантировать отсутствие инлайна никуда вы не отвертитись от указателя в памяти в явном виде.


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

Автор: Kabdim Jul 10 2018, 15:26

Почему ничего не меняется? http://electronix.ru/redirect.php?https://godbolt.org/g/sPh8kX. Возможно вы захватили ссылку на годболт в котором я описался в тайпдефе и постарался быстро это исправить, посмотрите это место внимательно.

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

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

УПД2: Вот кстати http://electronix.ru/redirect.php?https://godbolt.org/g/jFaEKS.

Автор: aiwa Jul 11 2018, 05:55

Цитата(Kabdim @ Jul 10 2018, 18:26) *
УПД2: Вот кстати http://electronix.ru/redirect.php?https://godbolt.org/g/jFaEKS.

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

Автор: jcxz Jul 11 2018, 06:57

Цитата(aiwa @ Jul 10 2018, 17:36) *
Если его объявление заменить просто вызовом функции ничего не поменяется.

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

Автор: scifi Jul 11 2018, 07:04

Цитата(jcxz @ Jul 11 2018, 09:57) *
ничто не мешает инлайнить последующим версиям.

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

Возражения есть? Возражений нет.

Автор: jcxz Jul 11 2018, 07:10

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

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

Автор: scifi Jul 11 2018, 07:23

Цитата(jcxz @ Jul 11 2018, 10:10) *
А я придерживаюсь строгого правила: пока не доказано обратное, может быть и так и сяк - гарантий нет.

Вы электрон видели? Вот и я не видел. Существует ли он в природе? "Может быть и так и сяк - гарантий нет" laughing.gif
Есть ещё такой анекдот: "- Какая вероятность встретить на улице динозавра? - 50/50: либо встретишь, либо нет" biggrin.gif

Автор: jcxz Jul 11 2018, 07:40

Цитата(scifi @ Jul 11 2018, 10:04) *
Возражения есть? Возражений нет.

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

Автор: scifi Jul 11 2018, 07:45

Код уже приводили:

Код
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 Jul 11 2018, 07:59

Цитата(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 Jul 11 2018, 08:03

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

Гарантируется порядок доступа к volatile-объектам. У вас в примере только один такой объект, поэтому говорить о порядке доступа не приходится.
Вы откровенно плохо знаете стандарт. При этом риторика огого. Почаще туда заглядывайте.

Автор: jcxz Jul 11 2018, 08:08

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

Возможно. Но и никто из "хорошо знающих" не смог привести конкретных ссылок, а только на словах. laughing.gif
Ладно - разговор пошёл по 3-му кругу. Больше не участвую.

Автор: scifi Jul 11 2018, 08:11

Цитата(jcxz @ Jul 11 2018, 11:08) *
Ладно - разговор пошёл по 3-му кругу. Больше не участвую.

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

Автор: jcxz Jul 11 2018, 08:12

Цитата(scifi @ Jul 11 2018, 11:11) *
И это правильно. В этом топике стандарт знают 2-3 человека, остальные просто пришли поболтать,

Ну-ну.... знают и молчат biggrin.gif

Автор: scifi Jul 11 2018, 08:13

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

Ну, я свой аргумент приводил раз 5. Скорее, не слушают laughing.gif

Автор: Kabdim Jul 11 2018, 09:06

Цитата(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 Jul 11 2018, 10:01

Цитата(jcxz @ Jul 11 2018, 09:57) *
Так что - даже если современные версии компиляторов не инлайнят, то ничто не мешает инлайнить последующим версиям.

Имхо все идет именно к этому. Стандарт отдает работу с volatile на усмотрение компилятору.
Цитата
What constitutes an access to an object that has volatile-qualified type is implementation-defined.

Автор: scifi Jul 11 2018, 10:03

Цитата(aiwa @ Jul 11 2018, 13:01) *
Стандарт отдает работу с volatile на усмотрение компилятору.

Нет, не отдаёт. И вот эта цитата из стандарта - это вовсе не про то.

Автор: aiwa Jul 11 2018, 10:17

Насколько я понимаю, под реализацией имеется ввиду компилятор+платформа.
Но по поводу доступа к 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 Jul 11 2018, 10:20

Цитата(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 Jul 11 2018, 10:24

Цитата(aiwa @ Jul 11 2018, 13:01) *
Стандарт отдает работу с volatile на усмотрение компилятору.

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

А так все правила для волатайла которые записаны в стандарте должна выполнять любая реализация. Независимо от того как она их имплементирует.

Автор: scifi Jul 11 2018, 10:28

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

Значит ли это, что копирование волатайл объектов при помощи memcpy - это UB? Как страшно жЫть!
Мы-то понимаем, что memcpy может читать и писать в произвольном порядке, и даже повторно. Но зачем пугать этими страшными буквами UB?

Автор: aiwa Jul 11 2018, 10:30

Цитата(scifi @ Jul 11 2018, 13:20) *
Стандарт запрещает: "An object that has volatile-qualified type may be modified in ways unknown to the implementation". По-моему, это фразу нельзя толковать никак иначе.

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

Автор: Kabdim Jul 11 2018, 10:34

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

Если вы пишете абсолютно переносимый код - да. Представьте что у вас регистровый файл с байтовым доступом на 32битной машине (да, извращение). Компилятор про это извращение знает и волатайл доступ делает правильно. А теперь представьте что вы делаете memcpy в этот регистровый файл.
Стандарт такой, его задача формализовать язык которой возможно имплементировать на самой извращенской платформе, вкупе с максимальными возможностями для оптимизации.
Хотя сейчас наметилась тенденция по вычищению самых упоротых ЮБ, но комитет как всегда быстр (чуть быстрее улитки).

Автор: scifi Jul 11 2018, 10:35

Цитата(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 Jul 11 2018, 10:50

Кстати с волатайл буферами (если не хочется быть платформозависимым) стоит использовать std::copy, который вроде как правильно воспринимает волатайл. Но сам указатель-итератор не должен быть выхолощен от волатайл-квалификатора.

Автор: aiwa Jul 12 2018, 10:01

Цитата(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 (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)