Difference between GCC and Clang
I'm seeing this, superficially surprising, difference in behaviour between different editions of BBC BASIC for SDL 2.0 when presented with the statement a%% = 2^63:
GCC targetting x86 (32-bit or 64-bit): 'Number too big'
GCC targetting ARM (32-bit or 64-bit): 'Number too big'
Clang targetting x86 (64-bit): 'Number too big'
Clang targetting ARM (64-bit): No error (a%% set to &7FFFFFFFFFFFFFFF)!
Clang targetting web assembly: 'Number too big'
The code I'm using for the test is this:
Presumably some Undefined Behaviour is resulting in the difference with Clang targetting 64-bit ARM. Can anybody suggest an alternative method which will work reliably in all cases?
GCC targetting x86 (32-bit or 64-bit): 'Number too big'
GCC targetting ARM (32-bit or 64-bit): 'Number too big'
Clang targetting x86 (64-bit): 'Number too big'
Clang targetting ARM (64-bit): No error (a%% set to &7FFFFFFFFFFFFFFF)!
Clang targetting web assembly: 'Number too big'
The code I'm using for the test is this:
long long t = v.f ; if (t != truncl(v.f)) error (20, NULL) ; // 'Number too big'
Presumably some Undefined Behaviour is resulting in the difference with Clang targetting 64-bit ARM. Can anybody suggest an alternative method which will work reliably in all cases?
0
Comments
-
I don't have an ARM64 system/setup to play with, but a little thought...
Can you make it print off the values (either suitable printf()s or a gdb breakpoint) of v.f, t and truncl(v.f)?
(Aside: I get different results in Matrix Brandy for 2^63, on x86 and x86_64 I get "Number is out of range", on ARM32 I get &8000000000000000 - which, in a sense, isn't wrong. Edit - this was with GCC.)0 -
Can you make it print off the values (either suitable printf()s or a gdb breakpoint) of v.f, t and truncl(v.f)?(Aside: I get different results in Matrix Brandy for 2^63, on x86 and x86_64 I get "Number is out of range", on ARM32 I get &8000000000000000 - which, in a sense, isn't wrong.)
0 -
At some point I'll get an RPi4 and try a 64-bit OS on it. I'm currently running an RPi 3B+ running a 32-bit ARM OS. And yes, I was using GCC in all cases. (And, I get the same thing on ARM32 and ARM26 under RISC OS.)
Could your issue be that ARM doesn't support 80-bit floats in the hardware? That's just a straw being clutched! As you can't printf or logcat, you could perhaps print to the BBC display?0 -
Could your issue be that ARM doesn't support 80-bit floats in the hardware?
Anyway I said in my original post what the "issue" is: it has to be reliance on Undefined Behaviour (always assuming it's not a compiler or library bug).
My question was (and is): how can I modify the test to make it legitimate, in the sense of not relying on UB and therefore, hopefully, working equally well on every compiler and every platform?0 -
At some point I'll get an RPi4 and try a 64-bit OS on it.
#if defined(__arm__) || defined(__aarch64__) || defined(__EMSCRIPTEN__) double f ; #else long double f ; #endif
0 -
Back to your original point, having realised I can run Raspbian 64-bit on a RasPi 3B (so no need to buy a RPi4)....
(mclang is a copy of the makefile, altered to use clang instead of gcc.)soruk@raspberrypi:~/git/BBCSDL/console/rpi64 $ uname -a Linux raspberrypi 5.15.32-v8+ #1538 SMP PREEMPT Thu Mar 31 19:40:39 BST 2022 aarch64 GNU/Linux soruk@raspberrypi:~/git/BBCSDL/console/rpi64 $ make -f mclang clang -fPIC -Wall -I ../../include -I ../../../BBCSDL/include -Wno-attributes -c -O2 ../../src/bbmain.c -o bbmain.o clang -fPIC -Wall -I ../../include -I ../../../BBCSDL/include -c -O2 ../../src/bbexec.c -o bbexec.o clang -fPIC -Wall -I ../../include -I ../../../BBCSDL/include -Wno-array-bounds -c -O2 ../../src/bbeval.c -o bbeval.o clang -fPIC -Wall -I ../../include -I ../../../BBCSDL/include -c -Os ../../src/bbasmb_arm_64.c -o bbasmb.o sed 's/_\([a-z]*\)/\1/g' <../../../BBCSDL/src/bbdata_arm_64.s >bbdata.s as bbdata.s -o bbdata.o clang -fPIC -Wall -I ../../include -I ../../../BBCSDL/include -Wno-array-bounds -Wno-unused-result -c -Os ../../src/bbccos.c -o bbccos.o clang -fPIC -Wall -I ../../include -I ../../../BBCSDL/include -Wno-array-bounds -Wno-unused-result -c -O2 ../../src/bbccon.c -o bbccon.o clang -fPIC -Wall -I ../../include -I ../../../BBCSDL/include -c -O3 ../../src/sort.c -o sort.o clang -fPIC -Wall -I ../../include -I ../../../BBCSDL/include bbmain.o bbexec.o bbeval.o bbasmb.o bbdata.o bbccos.o bbccon.o sort.o -L . -L/usr/lib/ -ldl -lm -lrt -pthread \ -o bbcbasic -Wl,-s -Wl,-R,'$ORIGIN' cp bbcbasic ../../ soruk@raspberrypi:~/git/BBCSDL/console/rpi64 $ ./bbcbasic BBC BASIC for Linux Console v0.41 (C) Copyright R. T. Russell, 2022 >a%%=2^63 Number too big >_
0 -
Yes, it's iOS in which it doesn't work:
0 -
Yeah, it's curious, my thought at this point is it might be an iOS system library (or SDK component) issue then, since I don't think it's strictly a Clang on ARM64 issue, as the issue doesn't show up on Clang on ARM64 Linux.0
-
I don't think it's strictly a Clang on ARM64 issue, as the issue doesn't show up on Clang on ARM64 Linux.
But the cause isn't really important, the point is that it doesn't work. If we neglect the remote possibility that it's a genuine compiler or library bug, the likelihood is that I'm relying on UB for it to work at all. Even on the platforms (the majority) where it does currently work, it might stop working without warning.0 -
It's why I was wondering if there was a way to display the intermediate values in your function, including the truncl() function. Perhaps (and I admit it's a very dirty hack) make a build for your phone/ipad that calls your print functions to display these. It might give a pointer (pun not intended) to where it may be going wrong.0
-
make a build for your phone/ipad that calls your print functions to display these.
This is because I don't know of any way of building a version with a different filename etc. without having to go through all the hoops of creating new certificates, device lists, provisioning profiles etc. (i.e. treating it like a completely new app).It might give a pointer (pun not intended) to where it may be going wrong.
You seem to be convinced that it's not UB but a bug of some kind in the compiler, OS, libraries etc. What leads you to that conclusion? Are you of the opinion that the code I'm using is entirely legitimate and cannot trigger UB in the circumstances in which I am using it?
0 -
I don't think I can really say either way, without knowing what's in t, v.f and the result of truncl(v.f). Does the Apple developer kit not provide an emulator to test code before uploading it to real hardware? I'm pretty sure the Android SDK has this.
Incidentally, with my unexpected sign-flip on ARM26 and ARM32, I added a check to see if the sign flipped, and if so, trigger the "Number is out of range" error. This way I'm now getting consistent behaviour on Intel and ARM - including ARM64.0 -
Does the Apple developer kit not provide an emulator to test code before uploading it to real hardware?
For example if I run BBC BASIC for SDL 2.0 on the Android simulator I get an x86 CPU with 80-bit floats (and __ARM__ isn't defined). So it's a completely different environment, at a low level, from what will be running on a real device - and of course assembly-language code doesn't work.I don't think I can really say either way, without knowing what's in t, v.f and the result of truncl(v.f).
So, surely, we already know all the things you are asking about. v.f is 2^63, t is &7FFFFFFFFFFFFFFF, and so is truncl(v.f). What am I missing?0 -
Richard_Russell wrote: »We know from the code that t is equal to truncl(v.f) (at least, after a cast)
I've tried to find out how C compares a 64-bit double with a 64-bit integer. Seemingly it first converts the integer to a double, and then compares the two doubles. Of course this involves a loss of precision, because the double has only a 52-bit mantissa.
So it's entirely likely that the integer value &7FFFFFFFFFFFFFFF (2^63-1) will be converted to (exactly) 2^63 when promoted to a double, and the comparison will succeed.
This is what brings me back to the UB question. The correct functioning of my code (or not) crucially depends on how a float value of precisely 2^63 will be cast to a 64-bit integer (which cannot contain that value). I bet that's Undefined Behaviour in C.
(Distillery has become virtually unusable for me, again, because of the constant 'not responding' messages).
0 -
I've written more at the Raspberry Pi forum here.
0 -
Aside: I've been tweaking the TCP stack settings on the server, some might improve the situation, some might not... I'm testing (and posting) from a remote Linux machine, and my phone on a 4G connection, though again I am unable to reproduce any timeouts.0