X-Git-Url: http://git.megacz.com/?p=ghc-hetmet.git;a=blobdiff_plain;f=compiler%2Fstranal%2FDmdAnal.lhs;h=917c624280355905dce3cc77afefe51254c59827;hp=a93990781d528070cfccd6ced0c79b3f34d04a2c;hb=9ffadf219cbc4f8ec57264786df936a3cee88aec;hpb=7fc749a43b4b6b85d234fa95d4928648259584f4 diff --git a/compiler/stranal/DmdAnal.lhs b/compiler/stranal/DmdAnal.lhs index a939907..917c624 100644 --- a/compiler/stranal/DmdAnal.lhs +++ b/compiler/stranal/DmdAnal.lhs @@ -77,11 +77,7 @@ To think about dmdAnalPgm :: DynFlags -> [CoreBind] -> IO [CoreBind] dmdAnalPgm dflags binds = do { - showPass dflags "Demand analysis" ; let { binds_plus_dmds = do_prog binds } ; - - endPass dflags "Demand analysis" - Opt_D_dump_stranal binds_plus_dmds ; #ifdef OLD_STRICTNESS -- Only if OLD_STRICTNESS is on, because only then is the old -- strictness analyser run @@ -567,9 +563,47 @@ in the case where t turns out to be not-demanded. This is handled by dmdAnalTopBind. +Note [NOINLINE and strictness] +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +The strictness analyser used to have a HACK which ensured that NOINLNE +things were not strictness-analysed. The reason was unsafePerformIO. +Left to itself, the strictness analyser would discover this strictness +for unsafePerformIO: + unsafePerformIO: C(U(AV)) +But then consider this sub-expression + unsafePerformIO (\s -> let r = f x in + case writeIORef v r s of (# s1, _ #) -> + (# s1, r #) +The strictness analyser will now find that r is sure to be eval'd, +and may then hoist it out. This makes tests/lib/should_run/memo002 +deadlock. + +Solving this by making all NOINLINE things have no strictness info is overkill. +In particular, it's overkill for runST, which is perfectly respectable. +Consider + f x = runST (return x) +This should be strict in x. + +So the new plan is to define unsafePerformIO using the 'lazy' combinator: + + unsafePerformIO (IO m) = lazy (case m realWorld# of (# _, r #) -> r) + +Remember, 'lazy' is a wired-in identity-function Id, of type a->a, which is +magically NON-STRICT, and is inlined after strictness analysis. So +unsafePerformIO will look non-strict, and that's what we want. + +Now we don't need the hack in the strictness analyser. HOWEVER, this +decision does mean that even a NOINLINE function is not entirely +opaque: some aspect of its implementation leaks out, notably its +strictness. For example, if you have a function implemented by an +error stub, but which has RULES, you may want it not to be eliminated +in favour of error! + + \begin{code} mk_sig_ty never_inline thunk_cpr_ok rhs (DmdType fv dmds res) = (lazy_fv, mkStrictSig dmd_ty) + -- Re unused never_inline, see Note [NOINLINE and strictness] where dmd_ty = DmdType strict_fv final_dmds res' @@ -656,15 +690,6 @@ nonAbsentArgs (d : ds) = 1 + nonAbsentArgs ds %************************************************************************ \begin{code} -splitDmdTy :: DmdType -> (Demand, DmdType) --- Split off one function argument --- We already have a suitable demand on all --- free vars, so no need to add more! -splitDmdTy (DmdType fv (dmd:dmds) res_ty) = (dmd, DmdType fv dmds res_ty) -splitDmdTy ty@(DmdType fv [] res_ty) = (resTypeArgDmd res_ty, ty) -\end{code} - -\begin{code} unitVarDmd var dmd = DmdType (unitVarEnv var dmd) [] TopRes addVarDmd top_lvl dmd_ty@(DmdType fv ds res) var dmd @@ -714,6 +739,11 @@ annotateBndr dmd_ty@(DmdType fv ds res) var annotateBndrs = mapAccumR annotateBndr +annotateLamIdBndr :: DmdType -- Demand type of body + -> Id -- Lambda binder + -> (DmdType, -- Demand type of lambda + Id) -- and binder annotated with demand + annotateLamIdBndr dmd_ty@(DmdType fv ds res) id -- For lambdas we add the demand to the argument demands -- Only called for Ids @@ -869,6 +899,13 @@ dmdTransform sigs var dmd %************************************************************************ \begin{code} +splitDmdTy :: DmdType -> (Demand, DmdType) +-- Split off one function argument +-- We already have a suitable demand on all +-- free vars, so no need to add more! +splitDmdTy (DmdType fv (dmd:dmds) res_ty) = (dmd, DmdType fv dmds res_ty) +splitDmdTy ty@(DmdType fv [] res_ty) = (resTypeArgDmd res_ty, ty) + splitCallDmd :: Demand -> (Int, Demand) splitCallDmd (Call d) = case splitCallDmd d of (n, r) -> (n+1, r) @@ -883,7 +920,6 @@ deferType (DmdType fv _ _) = DmdType (deferEnv fv) [] TopRes -- Notice that we throw away info about both arguments and results -- For example, f = let ... in \x -> x -- We don't want to get a stricness type V->T for f. - -- Peter?? deferEnv :: DmdEnv -> DmdEnv deferEnv fv = mapVarEnv defer fv