Simon Peyton Jones pushed to branch wip/T26989 at Glasgow Haskell Compiler / GHC

Commits:

3 changed files:

Changes:

  • compiler/GHC/Core/Opt/Simplify/Iteration.hs
    ... ... @@ -1631,7 +1631,6 @@ rebuild_go env expr cont
    1631 1631
     
    
    1632 1632
           ApplyToVal { sc_arg = arg, sc_env = arg_se, sc_cast = arg_mco
    
    1633 1633
                      , sc_cont = cont, sc_hole_ty = fun_ty }
    
    1634
    -        -- See Note [Avoid redundant simplification]
    
    1635 1634
             -> do { arg' <- simplArg env Nothing fun_ty arg_se arg arg_mco
    
    1636 1635
                   ; rebuild_go env (App expr arg') cont }
    
    1637 1636
     
    
    ... ... @@ -1825,7 +1824,10 @@ simplArg :: SimplEnvIS -- ^ Used only for its InScopeSet
    1825 1824
              -> MOutCoercion            -- Wrap this around the result
    
    1826 1825
              -> SimplM OutExpr
    
    1827 1826
     simplArg _ _ _ (Simplified {}) arg mco
    
    1828
    -  = return (mkCastMCo arg mco)
    
    1827
    +  = -- See Note [Avoiding simplifying repeatedly]
    
    1828
    +    case mco of
    
    1829
    +       MRefl  -> return arg       -- Vastly common case
    
    1830
    +       MCo co -> return (mkCast arg co)
    
    1829 1831
     simplArg env mb_arg_info fun_ty (UnSimplified arg_se) arg mco
    
    1830 1832
       = do { let arg_env' = arg_se `setInScopeFromE` env
    
    1831 1833
                  arg_ty   = funArgTy fun_ty
    
    ... ... @@ -2047,94 +2049,6 @@ Simplifier without first calling SimpleOpt, so anything involving
    2047 2049
     GHCi or TH and operator sections will fall over if we don't take
    
    2048 2050
     care here.
    
    2049 2051
     
    
    2050
    -Note [Avoiding simplifying repeatedly]
    
    2051
    -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    
    2052
    -One way in which we can get exponential behaviour is if we simplify a
    
    2053
    -big expression, and then re-simplify it -- and then this happens in a
    
    2054
    -deeply-nested way.  So we must be jolly careful about re-simplifying
    
    2055
    -an expression (#26989).
    
    2056
    -
    
    2057
    -Example:
    
    2058
    -  f BIG, where f has a RULE
    
    2059
    -Then
    
    2060
    - * We simplify BIG before trying the rule; but the rule does not fire
    
    2061
    -   (forcing this simplification is why we have the RULE in this example)
    
    2062
    - * We inline f = \x. g x, in `simpl_lam`
    
    2063
    - * So if `simpl_lam` did preInlineUnconditionally we get (g BIG)
    
    2064
    - * Now if g has a RULE we'll simplify BIG again, and this whole thing can
    
    2065
    -   iterate.
    
    2066
    - * However, if `f` did not have a RULE, so that BIG has /not/ already been
    
    2067
    -   simplified, we /want/ to do preInlineUnconditionally in simpl_lam.
    
    2068
    -
    
    2069
    -So we go to some effort to avoid repeatedly simplifying the same thing.
    
    2070
    -Suppose we are in the Plan (AFTER) case of rule application, for a rule
    
    2071
    -      RULE forall x,y.  f (x,y) = ...x...
    
    2072
    -and a call
    
    2073
    -      f (e1,e2)
    
    2074
    -Then:
    
    2075
    -
    
    2076
    -* The (sc_env :: StaticEnv) field of ApplyToVal records if the argument
    
    2077
    -  has been evaluated.  See Note [StaticEnv] in GHC.Core.Opt.Simplify.Utils.
    
    2078
    -
    
    2079
    -* The rule fires returning
    
    2080
    -     RuleMatch { rm_rhs = (\x y. ...x..), rm_args = [ e1, e2 ] }
    
    2081
    -  We assume that `rm_rhs` has been occ-anal'd by whoever generates
    
    2082
    -  the `RuleMatch`.  (We do this once and for all when the rule is born;
    
    2083
    -  see Note [OccInfo in unfoldings and rules].)
    
    2084
    -
    
    2085
    -* `fireRuleAFTER` uses `pushOutArgs` to push [ e1, e2 ] back onto the
    
    2086
    -  continuation with sc_env=Simplified NoDup.
    
    2087
    -
    
    2088
    -* Beta-reduction fires (in `simpl_lam`) for the \x.
    
    2089
    -
    
    2090
    -* Suppose `x occurs many times.  Then we want to behave like `let x=e1 in ..`,
    
    2091
    -  but we use `simplArg`, which in turn uses that `sc_env` flag to avoid
    
    2092
    -  re-simplifying `e1`.
    
    2093
    -
    
    2094
    -* Suppose `x` occurs just once or not at all; then the call to
    
    2095
    -  `preInlineUnconditionally` in `simpl_lam` will fire, and extend the
    
    2096
    -  substitution with
    
    2097
    -      x :-> DoneEx e1
    
    2098
    -
    
    2099
    -* At the /occurrence/ of `x`, the function `simplInId` calls `simplOutExpr`
    
    2100
    -  on `e1`.  Calling `simplOutExpr` is critical: it knowns that we have already
    
    2101
    -  simplified `e1` so we must be cautious about doing so again.
    
    2102
    -
    
    2103
    -  The conservative case for `simplOutExpr` is just to call `rebuild_go`, which
    
    2104
    -  avoids re-simplifying `e1`.  But if `e1` turns out to be a lambda, and there
    
    2105
    -  are some arguments, we have a new beta redex so we occurrence-analyse and
    
    2106
    -  zoom off to `simplLam`.
    
    2107
    -
    
    2108
    -* We go to some efforts to avoid unnecessarily simplifying ApplyToVal,
    
    2109
    -  in at least two places
    
    2110
    -    - In simplCast/addCoerce, where we check for isReflCo
    
    2111
    -    - We sometimes try rewrite RULES befoe simplifying arguments;
    
    2112
    -      see Note [tryRules: plan (BEFORE)]
    
    2113
    -
    
    2114
    -You might wonder (#13379) if the same thing can happen for a deeply-nested
    
    2115
    -application like
    
    2116
    -   f (f (f ....) ) )
    
    2117
    -
    
    2118
    -The danger is that we may
    
    2119
    -o  - Simplify the  (big) function argument
    
    2120
    -  - Decide to inline the function
    
    2121
    -  - Then preInilneUnconditionally the argument
    
    2122
    -  - And then re-simplified the big argument
    
    2123
    -
    
    2124
    -But in fact we try inlining /before/ simplifying arguments at all, so this can't
    
    2125
    -really arise.  The main way that we get /simplified/ argument on the stack is
    
    2126
    -through rule application. Once they are there then the above scenario can
    
    2127
    -happen. But then the mechanism above prevents gratuitous re-simplification.
    
    2128
    -
    
    2129
    -
    
    2130
    -Wrinkles:
    
    2131
    -
    
    2132
    -(SR1) All that said /postInlineUnconditionally/ (called in `completeBind`) does
    
    2133
    -    fire in the above (f BIG) situation.  See Note [Post-inline for single-use
    
    2134
    -    things] in Simplify.Utils.  This certainly risks repeated simplification,
    
    2135
    -    but in practice seems to be a small win.
    
    2136
    -
    
    2137
    -
    
    2138 2052
     ************************************************************************
    
    2139 2053
     *                                                                      *
    
    2140 2054
                          Join points
    
    ... ... @@ -2702,17 +2616,92 @@ makes a particularly big difference for
    2702 2616
             +# 3# (+# 4# 5#)
    
    2703 2617
       We want this to happen in one pass
    
    2704 2618
     
    
    2705
    -Note [Avoid redundant simplification]
    
    2706
    -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    
    2707
    -Because RULES often apply to simplified arguments (see Note [Plan (AFTER)]),
    
    2708
    -there's a danger of simplifying already-simplified arguments.  For example,
    
    2709
    -suppose we have
    
    2710
    -   RULE f (x,y) = $sf x  y
    
    2711
    -and the expression
    
    2712
    -   f (p,q) e1 e2
    
    2713
    -With Plan (AFTER) by the time the rule fires, we will have already simplified e1, e2,
    
    2714
    -and we want to avoid doing so a second time.  So ApplyToVal records if the argument
    
    2715
    -is already Simplified.
    
    2619
    +
    
    2620
    +Note [Avoiding simplifying repeatedly]
    
    2621
    +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    
    2622
    +One way in which we can get exponential behaviour is if we simplify a
    
    2623
    +big expression, and then re-simplify it -- and then this happens in a
    
    2624
    +deeply-nested way.  So we must be jolly careful about re-simplifying
    
    2625
    +an expression (#26989).
    
    2626
    +
    
    2627
    +Example:
    
    2628
    +  f BIG, where f has a RULE
    
    2629
    +Then
    
    2630
    + * We simplify BIG before trying the rule; but the rule does not fire
    
    2631
    +   (forcing this simplification is why we have the RULE in this example)
    
    2632
    + * We inline f = \x. g x, in `simpl_lam`
    
    2633
    + * So if `simpl_lam` did preInlineUnconditionally we get (g BIG)
    
    2634
    + * Now if g has a RULE we'll simplify BIG again, and this whole thing can
    
    2635
    +   iterate.
    
    2636
    + * However, if `f` did not have a RULE, so that BIG has /not/ already been
    
    2637
    +   simplified, we /want/ to do preInlineUnconditionally in simpl_lam.
    
    2638
    +
    
    2639
    +So we go to some effort to avoid repeatedly simplifying the same thing.
    
    2640
    +Suppose we are in the Plan (AFTER) case of rule application, for a rule
    
    2641
    +      RULE forall x,y.  f (x,y) = ...x...
    
    2642
    +and a call
    
    2643
    +      f (e1,e2)
    
    2644
    +Then:
    
    2645
    +
    
    2646
    +* The (sc_env :: StaticEnv) field of ApplyToVal records if the argument
    
    2647
    +  has been evaluated.  See Note [StaticEnv] in GHC.Core.Opt.Simplify.Utils.
    
    2648
    +
    
    2649
    +* The rule fires returning
    
    2650
    +     RuleMatch { rm_rhs = (\x y. ...x..), rm_args = [ e1, e2 ] }
    
    2651
    +  We assume that `rm_rhs` has been occ-anal'd by whoever generates
    
    2652
    +  the `RuleMatch`.  (We do this once and for all when the rule is born;
    
    2653
    +  see Note [OccInfo in unfoldings and rules].)
    
    2654
    +
    
    2655
    +* `fireRuleAFTER` uses `pushOutArgs` to push [ e1, e2 ] back onto the
    
    2656
    +  continuation with sc_env=Simplified NoDup.
    
    2657
    +
    
    2658
    +* Beta-reduction fires (in `simpl_lam`) for the \x.
    
    2659
    +
    
    2660
    +* Suppose `x occurs many times.  Then we want to behave like `let x=e1 in ..`,
    
    2661
    +  but we use `simplArg`, which in turn uses that `sc_env` flag to avoid
    
    2662
    +  re-simplifying `e1`.
    
    2663
    +
    
    2664
    +* Suppose `x` occurs just once or not at all; then the call to
    
    2665
    +  `preInlineUnconditionally` in `simpl_lam` will fire, and extend the
    
    2666
    +  substitution with
    
    2667
    +      x :-> DoneEx e1
    
    2668
    +
    
    2669
    +* At the /occurrence/ of `x`, the function `simplInId` calls `simplOutExpr`
    
    2670
    +  on `e1`.  Calling `simplOutExpr` is critical: it knowns that we have already
    
    2671
    +  simplified `e1` so we must be cautious about doing so again.
    
    2672
    +
    
    2673
    +  The conservative case for `simplOutExpr` is just to call `rebuild_go`, which
    
    2674
    +  avoids re-simplifying `e1`.  But if `e1` turns out to be a lambda, and there
    
    2675
    +  are some arguments, we have a new beta redex so we occurrence-analyse and
    
    2676
    +  zoom off to `simplLam`.
    
    2677
    +
    
    2678
    +* We go to some efforts to avoid unnecessarily simplifying ApplyToVal,
    
    2679
    +  in at least two places
    
    2680
    +    - In simplCast/addCoerce, where we check for isReflCo
    
    2681
    +    - We sometimes try rewrite RULES befoe simplifying arguments;
    
    2682
    +      see Note [tryRules: plan (BEFORE)]
    
    2683
    +
    
    2684
    +You might wonder (#13379) if the same thing can happen for a deeply-nested
    
    2685
    +application like
    
    2686
    +   f (f (f ....) ) )
    
    2687
    +
    
    2688
    +The danger is that we may
    
    2689
    +  - Simplify the  (big) function argument
    
    2690
    +  - Decide to inline the function
    
    2691
    +  - Then preInilneUnconditionally the argument
    
    2692
    +  - And then re-simplified the big argument
    
    2693
    +
    
    2694
    +But in fact we try inlining /before/ simplifying arguments at all, so this can't
    
    2695
    +really arise.  The main way that we get /simplified/ argument on the stack is
    
    2696
    +through rule application. Once they are there then the above scenario can
    
    2697
    +happen. But then the mechanism above prevents gratuitous re-simplification.
    
    2698
    +
    
    2699
    +Wrinkles:
    
    2700
    +
    
    2701
    +(SR1) All that said /postInlineUnconditionally/ (called in `completeBind`) does
    
    2702
    +    fire in the above (f BIG) situation.  See Note [Post-inline for single-use
    
    2703
    +    things] in Simplify.Utils.  This certainly risks repeated simplification,
    
    2704
    +    but in practice seems to be a small win.
    
    2716 2705
     
    
    2717 2706
     Note [Shadowing in the Simplifier]
    
    2718 2707
     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    

  • compiler/GHC/Core/Opt/Simplify/Utils.hs
    ... ... @@ -1624,7 +1624,9 @@ preInlineUnconditionally env top_lvl bndr rhs_se rhs rhs_mco
    1624 1624
         extend_subst_with inl_rhs
    
    1625 1625
           = extendIdSubst env bndr $!
    
    1626 1626
             case rhs_se of
    
    1627
    -          Simplified _         -> DoneEx (mkCastMCo inl_rhs rhs_mco) NotJoinPoint
    
    1627
    +          Simplified _ -> case rhs_mco of
    
    1628
    +                             MRefl  -> DoneEx inl_rhs NotJoinPoint -- Common case
    
    1629
    +                             MCo co -> DoneEx (mkCast inl_rhs co) NotJoinPoint
    
    1628 1630
               UnSimplified rhs_env -> ContEx rhs_env inl_rhs rhs_mco
    
    1629 1631
     
    
    1630 1632
         one_occ IAmDead = True -- Happens in ((\x.1) v)
    

  • compiler/GHC/Types/Id/Make.hs
    ... ... @@ -564,6 +564,34 @@ dictSelRule :: Name -> Arity -> Int -> CoreRule
    564 564
     --       sel_i t1..tk (D t1..tk op1 ... opm) = opi
    
    565 565
     --
    
    566 566
     -- See Note [ClassOp/DFun selection] in GHC.Tc.TyCl.Instance
    
    567
    +
    
    568
    +dictSelRule name n_ty_args val_index
    
    569
    +  = rule
    
    570
    +  where
    
    571
    +    rule = BuiltinRule { ru_name = fsLit "Class op " `appendFS`
    
    572
    +                                     occNameFS (getOccName name)
    
    573
    +                       , ru_fn    = name
    
    574
    +                       , ru_nargs = n_ty_args + 1
    
    575
    +                       , ru_try   = try }
    
    576
    +
    
    577
    +    try :: RuleFun
    
    578
    +    try _opts in_scope_env _fn args
    
    579
    +      | (dict_arg : _) <- drop n_ty_args args
    
    580
    +      , Just (_, floats, _, _, con_args) <- exprIsConApp_maybe in_scope_env dict_arg
    
    581
    +      , let meth_e = getNth con_args val_index
    
    582
    +      = Just (RM { rm_floats = floats
    
    583
    +                 , rm_rhs    = meth_e
    
    584
    +                 , rm_args   = []
    
    585
    +                 , rm_rule   = rule })
    
    586
    +      | otherwise
    
    587
    +      = Nothing
    
    588
    +
    
    589
    +{-  Here is another variant
    
    590
    +This one rewrites
    
    591
    +    op (m1,..,mn)  -->   (\x.x) mi
    
    592
    +This way we can take advantage of the stuff described in
    
    593
    +Note [Avoiding simplifying repeatedly] in GHC.Core.Opt.Simplify.Iteration
    
    594
    +
    
    567 595
     dictSelRule name n_ty_args val_index
    
    568 596
       = rule
    
    569 597
       where
    
    ... ... @@ -586,7 +614,6 @@ dictSelRule name n_ty_args val_index
    586 614
           | otherwise
    
    587 615
           = Nothing
    
    588 616
     
    
    589
    -
    
    590 617
     mkIdLam :: Type -> CoreExpr
    
    591 618
     -- Make an identity lambda (\(x::ty).x), already occ-analysed
    
    592 619
     mkIdLam ty
    
    ... ... @@ -597,6 +624,7 @@ mkIdLam ty
    597 624
                                   , occ_n_br    = 1
    
    598 625
                                   , occ_int_cxt = NotInteresting
    
    599 626
                                   , occ_tail    = NoTailCallInfo }
    
    627
    +-}
    
    600 628
     
    
    601 629
     {-
    
    602 630
     ************************************************************************