[GHC] #15696: Derived Ord instance for enumerations with more than 8 elements seems to be incorrect

GHC ghc-devs at haskell.org
Wed Oct 3 09:06:35 UTC 2018


#15696: Derived Ord instance for enumerations with more than 8 elements seems to be
incorrect
-------------------------------------+-------------------------------------
        Reporter:  mrkkrp            |                Owner:  (none)
            Type:  bug               |               Status:  patch
        Priority:  highest           |            Milestone:  8.6.2
       Component:  Compiler          |              Version:  8.6.1
      Resolution:                    |             Keywords:
Operating System:  Unknown/Multiple  |         Architecture:
 Type of failure:  Incorrect result  |  Unknown/Multiple
  at runtime                         |            Test Case:
      Blocked By:                    |             Blocking:
 Related Tickets:                    |  Differential Rev(s):  Phab:D5196
       Wiki Page:                    |
-------------------------------------+-------------------------------------

Comment (by simonpj):

 Before deciding on a ''solution'', let's record what the ''problem'' is.

 The original thinking was this.

 * `dataToTag#` is a primop, so it has no business doing anything as
 complicated as evaluating its argument; we already have `case` expressions
 that the code-gen knows how to compile.

 * So `dataToTag#` expects an evaluated argument; in fact, stronger than
 that, it expects a pointer ''to the data value itself'', so that it can
 extract the tag directly from the info table.

 * But if it so happens that the value in question already ''is''
 evaluated, that's a waste.  Example
 {{{
 f x = case x of y -> ...(dataToTag# y)...
 }}}
   It seems a bit silly for `dataToTag#` to re-evaluate `y`.

 * Hence, in `CorePrep` (see `Note [dataToTag magic]`) we add a `case`
 around the argument to `dataToTag#` ''unless'' the argument is already
 evaluated.

 * The "already-evaluated" test is `exprIsHNF`.

 * '''But alas''', while `exprIsHNF` guarantees that the thing will
 evaluate in O(1) time, it does ''not'' guarantee that we have a pointer to
 the data value itself.  Omer accurately diagnoses this problem in the Note
 in his draft Phab:D5196:
 {{{
 Note [Always introduce case around dataToTag# arg]
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 We used to only generate a case expression around dataToTag# argument when
 it's
 not known to be evaluated (checked with `exprIsHNF`), but this is
 incorrect.
 Here's an example:

   data T = T1 | T2

   main = print (I# (dataToTag# a))
     where
       {-# NOINLINE f #-}
       f = T2
       {-# NOINLINE a #-}
       a = f

 `f` is a static closure

   f_r1zz :: Main.T
   [GblId, Caf=NoCafRefs, Unf=OtherCon []] =
       CCS_DONT_CARE Main.T2! [];

 but `a` is an _updatable_ CAF!

   a_r1zA :: Main.T
   [GblId, Unf=OtherCon []] =
       [] \u [] f_r1zz;

 An updatable CAF is not in HNF (entering the closure does the `newCAF()`
 stuff
 and updates the closure with an IND_STATIC, the usual CAF evaluation
 routines),
 but according to `exprIsHNF` `a` is!
 }}}

 * I thought of having a more conservative test in `CorePrep`.  But the rot
 goes further.  Consider this, from `Note [dataToTag magic]`
 {{{
    data T = MkT !Bool
    f v = case v of
             MkT y -> dataToTag# y
 }}}
   We certainly know that `y` will be evaluated, because `MkT` is a strict
 constructor.  But does it guarantee to point directly to the data value?
 No!  The case-to-let transformation in the Simplifier
 (`Simplify.doCaseToLet`) uses `exprIsHNF` and hence will drop the eval on
 `MkT`'s argument for things like Omer's `a` binding.  And that is right in
 a way: the argument to `MkT a` certainly isn't bottom!  But nor does it
 point to the data value.

 So that is a problem.  But I think there is another.  Look in comment:13
 and comment:14. Here we have the extra `case` expressions correctly
 inserted, but we ''still'' get the wrong answer.  '''So I think there may
 be ''two'' bugs'''.

 I'd like to understand the second before looking for a fix.  Omer: could
 you investigate why comments 13 and 14 go wrong?

-- 
Ticket URL: <http://ghc.haskell.org/trac/ghc/ticket/15696#comment:30>
GHC <http://www.haskell.org/ghc/>
The Glasgow Haskell Compiler


More information about the ghc-tickets mailing list