From: | Bart <bc@freeuk.com> |
Newsgroups: | comp.compilers |
Date: | Wed, 1 May 2019 12:40:08 +0100 |
Organization: | virginmedia.com |
References: | <72d208c9-169f-155c-5e73-9ca74f78e390@gkc.org.uk> 19-04-021 19-04-023 19-04-037 19-04-039 19-04-042 19-04-045 19-04-049 |
Injection-Info: | gal.iecc.com; posting-host="news.iecc.com:2001:470:1f07:1126:0:676f:7373:6970"; logging-data="54093"; mail-complaints-to="abuse@iecc.com" |
Keywords: | standards, arithmetic |
Posted-Date: | 01 May 2019 21:32:14 EDT |
Content-Language: | en-GB |
On 30/04/2019 14:48, David Brown wrote:
> On 29/04/2019 19:15, Bart wrote:
>> On 29/04/2019 16:08, David Brown wrote:
>>> On 29/04/2019 01:31, Bart wrote:
>>
>>>> then you don't want the compiler being clever about overflow.
>>>
>>> I /do/ want a result consistent with a single expression, or splitting
>>> up the expression.
>>
>> Then the choice is between both ways giving you 1500000000, or both
>> giving you -647483648.
>
> Let me repeat - I do not care what the results are here. I don't care
> if they are consistent with each other. I don't care if they change
> between runs of the compiler. I don't care if the result is a pink
> umbrella.
So, there's a bug in the program, an inadvertent overflow. But rather
than help in discovering that bug (such as giving the wrong results)
gcc (and its clone Clang) conveniently pretend that such bugs cannot
exist, and use that to give their code an unfair advantage:
#include <stdio.h>
int main(void) {
int x,y,z;
x=1000000000;
z=0;
for (int i=0; i<1000000000; ++i) {
y=x*3/3;
z+=y;
++x;
}
printf("%d\n",x);
printf("%d\n",y);
printf("%d\n",z);
}
Optimising compilers that don't take advantage of that undefined
behaviour give timings here of 1.25 seconds (msvc) and 1.9 seconds
(pelles c), with some taking much longer.
The two that do, give timings of 0.22 seconds (gcc) and 0.05 seconds
(clang).
However, there are a couple of problems: (1) they give different
results; (2) they cheated by not doing a billion multiplies and divides.
Note this example also includes UB due to z+=y line, but I'm only
interested in the bottom 32 bits, albeit signed, as a kind of checksum
to compare with other compilers.
For that purpose, I need the final z value to be -101627306, which will
match the same 32-bit arithmetic across languages** and in assembly.
I don't need it to be the mathematically correct 1499999999500000000,
which seems to me what you'd like it to be. gcc/clang-O3 give me
1565039360 which is neither one nor the other.
-------------------------------
(** This is the above program auto-translated from C to one of my
languages, which is sort of interesting, this being a compiler group.
Normally this is just for to help in viewing torturous C source code as
the C semantics are not translated. But tweaked with the int32() cast to
match C's intermediate calculations (usually 64-bit here), this actually
works:
import clib
global function main()int32 =
var int32 x
var int32 y
var int32 z
var int32 i
x := 1000000000
z := 0
i := 0
while i<1000000000 do
y := int32(x*3)/3
z +:= y
++x
++i
od
printf("%d\n",x)
printf("%d\n",y)
printf("%d\n",z)
return 0
end
proc start =
stop main()
end
The results match those of the non-gcc/non-clang C compilers (apart from
speed which is poor).)
Return to the
comp.compilers page.
Search the
comp.compilers archives again.