[GHC] #16122: `round :: Double -> Int64` much slower than `fromIntegral @Int @Int64 . round`

GHC ghc-devs at haskell.org
Mon Jan 7 09:04:30 UTC 2019


#16122: `round :: Double -> Int64` much slower than `fromIntegral @Int @Int64 .
round`
-------------------------------------+-------------------------------------
        Reporter:  Fuuzetsu          |                Owner:  (none)
            Type:  bug               |               Status:  new
        Priority:  normal            |            Milestone:
       Component:  Compiler          |              Version:  8.6.3
      Resolution:                    |             Keywords:
Operating System:  Unknown/Multiple  |         Architecture:
                                     |  Unknown/Multiple
 Type of failure:  None/Unknown      |            Test Case:
      Blocked By:                    |             Blocking:
 Related Tickets:                    |  Differential Rev(s):
       Wiki Page:                    |
-------------------------------------+-------------------------------------

Comment (by simonpj):

 > It looks like user-defined rules are never applied to the RHS of other
 rules

 Hmm. You are right.  See `Note [Simplifying rules]` in `SimplUtils`.  So
 rules are switched off on both RHS and LHS of rules.

 But as noted above, built-in rules are not switched off.  In `Rules.hs` I
 see
 {{{
 matchRule dflags rule_env _is_active fn args _rough_args
           (BuiltinRule { ru_try = match_fn })
 -- Built-in rules can't be switched off, it seems
   = case match_fn dflags rule_env fn args of
         Nothing   -> Nothing
         Just expr -> Just expr
 }}}
 This seems wrong.  If we are going to switch off rules we should switch
 them all off.  We could just add
 {{{
 matchRule dflags rule_env _is_active fn args _rough_args
           (BuiltinRule { ru_try = match_fn })
   | not (is_active AlwaysActive)  -- Built-in rules are always active, but
   = Nothing                       -- sometimes we switch off rules
 altogether
                                   -- E.g. see SimplUtils.updModeForRules
   | otherwise
   = case match_fn dflags rule_env fn args of
         Nothing   -> Nothing
         Just expr -> Just expr
 }}}
 That still leaves the issue that two rules, a built-in one and a user-
 specified one, can be simultaneously active.  Which will win?  Well, it
 turns out that that user specified one does.  See this code in `Rules.hs`
 {{{
 isMoreSpecific :: CoreRule -> CoreRule -> Bool
 -- This tests if one rule is more specific than another
 -- We take the view that a BuiltinRule is less specific than
 -- anything else, because we want user-define rules to "win"
 -- In particular, class ops have a built-in rule, but we
 -- any user-specific rules to win
 --   eg (Trac #4397)
 --      truncate :: (RealFrac a, Integral b) => a -> b
 --      {-# RULES "truncate/Double->Int" truncate = double2Int #-}
 --      double2Int :: Double -> Int
 --   We want the specific RULE to beat the built-in class-op rule
 }}}
 I don't think this behaviour is documented in the user manual -- it should
 be.

 That would fix this ticket.  But in a rather delicate way: we rely on
 /not/ applying a built-in rule R1 to the RHS of another rule R2, in case
 when R2 fires there is a user-defined rule R3 that will beat R1.

 However, ignore built-in rules for the moment.  The `isMoreSpecfic` code
 above makes rule S1 "beat" rule S2 if S1 is more specific -- that is, if
 S1's LHS is a substitution instance of S2's.  (We should document this
 behaviour too.)  So consider
 {{{
 {-# RULES
   "S1" forall x. f [x]      = blah1
   "S2" forall y. f [Just y] = blah2
   "S3" forall z. h z        = f [z]
 #-}
 If we applied rules to the RHS of S3, only S1 would apply.  But if didn't
 (as happens now), and we had a term `h (Just 3)`, we'd rewrite it with S3
 to `f [Just 3]`, and now both S1 and S2 apply, and S2 would win.

 So this is a distinct reason, which we should add to `Note [Simplifying
 rules]`, for not applying rules to the RHS of rules.

 Would anyone like to write a patch for these fixes?
 * Make the above change to `matchRule`
 * Document the overlap behaviour of RULES in the user manual
 * Add the above reasoning to `Note [Simplifying rules]`

 Thanks!

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


More information about the ghc-tickets mailing list