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

Commits:

4 changed files:

Changes:

  • compiler/GHC/Core/Opt/Simplify/Iteration.hs
    ... ... @@ -40,7 +40,7 @@ import GHC.Core.Opt.Arity ( ArityType, exprArity, arityTypeBotSigs_maybe
    40 40
                               , typeArity, arityTypeArity, etaExpandAT )
    
    41 41
     import GHC.Core.SimpleOpt ( exprIsConApp_maybe, joinPointBinding_maybe, joinPointBindings_maybe )
    
    42 42
     import GHC.Core.FVs     ( mkRuleInfo {- exprsFreeIds -} )
    
    43
    -import GHC.Core.Rules   ( lookupRule, getRules )
    
    43
    +import GHC.Core.Rules   ( lookupRule, getRules, RuleMatch(..) )
    
    44 44
     import GHC.Core.Multiplicity
    
    45 45
     
    
    46 46
     import GHC.Hs.Extension
    
    ... ... @@ -413,9 +413,9 @@ simplAuxBind _str env bndr new_rhs
    413 413
       --   and more direct to focus on the "hot" cases.
    
    414 414
       -- e.g. auxiliary bindings have no NOLINE pragmas, RULEs, or stable unfoldings
    
    415 415
       | exprIsTrivial new_rhs  -- Short-cut for let x = y in ...
    
    416
    -    || case (idOccInfo bndr) of
    
    417
    -          OneOcc{ occ_n_br = 1, occ_in_lam = NotInsideLam } -> True
    
    418
    -          _                                                 -> False
    
    416
    +--    || case (idOccInfo bndr) of
    
    417
    +--          OneOcc{ occ_n_br = 1, occ_in_lam = NotInsideLam } -> True
    
    418
    +--          _                                                 -> False
    
    419 419
       = return ( emptyFloats env
    
    420 420
                , extendCvIdSubst env bndr new_rhs )  -- bndr can be a CoVar
    
    421 421
     
    
    ... ... @@ -2361,8 +2361,9 @@ simplOutId env fun cont
    2361 2361
                  out_args     = contOutArgs env cont :: [OutExpr]
    
    2362 2362
            ; mb_match <- if not (null rules_for_me) &&
    
    2363 2363
                             (isClassOpId fun || activeUnfolding (seMode env) fun)
    
    2364
    -                     then tryRules env rules_for_me fun out_args
    
    2364
    +                     then tryRules False env rules_for_me fun out_args
    
    2365 2365
                          else return Nothing
    
    2366
    +
    
    2366 2367
            ; case mb_match of {
    
    2367 2368
                  Just (rule_arity, rhs) -> simplExprF env rhs $
    
    2368 2369
                                            dropContArgs rule_arity cont ;
    
    ... ... @@ -2455,7 +2456,7 @@ rebuildCall env (ArgInfo { ai_fun = fun, ai_args = rev_args, ai_rules = rules })
    2455 2456
       = rebuild env (argInfoExpr fun rev_args) cont
    
    2456 2457
       | otherwise  -- Try rules again: Plan (AFTER) in Note [When to apply rewrite rules]
    
    2457 2458
       = do { let args = reverse rev_args
    
    2458
    -       ; mb_match <- tryRules env rules fun (map argSpecArg args)
    
    2459
    +       ; mb_match <- tryRules True env rules fun (map argSpecArg args)
    
    2459 2460
            ; case mb_match of
    
    2460 2461
                Just (rule_arity, rhs) -> simplExprF env rhs $
    
    2461 2462
                                          pushSimplifiedArgs env (drop rule_arity args) cont
    
    ... ... @@ -2641,17 +2642,20 @@ See Note [No free join points in arityType] in GHC.Core.Opt.Arity
    2641 2642
     ************************************************************************
    
    2642 2643
     -}
    
    2643 2644
     
    
    2644
    -tryRules :: SimplEnv -> [CoreRule]
    
    2645
    -         -> OutId -> [OutExpr]
    
    2645
    +tryRules :: Bool  -- True  <=> args are already simplified
    
    2646
    +         -> SimplEnv -> [CoreRule]
    
    2647
    +         -> OutId -> [CoreExpr]
    
    2646 2648
              -> SimplM (Maybe (FullArgCount, CoreExpr))
    
    2647 2649
     
    
    2648
    -tryRules env rules fn args
    
    2649
    -  | Just (rule, rule_rhs) <- lookupRule ropts in_scope_env
    
    2650
    -                                        act_fun fn args rules
    
    2650
    +tryRules args_are_simplified env rules fn args
    
    2651
    +  | Just (RM { rm_rule = rule, rm_rhs = rule_rhs })
    
    2652
    +       <- -- pprTrace ("tryRules "++show args_are_simplified) (ppr fn) $
    
    2653
    +          lookupRule ropts in_scope_env act_fun fn args rules
    
    2651 2654
       -- Fire a rule for the function
    
    2652 2655
       = do { logger <- getLogger
    
    2653 2656
            ; checkedTick (RuleFired (ruleName rule))
    
    2654
    -       ; let occ_anald_rhs = occurAnalyseExpr rule_rhs
    
    2657
    +       ; let occ_anald_rhs | args_are_simplified = rule_rhs
    
    2658
    +                           | otherwise           = occurAnalyseExpr rule_rhs
    
    2655 2659
                      -- See Note [Occurrence-analyse after rule firing]
    
    2656 2660
            ; dump logger rule rule_rhs
    
    2657 2661
            ; return (Just (ruleArity rule, occ_anald_rhs)) }
    
    ... ... @@ -2718,7 +2722,7 @@ trySeqRules :: SimplEnv
    2718 2722
     trySeqRules in_env scrut rhs cont
    
    2719 2723
       = do { rule_base <- getSimplRules
    
    2720 2724
            ; let seq_rules = getRules rule_base seqId
    
    2721
    -       ; mb_match <- tryRules in_env seq_rules seqId out_args
    
    2725
    +       ; mb_match <- tryRules True in_env seq_rules seqId out_args
    
    2722 2726
            ; case mb_match of
    
    2723 2727
                 Nothing                -> return Nothing
    
    2724 2728
                 Just (rule_arity, rhs) -> return (Just (rhs, cont'))
    

  • compiler/GHC/Core/Opt/Simplify/Utils.hs
    ... ... @@ -1715,6 +1715,7 @@ postInlineUnconditionally env bind_cxt old_bndr bndr rhs
    1715 1715
             | n_br >= 100 -> False  -- See #23627
    
    1716 1716
     
    
    1717 1717
             | n_br == 1, NotInsideLam <- in_lam  -- One syntactic occurrence
    
    1718
    +        , unf_is_small
    
    1718 1719
             -> True                              -- See Note [Post-inline for single-use things]
    
    1719 1720
     
    
    1720 1721
     --        | is_unlifted                        -- Unlifted binding, hence ok-for-spec
    
    ... ... @@ -1728,7 +1729,7 @@ postInlineUnconditionally env bind_cxt old_bndr bndr rhs
    1728 1729
                                                 -- so inlining duplicates code but nothing more
    
    1729 1730
     
    
    1730 1731
             | otherwise
    
    1731
    -        -> work_ok in_lam int_cxt && (n_br == 1 || smallEnoughToInline uf_opts unfolding)
    
    1732
    +        -> work_ok in_lam int_cxt && ({- n_br == 1 || -} unf_is_small)
    
    1732 1733
                   -- Multiple syntactic occurences; but lazy, and small enough to dup
    
    1733 1734
                   -- ToDo: consider discount on smallEnoughToInline if int_cxt is true
    
    1734 1735
     
    
    ... ... @@ -1740,6 +1741,8 @@ postInlineUnconditionally env bind_cxt old_bndr bndr rhs
    1740 1741
           _ -> False
    
    1741 1742
     
    
    1742 1743
       where
    
    1744
    +    unf_is_small = smallEnoughToInline uf_opts unfolding
    
    1745
    +
    
    1743 1746
         work_ok NotInsideLam _              = True
    
    1744 1747
         work_ok IsInsideLam  IsInteresting  = isCheapUnfolding unfolding
    
    1745 1748
         work_ok IsInsideLam  NotInteresting = False
    

  • compiler/GHC/Core/Opt/Specialise.hs
    ... ... @@ -1266,7 +1266,7 @@ fireRewriteRules :: SpecEnv -- Substitution is already zapped
    1266 1266
                      -> OutExpr -> [OutExpr] -> (OutExpr, [OutExpr])
    
    1267 1267
     fireRewriteRules env (Var f) args
    
    1268 1268
       | let rules = getRules (se_rules env) f
    
    1269
    -  , Just (rule, expr) <- specLookupRule env f args activeInInitialPhase rules
    
    1269
    +  , Just (RM { rm_rule = rule, rm_rhs = expr }) <- specLookupRule env f args activeInInitialPhase rules
    
    1270 1270
       , let rest_args    = drop (ruleArity rule) args -- See Note [Extra args in the target]
    
    1271 1271
             zapped_subst = se_subst env   -- Just needed for the InScopeSet
    
    1272 1272
             expr'        = simpleOptExprWith defaultSimpleOpts zapped_subst (mkApps expr rest_args)
    
    ... ... @@ -1801,7 +1801,7 @@ alreadyCovered :: SpecEnv
    1801 1801
     alreadyCovered env bndrs fn args is_active rules
    
    1802 1802
       = case specLookupRule env fn args is_active rules of
    
    1803 1803
           Nothing             -> False
    
    1804
    -      Just (rule, _)
    
    1804
    +      Just (RM { rm_rule = rule })
    
    1805 1805
             | isAutoRule rule -> -- Discard identical rules
    
    1806 1806
                                  -- We know that (fn args) is an instance of RULE
    
    1807 1807
                                  -- Check if RULE is an instance of (fn args)
    
    ... ... @@ -1815,7 +1815,7 @@ alreadyCovered env bndrs fn args is_active rules
    1815 1815
     specLookupRule :: HasDebugCallStack
    
    1816 1816
                    => SpecEnv -> Id -> [CoreExpr]
    
    1817 1817
                    -> (ActivationGhc -> Bool)  -- Which rules are active
    
    1818
    -               -> [CoreRule] -> Maybe (CoreRule, CoreExpr)
    
    1818
    +               -> [CoreRule] -> Maybe RuleMatch
    
    1819 1819
     specLookupRule env fn args is_active rules
    
    1820 1820
       | null rules
    
    1821 1821
       = Nothing    -- Saves building a few thunks in the common case
    

  • compiler/GHC/Core/Rules.hs
    ... ... @@ -10,6 +10,7 @@
    10 10
     module GHC.Core.Rules (
    
    11 11
             -- ** Looking up rules
    
    12 12
             lookupRule, matchExprs, ruleLhsIsMoreSpecific,
    
    13
    +        RuleMatch(..),
    
    13 14
     
    
    14 15
             -- ** RuleBase, RuleEnv
    
    15 16
             RuleBase, RuleEnv(..), mkRuleEnv, emptyRuleEnv,
    
    ... ... @@ -542,6 +543,14 @@ map.
    542 543
     ************************************************************************
    
    543 544
     -}
    
    544 545
     
    
    546
    +data RuleMatch = RM { rm_rule  :: CoreRule
    
    547
    +                    , rm_rhs   :: CoreExpr }
    
    548
    +  -- Rule `rm_rule` matches, and the result is `rm_rhs`
    
    549
    +  --
    
    550
    +  -- Example:   RULE forall x y. f (g y x) = h [x,y]
    
    551
    +  -- If the target is (f (g e1 e2)), the RuleMatch has
    
    552
    +  --    rm_rhs = let {x = e1; y = e2 } in h [x,y]
    
    553
    +
    
    545 554
     -- | The main rule matching function. Attempts to apply all (active)
    
    546 555
     -- supplied rules to this instance of an application in a given
    
    547 556
     -- context, returning the rule applied and the resulting expression if
    
    ... ... @@ -552,7 +561,7 @@ lookupRule :: HasDebugCallStack
    552 561
                -> Id -- Function head
    
    553 562
                -> [CoreExpr] -- Args
    
    554 563
                -> [CoreRule] -- Rules
    
    555
    -           -> Maybe (CoreRule, CoreExpr)
    
    564
    +           -> Maybe RuleMatch
    
    556 565
     
    
    557 566
     -- See Note [Extra args in the target]
    
    558 567
     -- See comments on matchRule
    
    ... ... @@ -570,11 +579,11 @@ lookupRule opts rule_env@(ISE in_scope _) is_active fn args rules
    570 579
         args' = map (stripTicksTopE tickishFloatable) args
    
    571 580
         ticks = concatMap (stripTicksTopT tickishFloatable) args
    
    572 581
     
    
    573
    -    go :: [(CoreRule,CoreExpr)] -> [CoreRule] -> [(CoreRule,CoreExpr)]
    
    582
    +    go :: [RuleMatch] -> [CoreRule] -> [RuleMatch]
    
    574 583
         go ms [] = ms
    
    575 584
         go ms (r:rs)
    
    576
    -      | Just e <- matchRule opts rule_env is_active fn args' rough_args r
    
    577
    -      = go ((r,mkTicks ticks e):ms) rs
    
    585
    +      | Just rhs <- matchRule opts rule_env is_active fn args' rough_args r
    
    586
    +      = go (RM { rm_rule = r, rm_rhs = mkTicks ticks rhs } : ms) rs
    
    578 587
           | otherwise
    
    579 588
           = -- pprTrace "match failed" (ppr r $$ ppr args $$
    
    580 589
             --   ppr [ (arg_id, maybeUnfoldingTemplate unf)
    
    ... ... @@ -584,15 +593,17 @@ lookupRule opts rule_env@(ISE in_scope _) is_active fn args rules
    584 593
             go ms rs
    
    585 594
     
    
    586 595
     findBest :: InScopeSet -> (Id, [CoreExpr])
    
    587
    -         -> (CoreRule,CoreExpr) -> [(CoreRule,CoreExpr)] -> (CoreRule,CoreExpr)
    
    596
    +         -> RuleMatch -> [RuleMatch] -> RuleMatch
    
    588 597
     -- All these pairs matched the expression
    
    589 598
     -- Return the pair the most specific rule
    
    590 599
     -- The (fn,args) is just for overlap reporting
    
    591 600
     
    
    592
    -findBest _        _      (rule,ans)   [] = (rule,ans)
    
    593
    -findBest in_scope target (rule1,ans1) ((rule2,ans2):prs)
    
    594
    -  | ruleIsMoreSpecific in_scope rule1 rule2 = findBest in_scope target (rule1,ans1) prs
    
    595
    -  | ruleIsMoreSpecific in_scope rule2 rule1 = findBest in_scope target (rule2,ans2) prs
    
    601
    +findBest _ _ rm [] = rm
    
    602
    +findBest in_scope target@(fn,args)
    
    603
    +         rm1@(RM { rm_rule = rule1 })
    
    604
    +         (rm2@(RM { rm_rule = rule2 }) : prs)
    
    605
    +  | ruleIsMoreSpecific in_scope rule1 rule2 = findBest in_scope target rm1 prs
    
    606
    +  | ruleIsMoreSpecific in_scope rule2 rule1 = findBest in_scope target rm2 prs
    
    596 607
       | debugIsOn = let pp_rule rule
    
    597 608
                           = ifPprDebug (ppr rule)
    
    598 609
                                        (doubleQuotes (ftext (ruleName rule)))
    
    ... ... @@ -602,10 +613,8 @@ findBest in_scope target (rule1,ans1) ((rule2,ans2):prs)
    602 613
                                      <+> sep (map ppr args)
    
    603 614
                                    , text "Rule 1:" <+> pp_rule rule1
    
    604 615
                                    , text "Rule 2:" <+> pp_rule rule2]) $
    
    605
    -                findBest in_scope target (rule1,ans1) prs
    
    606
    -  | otherwise = findBest in_scope target (rule1,ans1) prs
    
    607
    -  where
    
    608
    -    (fn,args) = target
    
    616
    +                findBest in_scope target rm1 prs
    
    617
    +  | otherwise = findBest in_scope target rm1 prs
    
    609 618
     
    
    610 619
     ruleIsMoreSpecific :: InScopeSet -> CoreRule -> CoreRule -> Bool
    
    611 620
     -- The call (rule1 `ruleIsMoreSpecific` rule2)
    
    ... ... @@ -684,7 +693,7 @@ matchRule :: HasDebugCallStack
    684 693
               -> Id -> [CoreExpr] -> [Maybe Name]
    
    685 694
               -> CoreRule -> Maybe CoreExpr
    
    686 695
     
    
    687
    --- If (matchRule rule args) returns Just (name,rhs)
    
    696
    +-- If (matchRule rule args) returns Just rhs
    
    688 697
     -- then (f args) matches the rule, and the corresponding
    
    689 698
     -- rewritten RHS is rhs
    
    690 699
     --
    
    ... ... @@ -709,25 +718,31 @@ matchRule :: HasDebugCallStack
    709 718
     -- NB: The 'surplus' argument e4 in the input is simply dropped.
    
    710 719
     -- See Note [Extra args in the target]
    
    711 720
     
    
    712
    -matchRule opts rule_env _is_active fn args _rough_args
    
    721
    +matchRule opts ise _is_active fn args _rough_args
    
    713 722
               (BuiltinRule { ru_try = match_fn })
    
    714
    -  | not (roBuiltinRules opts) = Nothing
    
    715
    -  | otherwise                 = match_fn opts rule_env fn args
    
    716 723
     
    
    717
    -matchRule _ rule_env is_active _ args rough_args
    
    718
    -          (Rule { ru_name = rule_name, ru_act = act, ru_rough = tpl_tops
    
    719
    -                , ru_bndrs = tpl_vars, ru_args = tpl_args, ru_rhs = rhs })
    
    720
    -  | not (is_active act) = Nothing
    
    721
    -  | ruleCantMatch tpl_tops rough_args      = Nothing
    
    722
    -  | otherwise = matchN rule_env rule_name tpl_vars tpl_args args rhs
    
    724
    +  | roBuiltinRules opts = match_fn opts ise fn args
    
    725
    +  | otherwise           = Nothing
    
    723 726
     
    
    727
    +matchRule _ ise is_active _ target_args rough_args
    
    728
    +          (Rule { ru_act = act, ru_rough = tpl_tops
    
    729
    +                , ru_bndrs = tpl_vars, ru_args = tpl_args, ru_rhs = rhs })
    
    730
    +  | is_active act
    
    731
    +  , not (ruleCantMatch tpl_tops rough_args)
    
    732
    +  , Just (bind_wrapper, matched_es) <- matchExprs ise tpl_vars tpl_args target_args
    
    733
    +  = Just (bind_wrapper $
    
    734
    +          mkLams tpl_vars rhs `mkApps` matched_es )
    
    735
    +          -- NB: We cannot say:
    
    736
    +          --       mkLets [NonRec b e | (b,e) <- zip tpl_vars matched_es] rhs
    
    737
    +          --     because that brings tpl_vars into scope in a way that
    
    738
    +          --     shadows the matched_es.  Bad bad.
    
    739
    +  | otherwise
    
    740
    +  = Nothing
    
    724 741
     
    
    725 742
     ---------------------------------------
    
    726
    -matchN  :: HasDebugCallStack
    
    727
    -        => InScopeEnv
    
    728
    -        -> RuleName -> [Var] -> [CoreExpr]
    
    729
    -        -> [CoreExpr] -> CoreExpr           -- ^ Target; can have more elements than the template
    
    730
    -        -> Maybe CoreExpr
    
    743
    +matchExprs :: HasDebugCallStack
    
    744
    +           => InScopeEnv -> [Var] -> [CoreExpr] -> [CoreExpr]
    
    745
    +           -> Maybe (BindWrapper, [CoreExpr])  -- 1-1 with the [Var]
    
    731 746
     -- For a given match template and context, find bindings to wrap around
    
    732 747
     -- the entire result and what should be substituted for each template variable.
    
    733 748
     --
    
    ... ... @@ -737,15 +752,6 @@ matchN :: HasDebugCallStack
    737 752
     -- If there are too /many/ actual arguments, we simply ignore the
    
    738 753
     -- trailing ones, returning the result of applying the rule to a prefix
    
    739 754
     -- of the actual arguments.
    
    740
    -
    
    741
    -matchN ise _rule_name tmpl_vars tmpl_es target_es rhs
    
    742
    -  = do { (bind_wrapper, matched_es) <- matchExprs ise tmpl_vars tmpl_es target_es
    
    743
    -       ; return (bind_wrapper $
    
    744
    -                 mkLams tmpl_vars rhs `mkApps` matched_es) }
    
    745
    -
    
    746
    -matchExprs :: HasDebugCallStack
    
    747
    -           => InScopeEnv -> [Var] -> [CoreExpr] -> [CoreExpr]
    
    748
    -           -> Maybe (BindWrapper, [CoreExpr])  -- 1-1 with the [Var]
    
    749 755
     matchExprs (ISE in_scope id_unf) tmpl_vars tmpl_es target_es
    
    750 756
       = do  { rule_subst <- match_exprs init_menv emptyRuleSubst tmpl_es target_es
    
    751 757
             ; let (_, matched_es) = mapAccumL (lookup_tmpl rule_subst)
    
    ... ... @@ -806,7 +812,7 @@ match_exprs :: HasDebugCallStack
    806 812
                 -> [CoreExpr]       -- Targets
    
    807 813
                 -> Maybe RuleSubst
    
    808 814
     -- If the targets are longer than templates, succeed, simply ignoring
    
    809
    --- the leftover targets. This matters in the call in matchN.
    
    815
    +-- the leftover targets. This matters in the call in matchExprs.
    
    810 816
     --
    
    811 817
     -- Precondition: corresponding elements of es1 and es2 have the same
    
    812 818
     --               type, assuming earlier elements match.