This is the mail archive of the
gcc-help@gcc.gnu.org
mailing list for the GCC project.
Re: Optimisations and undefined behaviour
- From: Richard Earnshaw <Richard dot Earnshaw at foss dot arm dot com>
- To: Andrew Haley <aph at redhat dot com>, Florian Weimer <fweimer at redhat dot com>
- Cc: Segher Boessenkool <segher at kernel dot crashing dot org>, David Brown <david dot brown at hesbynett dot no>, [gcc-help] <gcc-help at gcc dot gnu dot org>
- Date: Mon, 9 Nov 2015 14:58:40 +0000
- Subject: Re: Optimisations and undefined behaviour
- Authentication-results: sourceware.org; auth=none
- References: <563BC190 dot 7080406 at hesbynett dot no> <563C7EB6 dot 9050401 at redhat dot com> <563C9DD3 dot 9030407 at hesbynett dot no> <563F9E4C dot 5000504 at redhat dot com> <20151108193430 dot GA28206 at gate dot crashing dot org> <56407162 dot 7050106 at redhat dot com> <56408D14 dot 2090101 at redhat dot com> <5640A8D3 dot 8060706 at redhat dot com> <5640AAC5 dot 9090509 at redhat dot com> <5640ADC5 dot 4090604 at redhat dot com> <5640B40C dot 9000906 at foss dot arm dot com>
On 09/11/15 14:56, Richard Earnshaw wrote:
> On 09/11/15 14:29, Andrew Haley wrote:
>> On 11/09/2015 02:16 PM, Florian Weimer wrote:
>>> On 11/09/2015 03:08 PM, Andrew Haley wrote:
>>>> On 11/09/2015 12:09 PM, Florian Weimer wrote:
>>>>> On 11/09/2015 11:11 AM, Andrew Haley wrote:
>>>>>> On 08/11/15 19:34, Segher Boessenkool wrote:
>>>>>>> The compiler is free to transform it to
>>>>>>>
>>>>>>> int foo(int x) {
>>>>>>> int t = x*x*x;
>>>>>>> if (x > 1290) {
>>>>>>> printf("X is wrong here %d, but we don't care\n", x);
>>>>>>> }
>>>>>>> return t;
>>>>>>> }
>>>>>>>
>>>>>>> because x*x*x does not have any observable behaviour, and then it is
>>>>>>> obvious it _can_ remove the printf and conditional.
>>>>>
>>>>> I'm not sure if this is a valid transformation for printf, even if
>>>>> targets stdout and does not use any custom format specifiers. Isn't it
>>>>> a cancellation point? But let's assume it's not.
>>>>>
>>>>>> Yes, that is correct. And, indeed, the hardware is free to do taht
>>>>>> too. With speculative execution, the "as if" rule is not limited to
>>>>>> the compiler.
>>>>>
>>>>> Can we disallow that optimization as a quality-of-implementation matter?
>>>>> What would be the benefit of such optimizations, other than
>>>>> discouraging programmers from using C or C++?
>>>>
>>>> There isn't really any way to distinguish between wanted optimizations
>>>> and unwanted ones.
>>>
>>> Of course there isâyou define the semantics you want, and then any
>>> optimization which breaks them is a bug.
>>>
>>>> If GCC determines that a statement is unreachable
>>>> it can be deleted, and this depends on its knowledge of UB. Like this:
>>>>
>>>> void foo(int b) {
>>>> if (b > 0) {
>>>> int m = b * 3 / 6;
>>>> if (m < 0)
>>>> die();
>>>> }
>>>> }
>>>> }
>>>>
>>>> Deleting such unreachable code happens all the time. IMO we should
>>>> not disable this optimization.
>>>
>>> This is very different from the printf example. The call to die is
>>> unreachable according to the standard semantics. The original printf
>>> call is reachable, and according to my interpretation, the
>>> transformation shown above is invalid because the abstract machine
>>> performs the side effect from the printf before undefined behavior is
>>> reached.
>>
>> Here it is again:
>>
>> int foo(int x) {
>> if (x > 1290) {
>> printf("X is wrong here %d, but we don't care\n", x);
>> }
>> return x*x*x;
>>
>> Here, the printf writes to a stream then the UB happens.
>
>
> Not if setvbuf has been used to make the stream unbuffered.
Sorry, that shouldn't appear here...
>
>> But the
>> stream is buffered and the UB kills the process before the stream is
>> flushed. There is nothing in the C specification to prevent this, and
>> neither should there be. I don't think it's even possible.
... it should be here. If the stream is unbuffered, then the ordering
is certainly well defined.
R.
>>
>>>>> I'm worried that this particular line of argument would also allow the
>>>>> movement of undefined behavior which occurs after an infinite loop in
>>>>> front of it, even if this loop performs I/O.
>>>>
>>>> Sure. But it can already do that even if the compiler does not move
>>>> anything. The I/O writes to a stream, the UB causes a segfault which
>>>> kills a process, the stream never gets written.
>>>
>>> Based on my C semantics, the UB is never reached because the loop never
>>> exits.
>>
>> a. You have your own C semantics?
>> b. Which loop? You need to let us look at it.
>>
>> I don't think that there is a program which will exhibit such
>> behaviour.
>>
>>> I just think that C semantics which only deal with terminating programs,
>>> Turing-machine-style, are not very useful for the programs we generally
>>> write.
>>
>> This is an incomprehensible statement. At leas, I don't know what it
>> means.
>>
>> Andrew.
>>
>