Перейти к содержанию
    

Не понятно, что SII не нравится в создании локальной неквалифицированной версии идентификатора, ведь это:

а) максимально короткий по тексту в исходнике способ, который не мозолит глаза, ведь в случае с какими-то директивами нужно было бы указывать некий диапазон (т.е. иметь открывающий и закрывающий тэг директивы, что дает куда больше лишнего текста);

б) не сует палки в колеса оптимизатору, который будет работать максимально эффективно, если как раз руками не расставлять кускам кода "тут оптимизировать, а тут нет";

в) дает возможность обращаться как к volatile-версии, так и к неквалифицированной локальной копии в тех местах, где это крайне необходимо. А нужно это там, где volatile-переменная используется в режиме read-read-...-modify-write.

А еще же ведь бывают ситуации, где в одной операции используется несколько volatile-объектов, и доступ к ним необходимо сериализовать. Там тоже без чтения в локальную копию не обойтись.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

2 часа назад, Arlleex сказал:

Не понятно, что SII не нравится в создании локальной неквалифицированной версии идентификатора, ведь это:

А ещё это -- загромождение текста лишними объявлениями. Мне не нравится то, что, кроме volatile, нет других атрибутов для переменных, которые могли бы указать, в частности, что данную переменную нельзя выкинуть из программы по желанию компилятора. Если бы был такой атрибут, его пришлось бы указать ровно один раз -- в объявлении самой переменной. Нет и атрибутов для функций, чтобы можно было, скажем, указать, что функция может вызывать побочные эффекты, поэтому нельзя перемещать код до и после вызова этой функции. Ну и т.д. и т.п.

2 часа назад, Arlleex сказал:

Там тоже без чтения в локальную копию не обойтись.

Да, бывают случаи, когда действительно не обойтись. Однако мне не нравится, что нужно постоянно применять костыли просто из-за того, что в языке отсутствуют средства, которые позволили бы объяснить компилятору, что можно делать, а что нельзя. Как человек выше указал, существуют же барьеры памяти -- так почему нельзя указать, что некая функция является барьером для оптимизации?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

7 минут назад, SII сказал:

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

Компилятор может выкинуть и volatile-объект. А атрибут есть - __attribute__((used)).

Цитата

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

Это какие, например, побочные эффекты и для чего запрещать перемещение? Так-то для этого есть барьеры оптимизации.

Может, Вы о них просто не в курсе?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

16 минут назад, SII сказал:

Мне не нравится то, что, кроме volatile, нет других атрибутов для переменных, которые могли бы указать, в частности, что данную переменную нельзя выкинуть из программы по желанию компилятора. Если бы был такой атрибут, его пришлось бы указать ровно один раз -- в объявлении самой переменной.

В IAR есть атрибут __root:

__root int x;

Он указывает компилятору не выбрасывать сам объект (переменную, константу, ...) из программы даже если к нему нет обращений. Но именно только: не выбрасывать сам объект. __root совсем не даёт гарантии от удаления операций работы с переменной, если оптимизатор решил, что скажем x нигде не используется. Если скажем в программе оптимизатор видит только обращения по записи к x, но нет чтений; или наоборот - только чтения, без записи; или есть запись и чтение, но потом считанное никак не используется - в этих случаях с _root сама x останется в памяти, но все обращения к ней могут быть удалены полностью.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

6 минут назад, Arlleex сказал:

А атрибут есть - __attribute__((used))

Стандартный? Или конкретного компилятора? В числе стандартных я не находил.

7 минут назад, Arlleex сказал:

Это какие, например, побочные эффекты и для чего запрещать перемещение?

Ну, выше я указывал проблему с моей функцией Append, добавляющей новый элемент в хвост очереди:

inline void  FIFO_HDR::Append(FIFO_LNK  *Entry)
{
    Entry->Next = nullptr;
    Last->Next = Entry;
    Last = Entry;
}

Когда очередь пуста, поле First заголовка очереди содержит нуль, а поле Last -- адрес поля First. Поле Next всегда является самым первым полем элемента очереди, поэтому такой "трюк" благополучно работает. Собственно, это очень распространённый способ организации очереди, который я встречал миллион раз (в частности, в Винде, но далеко не только в ней).

Проблема возникла из-за того, что компилятор не способен увидеть, что вызов Append может поменять поле First заголовка очереди (что происходит, когда перед вызовом очередь пуста), он видит изменение только Last. В моём случае он выполнил предвыборку полей First и Last одной командой LDRD, затем сгенерировал вызов Append, а потом воспользовался предвыбранным, а не обновлённым значением поля First -- что дало неверный результат. Если бы была возможность атрибутировать эту функцию как имеющую побочные эффекты, запрещающие перемещение кода мимо неё, проблема бы не возникала. Конечно, это в какой-то мере ограничило бы оптимизатор, но не слишком сильно, думается.

14 минут назад, Arlleex сказал:

Может, Вы о них просто не в курсе?

Запросто. Це++ необъятен.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

29 минут назад, SII сказал:

Как человек выше указал, существуют же барьеры памяти -- так почему нельзя указать, что некая функция является барьером для оптимизации?

Так укажите - внесите их внутрь функции. Кто вам мешает? Либо можно функцию обернуть в макрос, в котором перед и после вызова функции поставить барьеры.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

1 минуту назад, jcxz сказал:

В IAR есть атрибут __root:

__root int x;

Он указывает компилятору не выбрасывать сам объект (переменную, константу, ...) из программы даже если к нему нет обращений. Но именно только: не выбрасывать сам объект. __root совсем не даёт гарантии от удаления операций работы с переменной, если оптимизатор решил, что скажем x нигде не используется.

Ну, во-первых, он не решает данную проблему, как понимаете. А во-вторых, он специфичен для конкретного компилятора, что не шибко хорошо.

1 минуту назад, jcxz сказал:

Так укажите - внесите их внутрь функции. Кто вам мешает? Либо можно функцию обернуть в макрос, в котором перед и после вызова функции поставить барьеры.

Ну, в моём представлении, барьер памяти влияет на работу процессора, а не компилятора (применительно к ARM -- команды DMB, DSB, ISB). А мне нужно именно на компилятор повлиять, чтоб не переносил код, куда ему вздумается. Или речь о чём-то другом?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

13 минут назад, SII сказал:

В моём случае он выполнил предвыборку полей First и Last одной командой LDRD, затем сгенерировал вызов Append, а потом воспользовался предвыбранным, а не обновлённым значением поля First -- что дало неверный результат.

Вы бы хоть привели это в качестве примера. Но примера полного, компилируемого, со всеми объявлениями, который любой желающий может просто скопировать КАК ЕСТЬ себе в компилятор, скомпилить и проверить. А не лазать по всему топику, собирая по крупицам и додумывая, "что же у вас там твориться"? Тогда может кто и посоветовал бы, что дельное. А то складывается впечатление, что ИЛИ вы что-то не то делаете, но не договариваете; ИЛИ баг в компиляторе. Телепатическими способностями никто не обладает. Вам это уже говорили, но вы продолжаете просто жаловаться не делая реальных попыток к решению проблемы.  :unknw:

Достаточно минимального фрагмента кода. Главное - чтобы он компилировался.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Да решил я уже проблему, решил. И не жалуюсь я, а просто констатирую, что без костылей и/или потери эффективности в современной версии языка, похоже, не обойтись.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

57 minutes ago, SII said:

Проблема возникла из-за того, что компилятор не способен увидеть, что вызов Append может поменять поле First заголовка очереди (что происходит, когда перед вызовом очередь пуста), он видит изменение только Last. В моём случае он выполнил предвыборку полей First и Last одной командой LDRD, затем сгенерировал вызов Append, а потом воспользовался предвыбранным, а не обновлённым значением поля First -- что дало неверный результат. Если бы была возможность атрибутировать эту функцию как имеющую побочные эффекты, запрещающие перемещение кода мимо неё, проблема бы не возникала. Конечно, это в какой-то мере ограничило бы оптимизатор, но не слишком сильно, думается.

Это называется aliasing, обычно наоборот приходится объяснять компилятору (квалификатор restrict в аргументах функции), что это гарантированно разные переменные и перечитывать после записи по указателю не нужно. Есть правила запрещающие обращаться к одной области памяти по указателям разных типов, может быть UB, зависит от настроек компилятора.

1 hour ago, SII said:

Ну, в моём представлении, барьер памяти влияет на работу процессора, а не компилятора

Есть и на уровне компилятора барьеры, любой вызов extern функции (компилятор не видит реализации) не помеченной как pure имеет такой эффект, например.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

1 час назад, amaora сказал:

квалификатор restrict в аргументах функции

Он чисто сишный, вроде как, а в це++ не поддерживается.

1 час назад, amaora сказал:

Есть и на уровне компилятора барьеры, любой вызов extern функции

А в данном случае она inline -- для эффективности.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

1 час назад, Arlleex сказал:

В ARM CLang тоже поддерживаются

О, спасибо. Похоже, то, что нужно. Жаль, конечно, что это не стандартное средство языка, а расширение компилятора, но жрём, что дают 🙂

ADD. Правда, ссылка -- не для ARM Clang, а для старого компилятора 5-й версии, но в ARM Clang тоже есть.

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

9 часов назад, Arlleex сказал:

Компилятор может выкинуть и volatile-объект.

На основании чего?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

2 часа назад, dxp сказал:

На основании чего?

А зачем его оставлять, если нет обращений к нему?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

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

Гость
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...