- return (new_bind, spec_uds)
-
-specBindItself rhs_subst (Rec pairs) call_info = do
- stuff <- mapM (specDefn rhs_subst call_info) pairs
- let
- (pairs', spec_defns_s, spec_uds_s) = unzip3 stuff
- spec_defns = concat spec_defns_s
- spec_uds = plusUDList spec_uds_s
- new_bind = Rec (spec_defns ++ pairs')
- return (new_bind, spec_uds)
-
-
-specDefn :: Subst -- Subst to use for RHS
+
+specBindItself rhs_subst (Rec pairs) call_info
+ -- Note [Specialising a recursive group]
+ = do { let (bndrs,rhss) = unzip pairs
+ ; (rhss', rhs_uds) <- mapAndCombineSM (specExpr rhs_subst) rhss
+ ; let all_calls = call_info `unionCalls` calls rhs_uds
+ ; (bndrs1, spec_defns1, spec_uds1) <- specDefns rhs_subst all_calls pairs
+
+ ; if null spec_defns1 then -- Common case: no specialisation
+ return (Rec (bndrs `zip` rhss'), rhs_uds)
+ else do -- Specialisation occurred; do it again
+ { (bndrs2, spec_defns2, spec_uds2) <-
+ -- pprTrace "specB" (ppr bndrs $$ ppr rhs_uds) $
+ specDefns rhs_subst (calls spec_uds1) (bndrs1 `zip` rhss)
+
+ ; let all_defns = spec_defns1 ++ spec_defns2 ++ zip bndrs2 rhss'
+
+ ; return (Rec all_defns, rhs_uds `plusUDs` spec_uds1 `plusUDs` spec_uds2) } }
+
+
+---------------------------
+specDefns :: Subst
+ -> CallDetails -- Info on how it is used in its scope
+ -> [(Id,CoreExpr)] -- The things being bound and their un-processed RHS
+ -> SpecM ([Id], -- Original Ids with RULES added
+ [(Id,CoreExpr)], -- Extra, specialised bindings
+ UsageDetails) -- Stuff to fling upwards from the specialised versions
+
+-- Specialise a list of bindings (the contents of a Rec), but flowing usages
+-- upwards binding by binding. Example: { f = ...g ...; g = ...f .... }
+-- Then if the input CallDetails has a specialised call for 'g', whose specialisation
+-- in turn generates a specialised call for 'f', we catch that in this one sweep.
+-- But not vice versa (it's a fixpoint problem).
+
+specDefns _subst _call_info []
+ = return ([], [], emptyUDs)
+specDefns subst call_info ((bndr,rhs):pairs)
+ = do { (bndrs', spec_defns, spec_uds) <- specDefns subst call_info pairs
+ ; let all_calls = call_info `unionCalls` calls spec_uds
+ ; (bndr', spec_defns1, spec_uds1) <- specDefn subst all_calls bndr rhs
+ ; return (bndr' : bndrs',
+ spec_defns1 ++ spec_defns,
+ spec_uds1 `plusUDs` spec_uds) }
+
+---------------------------
+specDefn :: Subst