X-Git-Url: http://git.megacz.com/?a=blobdiff_plain;f=ghc%2Fcompiler%2FdeSugar%2FDsBinds.lhs;fp=ghc%2Fcompiler%2FdeSugar%2FDsBinds.lhs;h=fe3276fd23a8d5e22a5cd731358424b87dedb9d6;hb=a7ecdf96844404b7bc8273d4ff6d85759278427c;hp=70e5d16f73aac7d306405a994d4d6bf35be46538;hpb=8a9aba1ff5e66aad02aba0997339ea6ec60d6b1e;p=ghc-hetmet.git diff --git a/ghc/compiler/deSugar/DsBinds.lhs b/ghc/compiler/deSugar/DsBinds.lhs index 70e5d16..fe3276f 100644 --- a/ghc/compiler/deSugar/DsBinds.lhs +++ b/ghc/compiler/deSugar/DsBinds.lhs @@ -8,12 +8,12 @@ in that the @Rec@/@NonRec@/etc structure is thrown away (whereas at lower levels it is preserved with @let@/@letrec@s). \begin{code} -module DsBinds ( dsHsBinds, dsHsNestedBinds, AutoScc(..) ) where +module DsBinds ( dsTopLHsBinds, dsLHsBinds, decomposeRuleLhs, AutoScc(..) ) where #include "HsVersions.h" -import {-# SOURCE #-} DsExpr( dsLExpr ) +import {-# SOURCE #-} DsExpr( dsLExpr, dsExpr ) import {-# SOURCE #-} Match( matchWrapper ) import DsMonad @@ -26,17 +26,23 @@ import CoreUtils ( exprType, mkInlineMe, mkSCC ) import StaticFlags ( opt_AutoSccsOnAllToplevs, opt_AutoSccsOnExportedToplevs ) +import OccurAnal ( occurAnalyseExpr ) import CostCentre ( mkAutoCC, IsCafCC(..) ) -import Id ( idType, idName, isExportedId, isSpecPragmaId, Id ) -import NameSet -import VarSet +import Id ( Id, idType, idName, isExportedId, mkLocalId, setInlinePragma ) +import Rules ( addIdSpecialisations, mkLocalRule ) +import Var ( Var, isGlobalId ) +import VarEnv import Type ( mkTyVarTy, substTyWith ) import TysWiredIn ( voidTy ) import Outputable import SrcLoc ( Located(..) ) -import Maybe ( isJust ) +import Maybes ( isJust, catMaybes, orElse ) import Bag ( bagToList ) +import BasicTypes ( Activation(..), isAlwaysActive ) import Monad ( foldM ) +import FastString ( mkFastString ) +import List ( (\\) ) +import Util ( mapSnd ) \end{code} %************************************************************************ @@ -46,16 +52,17 @@ import Monad ( foldM ) %************************************************************************ \begin{code} -dsHsNestedBinds :: LHsBinds Id -> DsM [(Id,CoreExpr)] -dsHsNestedBinds binds = dsHsBinds NoSccs binds [] +dsTopLHsBinds :: AutoScc -> LHsBinds Id -> DsM [(Id,CoreExpr)] +dsTopLHsBinds auto_scc binds = ds_lhs_binds auto_scc binds -dsHsBinds :: AutoScc -- scc annotation policy (see below) - -> LHsBinds Id - -> [(Id,CoreExpr)] -- Put this on the end (avoid quadratic append) - -> DsM [(Id,CoreExpr)] -- Result +dsLHsBinds :: LHsBinds Id -> DsM [(Id,CoreExpr)] +dsLHsBinds binds = ds_lhs_binds NoSccs binds -dsHsBinds auto_scc binds rest - = foldM (dsLHsBind auto_scc) rest (bagToList binds) + +------------------------ +ds_lhs_binds :: AutoScc -> LHsBinds Id -> DsM [(Id,CoreExpr)] + -- scc annotation policy (see below) +ds_lhs_binds auto_scc binds = foldM (dsLHsBind auto_scc) [] (bagToList binds) dsLHsBind :: AutoScc -> [(Id,CoreExpr)] -- Put this on the end (avoid quadratic append) @@ -75,25 +82,14 @@ dsHsBind auto_scc rest (VarBind var expr) -- Dictionary bindings are always VarMonoBinds, so -- we only need do this here addDictScc var core_expr `thenDs` \ core_expr' -> + returnDs ((var, core_expr') : rest) - let - -- Gross hack to prevent inlining into SpecPragmaId rhss - -- Consider fromIntegral = fromInteger . toInteger - -- spec1 = fromIntegral Int Float - -- Even though fromIntegral is small we don't want to inline - -- it inside spec1, so that we collect the specialised call - -- Solution: make spec1 an INLINE thing. - core_expr'' = mkInline (isSpecPragmaId var) core_expr' - in - - returnDs ((var, core_expr'') : rest) - -dsHsBind auto_scc rest (FunBind (L _ fun) _ matches) +dsHsBind auto_scc rest (FunBind (L _ fun) _ matches _) = matchWrapper (FunRhs (idName fun)) matches `thenDs` \ (args, body) -> addAutoScc auto_scc (fun, mkLams args body) `thenDs` \ pair -> returnDs (pair : rest) -dsHsBind auto_scc rest (PatBind pat grhss ty) +dsHsBind auto_scc rest (PatBind pat grhss ty _) = dsGuarded grhss ty `thenDs` \ body_expr -> mkSelectorBinds pat body_expr `thenDs` \ sel_binds -> mappM (addAutoScc auto_scc) sel_binds `thenDs` \ sel_binds -> @@ -103,67 +99,133 @@ dsHsBind auto_scc rest (PatBind pat grhss ty) -- For the (rare) case when there are some mixed-up -- dictionary bindings (for which a Rec is convenient) -- we reply on the enclosing dsBind to wrap a Rec around. -dsHsBind auto_scc rest (AbsBinds [] [] exports inlines binds) - = dsHsBinds (addSccs auto_scc exports) binds []`thenDs` \ core_prs -> +dsHsBind auto_scc rest (AbsBinds [] [] exports binds) + = ds_lhs_binds (addSccs auto_scc exports) binds `thenDs` \ core_prs -> let - core_prs' = addLocalInlines exports inlines core_prs - exports' = [(global, Var local) | (_, global, local) <- exports] + core_prs' = addLocalInlines exports core_prs + exports' = [(global, Var local) | (_, global, local, _) <- exports] in returnDs (core_prs' ++ exports' ++ rest) -- Another common case: one exported variable -- Non-recursive bindings come through this way dsHsBind auto_scc rest - (AbsBinds all_tyvars dicts exps@[(tyvars, global, local)] inlines binds) + (AbsBinds all_tyvars dicts exports@[(tyvars, global, local, prags)] binds) = ASSERT( all (`elem` tyvars) all_tyvars ) - dsHsBinds (addSccs auto_scc exps) binds [] `thenDs` \ core_prs -> + ds_lhs_binds (addSccs auto_scc exports) binds `thenDs` \ core_prs -> let -- Always treat the binds as recursive, because the typechecker -- makes rather mixed-up dictionary bindings core_bind = Rec core_prs - - -- The mkInline does directly what the - -- addLocalInlines do in the other cases - export' = (global, mkInline (idName global `elemNameSet` inlines) $ - mkLams tyvars $ mkLams dicts $ - Let core_bind (Var local)) + inline_env = mkVarEnv [(global, prag) | prag <- prags, isInlinePrag prag] in - returnDs (export' : rest) + mappM (dsSpec all_tyvars dicts tyvars global local core_bind) + prags `thenDs` \ mb_specs -> + let + (spec_binds, rules) = unzip (catMaybes mb_specs) + global' = addIdSpecialisations global rules + rhs' = mkLams tyvars $ mkLams dicts $ Let core_bind (Var local) + in + returnDs (addInlineInfo inline_env (global', rhs') : spec_binds ++ rest) -dsHsBind auto_scc rest (AbsBinds all_tyvars dicts exports inlines binds) - = dsHsBinds (addSccs auto_scc exports) binds []`thenDs` \ core_prs -> - let +dsHsBind auto_scc rest (AbsBinds all_tyvars dicts exports binds) + = ds_lhs_binds (addSccs auto_scc exports) binds `thenDs` \ core_prs -> + let -- Rec because of mixed-up dictionary bindings - core_bind = Rec (addLocalInlines exports inlines core_prs) + core_bind = Rec (addLocalInlines exports core_prs) tup_expr = mkTupleExpr locals tup_ty = exprType tup_expr poly_tup_expr = mkLams all_tyvars $ mkLams dicts $ Let core_bind tup_expr - locals = [local | (_, _, local) <- exports] + locals = [local | (_, _, local, _) <- exports] local_tys = map idType locals in newSysLocalDs (exprType poly_tup_expr) `thenDs` \ poly_tup_id -> let dict_args = map Var dicts - mk_bind ((tyvars, global, local), n) -- locals !! n == local + mk_bind ((tyvars, global, local, prags), n) -- locals !! n == local = -- Need to make fresh locals to bind in the selector, because -- some of the tyvars will be bound to voidTy newSysLocalsDs (map substitute local_tys) `thenDs` \ locals' -> newSysLocalDs (substitute tup_ty) `thenDs` \ tup_id -> - returnDs (global, mkLams tyvars $ mkLams dicts $ - mkTupleSelector locals' (locals' !! n) tup_id $ - mkApps (mkTyApps (Var poly_tup_id) ty_args) dict_args) + mapM (dsSpec all_tyvars dicts tyvars global local core_bind) + prags `thenDs` \ mb_specs -> + let + (spec_binds, rules) = unzip (catMaybes mb_specs) + global' = addIdSpecialisations global rules + rhs = mkLams tyvars $ mkLams dicts $ + mkTupleSelector locals' (locals' !! n) tup_id $ + mkApps (mkTyApps (Var poly_tup_id) ty_args) dict_args + in + returnDs ((global', rhs) : spec_binds) where mk_ty_arg all_tyvar | all_tyvar `elem` tyvars = mkTyVarTy all_tyvar | otherwise = voidTy ty_args = map mk_ty_arg all_tyvars substitute = substTyWith all_tyvars ty_args in - mappM mk_bind (exports `zip` [0..]) `thenDs` \ export_binds -> + mappM mk_bind (exports `zip` [0..]) `thenDs` \ export_binds_s -> -- don't scc (auto-)annotate the tuple itself. - returnDs ((poly_tup_id, poly_tup_expr) : (export_binds ++ rest)) + + returnDs ((poly_tup_id, poly_tup_expr) : (concat export_binds_s ++ rest)) + +-- Example: +-- f :: (Eq a, Ix b) => a -> b -> b +-- +-- AbsBinds [ab] [d1,d2] [([ab], f, f_mono, prags)] binds +-- +-- SpecPrag (/\b.\(d:Ix b). f Int b dInt d) +-- (forall b. Ix b => Int -> b -> b) +-- +-- Rule: forall b,(d:Ix b). f Int b dInt d = f_spec b d +-- +-- Spec bind: f_spec = Let f = /\ab \(d1:Eq a)(d2:Ix b). let binds in f_mono +-- /\b.\(d:Ix b). in f Int b dInt d + +dsSpec all_tvs dicts tvs poly_id mono_id mono_bind (InlinePrag {}) + = return Nothing + +dsSpec all_tvs dicts tvs poly_id mono_id mono_bind + (SpecPrag spec_expr spec_ty const_dicts) + = do { let poly_name = idName poly_id + ; spec_name <- newLocalName (idName poly_id) + ; ds_spec_expr <- dsExpr spec_expr + ; let (bndrs, body) = collectBinders ds_spec_expr + mb_lhs = decomposeRuleLhs (bndrs ++ const_dicts) body + + ; case mb_lhs of + Nothing -> do { dsWarn msg; return Nothing } + + Just (bndrs', var, args) -> return (Just ((spec_id, spec_rhs), rule)) + where + spec_id = mkLocalId spec_name spec_ty + spec_rhs = Let (NonRec poly_id poly_f_body) ds_spec_expr + poly_f_body = mkLams (tvs ++ dicts) $ + fix_up (Let mono_bind (Var mono_id)) + + -- Quantify over constant dicts on the LHS, since + -- their value depends only on their type + -- The ones we are interested in may even be imported + -- e.g. GHC.Base.dEqInt + + rule = mkLocalRule (mkFastString ("SPEC " ++ showSDoc (ppr poly_name))) + AlwaysActive poly_name + bndrs' -- Includes constant dicts + args + (mkVarApps (Var spec_id) bndrs) + } + where + -- Bind to voidTy any of all_ptvs that aren't + -- relevant for this particular function + fix_up body | null void_tvs = body + | otherwise = mkTyApps (mkLams void_tvs body) + (map (const voidTy) void_tvs) + void_tvs = all_tvs \\ tvs + + msg = hang (ptext SLIT("Specialisation too complicated to desugar; ignored")) + 2 (ppr spec_expr) \end{code} @@ -174,15 +236,78 @@ dsHsBind auto_scc rest (AbsBinds all_tyvars dicts exports inlines binds) %************************************************************************ \begin{code} -mkInline :: Bool -> CoreExpr -> CoreExpr -mkInline True body = mkInlineMe body -mkInline False body = body +decomposeRuleLhs :: [Var] -> CoreExpr -> Maybe ([Var], Id, [CoreExpr]) +-- Returns Nothing if the LHS isn't of the expected shape +-- The argument 'all_bndrs' includes the "constant dicts" of the LHS, +-- and they may be GlobalIds, which we can't forall-ify. +-- So we substitute them out instead +decomposeRuleLhs all_bndrs lhs + = go init_env (occurAnalyseExpr lhs) -- Occurrence analysis sorts out the dict + -- bindings so we know if they are recursive + where -addLocalInlines :: [(a, Id, Id)] -> NameSet -> [(Id,CoreExpr)] -> [(Id,CoreExpr)] -addLocalInlines exports inlines pairs - = [(bndr, mkInline (bndr `elemVarSet` local_inlines) rhs) | (bndr,rhs) <- pairs] + -- all_bndrs may include top-level imported dicts, + -- imported things with a for-all. + -- So we localise them and subtitute them out + bndr_prs = [ (id, Var (localise id)) | id <- all_bndrs, isGlobalId id ] + localise d = mkLocalId (idName d) (idType d) + + init_env = mkVarEnv bndr_prs + all_bndrs' = map subst_bndr all_bndrs + subst_bndr bndr = case lookupVarEnv init_env bndr of + Just (Var bndr') -> bndr' + Just other -> panic "decomposeRuleLhs" + Nothing -> bndr + + -- Substitute dicts in the LHS args, so that there + -- aren't any lets getting in the way + go env (Let (NonRec dict rhs) body) + = go (extendVarEnv env dict (simpleSubst env rhs)) body + go env body + = case collectArgs body of + (Var fn, args) -> Just (all_bndrs', fn, map (simpleSubst env) args) + other -> Nothing + +simpleSubst :: IdEnv CoreExpr -> CoreExpr -> CoreExpr +-- Similar to CoreSubst.substExpr, except that +-- (a) takes no account of capture; dictionary bindings use new names +-- (b) can have a GlobalId (imported) in its domain +-- (c) Ids only; no types are substituted + +simpleSubst subst expr + = go expr + where + go (Var v) = lookupVarEnv subst v `orElse` Var v + go (Type ty) = Type ty + go (Lit lit) = Lit lit + go (App fun arg) = App (go fun) (go arg) + go (Note note e) = Note note (go e) + go (Lam bndr body) = Lam bndr (go body) + go (Let (NonRec bndr rhs) body) = Let (NonRec bndr (go rhs)) (go body) + go (Let (Rec pairs) body) = Let (Rec (mapSnd go pairs)) (go body) + go (Case scrut bndr ty alts) = Case (go scrut) bndr ty + [(c,bs,go r) | (c,bs,r) <- alts] + +addLocalInlines exports core_prs + = map (addInlineInfo inline_env) core_prs where - local_inlines = mkVarSet [l | (_,g,l) <- exports, idName g `elemNameSet` inlines] + inline_env = mkVarEnv [(mono_id, prag) + | (_, _, mono_id, prags) <- exports, + prag <- prags, isInlinePrag prag] + +addInlineInfo :: IdEnv Prag -> (Id,CoreExpr) -> (Id,CoreExpr) +addInlineInfo inline_env (bndr,rhs) + | Just (InlinePrag is_inline phase) <- lookupVarEnv inline_env bndr + = (attach_phase bndr phase, wrap_inline is_inline rhs) + | otherwise + = (bndr, rhs) + where + attach_phase bndr phase + | isAlwaysActive phase = bndr -- Default phase + | otherwise = bndr `setInlinePragma` phase + + wrap_inline True body = mkInlineMe body + wrap_inline False body = body \end{code} @@ -198,11 +323,11 @@ data AutoScc | TopLevelAddSccs (Id -> Maybe Id) | NoSccs -addSccs :: AutoScc -> [(a,Id,Id)] -> AutoScc +addSccs :: AutoScc -> [(a,Id,Id,[Prag])] -> AutoScc addSccs auto_scc@(TopLevelAddSccs _) exports = auto_scc addSccs NoSccs exports = NoSccs addSccs TopLevel exports - = TopLevelAddSccs (\id -> case [ exp | (_,exp,loc) <- exports, loc == id ] of + = TopLevelAddSccs (\id -> case [ exp | (_,exp,loc,_) <- exports, loc == id ] of (exp:_) | opt_AutoSccsOnAllToplevs || (isExportedId exp && opt_AutoSccsOnExportedToplevs) @@ -233,7 +358,7 @@ addDictScc var rhs = returnDs rhs {- DISABLED for now (need to somehow make up a name for the scc) -- SDM | not ( opt_SccProfilingOn && opt_AutoSccsOnDicts) - || not (isDictTy (idType var)) + || not (isDictId var) = returnDs rhs -- That's easy: do nothing | otherwise