| ... |
... |
@@ -9,7 +9,7 @@ |
|
9
|
9
|
-- The 'CoreRule' datatype itself is declared elsewhere.
|
|
10
|
10
|
module GHC.Core.Rules (
|
|
11
|
11
|
-- ** Looking up rules
|
|
12
|
|
- lookupRule, matchExprs, ruleLhsIsMoreSpecific,
|
|
|
12
|
+ RuleMatch(..), lookupRule, matchExprs, ruleLhsIsMoreSpecific,
|
|
13
|
13
|
|
|
14
|
14
|
-- ** RuleBase, RuleEnv
|
|
15
|
15
|
RuleBase, RuleEnv(..), mkRuleEnv, emptyRuleEnv,
|
| ... |
... |
@@ -542,6 +542,23 @@ map. |
|
542
|
542
|
************************************************************************
|
|
543
|
543
|
-}
|
|
544
|
544
|
|
|
|
545
|
+data RuleMatch
|
|
|
546
|
+ = RM { rm_rule :: CoreRule
|
|
|
547
|
+ , rm_rhs :: CoreExpr
|
|
|
548
|
+ , rm_args :: [CoreExpr]
|
|
|
549
|
+ , rm_binds :: BindWrapper -- Floated let-bindings
|
|
|
550
|
+ -- See Note [Matching lets]
|
|
|
551
|
+ , rm_bndrs :: [Var] -- Binders of rm_binds
|
|
|
552
|
+ }
|
|
|
553
|
+ -- E.g. match r = RULE forall x,y. f (Just (y,x)) = g x y True
|
|
|
554
|
+ -- target f (let v = ev in Just (ey, ex)) ez
|
|
|
555
|
+ -- We get the RuleMatch
|
|
|
556
|
+ -- RMM { rm_rule = r, rm_rhs = \xy. g x y True
|
|
|
557
|
+ -- , rm_args = [ex, ey]
|
|
|
558
|
+ -- , rm_binds = Let v=ev, rm_bndrs = [v] )
|
|
|
559
|
+ -- The leftover `ez` is not returned; the caller is responsible for
|
|
|
560
|
+ -- counting (ruleArity r) arguments
|
|
|
561
|
+
|
|
545
|
562
|
-- | The main rule matching function. Attempts to apply all (active)
|
|
546
|
563
|
-- supplied rules to this instance of an application in a given
|
|
547
|
564
|
-- context, returning the rule applied and the resulting expression if
|
| ... |
... |
@@ -552,7 +569,7 @@ lookupRule :: HasDebugCallStack |
|
552
|
569
|
-> Id -- Function head
|
|
553
|
570
|
-> [CoreExpr] -- Args
|
|
554
|
571
|
-> [CoreRule] -- Rules
|
|
555
|
|
- -> Maybe (CoreRule, CoreExpr)
|
|
|
572
|
+ -> Maybe RuleMatch
|
|
556
|
573
|
|
|
557
|
574
|
-- See Note [Extra args in the target]
|
|
558
|
575
|
-- See comments on matchRule
|
| ... |
... |
@@ -564,17 +581,17 @@ lookupRule opts rule_env@(ISE in_scope _) is_active fn args rules |
|
564
|
581
|
where
|
|
565
|
582
|
rough_args = map roughTopName args
|
|
566
|
583
|
|
|
567
|
|
- -- Strip ticks from arguments, see Note [Tick annotations in RULE
|
|
568
|
|
- -- matching]. We only collect ticks if a rule actually matches -
|
|
|
584
|
+ -- Strip ticks from arguments, see Note [Tick annotations in RULE matching]
|
|
|
585
|
+ -- We only collect ticks if a rule actually matches -
|
|
569
|
586
|
-- this matters for performance tests.
|
|
570
|
587
|
args' = map (stripTicksTopE tickishFloatable) args
|
|
571
|
588
|
ticks = concatMap (stripTicksTopT tickishFloatable) args
|
|
572
|
589
|
|
|
573
|
|
- go :: [(CoreRule,CoreExpr)] -> [CoreRule] -> [(CoreRule,CoreExpr)]
|
|
|
590
|
+ go :: [RuleMatch] -> [CoreRule] -> [RuleMatch]
|
|
574
|
591
|
go ms [] = ms
|
|
575
|
592
|
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
|
|
|
593
|
+ | Just rm <- matchRule opts rule_env is_active fn args' rough_args r
|
|
|
594
|
+ = go (rm { rm_binds = mkTicks ticks . rm_binds rm } : ms) rs
|
|
578
|
595
|
| otherwise
|
|
579
|
596
|
= -- pprTrace "match failed" (ppr r $$ ppr args $$
|
|
580
|
597
|
-- ppr [ (arg_id, maybeUnfoldingTemplate unf)
|
| ... |
... |
@@ -583,35 +600,38 @@ lookupRule opts rule_env@(ISE in_scope _) is_active fn args rules |
|
583
|
600
|
-- , isCheapUnfolding unf] )
|
|
584
|
601
|
go ms rs
|
|
585
|
602
|
|
|
586
|
|
-findBest :: InScopeSet -> (Id, [CoreExpr])
|
|
587
|
|
- -> (CoreRule,CoreExpr) -> [(CoreRule,CoreExpr)] -> (CoreRule,CoreExpr)
|
|
|
603
|
+findBest :: InScopeSet
|
|
|
604
|
+ -> (Id, [CoreExpr]) -- Target, just for overlap reporting
|
|
|
605
|
+ -> RuleMatch -- Most specific so far
|
|
|
606
|
+ -> [RuleMatch]
|
|
|
607
|
+ -> RuleMatch
|
|
588
|
608
|
-- All these pairs matched the expression
|
|
589
|
609
|
-- Return the pair the most specific rule
|
|
590
|
610
|
-- The (fn,args) is just for overlap reporting
|
|
591
|
611
|
|
|
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
|
|
596
|
|
- | debugIsOn = let pp_rule rule
|
|
|
612
|
+findBest _ _ rm [] = rm
|
|
|
613
|
+findBest in_scope target rm1 (rm2: rms)
|
|
|
614
|
+ | ruleIsMoreSpecific in_scope rm1 rm2 = findBest in_scope target rm1 rms
|
|
|
615
|
+ | ruleIsMoreSpecific in_scope rm2 rm1 = findBest in_scope target rm2 rms
|
|
|
616
|
+ | debugIsOn = let pp_rule (RM { rm_rule = rule })
|
|
597
|
617
|
= ifPprDebug (ppr rule)
|
|
598
|
618
|
(doubleQuotes (ftext (ruleName rule)))
|
|
599
|
619
|
in pprTrace "Rules.findBest: rule overlap (Rule 1 wins)"
|
|
600
|
620
|
(vcat [ whenPprDebug $
|
|
601
|
621
|
text "Expression to match:" <+> ppr fn
|
|
602
|
622
|
<+> sep (map ppr args)
|
|
603
|
|
- , text "Rule 1:" <+> pp_rule rule1
|
|
604
|
|
- , text "Rule 2:" <+> pp_rule rule2]) $
|
|
605
|
|
- findBest in_scope target (rule1,ans1) prs
|
|
606
|
|
- | otherwise = findBest in_scope target (rule1,ans1) prs
|
|
|
623
|
+ , text "Rule 1:" <+> pp_rule rm1
|
|
|
624
|
+ , text "Rule 2:" <+> pp_rule rm2]) $
|
|
|
625
|
+ findBest in_scope target rm1 rms
|
|
|
626
|
+ | otherwise = findBest in_scope target rm1 rms
|
|
607
|
627
|
where
|
|
608
|
628
|
(fn,args) = target
|
|
609
|
629
|
|
|
610
|
|
-ruleIsMoreSpecific :: InScopeSet -> CoreRule -> CoreRule -> Bool
|
|
|
630
|
+ruleIsMoreSpecific :: InScopeSet -> RuleMatch -> RuleMatch -> Bool
|
|
611
|
631
|
-- The call (rule1 `ruleIsMoreSpecific` rule2)
|
|
612
|
632
|
-- sees if rule2 can be instantiated to look like rule1
|
|
613
|
633
|
-- See Note [ruleIsMoreSpecific]
|
|
614
|
|
-ruleIsMoreSpecific in_scope rule1 rule2
|
|
|
634
|
+ruleIsMoreSpecific in_scope (RM { rm_rule = rule1 }) (RM { rm_rule = rule2 })
|
|
615
|
635
|
= case rule1 of
|
|
616
|
636
|
BuiltinRule {} -> False
|
|
617
|
637
|
Rule { ru_bndrs = bndrs1, ru_args = args1 }
|
| ... |
... |
@@ -682,7 +702,7 @@ start, in general eta expansion wastes work. SLPJ July 99 |
|
682
|
702
|
matchRule :: HasDebugCallStack
|
|
683
|
703
|
=> RuleOpts -> InScopeEnv -> (ActivationGhc -> Bool)
|
|
684
|
704
|
-> Id -> [CoreExpr] -> [Maybe Name]
|
|
685
|
|
- -> CoreRule -> Maybe CoreExpr
|
|
|
705
|
+ -> CoreRule -> Maybe RuleMatch
|
|
686
|
706
|
|
|
687
|
707
|
-- If (matchRule rule args) returns Just (name,rhs)
|
|
688
|
708
|
-- then (f args) matches the rule, and the corresponding
|
| ... |
... |
@@ -708,26 +728,7 @@ matchRule :: HasDebugCallStack |
|
708
|
728
|
--
|
|
709
|
729
|
-- NB: The 'surplus' argument e4 in the input is simply dropped.
|
|
710
|
730
|
-- See Note [Extra args in the target]
|
|
711
|
|
-
|
|
712
|
|
-matchRule opts rule_env _is_active fn args _rough_args
|
|
713
|
|
- (BuiltinRule { ru_try = match_fn })
|
|
714
|
|
- | not (roBuiltinRules opts) = Nothing
|
|
715
|
|
- | otherwise = match_fn opts rule_env fn args
|
|
716
|
|
-
|
|
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
|
|
723
|
|
-
|
|
724
|
|
-
|
|
725
|
|
----------------------------------------
|
|
726
|
|
-matchN :: HasDebugCallStack
|
|
727
|
|
- => InScopeEnv
|
|
728
|
|
- -> RuleName -> [Var] -> [CoreExpr]
|
|
729
|
|
- -> [CoreExpr] -> CoreExpr -- ^ Target; can have more elements than the template
|
|
730
|
|
- -> Maybe CoreExpr
|
|
|
731
|
+--
|
|
731
|
732
|
-- For a given match template and context, find bindings to wrap around
|
|
732
|
733
|
-- the entire result and what should be substituted for each template variable.
|
|
733
|
734
|
--
|
| ... |
... |
@@ -738,24 +739,43 @@ matchN :: HasDebugCallStack |
|
738
|
739
|
-- trailing ones, returning the result of applying the rule to a prefix
|
|
739
|
740
|
-- of the actual arguments.
|
|
740
|
741
|
|
|
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) }
|
|
|
742
|
+matchRule opts rule_env _is_active fn args _rough_args
|
|
|
743
|
+ rule@(BuiltinRule { ru_try = match_fn })
|
|
|
744
|
+ = do { guard (roBuiltinRules opts)
|
|
|
745
|
+ ; rhs <- match_fn opts rule_env fn args
|
|
|
746
|
+ ; return (RM { rm_rule = rule
|
|
|
747
|
+ , rm_rhs = rhs
|
|
|
748
|
+ , rm_args = []
|
|
|
749
|
+ , rm_binds = id
|
|
|
750
|
+ , rm_bndrs = [] }) }
|
|
|
751
|
+
|
|
|
752
|
+matchRule _opts rule_env is_active _fn target_es rough_args
|
|
|
753
|
+ rule@(Rule { ru_act = act, ru_rough = tpl_tops
|
|
|
754
|
+ , ru_bndrs = tpl_vars, ru_args = tpl_args, ru_rhs = rhs })
|
|
|
755
|
+ | not (is_active act)
|
|
|
756
|
+ = Nothing
|
|
|
757
|
+ | ruleCantMatch tpl_tops rough_args
|
|
|
758
|
+ = Nothing
|
|
|
759
|
+ | otherwise
|
|
|
760
|
+ = do { (matched_es, bind_wrapper, wrap_bndrs)
|
|
|
761
|
+ <- matchExprs rule_env tpl_vars tpl_args target_es
|
|
|
762
|
+
|
|
|
763
|
+ ; return (RM { rm_rule = rule
|
|
|
764
|
+ , rm_rhs = mkLams tpl_vars rhs
|
|
|
765
|
+ , rm_args = matched_es
|
|
|
766
|
+ , rm_binds = bind_wrapper
|
|
|
767
|
+ , rm_bndrs = wrap_bndrs }) }
|
|
745
|
768
|
|
|
746
|
769
|
matchExprs :: HasDebugCallStack
|
|
747
|
770
|
=> InScopeEnv -> [Var] -> [CoreExpr] -> [CoreExpr]
|
|
748
|
|
- -> Maybe (BindWrapper, [CoreExpr]) -- 1-1 with the [Var]
|
|
|
771
|
+ -> Maybe ( [CoreExpr] -- 1-1 with the incoming [Var]
|
|
|
772
|
+ , BindWrapper, [Var]) -- Floated binds
|
|
749
|
773
|
matchExprs (ISE in_scope id_unf) tmpl_vars tmpl_es target_es
|
|
750
|
774
|
= do { rule_subst <- match_exprs init_menv emptyRuleSubst tmpl_es target_es
|
|
751
|
775
|
; let (_, matched_es) = mapAccumL (lookup_tmpl rule_subst)
|
|
752
|
776
|
(mkEmptySubst in_scope) $
|
|
753
|
777
|
tmpl_vars `zip` tmpl_vars1
|
|
754
|
|
-
|
|
755
|
|
- ; let bind_wrapper = rs_binds rule_subst
|
|
756
|
|
- -- Floated bindings; see Note [Matching lets]
|
|
757
|
|
-
|
|
758
|
|
- ; return (bind_wrapper, matched_es) }
|
|
|
778
|
+ ; return (matched_es, rs_binds rule_subst, rs_bndrs rule_subst) }
|
|
759
|
779
|
where
|
|
760
|
780
|
(init_rn_env, tmpl_vars1) = mapAccumL rnBndrL (mkRnEnv2 in_scope) tmpl_vars
|
|
761
|
781
|
-- See Note [Cloning the template binders]
|