Opened 5 years ago

Closed 4 years ago

Last modified 4 years ago

#10215 closed bug (duplicate)

Optimizer has bugs regarding handling of -0.0

Reported by: lerkok Owned by:
Priority: high Milestone:
Component: Compiler Version: 7.8.3
Keywords: Cc:
Operating System: Unknown/Multiple Architecture: Unknown/Multiple
Type of failure: Incorrect result at runtime Test Case:
Blocked By: Blocking:
Related Tickets: #9238 Differential Rev(s):
Wiki Page:

Description

This is most likely related to https://ghc.haskell.org/trac/ghc/ticket/9238

Perhaps it can be merged into that if it is indeed the case, though it'd be good for an expert to take a look and make sure first that the culprit is indeed the same. In any case, the program in this ticket can at least serve as a test-case.

I observed this on 7.8.3; though I suspect the same holds in the just released 7.10.1 as well. For the following program:

testF :: Float -> Bool
testF x = x == 0 && not (isNegativeZero x)

testD :: Double -> Bool
testD x = x == 0 && not (isNegativeZero x)

main :: IO ()
main = do print $ testF (-0.0)
          print $ testD (-0.0)

If I compile with no optimizations, then I get the correct answers:

$ /bin/rm -f a.hi a.o a; ghc -O0 a; ./a
[1 of 1] Compiling Main             ( a.hs, a.o )
Linking a ...
False
False

But if I turn optimizations on, then I get:

$ /bin/rm -f a.hi a.o a; ghc -O2 a; ./a
[1 of 1] Compiling Main             ( a.hs, a.o )
Linking a ...
True
True

which is just plain wrong.

Change History (2)

comment:1 Changed 4 years ago by bgamari

Resolution: duplicate
Status: newclosed

Indeed this gets turned into a case expression matching on a float so I believe this is the same as #9238.

Last edited 4 years ago by bgamari (previous) (diff)

comment:2 Changed 4 years ago by Ben Gamari <ben@…>

In eb975d2/ghc:

Fix treatment of -0.0

Here we fix a few mis-optimizations that could occur in code with
floating point comparisons with -0.0. These issues arose from our
insistence on rewriting equalities into case analyses and the
simplifier's ignorance of floating-point semantics.

For instance, in Trac #10215 (and the similar issue Trac #9238) we
turned `ds == 0.0` into a case analysis,

```
case ds of
    __DEFAULT -> ...
    0.0 -> ...
```

Where the second alternative matches where `ds` is +0.0 and *also* -0.0.
However, the simplifier doesn't realize this and will introduce a local
inlining of `ds = -- +0.0` as it believes this is the only
value that matches this pattern.

Instead of teaching the simplifier about floating-point semantics
we simply prohibit case analysis on floating-point scrutinees and keep
this logic in the comparison primops, where it belongs.

We do several things here,

 - Add test cases from relevant tickets
 - Clean up a bit of documentation
 - Desugar literal matches against floats into applications of the
   appropriate equality primitive instead of case analysis
 - Add a CoreLint to ensure we don't pattern match on floats in Core

Test Plan: validate with included testcases

Reviewers: goldfire, simonpj, austin

Subscribers: thomie

Differential Revision: https://phabricator.haskell.org/D1061

GHC Trac Issues: #10215, #9238
Note: See TracTickets for help on using tickets.