Strange behavior of Abs()! @PureBasicTeam

Just starting out? Need help? Post your questions and find answers here.
juergenkulow
Enthusiast
Enthusiast
Posts: 581
Joined: Wed Sep 25, 2019 10:18 am

Re: Strange behavior of Abs()! @PureBasicTeam

Post by juergenkulow »

STARGÅTE wrote: Thu Jan 04, 2024 1:50 pm This was fixed now in PB 6.0.

Code: Select all

; Sqt 6.10 Beta 1 Linux x64 ASM Backend 
Define x.d = 0.2
ySqr.d=Sqr(x)
If ySqr = Sqr(x)
  Debug "Same"
Else
  Debug "Unsame"
EndIf 
; Unsame

Code: Select all

; ACosH Linux x64 6.10 Beta 1 C Backend
Define x.d = 0.2
yACosH.d=ACosH(x)
If yACosH = ACosH(x)
  Debug "Same"
Else
  Debug "Unsame"
EndIf 

CompilerIf #PB_Backend_C<>#PB_Compiler_Backend 
  CompilerError "Please use C Backend."
CompilerEndIf 
; Unsame
If a fault pattern is known, is there no systematic test for similar faults?
SMaag
Enthusiast
Enthusiast
Posts: 302
Joined: Sat Jan 14, 2023 6:55 pm
Location: Bavaria/Germany

Re: Strange behavior of Abs()! @PureBasicTeam

Post by SMaag »

It's not a Bug! It's a tricky float handling!

now I think I analysed it completely. It's a little bit hard because C is doing some crazy things.

The result:
C - internaly converts the Integer to Float an store it in memory or a xmm register. But in 64-Bit Float notation.
As next C removes the sing Bit from the Float with

andps xmm0, 7FFFFFFFFFFFFFFF7FFFFFFFFFFFFFFFh

now for Integers, the value (what is a float) ist pushed on the Floating Stack with FLD command
next command is FISTP what converts back to integer and store in memory.

That's completely correct but it is done with 64-Bit notation of floats

At ASM Backend

fild value ; loads the integer into 80Bit Floating-Point
fabs ; abs of a 80 Bit floating point
fistp ; convert back from 80Bit floating point to integer

There is no Bug, but a different floating point notation
here the complete analyse (added C-Code Output 2024/01/05)

Code: Select all

s.s ="123"  ; just to find start of the code
xd.d = -7
yd.d = Abs(xd)

xf.f = -7
yf.f = Abs(xf)

xi.i = -7
yi.i = Abs(xi)

xl.l = -7
yl.l = Abs(xl)


MessageRequester("Result", "Abs() = " + yd)

; ----------------------------------------------
; C-Code Output
; ----------------------------------------------
// xd.d = -7
v_xd=-7.0;
// yd.d = Abs(xd)
double r5=PB_Abs_DOUBLE(v_xd);
v_yd=r5;

// xf.f = -7
v_xf=-7.0;
// yf.f = Abs(xf)
double r6=PB_Abs_DOUBLE(v_xf);
v_yf=r6;
 
// xi.i = -7
v_xi=-7;
// yi.i = Abs(xi)
double r7=PB_Abs_DOUBLE(v_xi);
v_yi=SYS_BankerRoundQuad(r7);
 
// xl.l = -7
v_xl=-7;
// yl.l = Abs(xl)
double r8=PB_Abs_DOUBLE(v_xl);
v_yl=SYS_BankerRound(r8);

; ----------------------------------------------
; ASM Backend - IDA disassembley
; ----------------------------------------------

; the x.d Version
fld     cs:dbl_140005050
fstp    cs:dbl_140005578
fld     cs:dbl_140005578
fabs
fstp    cs:dbl_140005588

; the x.f Version
mov     cs:dword_140005598, 0C0E00000h
fld     cs:dword_140005598
fabs
fstp    cs:flt_1400055A0

; the x.i Version
mov     cs:qword_140005580, 0FFFFFFFFFFFFFFF9h
fild    cs:qword_140005580
fabs
fistp   cs:qword_140005590

; the x.l Version
mov     cs:dword_14000559C, 0FFFFFFF9h
fild    cs:dword_14000559C
fabs
push    rax
fistp   [rsp+30h+var_30]
pop     rax
mov     cs:dword_1400055A4, eax

; ----------------------------------------------
; C Backend  - IDA disassembley
; ----------------------------------------------

; the x.d Version
; the C-Compiler moves the -7 float to xmm6 register to reuse it later
movsd   xmm6, cs:qword_140003170  ; 0C01C000000000000h ; -7 double

;now it saves the xmm6 Register.But this has now function for the ABS
movsd   cs:qword_1400057A0, xmm6

;here starts the ABS()
movapd  xmm0, xmm6
call    sub_140001CB0			; andps   xmm0, 7FFFFFFFFFFFFFFF7FFFFFFFFFFFFFFFh
movsd   cs:qword_140005780, xmm0

; the x.f Version
; store a value in Memory, maybe the -7 as single
mov     cs:dword_140005798, 0C0E00000h  
; get back the -7 from xmm6 Register
movapd  xmm0, xmm6
call    sub_140001CB0   		; andps   xmm0, 7FFFFFFFFFFFFFFF7FFFFFFFFFFFFFFFh
cvtsd2ss xmm0, xmm0
movss   cs:dword_140005778, xmm0

; the x.i Version
; store -7 quad in memory
mov     cs:qword_140005790, 0FFFFFFFFFFFFFFF9h
: but after reuse -7 double from xmm6  
movapd  xmm0, xmm6
call    sub_140001CB0			; andps   xmm0, 7FFFFFFFFFFFFFFF7FFFFFFFFFFFFFFFh
movsd   [rsp+48h+var_28], xmm0
fld     [rsp+48h+var_28]
fistp   [rsp+48h+var_20]
mov     rax, [rsp+48h+var_20]
mov     cs:qword_140005770, rax

; the x.l Version
mov     cs:dword_140005788, 0FFFFFFF9h   ; = -7 Long notation
movapd  xmm0, xmm6
call    sub_140001CB0				andps   xmm0, 7FFFFFFFFFFFFFFF7FFFFFFFFFFFFFFFh 
movsd   [rsp+48h+var_28], xmm0
fld     [rsp+48h+var_28]
fistp   [rsp+48h+var_20]
mov     rax, [rsp+48h+var_20]
mov     cs:dword_140005768, eax


; the sub to remove the sign bit
sub_140001CB0 proc near
andps   xmm0, 7FFFFFFFFFFFFFFF7FFFFFFFFFFFFFFFh
retn
sub_140001CB0 endp


Last edited by SMaag on Fri Jan 05, 2024 7:59 pm, edited 4 times in total.
DarkDragon
Addict
Addict
Posts: 2344
Joined: Mon Jun 02, 2003 9:16 am
Location: Germany
Contact:

Re: Strange behavior of Abs()! @PureBasicTeam

Post by DarkDragon »

SMaag wrote: Thu Jan 04, 2024 8:16 pm It's not a Bug! It's a tricky float handling!
It's always a bug if behavior changes without being the intention of the user. C and ASM backend should use the same function for Abs, those optimizations are a compiler thing, no linker thing. If they'd point to the same precompiled Abs it wouldn't be a problem at all. Why does the implementation of a library function change?! If the user switches backend, he still expects the results to be the same.
bye,
Daniel
User avatar
mk-soft
Always Here
Always Here
Posts: 6206
Joined: Fri May 12, 2006 6:51 pm
Location: Germany

Re: Strange behavior of Abs()! @PureBasicTeam

Post by mk-soft »

I'm not sure that all the different C compilers always come up with the same results. Or whether Intel and Arm processors deliver the same floating point results.
My Projects ThreadToGUI / OOP-BaseClass / EventDesigner V3
PB v3.30 / v5.75 - OS Mac Mini OSX 10.xx - VM Window Pro / Linux Ubuntu
Downloads on my Webspace / OneDrive
DarkDragon
Addict
Addict
Posts: 2344
Joined: Mon Jun 02, 2003 9:16 am
Location: Germany
Contact:

Re: Strange behavior of Abs()! @PureBasicTeam

Post by DarkDragon »

mk-soft wrote: Thu Jan 04, 2024 9:37 pm I'm not sure that all the different C compilers always come up with the same results. Or whether Intel and Arm processors deliver the same floating point results.
Abs is a library function, I'm not expecting library functions to be recompiled. It should be linked or not, but not recompiled. If PureBasic does some kind of inlining stop it for the C backend if it doesn't deliver the same results.

Btw. is there a way to turn SIMD optimizations off in PureBasic on C backend? The xmm0 sounds like some SSE stuff.
bye,
Daniel
SMaag
Enthusiast
Enthusiast
Posts: 302
Joined: Sat Jan 14, 2023 6:55 pm
Location: Bavaria/Germany

Re: Strange behavior of Abs()! @PureBasicTeam

Post by SMaag »

Btw. is there a way to turn SIMD optimizations off in PureBasic on C backend? The xmm0 sounds like some SSE stuff.
Theoretically yes, but it don't work!

I chaned compiler setting: compile for "all CPU s", what means no MMS, SSE, SSE2

But the C compiled result is the same.(havy use of xmm register) It seems that setting is not passed to the C-Compiler!
It's always a bug if behavior changes without being the intention of the user. C and ASM backend should use the same function for Abs
I fully agree. For a Basic dialekt this should not happen. I will do feature request to solve this inconsistency!
At least it should be added to the docmentation of the Abs()
DarkDragon
Addict
Addict
Posts: 2344
Joined: Mon Jun 02, 2003 9:16 am
Location: Germany
Contact:

Re: Strange behavior of Abs()! @PureBasicTeam

Post by DarkDragon »

SMaag wrote: Fri Jan 05, 2024 2:23 pm
Btw. is there a way to turn SIMD optimizations off in PureBasic on C backend? The xmm0 sounds like some SSE stuff.
Theoretically yes, but it don't work!

I chaned compiler setting: compile for "all CPU s", what means no MMS, SSE, SSE2

But the C compiled result is the same.(havy use of xmm register) It seems that setting is not passed to the C-Compiler!
It's always a bug if behavior changes without being the intention of the user. C and ASM backend should use the same function for Abs
I fully agree. For a Basic dialekt this should not happen. I will do feature request to solve this inconsistency!
At least it should be added to the docmentation of the Abs()
I'd prefer to see this in Bugs - C backend, as it's a bug related to backend switching. An admin could move the topic there. The compiler setting combobox for SIMD never worked 😅. It's just there for user libraries if I remember correctly.
bye,
Daniel
User avatar
mk-soft
Always Here
Always Here
Posts: 6206
Joined: Fri May 12, 2006 6:51 pm
Location: Germany

Re: Strange behavior of Abs()! @PureBasicTeam

Post by mk-soft »

Shouldn't it be a GCC compiler bug and not a PB bug?
My Projects ThreadToGUI / OOP-BaseClass / EventDesigner V3
PB v3.30 / v5.75 - OS Mac Mini OSX 10.xx - VM Window Pro / Linux Ubuntu
Downloads on my Webspace / OneDrive
SMaag
Enthusiast
Enthusiast
Posts: 302
Joined: Sat Jan 14, 2023 6:55 pm
Location: Bavaria/Germany

Re: Strange behavior of Abs()! @PureBasicTeam

Post by SMaag »

It's PB-Bug from PB_Abs_DOUBLE()
Now I got the C-Code Output

Code: Select all

// xd.d = -7
v_xd=-7.0;
// yd.d = Abs(xd)
double r5=PB_Abs_DOUBLE(v_xd);
v_yd=r5;

// xi.i = -7
v_xi=-7;
// yi.i = Abs(xi)
double r7=PB_Abs_DOUBLE(v_xi);
v_yi=SYS_BankerRoundQuad(r7);

I guesss

PB_Abs_DOUBLE()
is compiled to

sub_140001CB0 proc near
andps   xmm0, 7FFFFFFFFFFFFFFF7FFFFFFFFFFFFFFFh
retn
sub_140001CB0 endp

and
SYS_BankerRoundQuad()
fld     [rsp+48h+var_28]
fistp   [rsp+48h+var_20]
DarkDragon
Addict
Addict
Posts: 2344
Joined: Mon Jun 02, 2003 9:16 am
Location: Germany
Contact:

Re: Strange behavior of Abs()! @PureBasicTeam

Post by DarkDragon »

mk-soft wrote: Fri Jan 05, 2024 6:31 pm Shouldn't it be a GCC compiler bug and not a PB bug?
No, if the C compiler isn't compiled/called appropriately, it will use whatever it is allowed to in it's default configuration. I'm not sure, does PureBasic ship with a C compiler now or does it require you to install one? I'm mostly on my smartphone nowadays, so I cannot check.

Usually you can configure every single bit in C/C++ compilers when you compile them AND when calling them. You can change so many things, you could fill books with all the tweaks of gcc or clang.
bye,
Daniel
Post Reply