Closed dafhi closed 1 year ago
Following example should help provide a simplified starting point to debug:
sub doCompare( byval a as single, byval b as single )
print "a:"; a, "b:"; b
print "a = b :"; cbool(a = b)
print "a <> b :"; cbool(a <> b)
print "a > b :"; cbool(a > b)
print "a < b :"; cbool(a < b)
print "a >= b :"; cbool(a >= b)
print "a <= b :"; cbool(a <= b)
print
end sub
dim as single a = 1/0
dim as single b = 1/0
doCompare( a, b )
a *= 0
b *= 0
doCompare( a, b )
Results comaring gcc and gas backends (generated on win targets):
fbc version 1.10.0, 32-bit or 64-bit gcc backend
a: 1.#INF b: 1.#INF
a = b :true
a <> b :false
a > b :false
a < b :false
a >= b :true
a <= b :true
a:-1.#IND b:-1.#IND
a = b :false
a <> b :true
a > b :false
a < b :false
a >= b :false
a <= b :false
fbc version 1.10.0, 32-bit gas backend or 64-bit gas64 backend
a: 1.#INF b: 1.#INF
a = b :true
a <> b :false
a > b :false
a < b :false
a >= b :true
a <= b :true
a:-1.#IND b:-1.#IND
a = b :false
a <> b :true
a > b :false
a < b :true
a >= b :false
a <= b :true
bug no longer appears even with my January MX Linux LiveCD w/ fbc 1.09 and Geany. methinks firmware was updated
my bad. it's still there. forgot fbc -w all
For gas 32-bit backend targeting 386, 486, 586, we get additional different results for #IND
:
a: 1.#INF b: 1.#INF
a = b :true
a <> b :false
a > b :false
a < b :false
a >= b :true
a <= b :true
a:-1.#IND b:-1.#IND
a = b :true
a <> b :false
a > b :false
a < b :true
a >= b :false
a <= b :true
After some investigation, here's kind of what is happening:
If we have some user code:
if( float rel-op float ) then
true-statement
else
false-statement
endif
where rel-op
is one of =, <>, >, <, >=, <=
.
This gets translated in the backend roughly to:
if( float inverse-rel-op ) then goto false-label
true-statement
goto exit-label
false-label:
false-statement
exit-label
Where inverse-rel-op
is the swapping of relation operators:
=
and <>
,
<
and >=
,
>
and <=
Which should be fine for integer comparisons, but messes up on float comparisons since the expectation on NaN floats is not symmetrical in this way.
Initially (float rel-op float)
returns an integer result either 0
or -1
. This is then compared to zero and we get ((float rel-op float) = 0)
to check for the false condition allowing a jump to the false label. Currently, fbc optimizes this in the AST as (float inverse-rel-op float)
, and then pass it on to the backend to deal with. Possibly we could solve in AST by never allowing this particular optimization but when trying this by disabling the optimization, fbc just crashes and it appears that the IR is not prepared to handle relation operations in this way. So currently is not really an optional optimization but a requirement so that AST/IR/BACKEND all work together. It is probably worth looking at what is going on here in more depth for understanding, but it is also probably worthwhile to hand off the optimization to the backend anyway.
Eventually, there are several areas that should be tested:
IIF( float rel-op float, true, false)
if (float rel-op float) ...
select case
, conditions/branchingfor ... next
, conditions/branching (exit)while
or do|loop
with while|until
conditions/branching (exit)resolved by #412
[update 2: simplified & run-time comment]
[old version]