Optimisations and undefined behaviour

Vincent Lefevre vincent+gcc@vinc17.org
Mon Nov 9 00:13:00 GMT 2015

On 2015-11-08 20:26:56 +0100, David Brown wrote:
> On 08/11/15 18:17, Vincent Lefevre wrote:
> >On 2015-11-08 16:14:56 +0100, David Brown wrote:
> >>I got close with a dont_care() :
> >>
> >>static inline int dont_care(void) {
> >>     int x;
> >>     asm ("" : "=r" (x) : );
> >>     return x;
> >>}
> >>
> >>This lets gcc "generate" an int without any instructions.  But the compiler
> >>doesn't know that you don't care what value it has, so this won't let the
> >   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
> >>compiler eliminate the conditional in :
> >>
> >>int foo(int x) {
> >>	if (x < 1000) {
> >>		return x * x * x;
> >>	} else {
> >>		return dont_care();
> >>	}
> >>}
> >
> >I don't think that this is the problem here. First, the conditional
> >could be eliminated only if the code is in the x < 1000 case does not
> >have side effects (such as traps in case of overflow). Moreover, even
> >if the compiler knows that it is safe to do the transformation, would
> >it know that doing it would yield faster code? This is not obvious.
> >
> The compiler knows that the code in the "x * x * x" branch is without
> side-effects or traps.  It also knows that omitting the conditional leads to
> smaller and faster code.  But what it does not know, is if the /asm/
> instruction has side effects or not.

This is exactly what I meant (sorry if this was not clear).

And about "It also knows that omitting the conditional leads to
smaller and faster code.", this also depends on the target. The
problem is that if you eliminate the conditional, the multiplications
will be done in all cases, while in the "else" part, one doesn't
need to do anything. On a target with fast conditionals and slow
multiplication, omitting the conditional may not be a good idea.
Then, I don't know how GCC decides in such cases.

> >IMHO, the right thing to do is to have a way to instruct the compiler
> >that the multiplication has some defined behavior even in case of
> >overflow. Something like -fwrapv. However, the problems with -fwrapv
> >is that it is not part of the semantic of the code and that it is
> >global.
> That would not help, as it is not the behaviour of the integer
> multiplication that matters.

In your case, it would help: without initial example

        int foo(int x) {
                if (x < 50000) bar(x);
                return x*x*x;

if -fwrapv is used, the compiler mustn't call bar(x) directly,
because the behavior is defined even for x >= 50000.

> (Changing to unsigned int, which has no undefined behaviour on
> overflow, does not make a difference.)

Changing to unsigned int could help in some cases, but not here
(unless x cannot be negative and the return type can be changed
to unsigned int too).

Vincent Lefèvre <vincent@vinc17.net> - Web: <https://www.vinc17.net/>
100% accessible validated (X)HTML - Blog: <https://www.vinc17.net/blog/>
Work: CR INRIA - computer arithmetic / AriC project (LIP, ENS-Lyon)

More information about the Gcc-help mailing list