Re: const volatile

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Again - /please/ keep gcc-help@xxxxxxxxxxx in the "to" or "cc" list so that these mails go to mailing list. This is a public discussion and help, not personal email.


On 26/09/18 18:11, Kalamatee wrote:


On Wed, 26 Sep 2018 at 16:44, David Brown <david@xxxxxxxxxxxxxxx <mailto:david@xxxxxxxxxxxxxxx>> wrote:

    (Please keep the gcc help list on the copies here - it saves
    duplication
    of answers, and means everyone gets to see them.)

    On 26/09/2018 17:24, Kalamatee wrote:
     >
     >
     > On Wed, 26 Sep 2018 at 16:00, David Brown <david@xxxxxxxxxxxxxxx
    <mailto:david@xxxxxxxxxxxxxxx>
     > <mailto:david@xxxxxxxxxxxxxxx <mailto:david@xxxxxxxxxxxxxxx>>> wrote:
     >
     >     On 26/09/18 14:54, Kalamatee wrote:
     >      > Hi
     >      >
     >      > I am wondering if there is a reason globals marked const
    volatile
     >     are put
     >      > into the data section and not read-only as const should imply?
     >      >
     >
     >     "const" says /you/ promise not to change the value from your
    code.
     >     "volatile" says that something else might change its value
    unknown to
     >     the compiler.


That’s not ‘all’ it says. To be precise volatile tells the compiler that the object is subject to sudden change for reasons which cannot be predicted from a study of the program itself*, and forces every reference to such an object to be a genuine reference.*

Yes, that is true.

The second part is the important part - since it implies the compiler will not optimize those references away - in the case in hand this means zero is not optimized away resulting in the wrong/no exception being generated.


And that is not true.

The compiler needs to generate the same /defined/ effects for division by zero whether the zero is given as a literal constant in the code, or read in some way (such as from a volatile variable). If an operation has /undefined/ effect - such as integer division by 0 - then there is no correct behaviour to expect regardless of where the 0 comes from. For floating point division, it depends on the compiler and some settings (I am not an expert here). If the effects are defined, then they will be the same for a compile-time constant and a 0 loaded from a volatile - if not, there is a bug in the compiler.

This is only one of the many places it is used in the math code for this specific reason.


I am confident that this is either unnecessary, or a work-around for compiler problems. Others with more expertise on floating point errors can confirm or correct this.


     >
     >     It is rare to define "const volatile" variables.  It is
    usually more
     >     useful to declare pointers to them.  They are used for things
    like
     >     read-only hardware registers in microcontrollers, or for data
    that is
     >     set from outside a program but is constant from within it
    (perhaps you
     >     patch your binaries with a serial number, or a checksum - you
    could use
     >     a pointer to const volatile for reading the number in the code).
     >
     >     The only real use of defined "const volatile" variables I
    have had is
     >     for debugging - these would be variables that cannot be
    changed by the
     >     code, but you might change them via a debugger.  Usually such
    things are
     >     temporary during software development, and it's easier just
    to make them
     >     normal volatile variables.
     >
     >      > I am trying to compile code for m68k AmigaOS which is resident
     >     using the
     >      > mathlib functions which need certain constants as volatile
    to prevent
     >      > incorrect sequence re-ordering in gcc's optimizations -
    however
     >     doing so
     >      > puts the value in bss data without const.
     >      >
     >
     >     That is almost certainly not the best way to get the
    sequencing you
     >     want.  Post more details on what you are trying to do, and I
    am sure
     >     someone can give you advice.
     >
     >
     > This comes from the standard sun mathlib code.
     >
     > Here’s one example where it isn’t for the sequence but to cause a
     > controlled crash in the correct way -:
     >
    https://github.com/ezrec/AROS-mirror/blob/ABI_V1/AROS/compiler/stdc/math/e_log.c
     >

    I am not an expert in floating point details, especially not for
non-finite things, but to my mind this code is clearly unnecessary. The
    compiler will give the same result for "-two54 / vzero" whether
    vzero is
    declared "static const volatile double = 0.0;", or without the
    volatile,
    or given just as the literal 0.0 in the code.  Without the volatile,
    the
    code will be (marginally) shorter and faster as the construction of the
    infinity will be done at compile-time instead of run-time.

    Wait for others to give an opinion before changing this, however.

     >
     >      > How can we have a global that is both volatile (to prevent
    incorrect
     >      > sequencing) and const (so it is read only and stored in
    read only
     >     data
     >      > section) ?
     >
     >     Why does it matter where the data is stored?
     >
     >
     > Because .data/.bss cannot exist in the rom image.

    That is irrelevant.


It is not irrelevant.

if the value is const - it is put in .rodata but the code may be (and does end up) optimized incorrectly.

"Incorrect optimisation" sounds like a compiler bug. I think it is more likely that the situation is a bug in the code, or the programmer's expectations.

if the value is volatile - it is put in the .bss section and the code is always compiled correctly. however we can not use it in rom because .bss/.data sections cannot be used there.

That is, as I say, irrelevant.

The compiler (or, more accurately, the implementation - including linker and C startup library) will ensure that the variable has the correct initialised value before main() (or any global constructors, for C++) is called. It does not matter if the object containing the "0.0" value is in rom or in ram, as long as it has the correct value.


       If the "const volatile" variable has an explicit
    initialisation, it will be allocated to .data and initialised at
    startup
    just like any other initialised data variable.  If it is not explicitly
    initialised, it will be allocated to .bss and zeroed at startup - like
    any other uninitialised variable.

    It is only from /your/ code - code run after "main()" starts - that
    "const" says you can't write to the variable.  The C startup code will
    initialise it as normal before main() starts.


I understand what you are saying fine - and I'm sorry if it seems I am being argumentative - but it still sounds like the compiler is doing the wrong thing when it knows from "const" that the data is to be read only.

The compiler is not doing the wrong thing. "const" does /not/ mean that the data is read only - it means that /you/ are not allowed to change it. If the compiler also knows that it has full control of the variable - as is normally the case - then it knows a "const" variable can be put in rom data to save a little memory and perhaps improve cache locality. If the compiler knows that it does /not/ have full control - as is the case for a "volatile" - it will put it in modifiable ram. That is where you would normally want your volatile variables, whether they are marked "const" or not.

My only interest is in getting the issue resolved "correctly".

For now I guess I will have to add the section attribute to all constant volatiles to force the correct thing to happen.

Have you actually checked to see if something is failing to work correctly? As far as I can see, that could only happen if your system is otherwise broken and failing to correctly initialise the data section. Have you checked that what you /think/ should happen is actually correctly defined behaviour, rather than just something that happens to be the case on some targets or some circumstances?

Have you looked at other solutions, such putting the zero in read-only memory as a normal "const" variable, and then using a forced volatile read of it? ACCESS_ONCE from Linux helps for that:

	#define ACCESS_ONCE(v) *((volatile typeof((v)) *) &(v))

Have you looked at what happens if you use 0.0 instead of this "volatile const", to see that it is in some way necessary?


As I say, I am not an expert on floating point errors. But my feeling here is that you will get exactly the same results in all cases - which may not be the results you think you should get.




[Index of Archives]     [Linux C Programming]     [Linux Kernel]     [eCos]     [Fedora Development]     [Fedora Announce]     [Autoconf]     [The DWARVES Debugging Tools]     [Yosemite Campsites]     [Yosemite News]     [Linux GCC]

  Powered by Linux