[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