
#14941: Switching direct type family application to EqPred (~) prevents inlining in code using vector (10x slowdown) -------------------------------------+------------------------------------- Reporter: nh2 | Owner: davide Type: bug | Status: new Priority: normal | Milestone: Component: Compiler | Version: 8.2.2 Resolution: | Keywords: Operating System: Unknown/Multiple | Architecture: Type of failure: Runtime | Unknown/Multiple performance bug | Test Case: Blocked By: | Blocking: Related Tickets: | Differential Rev(s): Wiki Page: | -------------------------------------+------------------------------------- Comment (by simonpj): Thanks for the simpler example. I think I now understand what is going on. It's all to do with strictness analysis. Consider this function, and suppose it is strict in x: {{{ f1 :: Int -> blah f1 x = ...(case x of I# y -> ...)... }}} The strictness analysis sees that `f1` is strict in `x` and we get a w/w split {{{ f1 :: Int -> blah f1 x = case x of I# y -> $wf y $wf1 :: Int# -> blah $wf1 y = let x = I# y in ...original body of f... }}} Now suppose that we have {{{ type family F a type instance F Bool = Int f2 :: F Bool -> blah f2 x = ...same as before... }}} In fact the strictness analysis still sees that `f2` is strict in `x`, and worker wrapper works too -- all by using the family instances. We get this {{{ f2 :: F Bool -> blah f2 x = case (x |> g1) of I# y -> $wf2 y $wf2 :: Int# -> blah $wf2 y = let x = (I# y) |> sym g in ..as before... }}} Here `g` is a coercion `g :: F Bool ~ Int`, constructed from the family instances. This coersionn is generated by `topNormaliseType_maybe`, itself called from `deepSplitCprType_maybe` in `WwLib`, during worker/wrapper generation. But it's harder if the coercion is purely local. Let's start with this (yes I know you can't write `(~#)` in source Haskell but imagine this is Core: {{{ f3 :: forall a. (a ~# Int) => a -> blah f3 a (g :: (a ~# Int) (x :: a) = ...as before... }}} What we'd like is this: {{{ f3 :: forall a. (a ~# Int) => a -> blah f3 a (g :: (a ~# Int) (x :: a) = case (x |> g) of I# y -> $wf3 a g y $wf3 :: forall a. (a ~# Int) => Int# -> blah $wf3 a g y = let x = (I# y) |> sym g in ...as before... }}} but alas neither the demand analyser, nor the worker/wrapper generator are clever enough to do this. We need a kind of `normaliseType` that can take some local "givens" as well as the top-level family instance envs. This has the same ring as something Ryan wanted in the coverage checker. It's not obvious exactly what "should work". Eg what about `(Int ~# a)`, or even `([Int] ~# [a])`? Finally, there is the question of `(~)` vs `(~#)`. I think we are very aggressive about unboxing `(~)` constraints, so I'd like this: {{{ f4 :: forall a. (a ~ Int) => a -> blah f4 a (g :: (a ~ Int) (x :: a) = case g of MkTwiddle (g2 :: a ~# Int) -> case (x |> g2) of I# y -> $wf4 a g2 y $wf4 :: forall a. (a ~# Int) => Int# -> blah $wf4 a g2 y = let x = (I# y) |> sym g2 g = MkTwiddle g2 in ...as before... }}} Making all this happen will take some work though. How important is it. I'm tempted to say "don't write types like that"! (Although the type checker goes to some trouble to support them well.) -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/14941#comment:9 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler