This is the mail archive of the mailing list for the GCC project.

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: const volatile behaviour change in GCC 7

On 22/09/16 17:30, Richard Biener wrote:
On September 22, 2016 5:20:56 PM GMT+02:00,

On Sep 22, 2016, at 11:16 AM, David Brown

On 22/09/16 16:57, wrote:

On Sep 22, 2016, at 6:17 AM, David Brown

... Your trouble is that your two pointers, cur and end, are
pointing at different variables. Comparing two pointers that
are independent (i.e., not pointing to parts of the same
aggregate object) is undefined - the compiler can assume that
these two external objects could beanywhere in
memory, so there is no way (in pure C) for you to know or
care how they are related. Therefore it can assume that you
will never reach "cur == end".

Would making them intptr_t instead of pointers fix that?

With care, yes.  But I think it still relies on gcc not being
smart as it could be.  This seems to generate working code, but
the compier could in theory still apply the same analysis:

void rtems_initialize_executive(void) { uintptr_t cur =
(uintptr_t) _Linker_set__Sysinit_begin; uintptr_t end =
(uintptr_t) _Linker_set__Sysinit_end;

I would not expect the compiler to apply pointer rules for code
like this.  (u)intptr_t is an integer type; it happens to be one
whose width is chosen to match the width of pointers on the
platform in question, but that doesn't change the fact the type is
integer.  For example, it is perfectly valid for an intptr_t
variable to contain values that could not possibly be pointers on
a given platform.

The compiler /can/ perform such analysis and see the undefined behaviour of the code, and use that to optimise away the check for the loop. It is legal to convert (by cast or initialisation) an intptr_t or uintptr_t variable to a pointer - but it is /not/ legal to dereference it unless the intptr_t or uintptr_t was set from a legal pointer. Thus when the compiler is considering the validity of access through the casted uintptr_t variable, it can look back to where the contents of that variable came and consider those pointers. Since the compiler can assume that incrementing one pointer repeatedly never matches the other pointer (as they point to unrelated objects), the same applies even if the values have been cast back and forth through intptr_t variables.

In general, I find that if you can't figure out a simple way to express your desires for this sort of thing using fully defined standard C behaviour, then complex methods with castings and the like will not be entirely correct either. They might work at the moment - gcc is a smart compiler, but it has its limits - but they might not work in the future (as the compiler gets better all the time). Compiler-specific workarounds like the assembly macro proposed are often the safest methods. Alternatively, you accept a slight performance hit by using an extra "volatile" step to limit the optimisation. Or you change the requirements, by finding a different way to handle it - such as by letting the linker figure out the size of the table and including it as a readable constant.

I can't see how it could either.  BTW your testcase contains another
fragility, the order of two global vars.

That is, in fact, the crux of the problem - the two linker symbols are unrelated, so by the rules of C pointers they are incomparable as are all pointers derived from them.

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]