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

19 минут назад, VladislavS сказал:

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

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

В случае, если такой объект объявлен где-то в другом месте, а в данной функции к нему нет обращений, то тут и удалять нечего — объект в коде не присутствует (по определению: нет обращений к нему).

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


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

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

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

https://en.cppreference.com/w/c/language/volatile

Цитата

Every access (both read and write) made through an lvalue expression of volatile-qualified type is considered an observable side effect for the purpose of optimization and is evaluated strictly according to the rules of the abstract machine (that is, all writes are completed at some time before the next sequence point). This means that within a single thread of execution, a volatile access cannot be optimized out or reordered relative to another visible side effect that is separated by a sequence point from the volatile access.

 

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


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

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

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

Так все объекты описываются в языке для некой абстрактной машины - и если машина никоим образом не влияет (не читает, не пишет) volatile-объект, то и из образа оптимизатор его выкинет. Для того, чтобы точно не выкидывал, логично задействуют линкер, которому через __attribute__((used)) компилятор "помечает" нужную переменную (константу), мол, "не трожь!". Компилятор ничего сам не выкидывает, разумеется, у него не хватает для этого полномочий. А вот линкер - вполне. Ближайшая аналогия - неиспользуемые функции - в map-файле обычно их видно хорошо.
 

53 минуты назад, makc сказал:

Так это как раз не противоречит тому, о чем говорит VladislavS. Полагаю, Вы хотели процитировать SII

Цитата

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

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


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

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

Так это как раз не противоречит тому, о чем говорит VladislavS. Полагаю, Вы хотели процитировать SII

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

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

Компилятор ничего сам не выкидывает, разумеется, у него не хватает для этого полномочий. А вот линкер - вполне. Ближайшая аналогия - неиспользуемые функции - в map-файле обычно их видно хорошо.

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

В приведённой мною цитате прямо сказано, что volatile по сути отключает оптимизации и делает невозможным для компилятора удаление подобных присваиваний. В подтверждение своих слов приведу цитату из стандарта C99:

Цитата

5.1.2.3 Program execution
The semantic descriptions in this International Standard describe the behavior of an
abstract machine in which issues of optimization are irrelevant.


Accessing a volatile object, modifying an object, modifying a file, or calling a function
that does any of those operations are all side effects, which are changes in the state of
the execution environment.
Evaluation of an expression may produce side effects. At
certain specified points in the execution sequence called sequence points, all side effects
of previous evaluations shall be complete and no side effects of subsequent evaluations
shall have taken place. (A summary of the sequence points is given in annex C.)

 

Так что сказанное мною на основании стандарта C99 противоречит утверждению @VladislavS

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

Полагаю, Вы хотели процитировать SII

Нет, ни в коем разе.

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


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

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

Компилятор ничего сам не выкидывает, разумеется, у него не хватает для этого полномочий. А вот линкер - вполне.

Так и надо говорить, что линкер. Это таки две большие разницы.  🙂 Но и линкер имеет право выбросить только если нет ни одной ссылки (обращения) на объект.

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


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

2 минуты назад, makc сказал:

Обращение как раз есть - на запись.

Что-то я упустил. VladislavS (и я тоже) имели в виду случай, когда нет явных обращений к переменной из любых единиц трансляции. Откуда появилась запись?

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


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

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

Но и линкер имеет право выбросить только если нет ни одной ссылки (обращения) на объек

Совершенно верно. Но ведь запись по произвольному адресу (по произвольному указателю) это не обращение объекту, которым оперирует линкер, это просто некий ассемблерный код, порождаемый компилятором и оптимизируемый линкером на более на более высоком уровне. Поэтому линкер на подобные элементы кода не обращает внимания, на сколько я знаю.

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

Что-то я упустил. VladislavS (и я тоже) имели в виду случай, когда нет явных обращений к переменной из любых единиц трансляции. Откуда появилась запись?

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

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


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

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

Совершенно верно. Но ведь запись по произвольному адресу (по произвольному указателю) это не обращение объекту, которым оперирует линкер, это просто некий ассемблерный код, порождаемый компилятором и оптимизируемый линкером на более на более высоком уровне. Поэтому линкер на подобные элементы кода не обращает внимания, на сколько я знаю.

Очевидно, имеется в виду LTO. Хотя это уже не просто линкер, а про сути проход компилятором уже по собранному коду. Нестандартная вещь. Со спорными в смысле надёжности/"устойчивости" результатами.

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


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

Только что, dxp сказал:

Очевидно, имеется в виду LTO. Хотя это уже не просто линкер, а про сути проход компилятором уже по собранному коду. Нестандартная вещь. Со спорными в смысле надёжности/"устойчивости" результатами.

Исходя из моего понимания LTO в gcc (лечил пару ошибок в его работе) он делает только безопасные оптимизации типа замены команды с длинным параметром адреса, занимающей, допустим 4 байта, на её двухбайтовый аналог. И тому подобное. Сложных оптимизаций я там не видел, какие делаются внутри компилятора исходя из наличия зависимостей между данными и т.п., хотя может быть просто это прошло мимо меня.

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


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

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

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


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

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

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

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

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


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

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

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

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

Вот от выкидывания компоновщиком спасает __root в IAR, а не volatile.

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

Ближайшая аналогия - неиспользуемые функции - в map-файле обычно их видно хорошо.

Неиспользуемых функций  .map-файле не должно быть по определению. :wink:  По указанной выше причине.

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


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

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

Неиспользуемых функций  .map-файле не должно быть по определению.

"В map-файле их видно хорошо"... (в смысле список выкинутых функций, имеется в виду).

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


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

51 минуту назад, makc сказал:

Совершенно верно. Но ведь запись по произвольному адресу (по произвольному указателю) это не обращение объекту, которым оперирует линкер, это просто некий ассемблерный код, порождаемый компилятором и оптимизируемый линкером на более на более высоком уровне. Поэтому линкер на подобные элементы кода не обращает внимания, на сколько я знаю.

Вы не правы. Если обращение именно к объекту си-программы, а не по абсолютному констатному адресу, то в функции, в которой это обращение находится, должна быть запись о зависимости (или required-запись) с указанием на все объекты, к которым функция обращается. (такая запись находится в .obj-файле, полученном компилятором из функции). Комповщик должен просматривать все такие записи и по ним - строить карту обращений к объектам. Если по карте он увидит, что к какому-то объекту нет ни одного обращения (это касается как переменных/констант, так и функций без __root (или его аналога)), то компоновщик удалит такой объект. И его не будет в .map-файле.

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

"В map-файле их видно хорошо"... (в смысле список выкинутых функций, имеется в виду).

Вы уверены? В каком компиляторе/компоновщике?

Только что ещё раз на всякий случай проверил в IAR, создал:

int fff1()
{
  return UART0.RBR;
}

где UART0.RBR - volatile.

fff1() ни откуда не вызывается. В .lst она конечно же есть, в .map - нету.

          int fff1()                                                      
          {                                                               
            return UART0.RBR;                                             
                  _Z4fff1v: (+1)                                          
00000000   0x....             LDR.N    R0,??DataTable14_17  ;; 0x4000c000 
00000002   0x6800             LDR      R0,[R0, #+0]                       
00000004   0x4770             BX       LR               ;; return         
00000006                      REQUIRE UART0                               
          }                                                               

И вполне логично. Ведь в .map вроде должно находиться только то, что реально есть в образе программы.

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


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

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

Вы не правы. Если обращение именно к объекту си-программы, а не по абсолютному констатному адресу

Не вижу в чём я ошибаюсь, т.к. вы сказали по сути то же самое, что и я, когда говорил об обращении с помощью указателя по произвольному адресу (неважно константному или вычисляемому динамически). При обращении по адресу теряется связь с объектом и, соответственно, исчезает явная зависимость по данным. Вы же наоборот акцентируете внимание на обращении по указателю к некому объекту (по его имени символа, которым оперирует линкер) и в этом случае связь по данным прослеживается, линкер эту связь учитывает и не удаляет соответствующий объект при запуске алгоритма сборки мусора. Так что мы оба правы, просто смотрим на слона с разных сторон. 😉

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


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

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

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

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

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

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

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

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

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

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