| 1 | % |
|---|
| 2 | % (c) The GRASP/AQUA Project, Glasgow University, 1993-1998 |
|---|
| 3 | % |
|---|
| 4 | |
|---|
| 5 | ----------------- |
|---|
| 6 | A demand analysis |
|---|
| 7 | ----------------- |
|---|
| 8 | |
|---|
| 9 | \begin{code} |
|---|
| 10 | {-# OPTIONS -fno-warn-tabs #-} |
|---|
| 11 | -- The above warning supression flag is a temporary kludge. |
|---|
| 12 | -- While working on this module you are encouraged to remove it and |
|---|
| 13 | -- detab the module (please do the detabbing in a separate patch). See |
|---|
| 14 | -- http://hackage.haskell.org/trac/ghc/wiki/Commentary/CodingStyle#TabsvsSpaces |
|---|
| 15 | -- for details |
|---|
| 16 | |
|---|
| 17 | module DmdAnal ( dmdAnalPgm, dmdAnalTopRhs, |
|---|
| 18 | both {- needed by WwLib -} |
|---|
| 19 | ) where |
|---|
| 20 | |
|---|
| 21 | #include "HsVersions.h" |
|---|
| 22 | |
|---|
| 23 | import DynFlags ( DynFlags ) |
|---|
| 24 | import StaticFlags ( opt_MaxWorkerArgs ) |
|---|
| 25 | import Demand -- All of it |
|---|
| 26 | import CoreSyn |
|---|
| 27 | import PprCore |
|---|
| 28 | import Coercion ( isCoVarType ) |
|---|
| 29 | import CoreUtils ( exprIsHNF, exprIsTrivial ) |
|---|
| 30 | import CoreArity ( exprArity ) |
|---|
| 31 | import DataCon ( dataConTyCon, dataConRepStrictness ) |
|---|
| 32 | import TyCon ( isProductTyCon, isRecursiveTyCon ) |
|---|
| 33 | import Id ( Id, idType, idInlineActivation, |
|---|
| 34 | isDataConWorkId, isGlobalId, idArity, |
|---|
| 35 | idStrictness, |
|---|
| 36 | setIdStrictness, idDemandInfo, idUnfolding, |
|---|
| 37 | idDemandInfo_maybe, setIdDemandInfo |
|---|
| 38 | ) |
|---|
| 39 | import Var ( Var, isTyVar ) |
|---|
| 40 | import VarEnv |
|---|
| 41 | import TysWiredIn ( unboxedPairDataCon ) |
|---|
| 42 | import TysPrim ( realWorldStatePrimTy ) |
|---|
| 43 | import UniqFM ( addToUFM_Directly, lookupUFM_Directly, |
|---|
| 44 | minusUFM, filterUFM ) |
|---|
| 45 | import Type ( isUnLiftedType, eqType, tyConAppTyCon_maybe ) |
|---|
| 46 | import Coercion ( coercionKind ) |
|---|
| 47 | import Util ( mapAndUnzip, lengthIs, zipEqual ) |
|---|
| 48 | import BasicTypes ( Arity, TopLevelFlag(..), isTopLevel, isNeverActive, |
|---|
| 49 | RecFlag(..), isRec, isMarkedStrict ) |
|---|
| 50 | import Maybes ( orElse, expectJust ) |
|---|
| 51 | import Outputable |
|---|
| 52 | import Pair |
|---|
| 53 | import Data.List |
|---|
| 54 | import FastString |
|---|
| 55 | \end{code} |
|---|
| 56 | |
|---|
| 57 | To think about |
|---|
| 58 | |
|---|
| 59 | * set a noinline pragma on bottoming Ids |
|---|
| 60 | |
|---|
| 61 | * Consider f x = x+1 `fatbar` error (show x) |
|---|
| 62 | We'd like to unbox x, even if that means reboxing it in the error case. |
|---|
| 63 | |
|---|
| 64 | |
|---|
| 65 | %************************************************************************ |
|---|
| 66 | %* * |
|---|
| 67 | \subsection{Top level stuff} |
|---|
| 68 | %* * |
|---|
| 69 | %************************************************************************ |
|---|
| 70 | |
|---|
| 71 | \begin{code} |
|---|
| 72 | dmdAnalPgm :: DynFlags -> CoreProgram -> IO CoreProgram |
|---|
| 73 | dmdAnalPgm _ binds |
|---|
| 74 | = do { |
|---|
| 75 | let { binds_plus_dmds = do_prog binds } ; |
|---|
| 76 | return binds_plus_dmds |
|---|
| 77 | } |
|---|
| 78 | where |
|---|
| 79 | do_prog :: CoreProgram -> CoreProgram |
|---|
| 80 | do_prog binds = snd $ mapAccumL dmdAnalTopBind emptySigEnv binds |
|---|
| 81 | |
|---|
| 82 | dmdAnalTopBind :: SigEnv |
|---|
| 83 | -> CoreBind |
|---|
| 84 | -> (SigEnv, CoreBind) |
|---|
| 85 | dmdAnalTopBind sigs (NonRec id rhs) |
|---|
| 86 | = (sigs2, NonRec id2 rhs2) |
|---|
| 87 | where |
|---|
| 88 | ( _, _, (_, rhs1)) = dmdAnalRhs TopLevel NonRecursive (virgin sigs) (id, rhs) |
|---|
| 89 | (sigs2, _, (id2, rhs2)) = dmdAnalRhs TopLevel NonRecursive (nonVirgin sigs) (id, rhs1) |
|---|
| 90 | -- Do two passes to improve CPR information |
|---|
| 91 | -- See comments with ignore_cpr_info in mk_sig_ty |
|---|
| 92 | -- and with extendSigsWithLam |
|---|
| 93 | |
|---|
| 94 | dmdAnalTopBind sigs (Rec pairs) |
|---|
| 95 | = (sigs', Rec pairs') |
|---|
| 96 | where |
|---|
| 97 | (sigs', _, pairs') = dmdFix TopLevel (virgin sigs) pairs |
|---|
| 98 | -- We get two iterations automatically |
|---|
| 99 | -- c.f. the NonRec case above |
|---|
| 100 | \end{code} |
|---|
| 101 | |
|---|
| 102 | \begin{code} |
|---|
| 103 | dmdAnalTopRhs :: CoreExpr -> (StrictSig, CoreExpr) |
|---|
| 104 | -- Analyse the RHS and return |
|---|
| 105 | -- a) appropriate strictness info |
|---|
| 106 | -- b) the unfolding (decorated with strictness info) |
|---|
| 107 | dmdAnalTopRhs rhs |
|---|
| 108 | = (sig, rhs2) |
|---|
| 109 | where |
|---|
| 110 | call_dmd = vanillaCall (exprArity rhs) |
|---|
| 111 | (_, rhs1) = dmdAnal (virgin emptySigEnv) call_dmd rhs |
|---|
| 112 | (rhs_ty, rhs2) = dmdAnal (nonVirgin emptySigEnv) call_dmd rhs1 |
|---|
| 113 | sig = mkTopSigTy rhs rhs_ty |
|---|
| 114 | -- Do two passes; see notes with extendSigsWithLam |
|---|
| 115 | -- Otherwise we get bogus CPR info for constructors like |
|---|
| 116 | -- newtype T a = MkT a |
|---|
| 117 | -- The constructor looks like (\x::T a -> x), modulo the coerce |
|---|
| 118 | -- extendSigsWithLam will optimistically give x a CPR tag the |
|---|
| 119 | -- first time, which is wrong in the end. |
|---|
| 120 | \end{code} |
|---|
| 121 | |
|---|
| 122 | %************************************************************************ |
|---|
| 123 | %* * |
|---|
| 124 | \subsection{The analyser itself} |
|---|
| 125 | %* * |
|---|
| 126 | %************************************************************************ |
|---|
| 127 | |
|---|
| 128 | \begin{code} |
|---|
| 129 | dmdAnal :: AnalEnv -> Demand -> CoreExpr -> (DmdType, CoreExpr) |
|---|
| 130 | |
|---|
| 131 | dmdAnal _ Abs e = (topDmdType, e) |
|---|
| 132 | |
|---|
| 133 | dmdAnal env dmd e |
|---|
| 134 | | not (isStrictDmd dmd) |
|---|
| 135 | = let |
|---|
| 136 | (res_ty, e') = dmdAnal env evalDmd e |
|---|
| 137 | in |
|---|
| 138 | (deferType res_ty, e') |
|---|
| 139 | -- It's important not to analyse e with a lazy demand because |
|---|
| 140 | -- a) When we encounter case s of (a,b) -> |
|---|
| 141 | -- we demand s with U(d1d2)... but if the overall demand is lazy |
|---|
| 142 | -- that is wrong, and we'd need to reduce the demand on s, |
|---|
| 143 | -- which is inconvenient |
|---|
| 144 | -- b) More important, consider |
|---|
| 145 | -- f (let x = R in x+x), where f is lazy |
|---|
| 146 | -- We still want to mark x as demanded, because it will be when we |
|---|
| 147 | -- enter the let. If we analyse f's arg with a Lazy demand, we'll |
|---|
| 148 | -- just mark x as Lazy |
|---|
| 149 | -- c) The application rule wouldn't be right either |
|---|
| 150 | -- Evaluating (f x) in a L demand does *not* cause |
|---|
| 151 | -- evaluation of f in a C(L) demand! |
|---|
| 152 | |
|---|
| 153 | |
|---|
| 154 | dmdAnal _ _ (Lit lit) = (topDmdType, Lit lit) |
|---|
| 155 | dmdAnal _ _ (Type ty) = (topDmdType, Type ty) -- Doesn't happen, in fact |
|---|
| 156 | dmdAnal _ _ (Coercion co) = (topDmdType, Coercion co) |
|---|
| 157 | |
|---|
| 158 | dmdAnal env dmd (Var var) |
|---|
| 159 | = (dmdTransform env var dmd, Var var) |
|---|
| 160 | |
|---|
| 161 | dmdAnal env dmd (Cast e co) |
|---|
| 162 | = (dmd_ty, Cast e' co) |
|---|
| 163 | where |
|---|
| 164 | (dmd_ty, e') = dmdAnal env dmd' e |
|---|
| 165 | to_co = pSnd (coercionKind co) |
|---|
| 166 | dmd' |
|---|
| 167 | | Just tc <- tyConAppTyCon_maybe to_co |
|---|
| 168 | , isRecursiveTyCon tc = evalDmd |
|---|
| 169 | | otherwise = dmd |
|---|
| 170 | -- This coerce usually arises from a recursive |
|---|
| 171 | -- newtype, and we don't want to look inside them |
|---|
| 172 | -- for exactly the same reason that we don't look |
|---|
| 173 | -- inside recursive products -- we might not reach |
|---|
| 174 | -- a fixpoint. So revert to a vanilla Eval demand |
|---|
| 175 | |
|---|
| 176 | dmdAnal env dmd (Tick t e) |
|---|
| 177 | = (dmd_ty, Tick t e') |
|---|
| 178 | where |
|---|
| 179 | (dmd_ty, e') = dmdAnal env dmd e |
|---|
| 180 | |
|---|
| 181 | dmdAnal env dmd (App fun (Type ty)) |
|---|
| 182 | = (fun_ty, App fun' (Type ty)) |
|---|
| 183 | where |
|---|
| 184 | (fun_ty, fun') = dmdAnal env dmd fun |
|---|
| 185 | |
|---|
| 186 | dmdAnal sigs dmd (App fun (Coercion co)) |
|---|
| 187 | = (fun_ty, App fun' (Coercion co)) |
|---|
| 188 | where |
|---|
| 189 | (fun_ty, fun') = dmdAnal sigs dmd fun |
|---|
| 190 | |
|---|
| 191 | -- Lots of the other code is there to make this |
|---|
| 192 | -- beautiful, compositional, application rule :-) |
|---|
| 193 | dmdAnal env dmd (App fun arg) -- Non-type arguments |
|---|
| 194 | = let -- [Type arg handled above] |
|---|
| 195 | (fun_ty, fun') = dmdAnal env (Call dmd) fun |
|---|
| 196 | (arg_ty, arg') = dmdAnal env arg_dmd arg |
|---|
| 197 | (arg_dmd, res_ty) = splitDmdTy fun_ty |
|---|
| 198 | in |
|---|
| 199 | (res_ty `bothType` arg_ty, App fun' arg') |
|---|
| 200 | |
|---|
| 201 | dmdAnal env dmd (Lam var body) |
|---|
| 202 | | isTyVar var |
|---|
| 203 | = let |
|---|
| 204 | (body_ty, body') = dmdAnal env dmd body |
|---|
| 205 | in |
|---|
| 206 | (body_ty, Lam var body') |
|---|
| 207 | |
|---|
| 208 | | Call body_dmd <- dmd -- A call demand: good! |
|---|
| 209 | = let |
|---|
| 210 | env' = extendSigsWithLam env var |
|---|
| 211 | (body_ty, body') = dmdAnal env' body_dmd body |
|---|
| 212 | (lam_ty, var') = annotateLamIdBndr env body_ty var |
|---|
| 213 | in |
|---|
| 214 | (lam_ty, Lam var' body') |
|---|
| 215 | |
|---|
| 216 | | otherwise -- Not enough demand on the lambda; but do the body |
|---|
| 217 | = let -- anyway to annotate it and gather free var info |
|---|
| 218 | (body_ty, body') = dmdAnal env evalDmd body |
|---|
| 219 | (lam_ty, var') = annotateLamIdBndr env body_ty var |
|---|
| 220 | in |
|---|
| 221 | (deferType lam_ty, Lam var' body') |
|---|
| 222 | |
|---|
| 223 | dmdAnal env dmd (Case scrut case_bndr ty [alt@(DataAlt dc, _, _)]) |
|---|
| 224 | | let tycon = dataConTyCon dc |
|---|
| 225 | , isProductTyCon tycon |
|---|
| 226 | , not (isRecursiveTyCon tycon) |
|---|
| 227 | = let |
|---|
| 228 | env_alt = extendAnalEnv NotTopLevel env case_bndr case_bndr_sig |
|---|
| 229 | (alt_ty, alt') = dmdAnalAlt env_alt dmd alt |
|---|
| 230 | (alt_ty1, case_bndr') = annotateBndr alt_ty case_bndr |
|---|
| 231 | (_, bndrs', _) = alt' |
|---|
| 232 | case_bndr_sig = cprSig |
|---|
| 233 | -- Inside the alternative, the case binder has the CPR property. |
|---|
| 234 | -- Meaning that a case on it will successfully cancel. |
|---|
| 235 | -- Example: |
|---|
| 236 | -- f True x = case x of y { I# x' -> if x' ==# 3 then y else I# 8 } |
|---|
| 237 | -- f False x = I# 3 |
|---|
| 238 | -- |
|---|
| 239 | -- We want f to have the CPR property: |
|---|
| 240 | -- f b x = case fw b x of { r -> I# r } |
|---|
| 241 | -- fw True x = case x of y { I# x' -> if x' ==# 3 then x' else 8 } |
|---|
| 242 | -- fw False x = 3 |
|---|
| 243 | |
|---|
| 244 | -- Figure out whether the demand on the case binder is used, and use |
|---|
| 245 | -- that to set the scrut_dmd. This is utterly essential. |
|---|
| 246 | -- Consider f x = case x of y { (a,b) -> k y a } |
|---|
| 247 | -- If we just take scrut_demand = U(L,A), then we won't pass x to the |
|---|
| 248 | -- worker, so the worker will rebuild |
|---|
| 249 | -- x = (a, absent-error) |
|---|
| 250 | -- and that'll crash. |
|---|
| 251 | -- So at one stage I had: |
|---|
| 252 | -- dead_case_bndr = isAbsentDmd (idDemandInfo case_bndr') |
|---|
| 253 | -- keepity | dead_case_bndr = Drop |
|---|
| 254 | -- | otherwise = Keep |
|---|
| 255 | -- |
|---|
| 256 | -- But then consider |
|---|
| 257 | -- case x of y { (a,b) -> h y + a } |
|---|
| 258 | -- where h : U(LL) -> T |
|---|
| 259 | -- The above code would compute a Keep for x, since y is not Abs, which is silly |
|---|
| 260 | -- The insight is, of course, that a demand on y is a demand on the |
|---|
| 261 | -- scrutinee, so we need to `both` it with the scrut demand |
|---|
| 262 | |
|---|
| 263 | alt_dmd = Eval (Prod [idDemandInfo b | b <- bndrs', isId b]) |
|---|
| 264 | scrut_dmd = alt_dmd `both` |
|---|
| 265 | idDemandInfo case_bndr' |
|---|
| 266 | |
|---|
| 267 | (scrut_ty, scrut') = dmdAnal env scrut_dmd scrut |
|---|
| 268 | res_ty = alt_ty1 `bothType` scrut_ty |
|---|
| 269 | in |
|---|
| 270 | -- pprTrace "dmdAnal:Case1" (vcat [ text "scrut" <+> ppr scrut |
|---|
| 271 | -- , text "scrut_ty" <+> ppr scrut_ty |
|---|
| 272 | -- , text "alt_ty" <+> ppr alt_ty1 |
|---|
| 273 | -- , text "res_ty" <+> ppr res_ty ]) $ |
|---|
| 274 | (res_ty, Case scrut' case_bndr' ty [alt']) |
|---|
| 275 | |
|---|
| 276 | dmdAnal env dmd (Case scrut case_bndr ty alts) |
|---|
| 277 | = let |
|---|
| 278 | (alt_tys, alts') = mapAndUnzip (dmdAnalAlt env dmd) alts |
|---|
| 279 | (scrut_ty, scrut') = dmdAnal env evalDmd scrut |
|---|
| 280 | (alt_ty, case_bndr') = annotateBndr (foldr lubType botDmdType alt_tys) case_bndr |
|---|
| 281 | res_ty = alt_ty `bothType` scrut_ty |
|---|
| 282 | in |
|---|
| 283 | -- pprTrace "dmdAnal:Case2" (vcat [ text "scrut" <+> ppr scrut |
|---|
| 284 | -- , text "scrut_ty" <+> ppr scrut_ty |
|---|
| 285 | -- , text "alt_ty" <+> ppr alt_ty |
|---|
| 286 | -- , text "res_ty" <+> ppr res_ty ]) $ |
|---|
| 287 | (res_ty, Case scrut' case_bndr' ty alts') |
|---|
| 288 | |
|---|
| 289 | dmdAnal env dmd (Let (NonRec id rhs) body) |
|---|
| 290 | = let |
|---|
| 291 | (sigs', lazy_fv, (id1, rhs')) = dmdAnalRhs NotTopLevel NonRecursive env (id, rhs) |
|---|
| 292 | (body_ty, body') = dmdAnal (updSigEnv env sigs') dmd body |
|---|
| 293 | (body_ty1, id2) = annotateBndr body_ty id1 |
|---|
| 294 | body_ty2 = addLazyFVs body_ty1 lazy_fv |
|---|
| 295 | in |
|---|
| 296 | -- If the actual demand is better than the vanilla call |
|---|
| 297 | -- demand, you might think that we might do better to re-analyse |
|---|
| 298 | -- the RHS with the stronger demand. |
|---|
| 299 | -- But (a) That seldom happens, because it means that *every* path in |
|---|
| 300 | -- the body of the let has to use that stronger demand |
|---|
| 301 | -- (b) It often happens temporarily in when fixpointing, because |
|---|
| 302 | -- the recursive function at first seems to place a massive demand. |
|---|
| 303 | -- But we don't want to go to extra work when the function will |
|---|
| 304 | -- probably iterate to something less demanding. |
|---|
| 305 | -- In practice, all the times the actual demand on id2 is more than |
|---|
| 306 | -- the vanilla call demand seem to be due to (b). So we don't |
|---|
| 307 | -- bother to re-analyse the RHS. |
|---|
| 308 | (body_ty2, Let (NonRec id2 rhs') body') |
|---|
| 309 | |
|---|
| 310 | dmdAnal env dmd (Let (Rec pairs) body) |
|---|
| 311 | = let |
|---|
| 312 | bndrs = map fst pairs |
|---|
| 313 | (sigs', lazy_fv, pairs') = dmdFix NotTopLevel env pairs |
|---|
| 314 | (body_ty, body') = dmdAnal (updSigEnv env sigs') dmd body |
|---|
| 315 | body_ty1 = addLazyFVs body_ty lazy_fv |
|---|
| 316 | in |
|---|
| 317 | sigs' `seq` body_ty `seq` |
|---|
| 318 | let |
|---|
| 319 | (body_ty2, _) = annotateBndrs body_ty1 bndrs |
|---|
| 320 | -- Don't bother to add demand info to recursive |
|---|
| 321 | -- binders as annotateBndr does; |
|---|
| 322 | -- being recursive, we can't treat them strictly. |
|---|
| 323 | -- But we do need to remove the binders from the result demand env |
|---|
| 324 | in |
|---|
| 325 | (body_ty2, Let (Rec pairs') body') |
|---|
| 326 | |
|---|
| 327 | |
|---|
| 328 | dmdAnalAlt :: AnalEnv -> Demand -> Alt Var -> (DmdType, Alt Var) |
|---|
| 329 | dmdAnalAlt env dmd (con,bndrs,rhs) |
|---|
| 330 | = let |
|---|
| 331 | (rhs_ty, rhs') = dmdAnal env dmd rhs |
|---|
| 332 | rhs_ty' = addDataConPatDmds con bndrs rhs_ty |
|---|
| 333 | (alt_ty, bndrs') = annotateBndrs rhs_ty' bndrs |
|---|
| 334 | final_alt_ty | io_hack_reqd = alt_ty `lubType` topDmdType |
|---|
| 335 | | otherwise = alt_ty |
|---|
| 336 | |
|---|
| 337 | -- There's a hack here for I/O operations. Consider |
|---|
| 338 | -- case foo x s of { (# s, r #) -> y } |
|---|
| 339 | -- Is this strict in 'y'. Normally yes, but what if 'foo' is an I/O |
|---|
| 340 | -- operation that simply terminates the program (not in an erroneous way)? |
|---|
| 341 | -- In that case we should not evaluate y before the call to 'foo'. |
|---|
| 342 | -- Hackish solution: spot the IO-like situation and add a virtual branch, |
|---|
| 343 | -- as if we had |
|---|
| 344 | -- case foo x s of |
|---|
| 345 | -- (# s, r #) -> y |
|---|
| 346 | -- other -> return () |
|---|
| 347 | -- So the 'y' isn't necessarily going to be evaluated |
|---|
| 348 | -- |
|---|
| 349 | -- A more complete example (Trac #148, #1592) where this shows up is: |
|---|
| 350 | -- do { let len = <expensive> ; |
|---|
| 351 | -- ; when (...) (exitWith ExitSuccess) |
|---|
| 352 | -- ; print len } |
|---|
| 353 | |
|---|
| 354 | io_hack_reqd = con == DataAlt unboxedPairDataCon && |
|---|
| 355 | idType (head bndrs) `eqType` realWorldStatePrimTy |
|---|
| 356 | in |
|---|
| 357 | (final_alt_ty, (con, bndrs', rhs')) |
|---|
| 358 | |
|---|
| 359 | addDataConPatDmds :: AltCon -> [Var] -> DmdType -> DmdType |
|---|
| 360 | -- See Note [Add demands for strict constructors] |
|---|
| 361 | addDataConPatDmds DEFAULT _ dmd_ty = dmd_ty |
|---|
| 362 | addDataConPatDmds (LitAlt _) _ dmd_ty = dmd_ty |
|---|
| 363 | addDataConPatDmds (DataAlt con) bndrs dmd_ty |
|---|
| 364 | = foldr add dmd_ty str_bndrs |
|---|
| 365 | where |
|---|
| 366 | add bndr dmd_ty = addVarDmd dmd_ty bndr seqDmd |
|---|
| 367 | str_bndrs = [ b | (b,s) <- zipEqual "addDataConPatBndrs" |
|---|
| 368 | (filter isId bndrs) |
|---|
| 369 | (dataConRepStrictness con) |
|---|
| 370 | , isMarkedStrict s ] |
|---|
| 371 | \end{code} |
|---|
| 372 | |
|---|
| 373 | Note [Add demands for strict constructors] |
|---|
| 374 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
|---|
| 375 | Consider this program (due to Roman): |
|---|
| 376 | |
|---|
| 377 | data X a = X !a |
|---|
| 378 | |
|---|
| 379 | foo :: X Int -> Int -> Int |
|---|
| 380 | foo (X a) n = go 0 |
|---|
| 381 | where |
|---|
| 382 | go i | i < n = a + go (i+1) |
|---|
| 383 | | otherwise = 0 |
|---|
| 384 | |
|---|
| 385 | We want the worker for 'foo' too look like this: |
|---|
| 386 | |
|---|
| 387 | $wfoo :: Int# -> Int# -> Int# |
|---|
| 388 | |
|---|
| 389 | with the first argument unboxed, so that it is not eval'd each time |
|---|
| 390 | around the loop (which would otherwise happen, since 'foo' is not |
|---|
| 391 | strict in 'a'. It is sound for the wrapper to pass an unboxed arg |
|---|
| 392 | because X is strict, so its argument must be evaluated. And if we |
|---|
| 393 | *don't* pass an unboxed argument, we can't even repair it by adding a |
|---|
| 394 | `seq` thus: |
|---|
| 395 | |
|---|
| 396 | foo (X a) n = a `seq` go 0 |
|---|
| 397 | |
|---|
| 398 | because the seq is discarded (very early) since X is strict! |
|---|
| 399 | |
|---|
| 400 | There is the usual danger of reboxing, which as usual we ignore. But |
|---|
| 401 | if X is monomorphic, and has an UNPACK pragma, then this optimisation |
|---|
| 402 | is even more important. We don't want the wrapper to rebox an unboxed |
|---|
| 403 | argument, and pass an Int to $wfoo! |
|---|
| 404 | |
|---|
| 405 | |
|---|
| 406 | %************************************************************************ |
|---|
| 407 | %* * |
|---|
| 408 | Demand transformer |
|---|
| 409 | %* * |
|---|
| 410 | %************************************************************************ |
|---|
| 411 | |
|---|
| 412 | \begin{code} |
|---|
| 413 | dmdTransform :: AnalEnv -- The strictness environment |
|---|
| 414 | -> Id -- The function |
|---|
| 415 | -> Demand -- The demand on the function |
|---|
| 416 | -> DmdType -- The demand type of the function in this context |
|---|
| 417 | -- Returned DmdEnv includes the demand on |
|---|
| 418 | -- this function plus demand on its free variables |
|---|
| 419 | |
|---|
| 420 | dmdTransform env var dmd |
|---|
| 421 | |
|---|
| 422 | ------ DATA CONSTRUCTOR |
|---|
| 423 | | isDataConWorkId var -- Data constructor |
|---|
| 424 | = let |
|---|
| 425 | StrictSig dmd_ty = idStrictness var -- It must have a strictness sig |
|---|
| 426 | DmdType _ _ con_res = dmd_ty |
|---|
| 427 | arity = idArity var |
|---|
| 428 | in |
|---|
| 429 | if arity == call_depth then -- Saturated, so unleash the demand |
|---|
| 430 | let |
|---|
| 431 | -- Important! If we Keep the constructor application, then |
|---|
| 432 | -- we need the demands the constructor places (always lazy) |
|---|
| 433 | -- If not, we don't need to. For example: |
|---|
| 434 | -- f p@(x,y) = (p,y) -- S(AL) |
|---|
| 435 | -- g a b = f (a,b) |
|---|
| 436 | -- It's vital that we don't calculate Absent for a! |
|---|
| 437 | dmd_ds = case res_dmd of |
|---|
| 438 | Box (Eval ds) -> mapDmds box ds |
|---|
| 439 | Eval ds -> ds |
|---|
| 440 | _ -> Poly Top |
|---|
| 441 | |
|---|
| 442 | -- ds can be empty, when we are just seq'ing the thing |
|---|
| 443 | -- If so we must make up a suitable bunch of demands |
|---|
| 444 | arg_ds = case dmd_ds of |
|---|
| 445 | Poly d -> replicate arity d |
|---|
| 446 | Prod ds -> ASSERT( ds `lengthIs` arity ) ds |
|---|
| 447 | |
|---|
| 448 | in |
|---|
| 449 | mkDmdType emptyDmdEnv arg_ds con_res |
|---|
| 450 | -- Must remember whether it's a product, hence con_res, not TopRes |
|---|
| 451 | else |
|---|
| 452 | topDmdType |
|---|
| 453 | |
|---|
| 454 | ------ IMPORTED FUNCTION |
|---|
| 455 | | isGlobalId var, -- Imported function |
|---|
| 456 | let StrictSig dmd_ty = idStrictness var |
|---|
| 457 | = -- pprTrace "strict-sig" (ppr var $$ ppr dmd_ty) $ |
|---|
| 458 | if dmdTypeDepth dmd_ty <= call_depth then -- Saturated, so unleash the demand |
|---|
| 459 | dmd_ty |
|---|
| 460 | else |
|---|
| 461 | topDmdType |
|---|
| 462 | |
|---|
| 463 | ------ LOCAL LET/REC BOUND THING |
|---|
| 464 | | Just (StrictSig dmd_ty, top_lvl) <- lookupSigEnv env var |
|---|
| 465 | = let |
|---|
| 466 | fn_ty | dmdTypeDepth dmd_ty <= call_depth = dmd_ty |
|---|
| 467 | | otherwise = deferType dmd_ty |
|---|
| 468 | -- NB: it's important to use deferType, and not just return topDmdType |
|---|
| 469 | -- Consider let { f x y = p + x } in f 1 |
|---|
| 470 | -- The application isn't saturated, but we must nevertheless propagate |
|---|
| 471 | -- a lazy demand for p! |
|---|
| 472 | in |
|---|
| 473 | if isTopLevel top_lvl then fn_ty -- Don't record top level things |
|---|
| 474 | else addVarDmd fn_ty var dmd |
|---|
| 475 | |
|---|
| 476 | ------ LOCAL NON-LET/REC BOUND THING |
|---|
| 477 | | otherwise -- Default case |
|---|
| 478 | = unitVarDmd var dmd |
|---|
| 479 | |
|---|
| 480 | where |
|---|
| 481 | (call_depth, res_dmd) = splitCallDmd dmd |
|---|
| 482 | \end{code} |
|---|
| 483 | |
|---|
| 484 | %************************************************************************ |
|---|
| 485 | %* * |
|---|
| 486 | \subsection{Bindings} |
|---|
| 487 | %* * |
|---|
| 488 | %************************************************************************ |
|---|
| 489 | |
|---|
| 490 | \begin{code} |
|---|
| 491 | dmdFix :: TopLevelFlag |
|---|
| 492 | -> AnalEnv -- Does not include bindings for this binding |
|---|
| 493 | -> [(Id,CoreExpr)] |
|---|
| 494 | -> (SigEnv, DmdEnv, |
|---|
| 495 | [(Id,CoreExpr)]) -- Binders annotated with stricness info |
|---|
| 496 | |
|---|
| 497 | dmdFix top_lvl env orig_pairs |
|---|
| 498 | = loop 1 initial_env orig_pairs |
|---|
| 499 | where |
|---|
| 500 | bndrs = map fst orig_pairs |
|---|
| 501 | initial_env = addInitialSigs top_lvl env bndrs |
|---|
| 502 | |
|---|
| 503 | loop :: Int |
|---|
| 504 | -> AnalEnv -- Already contains the current sigs |
|---|
| 505 | -> [(Id,CoreExpr)] |
|---|
| 506 | -> (SigEnv, DmdEnv, [(Id,CoreExpr)]) |
|---|
| 507 | loop n env pairs |
|---|
| 508 | = -- pprTrace "dmd loop" (ppr n <+> ppr bndrs $$ ppr env) $ |
|---|
| 509 | loop' n env pairs |
|---|
| 510 | |
|---|
| 511 | loop' n env pairs |
|---|
| 512 | | found_fixpoint |
|---|
| 513 | = (sigs', lazy_fv, pairs') |
|---|
| 514 | -- Note: return pairs', not pairs. pairs' is the result of |
|---|
| 515 | -- processing the RHSs with sigs (= sigs'), whereas pairs |
|---|
| 516 | -- is the result of processing the RHSs with the *previous* |
|---|
| 517 | -- iteration of sigs. |
|---|
| 518 | |
|---|
| 519 | | n >= 10 |
|---|
| 520 | = pprTrace "dmdFix loop" (ppr n <+> (vcat |
|---|
| 521 | [ text "Sigs:" <+> ppr [ (id,lookupVarEnv sigs id, lookupVarEnv sigs' id) |
|---|
| 522 | | (id,_) <- pairs], |
|---|
| 523 | text "env:" <+> ppr env, |
|---|
| 524 | text "binds:" <+> pprCoreBinding (Rec pairs)])) |
|---|
| 525 | (sigEnv env, lazy_fv, orig_pairs) -- Safe output |
|---|
| 526 | -- The lazy_fv part is really important! orig_pairs has no strictness |
|---|
| 527 | -- info, including nothing about free vars. But if we have |
|---|
| 528 | -- letrec f = ....y..... in ...f... |
|---|
| 529 | -- where 'y' is free in f, we must record that y is mentioned, |
|---|
| 530 | -- otherwise y will get recorded as absent altogether |
|---|
| 531 | |
|---|
| 532 | | otherwise |
|---|
| 533 | = loop (n+1) (nonVirgin sigs') pairs' |
|---|
| 534 | where |
|---|
| 535 | sigs = sigEnv env |
|---|
| 536 | found_fixpoint = all (same_sig sigs sigs') bndrs |
|---|
| 537 | |
|---|
| 538 | ((sigs',lazy_fv), pairs') = mapAccumL my_downRhs (sigs, emptyDmdEnv) pairs |
|---|
| 539 | -- mapAccumL: Use the new signature to do the next pair |
|---|
| 540 | -- The occurrence analyser has arranged them in a good order |
|---|
| 541 | -- so this can significantly reduce the number of iterations needed |
|---|
| 542 | |
|---|
| 543 | my_downRhs (sigs,lazy_fv) (id,rhs) |
|---|
| 544 | = ((sigs', lazy_fv'), pair') |
|---|
| 545 | where |
|---|
| 546 | (sigs', lazy_fv1, pair') = dmdAnalRhs top_lvl Recursive (updSigEnv env sigs) (id,rhs) |
|---|
| 547 | lazy_fv' = plusVarEnv_C both lazy_fv lazy_fv1 |
|---|
| 548 | |
|---|
| 549 | same_sig sigs sigs' var = lookup sigs var == lookup sigs' var |
|---|
| 550 | lookup sigs var = case lookupVarEnv sigs var of |
|---|
| 551 | Just (sig,_) -> sig |
|---|
| 552 | Nothing -> pprPanic "dmdFix" (ppr var) |
|---|
| 553 | |
|---|
| 554 | dmdAnalRhs :: TopLevelFlag -> RecFlag |
|---|
| 555 | -> AnalEnv -> (Id, CoreExpr) |
|---|
| 556 | -> (SigEnv, DmdEnv, (Id, CoreExpr)) |
|---|
| 557 | -- Process the RHS of the binding, add the strictness signature |
|---|
| 558 | -- to the Id, and augment the environment with the signature as well. |
|---|
| 559 | |
|---|
| 560 | dmdAnalRhs top_lvl rec_flag env (id, rhs) |
|---|
| 561 | = (sigs', lazy_fv, (id', rhs')) |
|---|
| 562 | where |
|---|
| 563 | arity = idArity id -- The idArity should be up to date |
|---|
| 564 | -- The simplifier was run just beforehand |
|---|
| 565 | (rhs_dmd_ty, rhs') = dmdAnal env (vanillaCall arity) rhs |
|---|
| 566 | (lazy_fv, sig_ty) = WARN( arity /= dmdTypeDepth rhs_dmd_ty && not (exprIsTrivial rhs), ppr id ) |
|---|
| 567 | -- The RHS can be eta-reduced to just a variable, |
|---|
| 568 | -- in which case we should not complain. |
|---|
| 569 | mkSigTy top_lvl rec_flag id rhs rhs_dmd_ty |
|---|
| 570 | id' = id `setIdStrictness` sig_ty |
|---|
| 571 | sigs' = extendSigEnv top_lvl (sigEnv env) id sig_ty |
|---|
| 572 | \end{code} |
|---|
| 573 | |
|---|
| 574 | |
|---|
| 575 | %************************************************************************ |
|---|
| 576 | %* * |
|---|
| 577 | \subsection{Strictness signatures and types} |
|---|
| 578 | %* * |
|---|
| 579 | %************************************************************************ |
|---|
| 580 | |
|---|
| 581 | \begin{code} |
|---|
| 582 | mkTopSigTy :: CoreExpr -> DmdType -> StrictSig |
|---|
| 583 | -- Take a DmdType and turn it into a StrictSig |
|---|
| 584 | -- NB: not used for never-inline things; hence False |
|---|
| 585 | mkTopSigTy rhs dmd_ty = snd (mk_sig_ty False False rhs dmd_ty) |
|---|
| 586 | |
|---|
| 587 | mkSigTy :: TopLevelFlag -> RecFlag -> Id -> CoreExpr -> DmdType -> (DmdEnv, StrictSig) |
|---|
| 588 | mkSigTy top_lvl rec_flag id rhs dmd_ty |
|---|
| 589 | = mk_sig_ty never_inline thunk_cpr_ok rhs dmd_ty |
|---|
| 590 | where |
|---|
| 591 | never_inline = isNeverActive (idInlineActivation id) |
|---|
| 592 | maybe_id_dmd = idDemandInfo_maybe id |
|---|
| 593 | -- Is Nothing the first time round |
|---|
| 594 | |
|---|
| 595 | thunk_cpr_ok -- See Note [CPR for thunks] |
|---|
| 596 | | isTopLevel top_lvl = False -- Top level things don't get |
|---|
| 597 | -- their demandInfo set at all |
|---|
| 598 | | isRec rec_flag = False -- Ditto recursive things |
|---|
| 599 | | Just dmd <- maybe_id_dmd = isStrictDmd dmd |
|---|
| 600 | | otherwise = True -- Optimistic, first time round |
|---|
| 601 | -- See notes below |
|---|
| 602 | \end{code} |
|---|
| 603 | |
|---|
| 604 | Note [CPR for thunks] |
|---|
| 605 | ~~~~~~~~~~~~~~~~~~~~~ |
|---|
| 606 | If the rhs is a thunk, we usually forget the CPR info, because |
|---|
| 607 | it is presumably shared (else it would have been inlined, and |
|---|
| 608 | so we'd lose sharing if w/w'd it into a function). E.g. |
|---|
| 609 | |
|---|
| 610 | let r = case expensive of |
|---|
| 611 | (a,b) -> (b,a) |
|---|
| 612 | in ... |
|---|
| 613 | |
|---|
| 614 | If we marked r as having the CPR property, then we'd w/w into |
|---|
| 615 | |
|---|
| 616 | let $wr = \() -> case expensive of |
|---|
| 617 | (a,b) -> (# b, a #) |
|---|
| 618 | r = case $wr () of |
|---|
| 619 | (# b,a #) -> (b,a) |
|---|
| 620 | in ... |
|---|
| 621 | |
|---|
| 622 | But now r is a thunk, which won't be inlined, so we are no further ahead. |
|---|
| 623 | But consider |
|---|
| 624 | |
|---|
| 625 | f x = let r = case expensive of (a,b) -> (b,a) |
|---|
| 626 | in if foo r then r else (x,x) |
|---|
| 627 | |
|---|
| 628 | Does f have the CPR property? Well, no. |
|---|
| 629 | |
|---|
| 630 | However, if the strictness analyser has figured out (in a previous |
|---|
| 631 | iteration) that it's strict, then we DON'T need to forget the CPR info. |
|---|
| 632 | Instead we can retain the CPR info and do the thunk-splitting transform |
|---|
| 633 | (see WorkWrap.splitThunk). |
|---|
| 634 | |
|---|
| 635 | This made a big difference to PrelBase.modInt, which had something like |
|---|
| 636 | modInt = \ x -> let r = ... -> I# v in |
|---|
| 637 | ...body strict in r... |
|---|
| 638 | r's RHS isn't a value yet; but modInt returns r in various branches, so |
|---|
| 639 | if r doesn't have the CPR property then neither does modInt |
|---|
| 640 | Another case I found in practice (in Complex.magnitude), looks like this: |
|---|
| 641 | let k = if ... then I# a else I# b |
|---|
| 642 | in ... body strict in k .... |
|---|
| 643 | (For this example, it doesn't matter whether k is returned as part of |
|---|
| 644 | the overall result; but it does matter that k's RHS has the CPR property.) |
|---|
| 645 | Left to itself, the simplifier will make a join point thus: |
|---|
| 646 | let $j k = ...body strict in k... |
|---|
| 647 | if ... then $j (I# a) else $j (I# b) |
|---|
| 648 | With thunk-splitting, we get instead |
|---|
| 649 | let $j x = let k = I#x in ...body strict in k... |
|---|
| 650 | in if ... then $j a else $j b |
|---|
| 651 | This is much better; there's a good chance the I# won't get allocated. |
|---|
| 652 | |
|---|
| 653 | The difficulty with this is that we need the strictness type to |
|---|
| 654 | look at the body... but we now need the body to calculate the demand |
|---|
| 655 | on the variable, so we can decide whether its strictness type should |
|---|
| 656 | have a CPR in it or not. Simple solution: |
|---|
| 657 | a) use strictness info from the previous iteration |
|---|
| 658 | b) make sure we do at least 2 iterations, by doing a second |
|---|
| 659 | round for top-level non-recs. Top level recs will get at |
|---|
| 660 | least 2 iterations except for totally-bottom functions |
|---|
| 661 | which aren't very interesting anyway. |
|---|
| 662 | |
|---|
| 663 | NB: strictly_demanded is never true of a top-level Id, or of a recursive Id. |
|---|
| 664 | |
|---|
| 665 | Note [Optimistic in the Nothing case] |
|---|
| 666 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
|---|
| 667 | Demand info now has a 'Nothing' state, just like strictness info. |
|---|
| 668 | The analysis works from 'dangerous' towards a 'safe' state; so we |
|---|
| 669 | start with botSig for 'Nothing' strictness infos, and we start with |
|---|
| 670 | "yes, it's demanded" for 'Nothing' in the demand info. The |
|---|
| 671 | fixpoint iteration will sort it all out. |
|---|
| 672 | |
|---|
| 673 | We can't start with 'not-demanded' because then consider |
|---|
| 674 | f x = let |
|---|
| 675 | t = ... I# x |
|---|
| 676 | in |
|---|
| 677 | if ... then t else I# y else f x' |
|---|
| 678 | |
|---|
| 679 | In the first iteration we'd have no demand info for x, so assume |
|---|
| 680 | not-demanded; then we'd get TopRes for f's CPR info. Next iteration |
|---|
| 681 | we'd see that t was demanded, and so give it the CPR property, but by |
|---|
| 682 | now f has TopRes, so it will stay TopRes. Instead, with the Nothing |
|---|
| 683 | setting the first time round, we say 'yes t is demanded' the first |
|---|
| 684 | time. |
|---|
| 685 | |
|---|
| 686 | However, this does mean that for non-recursive bindings we must |
|---|
| 687 | iterate twice to be sure of not getting over-optimistic CPR info, |
|---|
| 688 | in the case where t turns out to be not-demanded. This is handled |
|---|
| 689 | by dmdAnalTopBind. |
|---|
| 690 | |
|---|
| 691 | |
|---|
| 692 | Note [NOINLINE and strictness] |
|---|
| 693 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
|---|
| 694 | The strictness analyser used to have a HACK which ensured that NOINLNE |
|---|
| 695 | things were not strictness-analysed. The reason was unsafePerformIO. |
|---|
| 696 | Left to itself, the strictness analyser would discover this strictness |
|---|
| 697 | for unsafePerformIO: |
|---|
| 698 | unsafePerformIO: C(U(AV)) |
|---|
| 699 | But then consider this sub-expression |
|---|
| 700 | unsafePerformIO (\s -> let r = f x in |
|---|
| 701 | case writeIORef v r s of (# s1, _ #) -> |
|---|
| 702 | (# s1, r #) |
|---|
| 703 | The strictness analyser will now find that r is sure to be eval'd, |
|---|
| 704 | and may then hoist it out. This makes tests/lib/should_run/memo002 |
|---|
| 705 | deadlock. |
|---|
| 706 | |
|---|
| 707 | Solving this by making all NOINLINE things have no strictness info is overkill. |
|---|
| 708 | In particular, it's overkill for runST, which is perfectly respectable. |
|---|
| 709 | Consider |
|---|
| 710 | f x = runST (return x) |
|---|
| 711 | This should be strict in x. |
|---|
| 712 | |
|---|
| 713 | So the new plan is to define unsafePerformIO using the 'lazy' combinator: |
|---|
| 714 | |
|---|
| 715 | unsafePerformIO (IO m) = lazy (case m realWorld# of (# _, r #) -> r) |
|---|
| 716 | |
|---|
| 717 | Remember, 'lazy' is a wired-in identity-function Id, of type a->a, which is |
|---|
| 718 | magically NON-STRICT, and is inlined after strictness analysis. So |
|---|
| 719 | unsafePerformIO will look non-strict, and that's what we want. |
|---|
| 720 | |
|---|
| 721 | Now we don't need the hack in the strictness analyser. HOWEVER, this |
|---|
| 722 | decision does mean that even a NOINLINE function is not entirely |
|---|
| 723 | opaque: some aspect of its implementation leaks out, notably its |
|---|
| 724 | strictness. For example, if you have a function implemented by an |
|---|
| 725 | error stub, but which has RULES, you may want it not to be eliminated |
|---|
| 726 | in favour of error! |
|---|
| 727 | |
|---|
| 728 | |
|---|
| 729 | \begin{code} |
|---|
| 730 | mk_sig_ty :: Bool -> Bool -> CoreExpr |
|---|
| 731 | -> DmdType -> (DmdEnv, StrictSig) |
|---|
| 732 | mk_sig_ty _never_inline thunk_cpr_ok rhs (DmdType fv dmds res) |
|---|
| 733 | = (lazy_fv, mkStrictSig dmd_ty) |
|---|
| 734 | -- Re unused never_inline, see Note [NOINLINE and strictness] |
|---|
| 735 | where |
|---|
| 736 | dmd_ty = DmdType strict_fv final_dmds res' |
|---|
| 737 | |
|---|
| 738 | lazy_fv = filterUFM (not . isStrictDmd) fv |
|---|
| 739 | strict_fv = filterUFM isStrictDmd fv |
|---|
| 740 | -- We put the strict FVs in the DmdType of the Id, so |
|---|
| 741 | -- that at its call sites we unleash demands on its strict fvs. |
|---|
| 742 | -- An example is 'roll' in imaginary/wheel-sieve2 |
|---|
| 743 | -- Something like this: |
|---|
| 744 | -- roll x = letrec |
|---|
| 745 | -- go y = if ... then roll (x-1) else x+1 |
|---|
| 746 | -- in |
|---|
| 747 | -- go ms |
|---|
| 748 | -- We want to see that roll is strict in x, which is because |
|---|
| 749 | -- go is called. So we put the DmdEnv for x in go's DmdType. |
|---|
| 750 | -- |
|---|
| 751 | -- Another example: |
|---|
| 752 | -- f :: Int -> Int -> Int |
|---|
| 753 | -- f x y = let t = x+1 |
|---|
| 754 | -- h z = if z==0 then t else |
|---|
| 755 | -- if z==1 then x+1 else |
|---|
| 756 | -- x + h (z-1) |
|---|
| 757 | -- in |
|---|
| 758 | -- h y |
|---|
| 759 | -- Calling h does indeed evaluate x, but we can only see |
|---|
| 760 | -- that if we unleash a demand on x at the call site for t. |
|---|
| 761 | -- |
|---|
| 762 | -- Incidentally, here's a place where lambda-lifting h would |
|---|
| 763 | -- lose the cigar --- we couldn't see the joint strictness in t/x |
|---|
| 764 | -- |
|---|
| 765 | -- ON THE OTHER HAND |
|---|
| 766 | -- We don't want to put *all* the fv's from the RHS into the |
|---|
| 767 | -- DmdType, because that makes fixpointing very slow --- the |
|---|
| 768 | -- DmdType gets full of lazy demands that are slow to converge. |
|---|
| 769 | |
|---|
| 770 | final_dmds = setUnpackStrategy dmds |
|---|
| 771 | -- Set the unpacking strategy |
|---|
| 772 | |
|---|
| 773 | res' = case res of |
|---|
| 774 | RetCPR | ignore_cpr_info -> TopRes |
|---|
| 775 | _ -> res |
|---|
| 776 | ignore_cpr_info = not (exprIsHNF rhs || thunk_cpr_ok) |
|---|
| 777 | \end{code} |
|---|
| 778 | |
|---|
| 779 | The unpack strategy determines whether we'll *really* unpack the argument, |
|---|
| 780 | or whether we'll just remember its strictness. If unpacking would give |
|---|
| 781 | rise to a *lot* of worker args, we may decide not to unpack after all. |
|---|
| 782 | |
|---|
| 783 | \begin{code} |
|---|
| 784 | setUnpackStrategy :: [Demand] -> [Demand] |
|---|
| 785 | setUnpackStrategy ds |
|---|
| 786 | = snd (go (opt_MaxWorkerArgs - nonAbsentArgs ds) ds) |
|---|
| 787 | where |
|---|
| 788 | go :: Int -- Max number of args available for sub-components of [Demand] |
|---|
| 789 | -> [Demand] |
|---|
| 790 | -> (Int, [Demand]) -- Args remaining after subcomponents of [Demand] are unpacked |
|---|
| 791 | |
|---|
| 792 | go n (Eval (Prod cs) : ds) |
|---|
| 793 | | n' >= 0 = Eval (Prod cs') `cons` go n'' ds |
|---|
| 794 | | otherwise = Box (Eval (Prod cs)) `cons` go n ds |
|---|
| 795 | where |
|---|
| 796 | (n'',cs') = go n' cs |
|---|
| 797 | n' = n + 1 - non_abs_args |
|---|
| 798 | -- Add one to the budget 'cos we drop the top-level arg |
|---|
| 799 | non_abs_args = nonAbsentArgs cs |
|---|
| 800 | -- Delete # of non-absent args to which we'll now be committed |
|---|
| 801 | |
|---|
| 802 | go n (d:ds) = d `cons` go n ds |
|---|
| 803 | go n [] = (n,[]) |
|---|
| 804 | |
|---|
| 805 | cons d (n,ds) = (n, d:ds) |
|---|
| 806 | |
|---|
| 807 | nonAbsentArgs :: [Demand] -> Int |
|---|
| 808 | nonAbsentArgs [] = 0 |
|---|
| 809 | nonAbsentArgs (Abs : ds) = nonAbsentArgs ds |
|---|
| 810 | nonAbsentArgs (_ : ds) = 1 + nonAbsentArgs ds |
|---|
| 811 | \end{code} |
|---|
| 812 | |
|---|
| 813 | |
|---|
| 814 | %************************************************************************ |
|---|
| 815 | %* * |
|---|
| 816 | \subsection{Strictness signatures and types} |
|---|
| 817 | %* * |
|---|
| 818 | %************************************************************************ |
|---|
| 819 | |
|---|
| 820 | \begin{code} |
|---|
| 821 | unitVarDmd :: Var -> Demand -> DmdType |
|---|
| 822 | unitVarDmd var dmd = DmdType (unitVarEnv var dmd) [] TopRes |
|---|
| 823 | |
|---|
| 824 | addVarDmd :: DmdType -> Var -> Demand -> DmdType |
|---|
| 825 | addVarDmd (DmdType fv ds res) var dmd |
|---|
| 826 | = DmdType (extendVarEnv_C both fv var dmd) ds res |
|---|
| 827 | |
|---|
| 828 | addLazyFVs :: DmdType -> DmdEnv -> DmdType |
|---|
| 829 | addLazyFVs (DmdType fv ds res) lazy_fvs |
|---|
| 830 | = DmdType both_fv1 ds res |
|---|
| 831 | where |
|---|
| 832 | both_fv = plusVarEnv_C both fv lazy_fvs |
|---|
| 833 | both_fv1 = modifyEnv (isBotRes res) (`both` Bot) lazy_fvs fv both_fv |
|---|
| 834 | -- This modifyEnv is vital. Consider |
|---|
| 835 | -- let f = \x -> (x,y) |
|---|
| 836 | -- in error (f 3) |
|---|
| 837 | -- Here, y is treated as a lazy-fv of f, but we must `both` that L |
|---|
| 838 | -- demand with the bottom coming up from 'error' |
|---|
| 839 | -- |
|---|
| 840 | -- I got a loop in the fixpointer without this, due to an interaction |
|---|
| 841 | -- with the lazy_fv filtering in mkSigTy. Roughly, it was |
|---|
| 842 | -- letrec f n x |
|---|
| 843 | -- = letrec g y = x `fatbar` |
|---|
| 844 | -- letrec h z = z + ...g... |
|---|
| 845 | -- in h (f (n-1) x) |
|---|
| 846 | -- in ... |
|---|
| 847 | -- In the initial iteration for f, f=Bot |
|---|
| 848 | -- Suppose h is found to be strict in z, but the occurrence of g in its RHS |
|---|
| 849 | -- is lazy. Now consider the fixpoint iteration for g, esp the demands it |
|---|
| 850 | -- places on its free variables. Suppose it places none. Then the |
|---|
| 851 | -- x `fatbar` ...call to h... |
|---|
| 852 | -- will give a x->V demand for x. That turns into a L demand for x, |
|---|
| 853 | -- which floats out of the defn for h. Without the modifyEnv, that |
|---|
| 854 | -- L demand doesn't get both'd with the Bot coming up from the inner |
|---|
| 855 | -- call to f. So we just get an L demand for x for g. |
|---|
| 856 | -- |
|---|
| 857 | -- A better way to say this is that the lazy-fv filtering should give the |
|---|
| 858 | -- same answer as putting the lazy fv demands in the function's type. |
|---|
| 859 | |
|---|
| 860 | annotateBndr :: DmdType -> Var -> (DmdType, Var) |
|---|
| 861 | -- The returned env has the var deleted |
|---|
| 862 | -- The returned var is annotated with demand info |
|---|
| 863 | -- No effect on the argument demands |
|---|
| 864 | annotateBndr dmd_ty@(DmdType fv ds res) var |
|---|
| 865 | | isTyVar var = (dmd_ty, var) |
|---|
| 866 | | otherwise = (DmdType fv' ds res, setIdDemandInfo var dmd) |
|---|
| 867 | where |
|---|
| 868 | (fv', dmd) = removeFV fv var res |
|---|
| 869 | |
|---|
| 870 | annotateBndrs :: DmdType -> [Var] -> (DmdType, [Var]) |
|---|
| 871 | annotateBndrs = mapAccumR annotateBndr |
|---|
| 872 | |
|---|
| 873 | annotateLamIdBndr :: AnalEnv |
|---|
| 874 | -> DmdType -- Demand type of body |
|---|
| 875 | -> Id -- Lambda binder |
|---|
| 876 | -> (DmdType, -- Demand type of lambda |
|---|
| 877 | Id) -- and binder annotated with demand |
|---|
| 878 | |
|---|
| 879 | annotateLamIdBndr env (DmdType fv ds res) id |
|---|
| 880 | -- For lambdas we add the demand to the argument demands |
|---|
| 881 | -- Only called for Ids |
|---|
| 882 | = ASSERT( isId id ) |
|---|
| 883 | (final_ty, setIdDemandInfo id hacked_dmd) |
|---|
| 884 | where |
|---|
| 885 | -- Watch out! See note [Lambda-bound unfoldings] |
|---|
| 886 | final_ty = case maybeUnfoldingTemplate (idUnfolding id) of |
|---|
| 887 | Nothing -> main_ty |
|---|
| 888 | Just unf -> main_ty `bothType` unf_ty |
|---|
| 889 | where |
|---|
| 890 | (unf_ty, _) = dmdAnal env dmd unf |
|---|
| 891 | |
|---|
| 892 | main_ty = DmdType fv' (hacked_dmd:ds) res |
|---|
| 893 | |
|---|
| 894 | (fv', dmd) = removeFV fv id res |
|---|
| 895 | hacked_dmd = argDemand dmd |
|---|
| 896 | -- This call to argDemand is vital, because otherwise we label |
|---|
| 897 | -- a lambda binder with demand 'B'. But in terms of calling |
|---|
| 898 | -- conventions that's Abs, because we don't pass it. But |
|---|
| 899 | -- when we do a w/w split we get |
|---|
| 900 | -- fw x = (\x y:B -> ...) x (error "oops") |
|---|
| 901 | -- And then the simplifier things the 'B' is a strict demand |
|---|
| 902 | -- and evaluates the (error "oops"). Sigh |
|---|
| 903 | |
|---|
| 904 | removeFV :: DmdEnv -> Var -> DmdResult -> (DmdEnv, Demand) |
|---|
| 905 | removeFV fv id res = (fv', zapUnlifted id dmd) |
|---|
| 906 | where |
|---|
| 907 | fv' = fv `delVarEnv` id |
|---|
| 908 | dmd = lookupVarEnv fv id `orElse` deflt |
|---|
| 909 | deflt | isBotRes res = Bot |
|---|
| 910 | | otherwise = Abs |
|---|
| 911 | |
|---|
| 912 | zapUnlifted :: Id -> Demand -> Demand |
|---|
| 913 | -- For unlifted-type variables, we are only |
|---|
| 914 | -- interested in Bot/Abs/Box Abs |
|---|
| 915 | zapUnlifted id dmd |
|---|
| 916 | = case dmd of |
|---|
| 917 | _ | isCoVarType ty -> lazyDmd -- For coercions, ignore str/abs totally |
|---|
| 918 | Bot -> Bot |
|---|
| 919 | Abs -> Abs |
|---|
| 920 | _ | isUnLiftedType ty -> lazyDmd -- For unlifted types, ignore strictness |
|---|
| 921 | | otherwise -> dmd |
|---|
| 922 | where |
|---|
| 923 | ty = idType id |
|---|
| 924 | \end{code} |
|---|
| 925 | |
|---|
| 926 | Note [Lamba-bound unfoldings] |
|---|
| 927 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
|---|
| 928 | We allow a lambda-bound variable to carry an unfolding, a facility that is used |
|---|
| 929 | exclusively for join points; see Note [Case binders and join points]. If so, |
|---|
| 930 | we must be careful to demand-analyse the RHS of the unfolding! Example |
|---|
| 931 | \x. \y{=Just x}. <body> |
|---|
| 932 | Then if <body> uses 'y', then transitively it uses 'x', and we must not |
|---|
| 933 | forget that fact, otherwise we might make 'x' absent when it isn't. |
|---|
| 934 | |
|---|
| 935 | |
|---|
| 936 | %************************************************************************ |
|---|
| 937 | %* * |
|---|
| 938 | \subsection{Strictness signatures} |
|---|
| 939 | %* * |
|---|
| 940 | %************************************************************************ |
|---|
| 941 | |
|---|
| 942 | \begin{code} |
|---|
| 943 | data AnalEnv |
|---|
| 944 | = AE { ae_sigs :: SigEnv |
|---|
| 945 | , ae_virgin :: Bool } -- True on first iteration only |
|---|
| 946 | -- See Note [Initialising strictness] |
|---|
| 947 | -- We use the se_env to tell us whether to |
|---|
| 948 | -- record info about a variable in the DmdEnv |
|---|
| 949 | -- We do so if it's a LocalId, but not top-level |
|---|
| 950 | -- |
|---|
| 951 | -- The DmdEnv gives the demand on the free vars of the function |
|---|
| 952 | -- when it is given enough args to satisfy the strictness signature |
|---|
| 953 | |
|---|
| 954 | type SigEnv = VarEnv (StrictSig, TopLevelFlag) |
|---|
| 955 | |
|---|
| 956 | instance Outputable AnalEnv where |
|---|
| 957 | ppr (AE { ae_sigs = env, ae_virgin = virgin }) |
|---|
| 958 | = ptext (sLit "AE") <+> braces (vcat |
|---|
| 959 | [ ptext (sLit "ae_virgin =") <+> ppr virgin |
|---|
| 960 | , ptext (sLit "ae_sigs =") <+> ppr env ]) |
|---|
| 961 | |
|---|
| 962 | emptySigEnv :: SigEnv |
|---|
| 963 | emptySigEnv = emptyVarEnv |
|---|
| 964 | |
|---|
| 965 | sigEnv :: AnalEnv -> SigEnv |
|---|
| 966 | sigEnv = ae_sigs |
|---|
| 967 | |
|---|
| 968 | updSigEnv :: AnalEnv -> SigEnv -> AnalEnv |
|---|
| 969 | updSigEnv env sigs = env { ae_sigs = sigs } |
|---|
| 970 | |
|---|
| 971 | extendAnalEnv :: TopLevelFlag -> AnalEnv -> Id -> StrictSig -> AnalEnv |
|---|
| 972 | extendAnalEnv top_lvl env var sig |
|---|
| 973 | = env { ae_sigs = extendSigEnv top_lvl (ae_sigs env) var sig } |
|---|
| 974 | |
|---|
| 975 | extendSigEnv :: TopLevelFlag -> SigEnv -> Id -> StrictSig -> SigEnv |
|---|
| 976 | extendSigEnv top_lvl sigs var sig = extendVarEnv sigs var (sig, top_lvl) |
|---|
| 977 | |
|---|
| 978 | lookupSigEnv :: AnalEnv -> Id -> Maybe (StrictSig, TopLevelFlag) |
|---|
| 979 | lookupSigEnv env id = lookupVarEnv (ae_sigs env) id |
|---|
| 980 | |
|---|
| 981 | addInitialSigs :: TopLevelFlag -> AnalEnv -> [Id] -> AnalEnv |
|---|
| 982 | -- See Note [Initialising strictness] |
|---|
| 983 | addInitialSigs top_lvl env@(AE { ae_sigs = sigs, ae_virgin = virgin }) ids |
|---|
| 984 | = env { ae_sigs = extendVarEnvList sigs [ (id, (init_sig id, top_lvl)) |
|---|
| 985 | | id <- ids ] } |
|---|
| 986 | where |
|---|
| 987 | init_sig | virgin = \_ -> botSig |
|---|
| 988 | | otherwise = idStrictness |
|---|
| 989 | |
|---|
| 990 | virgin, nonVirgin :: SigEnv -> AnalEnv |
|---|
| 991 | virgin sigs = AE { ae_sigs = sigs, ae_virgin = True } |
|---|
| 992 | nonVirgin sigs = AE { ae_sigs = sigs, ae_virgin = False } |
|---|
| 993 | |
|---|
| 994 | extendSigsWithLam :: AnalEnv -> Id -> AnalEnv |
|---|
| 995 | -- Extend the AnalEnv when we meet a lambda binder |
|---|
| 996 | -- If the binder is marked demanded with a product demand, then give it a CPR |
|---|
| 997 | -- signature, because in the likely event that this is a lambda on a fn defn |
|---|
| 998 | -- [we only use this when the lambda is being consumed with a call demand], |
|---|
| 999 | -- it'll be w/w'd and so it will be CPR-ish. E.g. |
|---|
| 1000 | -- f = \x::(Int,Int). if ...strict in x... then |
|---|
| 1001 | -- x |
|---|
| 1002 | -- else |
|---|
| 1003 | -- (a,b) |
|---|
| 1004 | -- We want f to have the CPR property because x does, by the time f has been w/w'd |
|---|
| 1005 | -- |
|---|
| 1006 | -- Also note that we only want to do this for something that |
|---|
| 1007 | -- definitely has product type, else we may get over-optimistic |
|---|
| 1008 | -- CPR results (e.g. from \x -> x!). |
|---|
| 1009 | |
|---|
| 1010 | extendSigsWithLam env id |
|---|
| 1011 | = case idDemandInfo_maybe id of |
|---|
| 1012 | Nothing -> extendAnalEnv NotTopLevel env id cprSig |
|---|
| 1013 | -- See Note [Optimistic in the Nothing case] |
|---|
| 1014 | Just (Eval (Prod _)) -> extendAnalEnv NotTopLevel env id cprSig |
|---|
| 1015 | _ -> env |
|---|
| 1016 | \end{code} |
|---|
| 1017 | |
|---|
| 1018 | Note [Initialising strictness] |
|---|
| 1019 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
|---|
| 1020 | Our basic plan is to initialise the strictness of each Id in |
|---|
| 1021 | a recursive group to "bottom", and find a fixpoint from there. |
|---|
| 1022 | However, this group A might be inside an *enclosing* recursive |
|---|
| 1023 | group B, in which case we'll do the entire fixpoint shebang on A |
|---|
| 1024 | for each iteration of B. |
|---|
| 1025 | |
|---|
| 1026 | To speed things up, we initialise each iteration of B from the result |
|---|
| 1027 | of the last one, which is neatly recorded in each binder. That way we |
|---|
| 1028 | make use of earlier iterations of the fixpoint algorithm. (Cunning |
|---|
| 1029 | plan.) |
|---|
| 1030 | |
|---|
| 1031 | But on the *first* iteration we want to *ignore* the current strictness |
|---|
| 1032 | of the Id, and start from "bottom". Nowadays the Id can have a current |
|---|
| 1033 | strictness, because interface files record strictness for nested bindings. |
|---|
| 1034 | To know when we are in the first iteration, we look at the ae_virgin |
|---|
| 1035 | field of the AnalEnv. |
|---|
| 1036 | |
|---|
| 1037 | |
|---|
| 1038 | %************************************************************************ |
|---|
| 1039 | %* * |
|---|
| 1040 | Demands |
|---|
| 1041 | %* * |
|---|
| 1042 | %************************************************************************ |
|---|
| 1043 | |
|---|
| 1044 | \begin{code} |
|---|
| 1045 | splitDmdTy :: DmdType -> (Demand, DmdType) |
|---|
| 1046 | -- Split off one function argument |
|---|
| 1047 | -- We already have a suitable demand on all |
|---|
| 1048 | -- free vars, so no need to add more! |
|---|
| 1049 | splitDmdTy (DmdType fv (dmd:dmds) res_ty) = (dmd, DmdType fv dmds res_ty) |
|---|
| 1050 | splitDmdTy ty@(DmdType _ [] res_ty) = (resTypeArgDmd res_ty, ty) |
|---|
| 1051 | |
|---|
| 1052 | splitCallDmd :: Demand -> (Int, Demand) |
|---|
| 1053 | splitCallDmd (Call d) = case splitCallDmd d of |
|---|
| 1054 | (n, r) -> (n+1, r) |
|---|
| 1055 | splitCallDmd d = (0, d) |
|---|
| 1056 | |
|---|
| 1057 | vanillaCall :: Arity -> Demand |
|---|
| 1058 | vanillaCall 0 = evalDmd |
|---|
| 1059 | vanillaCall n = Call (vanillaCall (n-1)) |
|---|
| 1060 | |
|---|
| 1061 | deferType :: DmdType -> DmdType |
|---|
| 1062 | deferType (DmdType fv _ _) = DmdType (deferEnv fv) [] TopRes |
|---|
| 1063 | -- Notice that we throw away info about both arguments and results |
|---|
| 1064 | -- For example, f = let ... in \x -> x |
|---|
| 1065 | -- We don't want to get a stricness type V->T for f. |
|---|
| 1066 | |
|---|
| 1067 | deferEnv :: DmdEnv -> DmdEnv |
|---|
| 1068 | deferEnv fv = mapVarEnv defer fv |
|---|
| 1069 | |
|---|
| 1070 | |
|---|
| 1071 | ---------------- |
|---|
| 1072 | argDemand :: Demand -> Demand |
|---|
| 1073 | -- The 'Defer' demands are just Lazy at function boundaries |
|---|
| 1074 | -- Ugly! Ask John how to improve it. |
|---|
| 1075 | argDemand Top = lazyDmd |
|---|
| 1076 | argDemand (Defer _) = lazyDmd |
|---|
| 1077 | argDemand (Eval ds) = Eval (mapDmds argDemand ds) |
|---|
| 1078 | argDemand (Box Bot) = evalDmd |
|---|
| 1079 | argDemand (Box d) = box (argDemand d) |
|---|
| 1080 | argDemand Bot = Abs -- Don't pass args that are consumed (only) by bottom |
|---|
| 1081 | argDemand d = d |
|---|
| 1082 | \end{code} |
|---|
| 1083 | |
|---|
| 1084 | \begin{code} |
|---|
| 1085 | ------------------------- |
|---|
| 1086 | lubType :: DmdType -> DmdType -> DmdType |
|---|
| 1087 | -- Consider (if x then y else []) with demand V |
|---|
| 1088 | -- Then the first branch gives {y->V} and the second |
|---|
| 1089 | -- *implicitly* has {y->A}. So we must put {y->(V `lub` A)} |
|---|
| 1090 | -- in the result env. |
|---|
| 1091 | lubType (DmdType fv1 ds1 r1) (DmdType fv2 ds2 r2) |
|---|
| 1092 | = DmdType lub_fv2 (lub_ds ds1 ds2) (r1 `lubRes` r2) |
|---|
| 1093 | where |
|---|
| 1094 | lub_fv = plusVarEnv_C lub fv1 fv2 |
|---|
| 1095 | lub_fv1 = modifyEnv (not (isBotRes r1)) absLub fv2 fv1 lub_fv |
|---|
| 1096 | lub_fv2 = modifyEnv (not (isBotRes r2)) absLub fv1 fv2 lub_fv1 |
|---|
| 1097 | -- lub is the identity for Bot |
|---|
| 1098 | |
|---|
| 1099 | -- Extend the shorter argument list to match the longer |
|---|
| 1100 | lub_ds (d1:ds1) (d2:ds2) = lub d1 d2 : lub_ds ds1 ds2 |
|---|
| 1101 | lub_ds [] [] = [] |
|---|
| 1102 | lub_ds ds1 [] = map (`lub` resTypeArgDmd r2) ds1 |
|---|
| 1103 | lub_ds [] ds2 = map (resTypeArgDmd r1 `lub`) ds2 |
|---|
| 1104 | |
|---|
| 1105 | ----------------------------------- |
|---|
| 1106 | bothType :: DmdType -> DmdType -> DmdType |
|---|
| 1107 | -- (t1 `bothType` t2) takes the argument/result info from t1, |
|---|
| 1108 | -- using t2 just for its free-var info |
|---|
| 1109 | -- NB: Don't forget about r2! It might be BotRes, which is |
|---|
| 1110 | -- a bottom demand on all the in-scope variables. |
|---|
| 1111 | -- Peter: can this be done more neatly? |
|---|
| 1112 | bothType (DmdType fv1 ds1 r1) (DmdType fv2 _ r2) |
|---|
| 1113 | = DmdType both_fv2 ds1 (r1 `bothRes` r2) |
|---|
| 1114 | where |
|---|
| 1115 | both_fv = plusVarEnv_C both fv1 fv2 |
|---|
| 1116 | both_fv1 = modifyEnv (isBotRes r1) (`both` Bot) fv2 fv1 both_fv |
|---|
| 1117 | both_fv2 = modifyEnv (isBotRes r2) (`both` Bot) fv1 fv2 both_fv1 |
|---|
| 1118 | -- both is the identity for Abs |
|---|
| 1119 | \end{code} |
|---|
| 1120 | |
|---|
| 1121 | |
|---|
| 1122 | \begin{code} |
|---|
| 1123 | lubRes :: DmdResult -> DmdResult -> DmdResult |
|---|
| 1124 | lubRes BotRes r = r |
|---|
| 1125 | lubRes r BotRes = r |
|---|
| 1126 | lubRes RetCPR RetCPR = RetCPR |
|---|
| 1127 | lubRes _ _ = TopRes |
|---|
| 1128 | |
|---|
| 1129 | bothRes :: DmdResult -> DmdResult -> DmdResult |
|---|
| 1130 | -- If either diverges, the whole thing does |
|---|
| 1131 | -- Otherwise take CPR info from the first |
|---|
| 1132 | bothRes _ BotRes = BotRes |
|---|
| 1133 | bothRes r1 _ = r1 |
|---|
| 1134 | \end{code} |
|---|
| 1135 | |
|---|
| 1136 | \begin{code} |
|---|
| 1137 | modifyEnv :: Bool -- No-op if False |
|---|
| 1138 | -> (Demand -> Demand) -- The zapper |
|---|
| 1139 | -> DmdEnv -> DmdEnv -- Env1 and Env2 |
|---|
| 1140 | -> DmdEnv -> DmdEnv -- Transform this env |
|---|
| 1141 | -- Zap anything in Env1 but not in Env2 |
|---|
| 1142 | -- Assume: dom(env) includes dom(Env1) and dom(Env2) |
|---|
| 1143 | |
|---|
| 1144 | modifyEnv need_to_modify zapper env1 env2 env |
|---|
| 1145 | | need_to_modify = foldr zap env (varEnvKeys (env1 `minusUFM` env2)) |
|---|
| 1146 | | otherwise = env |
|---|
| 1147 | where |
|---|
| 1148 | zap uniq env = addToUFM_Directly env uniq (zapper current_val) |
|---|
| 1149 | where |
|---|
| 1150 | current_val = expectJust "modifyEnv" (lookupUFM_Directly env uniq) |
|---|
| 1151 | \end{code} |
|---|
| 1152 | |
|---|
| 1153 | |
|---|
| 1154 | %************************************************************************ |
|---|
| 1155 | %* * |
|---|
| 1156 | \subsection{LUB and BOTH} |
|---|
| 1157 | %* * |
|---|
| 1158 | %************************************************************************ |
|---|
| 1159 | |
|---|
| 1160 | \begin{code} |
|---|
| 1161 | lub :: Demand -> Demand -> Demand |
|---|
| 1162 | |
|---|
| 1163 | lub Bot d2 = d2 |
|---|
| 1164 | lub Abs d2 = absLub d2 |
|---|
| 1165 | lub Top _ = Top |
|---|
| 1166 | lub (Defer ds1) d2 = defer (Eval ds1 `lub` d2) |
|---|
| 1167 | |
|---|
| 1168 | lub (Call d1) (Call d2) = Call (d1 `lub` d2) |
|---|
| 1169 | lub d1@(Call _) (Box d2) = d1 `lub` d2 -- Just strip the box |
|---|
| 1170 | lub (Call _) d2@(Eval _) = d2 -- Presumably seq or vanilla eval |
|---|
| 1171 | lub d1@(Call _) d2 = d2 `lub` d1 -- Bot, Abs, Top |
|---|
| 1172 | |
|---|
| 1173 | -- For the Eval case, we use these approximation rules |
|---|
| 1174 | -- Box Bot <= Eval (Box Bot ...) |
|---|
| 1175 | -- Box Top <= Defer (Box Bot ...) |
|---|
| 1176 | -- Box (Eval ds) <= Eval (map Box ds) |
|---|
| 1177 | lub (Eval ds1) (Eval ds2) = Eval (ds1 `lubs` ds2) |
|---|
| 1178 | lub (Eval ds1) (Box Bot) = Eval (mapDmds (`lub` Box Bot) ds1) |
|---|
| 1179 | lub (Eval ds1) (Box (Eval ds2)) = Eval (ds1 `lubs` mapDmds box ds2) |
|---|
| 1180 | lub (Eval ds1) (Box Abs) = deferEval (mapDmds (`lub` Box Bot) ds1) |
|---|
| 1181 | lub d1@(Eval _) d2 = d2 `lub` d1 -- Bot,Abs,Top,Call,Defer |
|---|
| 1182 | |
|---|
| 1183 | lub (Box d1) (Box d2) = box (d1 `lub` d2) |
|---|
| 1184 | lub d1@(Box _) d2 = d2 `lub` d1 |
|---|
| 1185 | |
|---|
| 1186 | lubs :: Demands -> Demands -> Demands |
|---|
| 1187 | lubs ds1 ds2 = zipWithDmds lub ds1 ds2 |
|---|
| 1188 | |
|---|
| 1189 | --------------------- |
|---|
| 1190 | box :: Demand -> Demand |
|---|
| 1191 | -- box is the smart constructor for Box |
|---|
| 1192 | -- It computes <B,bot> & d |
|---|
| 1193 | -- INVARIANT: (Box d) => d = Bot, Abs, Eval |
|---|
| 1194 | -- Seems to be no point in allowing (Box (Call d)) |
|---|
| 1195 | box (Call d) = Call d -- The odd man out. Why? |
|---|
| 1196 | box (Box d) = Box d |
|---|
| 1197 | box (Defer _) = lazyDmd |
|---|
| 1198 | box Top = lazyDmd -- Box Abs and Box Top |
|---|
| 1199 | box Abs = lazyDmd -- are the same <B,L> |
|---|
| 1200 | box d = Box d -- Bot, Eval |
|---|
| 1201 | |
|---|
| 1202 | --------------- |
|---|
| 1203 | defer :: Demand -> Demand |
|---|
| 1204 | |
|---|
| 1205 | -- defer is the smart constructor for Defer |
|---|
| 1206 | -- The idea is that (Defer ds) = <U(ds), L> |
|---|
| 1207 | -- |
|---|
| 1208 | -- It specifies what happens at a lazy function argument |
|---|
| 1209 | -- or a lambda; the L* operator |
|---|
| 1210 | -- Set the strictness part to L, but leave |
|---|
| 1211 | -- the boxity side unaffected |
|---|
| 1212 | -- It also ensures that Defer (Eval [LLLL]) = L |
|---|
| 1213 | |
|---|
| 1214 | defer Bot = Abs |
|---|
| 1215 | defer Abs = Abs |
|---|
| 1216 | defer Top = Top |
|---|
| 1217 | defer (Call _) = lazyDmd -- Approximation here? |
|---|
| 1218 | defer (Box _) = lazyDmd |
|---|
| 1219 | defer (Defer ds) = Defer ds |
|---|
| 1220 | defer (Eval ds) = deferEval ds |
|---|
| 1221 | |
|---|
| 1222 | deferEval :: Demands -> Demand |
|---|
| 1223 | -- deferEval ds = defer (Eval ds) |
|---|
| 1224 | deferEval ds | allTop ds = Top |
|---|
| 1225 | | otherwise = Defer ds |
|---|
| 1226 | |
|---|
| 1227 | --------------------- |
|---|
| 1228 | absLub :: Demand -> Demand |
|---|
| 1229 | -- Computes (Abs `lub` d) |
|---|
| 1230 | -- For the Bot case consider |
|---|
| 1231 | -- f x y = if ... then x else error x |
|---|
| 1232 | -- Then for y we get Abs `lub` Bot, and we really |
|---|
| 1233 | -- want Abs overall |
|---|
| 1234 | absLub Bot = Abs |
|---|
| 1235 | absLub Abs = Abs |
|---|
| 1236 | absLub Top = Top |
|---|
| 1237 | absLub (Call _) = Top |
|---|
| 1238 | absLub (Box _) = Top |
|---|
| 1239 | absLub (Eval ds) = Defer (absLubs ds) -- Or (Defer ds)? |
|---|
| 1240 | absLub (Defer ds) = Defer (absLubs ds) -- Or (Defer ds)? |
|---|
| 1241 | |
|---|
| 1242 | absLubs :: Demands -> Demands |
|---|
| 1243 | absLubs = mapDmds absLub |
|---|
| 1244 | |
|---|
| 1245 | --------------- |
|---|
| 1246 | both :: Demand -> Demand -> Demand |
|---|
| 1247 | |
|---|
| 1248 | both Abs d2 = d2 |
|---|
| 1249 | |
|---|
| 1250 | -- Note [Bottom demands] |
|---|
| 1251 | both Bot Bot = Bot |
|---|
| 1252 | both Bot Abs = Bot |
|---|
| 1253 | both Bot (Eval ds) = Eval (mapDmds (`both` Bot) ds) |
|---|
| 1254 | both Bot (Defer ds) = Eval (mapDmds (`both` Bot) ds) |
|---|
| 1255 | both Bot _ = errDmd |
|---|
| 1256 | |
|---|
| 1257 | both Top Bot = errDmd |
|---|
| 1258 | both Top Abs = Top |
|---|
| 1259 | both Top Top = Top |
|---|
| 1260 | both Top (Box d) = Box d |
|---|
| 1261 | both Top (Call d) = Call d |
|---|
| 1262 | both Top (Eval ds) = Eval (mapDmds (`both` Top) ds) |
|---|
| 1263 | both Top (Defer ds) -- = defer (Top `both` Eval ds) |
|---|
| 1264 | -- = defer (Eval (mapDmds (`both` Top) ds)) |
|---|
| 1265 | = deferEval (mapDmds (`both` Top) ds) |
|---|
| 1266 | |
|---|
| 1267 | |
|---|
| 1268 | both (Box d1) (Box d2) = box (d1 `both` d2) |
|---|
| 1269 | both (Box d1) d2@(Call _) = box (d1 `both` d2) |
|---|
| 1270 | both (Box d1) d2@(Eval _) = box (d1 `both` d2) |
|---|
| 1271 | both (Box d1) (Defer _) = Box d1 |
|---|
| 1272 | both d1@(Box _) d2 = d2 `both` d1 |
|---|
| 1273 | |
|---|
| 1274 | both (Call d1) (Call d2) = Call (d1 `both` d2) |
|---|
| 1275 | both (Call d1) (Eval _) = Call d1 -- Could do better for (Poly Bot)? |
|---|
| 1276 | both (Call d1) (Defer _) = Call d1 -- Ditto |
|---|
| 1277 | both d1@(Call _) d2 = d2 `both` d1 |
|---|
| 1278 | |
|---|
| 1279 | both (Eval ds1) (Eval ds2) = Eval (ds1 `boths` ds2) |
|---|
| 1280 | both (Eval ds1) (Defer ds2) = Eval (ds1 `boths` mapDmds defer ds2) |
|---|
| 1281 | both d1@(Eval _) d2 = d2 `both` d1 |
|---|
| 1282 | |
|---|
| 1283 | both (Defer ds1) (Defer ds2) = deferEval (ds1 `boths` ds2) |
|---|
| 1284 | both d1@(Defer _) d2 = d2 `both` d1 |
|---|
| 1285 | |
|---|
| 1286 | boths :: Demands -> Demands -> Demands |
|---|
| 1287 | boths ds1 ds2 = zipWithDmds both ds1 ds2 |
|---|
| 1288 | \end{code} |
|---|
| 1289 | |
|---|
| 1290 | Note [Bottom demands] |
|---|
| 1291 | ~~~~~~~~~~~~~~~~~~~~~ |
|---|
| 1292 | Consider |
|---|
| 1293 | f x = error x |
|---|
| 1294 | From 'error' itself we get demand Bot on x |
|---|
| 1295 | From the arg demand on x we get |
|---|
| 1296 | x :-> evalDmd = Box (Eval (Poly Abs)) |
|---|
| 1297 | So we get Bot `both` Box (Eval (Poly Abs)) |
|---|
| 1298 | = Seq Keep (Poly Bot) |
|---|
| 1299 | |
|---|
| 1300 | Consider also |
|---|
| 1301 | f x = if ... then error (fst x) else fst x |
|---|
| 1302 | Then we get (Eval (Box Bot, Bot) `lub` Eval (SA)) |
|---|
| 1303 | = Eval (SA) |
|---|
| 1304 | which is what we want. |
|---|
| 1305 | |
|---|
| 1306 | Consider also |
|---|
| 1307 | f x = error [fst x] |
|---|
| 1308 | Then we get |
|---|
| 1309 | x :-> Bot `both` Defer [SA] |
|---|
| 1310 | and we want the Bot demand to cancel out the Defer |
|---|
| 1311 | so that we get Eval [SA]. Otherwise we'd have the odd |
|---|
| 1312 | situation that |
|---|
| 1313 | f x = error (fst x) -- Strictness U(SA)b |
|---|
| 1314 | g x = error ('y':fst x) -- Strictness Tb |
|---|