X-Git-Url: http://git.megacz.com/?a=blobdiff_plain;f=compiler%2Fspecialise%2FSpecialise.lhs;h=9750bd042c8283c6243e84b98b6bcfd1f5cf117a;hb=35c5bf8991bd3954bc9dd3fe584da03791223a57;hp=fa9d2536215aa4709924276af4466987facace42;hpb=07f3c0c8ebbcc5298167b5b705a1660519b395c4;p=ghc-hetmet.git diff --git a/compiler/specialise/Specialise.lhs b/compiler/specialise/Specialise.lhs index fa9d253..9750bd0 100644 --- a/compiler/specialise/Specialise.lhs +++ b/compiler/specialise/Specialise.lhs @@ -4,6 +4,13 @@ \section[Specialise]{Stamping out overloading, and (optionally) polymorphism} \begin{code} +{-# OPTIONS -w #-} +-- The above warning supression flag is a temporary kludge. +-- While working on this module you are encouraged to remove it and fix +-- any warnings in the module. See +-- http://hackage.haskell.org/trac/ghc/wiki/Commentary/CodingStyle#Warnings +-- for details + module Specialise ( specProgram ) where #include "HsVersions.h" @@ -23,7 +30,7 @@ import VarSet import VarEnv import CoreSyn import CoreUtils ( applyTypeToArgs, mkPiTypes ) -import CoreFVs ( exprFreeVars, exprsFreeVars, idRuleVars ) +import CoreFVs ( exprFreeVars, exprsFreeVars, idFreeVars ) import CoreTidy ( tidyRules ) import CoreLint ( showPass, endPass ) import Rules ( addIdSpecialisations, mkLocalRule, lookupRule, emptyRuleBase, rulesOfBinds ) @@ -32,7 +39,7 @@ import UniqSupply ( UniqSupply, UniqSM, initUs_, thenUs, returnUs, getUniqueUs, getUs, mapUs ) -import Name ( nameOccName, mkSpecOcc, getSrcLoc ) +import Name import MkId ( voidArgId, realWorldPrimId ) import FiniteMap import Maybes ( catMaybes, maybeToBool ) @@ -783,8 +790,8 @@ specDefn :: Subst -- Subst to use for RHS specDefn subst calls (fn, rhs) -- The first case is the interesting one - | rhs_tyvars `lengthIs` n_tyvars -- Rhs of fn's defn has right number of big lambdas - && rhs_bndrs `lengthAtLeast` n_dicts -- and enough dict args + | rhs_tyvars `lengthIs` n_tyvars -- Rhs of fn's defn has right number of big lambdas + && rhs_ids `lengthAtLeast` n_dicts -- and enough dict args && notNull calls_for_me -- And there are some calls to specialise -- && not (certainlyWillInline (idUnfolding fn)) -- And it's not small @@ -806,7 +813,9 @@ specDefn subst calls (fn, rhs) rhs_uds `plusUDs` plusUDList spec_uds) | otherwise -- No calls or RHS doesn't fit our preconceptions - = specExpr subst rhs `thenSM` \ (rhs', rhs_uds) -> + = WARN( notNull calls_for_me, ptext SLIT("Missed specialisation opportunity for") <+> ppr fn ) + -- Note [Specialisation shape] + specExpr subst rhs `thenSM` \ (rhs', rhs_uds) -> returnSM ((fn, rhs'), [], rhs_uds) where @@ -883,7 +892,8 @@ specDefn subst calls (fn, rhs) -- The rule to put in the function's specialisation is: -- forall b,d, d1',d2'. f t1 b t3 d d1' d2' = f1 b d spec_env_rule = mkLocalRule (mkFastString ("SPEC " ++ showSDoc (ppr fn))) - AlwaysActive (idName fn) + inline_prag -- Note [Auto-specialisation and RULES] + (idName fn) (poly_tyvars ++ rhs_dicts') inst_args (mkVarApps (Var spec_f) app_args) @@ -898,10 +908,69 @@ specDefn subst calls (fn, rhs) where my_zipEqual doc xs ys - | not (equalLength xs ys) = pprPanic "my_zipEqual" (ppr xs $$ ppr ys $$ (ppr fn <+> ppr call_ts) $$ ppr rhs) +#ifdef DEBUG + | not (equalLength xs ys) = pprPanic "my_zipEqual" (vcat + [ ppr xs, ppr ys + , ppr fn <+> ppr call_ts + , ppr (idType fn), ppr theta + , ppr n_dicts, ppr rhs_dicts + , ppr rhs]) +#endif | otherwise = zipEqual doc xs ys \end{code} +Note [Auto-specialisation and RULES] +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Consider: + g :: Num a => a -> a + g = ... + + f :: (Int -> Int) -> Int + f w = ... + {-# RULE f g = 0 #-} + +Suppose that auto-specialisation makes a specialised version of +g::Int->Int That version won't appear in the LHS of the RULE for f. +So if the specialisation rule fires too early, the rule for f may +never fire. + +It might be possible to add new rules, to "complete" the rewrite system. +Thus when adding + RULE forall d. g Int d = g_spec +also add + RULE f g_spec = 0 + +But that's a bit complicated. For now we ask the programmer's help, +by *copying the INLINE activation pragma* to the auto-specialised rule. +So if g says {-# NOINLINE[2] g #-}, then the auto-spec rule will also +not be active until phase 2. + + +Note [Specialisation shape] +~~~~~~~~~~~~~~~~~~~~~~~~~~~ +We only specialise a function if it has visible top-level lambdas +corresponding to its overloading. E.g. if + f :: forall a. Eq a => .... +then its body must look like + f = /\a. \d. ... + +Reason: when specialising the body for a call (f ty dexp), we want to +substitute dexp for d, and pick up specialised calls in the body of f. + +This doesn't always work. One example I came across was htis: + newtype Gen a = MkGen{ unGen :: Int -> a } + + choose :: Eq a => a -> Gen a + choose n = MkGen (\r -> n) + + oneof = choose (1::Int) + +It's a silly exapmle, but we get + choose = /\a. g `cast` co +where choose doesn't have any dict arguments. Thus far I have not +tried to fix this (wait till there's a real example). + + Note [Inline specialisations] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ We transfer to the specialised function any INLINE stuff from the @@ -1072,10 +1141,12 @@ bind_fvs (Rec prs) = foldl delVarSet rhs_fvs bndrs bndrs = map fst prs rhs_fvs = unionVarSets (map pair_fvs prs) -pair_fvs (bndr, rhs) = exprFreeVars rhs `unionVarSet` idRuleVars bndr +pair_fvs (bndr, rhs) = exprFreeVars rhs `unionVarSet` idFreeVars bndr -- Don't forget variables mentioned in the -- rules of the bndr. C.f. OccAnal.addRuleUsage - + -- Also tyvars mentioned in its type; they may not appear in the RHS + -- type T a = Int + -- x :: T a = 3 addDictBind (dict,rhs) uds = uds { dict_binds = mkDB (NonRec dict rhs) `consBag` dict_binds uds } @@ -1182,7 +1253,7 @@ newIdSM old_id new_ty let -- Give the new Id a similar occurrence name to the old one name = idName old_id - new_id = mkUserLocal (mkSpecOcc (nameOccName name)) uniq new_ty (getSrcLoc name) + new_id = mkUserLocal (mkSpecOcc (nameOccName name)) uniq new_ty (getSrcSpan name) in returnSM new_id \end{code}