2 % (c) The GRASP/AQUA Project, Glasgow University, 1993-1998
4 \section[WwLib]{A library for the ``worker/wrapper'' back-end to the strictness analyser}
10 worthSplitting, setUnpackStrategy,
14 #include "HsVersions.h"
17 import Id ( Id, idType, mkSysLocal, getIdDemandInfo, setIdDemandInfo,
19 import IdInfo ( CprInfo(..), noCprInfo )
20 import Const ( Con(..), DataCon )
21 import DataCon ( dataConArgTys )
22 import Demand ( Demand(..) )
23 import PrelInfo ( realWorldPrimId, aBSENT_ERROR_ID )
24 import TysPrim ( realWorldStatePrimTy )
25 import TysWiredIn ( unboxedTupleCon, unboxedTupleTyCon )
26 import Type ( isUnLiftedType, mkTyVarTys, mkTyVarTy, mkFunTys,
27 splitForAllTys, splitFunTysN,
28 splitAlgTyConApp_maybe, mkTyConApp,
31 import TyCon ( isNewTyCon,
33 import BasicTypes ( NewOrData(..) )
35 import UniqSupply ( returnUs, thenUs, getUniqueUs, getUniquesUs,
37 import Util ( zipWithEqual, zipEqual )
41 %************************************************************************
43 \subsection[datatype-WwLib]{@WwBinding@: a datatype for worker/wrapper-ing}
45 %************************************************************************
47 In the worker/wrapper stuff, we want to carry around @CoreBindings@ in
48 an ``intermediate form'' that can later be turned into a \tr{let} or
49 \tr{case} (depending on strictness info).
54 | WwCase (CoreExpr -> CoreExpr)
55 -- the "case" will be a "strict let" of the form:
60 -- (instead of "let <blah> = rhs in body")
62 -- The expr you pass to the function is "body" (the
63 -- expression that goes "in the corner").
66 %************************************************************************
68 \subsection[mkWrapperAndWorker]{@mkWrapperAndWorker@}
70 %************************************************************************
72 ************ WARNING ******************
73 these comments are rather out of date
74 *****************************************
76 @mkWrapperAndWorker@ is given:
79 The {\em original function} \tr{f}, of the form:
81 f = /\ tyvars -> \ args -> body
83 The original-binder \tr{f}, the \tr{tyvars}, \tr{args}, and \tr{body}
86 We use the Id \tr{f} mostly to get its type.
89 Strictness information about \tr{f}, in the form of a list of
96 @mkWrapperAndWorker@ produces (A BIT OUT-OF-DATE...):
99 Maybe @Nothing@: no worker/wrappering going on in this case. This can
100 happen (a)~if the strictness info says that there is nothing
101 interesting to do or (b)~if *any* of the argument types corresponding
102 to ``active'' arg postitions is abstract or will be to the outside
103 world (i.e., {\em this} module can see the constructors, but nobody
104 else will be able to). An ``active'' arg position is one which the
105 wrapper has to unpack. An importing module can't do this unpacking,
106 so it simply has to give up and call the wrapper only.
109 Maybe \tr{Just (wrapper_Id, wrapper_body, worker_Id, worker_body)}.
111 The @wrapper_Id@ is just the one that was passed in, with its
112 strictness IdInfo updated.
115 The \tr{body} of the original function may not be given (i.e., it's
116 BOTTOM), in which case you'd jolly well better not tug on the
119 Here's an example. The original function is:
121 g :: forall a . Int -> [a] -> a
123 g = /\ a -> \ x ys ->
129 From this, we want to produce:
131 -- wrapper (an unfolding)
132 g :: forall a . Int -> [a] -> a
134 g = /\ a -> \ x ys ->
136 I# x# -> g.wrk a x# ys
137 -- call the worker; don't forget the type args!
140 g.wrk :: forall a . Int# -> [a] -> a
142 g.wrk = /\ a -> \ x# ys ->
146 case x of -- note: body of g moved intact
151 Something we have to be careful about: Here's an example:
153 -- "f" strictness: U(P)U(P)
154 f (I# a) (I# b) = a +# b
156 g = f -- "g" strictness same as "f"
158 \tr{f} will get a worker all nice and friendly-like; that's good.
159 {\em But we don't want a worker for \tr{g}}, even though it has the
160 same strictness as \tr{f}. Doing so could break laziness, at best.
162 Consequently, we insist that the number of strictness-info items is
163 exactly the same as the number of lambda-bound arguments. (This is
164 probably slightly paranoid, but OK in practice.) If it isn't the
165 same, we ``revise'' the strictness info, so that we won't propagate
166 the unusable strictness-info into the interfaces.
169 %************************************************************************
171 \subsection{Functions over Demands}
173 %************************************************************************
176 mAX_WORKER_ARGS :: Int -- ToDo: set via flag
179 setUnpackStrategy :: [Demand] -> [Demand]
181 = snd (go (mAX_WORKER_ARGS - nonAbsentArgs ds) ds)
183 go :: Int -- Max number of args available for sub-components of [Demand]
185 -> (Int, [Demand]) -- Args remaining after subcomponents of [Demand] are unpacked
187 go n (WwUnpack nd _ cs : ds) | n' >= 0
188 = WwUnpack nd True cs' `cons` go n'' ds
190 = WwUnpack nd False cs `cons` go n ds
192 n' = n + 1 - nonAbsentArgs cs
193 -- Add one because we don't pass the top-level arg any more
194 -- Delete # of non-absent args to which we'll now be committed
197 go n (d:ds) = d `cons` go n ds
200 cons d (n,ds) = (n, d:ds)
202 nonAbsentArgs :: [Demand] -> Int
204 nonAbsentArgs (WwLazy True : ds) = nonAbsentArgs ds
205 nonAbsentArgs (d : ds) = 1 + nonAbsentArgs ds
207 worthSplitting :: [Demand]
208 -> Bool -- Result is bottom
209 -> Bool -- True <=> the wrapper would not be an identity function
210 worthSplitting ds result_bot = not result_bot && any worth_it ds
211 -- Don't split if the result is bottom; there's no efficiency to
212 -- be gained, and (worse) the wrapper body may not look like a wrapper
213 -- body to getWorkerIdAndCons
215 worth_it (WwLazy True) = True -- Absent arg
216 worth_it (WwUnpack _ True _) = True -- Arg to unpack
217 worth_it WwStrict = False -- Don't w/w just because of strictness
218 worth_it other = False
220 allAbsent :: [Demand] -> Bool
221 allAbsent ds = all absent ds
223 absent (WwLazy is_absent) = is_absent
224 absent (WwUnpack _ True cs) = allAbsent cs
229 %************************************************************************
231 \subsection{The worker wrapper core}
233 %************************************************************************
235 @mkWrapper@ is called when importing a function. We have the type of
236 the function and the name of its worker, and we want to make its body (the wrapper).
239 mkWrapper :: Type -- Wrapper type
241 -> [Demand] -- Wrapper strictness info
242 -> CprInfo -- Wrapper cpr info
243 -> UniqSM (Id -> CoreExpr) -- Wrapper body, missing worker Id
245 mkWrapper fun_ty arity demands cpr_info
246 = getUniquesUs arity `thenUs` \ wrap_uniqs ->
248 (tyvars, tau_ty) = splitForAllTys fun_ty
249 (arg_tys, body_ty) = splitFunTysN "mkWrapper" arity tau_ty
250 -- The "expanding dicts" part here is important, even for the splitForAll
251 -- The imported thing might be a dictionary, such as Functor Foo
252 -- But Functor Foo = forall a b. (a->b) -> Foo a -> Foo b
253 -- and as such might have some strictness info attached.
254 -- Then we need to have enough args to zip to the strictness info
256 wrap_args = zipWith mk_ww_local wrap_uniqs arg_tys
258 mkWwBodies tyvars wrap_args body_ty demands cpr_info `thenUs` \ (wrap_fn, _, _) ->
262 @mkWwBodies@ is called when doing the worker/wrapper split inside a module.
265 mkWwBodies :: [TyVar] -> [Id] -> Type -- Original fn args and body type
266 -> [Demand] -- Strictness info for original fn; corresp 1-1 with args
267 -> CprInfo -- Result of CPR analysis
268 -> UniqSM (Id -> CoreExpr, -- Wrapper body, lacking only the worker Id
269 CoreExpr -> CoreExpr, -- Worker body, lacking the original function body
270 [Demand]) -- Strictness info for worker
272 mkWwBodies tyvars args body_ty demands cpr_info
273 | allAbsent demands &&
274 isUnLiftedType body_ty
275 = -- Horrid special case. If the worker would have no arguments, and the
276 -- function returns a primitive type value, that would make the worker into
277 -- an unboxed value. We box it by passing a dummy void argument, thus:
279 -- f = /\abc. \xyz. fw abc void
280 -- fw = /\abc. \v. body
282 -- We use the state-token type which generates no code
283 getUniqueUs `thenUs` \ void_arg_uniq ->
285 void_arg = mk_ww_local void_arg_uniq realWorldStatePrimTy
287 returnUs (\ work_id -> Note InlineMe $ -- Inline the wrapper
288 mkLams tyvars $ mkLams args $
290 (map (Type . mkTyVarTy) tyvars ++ [Var realWorldPrimId]),
291 \ body -> mkLams (tyvars ++ [void_arg]) body,
294 mkWwBodies tyvars wrap_args body_ty demands cpr_info
297 -- demands may be longer than number of args. If we aren't doing w/w
298 -- for strictness then demands is an infinite list of 'lazy' args.
299 wrap_args_w_demands = zipWith setIdDemandInfo wrap_args demands
301 mkWW wrap_args_w_demands `thenUs` \ (wrap_fn, work_args_w_demands, work_fn) ->
303 mkWWcpr body_ty cpr_info `thenUs` \ (wrap_fn_w_cpr, work_fn_w_cpr) ->
305 returnUs (\ work_id -> Note InlineMe $
306 mkLams tyvars $ mkLams wrap_args_w_demands $
307 (wrap_fn_w_cpr . wrap_fn) (mkTyApps (Var work_id) (mkTyVarTys tyvars)),
309 \ body -> mkLams tyvars $ mkLams work_args_w_demands $
310 (work_fn_w_cpr . work_fn) body,
312 map getIdDemandInfo work_args_w_demands)
317 mkWW :: [Id] -- Wrapper args; have their demand info on them
318 -> UniqSM (CoreExpr -> CoreExpr, -- Wrapper body, lacking the inner call to the worker
319 -- and without its lambdas
320 [Id], -- Worker args; have their demand info on them
321 CoreExpr -> CoreExpr) -- Worker body, lacking the original body of the function
326 = returnUs (\ wrapper_body -> wrapper_body,
328 \ worker_body -> worker_body)
332 = case getIdDemandInfo arg of
336 mkWW ds `thenUs` \ (wrap_fn, worker_args, work_fn) ->
337 returnUs (\ wrapper_body -> wrap_fn wrapper_body,
339 \ worker_body -> mk_absent_let arg (work_fn worker_body))
343 WwUnpack new_or_data True cs ->
344 getUniquesUs (length inst_con_arg_tys) `thenUs` \ uniqs ->
346 unpk_args = zipWith mk_ww_local uniqs inst_con_arg_tys
347 unpk_args_w_ds = zipWithEqual "mkWW" setIdDemandInfo unpk_args cs
349 mkWW (unpk_args_w_ds ++ ds) `thenUs` \ (wrap_fn, worker_args, work_fn) ->
350 returnUs (\ wrapper_body -> mk_unpk_case new_or_data arg unpk_args data_con arg_tycon
351 (wrap_fn wrapper_body),
353 \ worker_body -> work_fn (mk_pk_let new_or_data arg data_con
354 tycon_arg_tys unpk_args worker_body))
356 inst_con_arg_tys = dataConArgTys data_con tycon_arg_tys
357 (arg_tycon, tycon_arg_tys, data_con)
358 = case (splitAlgTyConApp_maybe (idType arg)) of
360 Just (arg_tycon, tycon_arg_tys, [data_con]) ->
361 -- The main event: a single-constructor data type
362 (arg_tycon, tycon_arg_tys, data_con)
364 Just (_, _, data_cons) ->
365 pprPanic "mk_ww_arg_processing:"
366 (text "not one constr (interface files not consistent/up to date?)"
367 $$ (ppr arg <+> ppr (idType arg)))
370 panic "mk_ww_arg_processing: not datatype"
375 mkWW ds `thenUs` \ (wrap_fn, worker_args, work_fn) ->
376 returnUs (\ wrapper_body -> wrap_fn (App wrapper_body (Var arg)),
381 @mkWWcpr@ takes the worker/wrapper pair produced from the strictness
382 info and adds in the CPR transformation. The worker returns an
383 unboxed tuple containing non-CPR components. The wrapper takes this
384 tuple and re-produces the correct structured output.
386 The non-CPR results appear ordered in the unboxed tuple as if by a
387 left-to-right traversal of the result structure.
391 mkWWcpr :: Type -- function body type
392 -> CprInfo -- CPR analysis results
393 -> UniqSM (CoreExpr -> CoreExpr, -- New wrapper
394 CoreExpr -> CoreExpr) -- New worker
396 mkWWcpr body_ty NoCPRInfo
397 = returnUs (id, id) -- Must be just the strictness transf.
398 mkWWcpr body_ty (CPRInfo cpr_args)
399 = getUniqueUs `thenUs` \ body_arg_uniq ->
401 body_var = mk_ww_local body_arg_uniq body_ty
403 cpr_reconstruct body_ty cpr_info' `thenUs` \reconst_fn ->
404 cpr_flatten body_ty cpr_info' `thenUs` \flatten_fn ->
405 returnUs (reconst_fn, flatten_fn)
407 -- We only make use of the outer level of CprInfo, otherwise we
408 -- may lose laziness. :-( Hopefully, we will find a use for the
409 -- extra info some day (e.g. creating versions specialized to
410 -- the use made of the components of the result by the callee)
411 cpr_info' = CPRInfo (map (const NoCPRInfo) cpr_args)
415 @cpr_flatten@ takes the result type produced by the body and the info
416 from the CPR analysis and flattens the constructed product components.
417 These are returned in an unboxed tuple.
420 cpr_flatten :: Type -> CprInfo -> UniqSM (CoreExpr -> CoreExpr)
421 cpr_flatten ty cpr_info
422 = mk_cpr_case (ty, cpr_info) `thenUs` \(res_id, tup_ids, flatten_exp) ->
423 returnUs (\body -> Case body res_id
424 [(DEFAULT, [], flatten_exp (fst $ mk_unboxed_tuple tup_ids))])
428 mk_cpr_case :: (Type, CprInfo) ->
429 UniqSM (CoreBndr, -- Name of binder for this part of result
430 [(CoreExpr, Type)], -- expressions for flattened result
431 CoreExpr -> CoreExpr) -- add in code to flatten result
433 mk_cpr_case (ty, NoCPRInfo)
434 -- this component must be returned as a component of the unboxed tuple result
435 = getUniqueUs `thenUs` \id_uniq ->
436 let id_id = mk_ww_local id_uniq ty in
437 returnUs (id_id, [(Var id_id, ty)], id)
438 mk_cpr_case (ty, cpr_info@(CPRInfo ci_args))
439 | isNewTyCon tycon -- a new type: under the coercions must be a
440 -- constructed product
441 = ASSERT ( null $ tail inst_con_arg_tys )
442 mk_cpr_case (head inst_con_arg_tys, cpr_info)
443 `thenUs` \(arg, tup, exp) ->
444 getUniqueUs `thenUs` \id_uniq ->
445 let id_id = mk_ww_local id_uniq ty
446 new_exp_case = \var -> Case (Note (Coerce (idType arg) ty) (Var id_id))
448 [(DEFAULT,[], exp var)]
450 returnUs (id_id, tup, new_exp_case)
452 | otherwise -- a data type
453 -- flatten components
454 = mapUs mk_cpr_case (zip inst_con_arg_tys ci_args)
455 `thenUs` \sub_builds ->
456 getUniqueUs `thenUs` \id_uniq ->
457 let id_id = mk_ww_local id_uniq ty
458 (args, tup, exp) = unzip3 sub_builds
459 con_app = mkConApp data_con (map Var args)
461 new_exp_case = \var -> Case (Var id_id) (mkWildId ty)
462 [(DataCon data_con, args,
463 foldl (\e f -> f e) var exp)]
465 returnUs (id_id, new_tup, new_exp_case)
467 (data_con, tycon, tycon_arg_tys, inst_con_arg_tys) = splitType "mk_cpr_case" ty
471 @cpr_reconstruct@ does the opposite of @cpr_flatten@. It takes the unboxed
472 tuple produced by the worker and reconstructs the structured result.
475 cpr_reconstruct :: Type -> CprInfo -> UniqSM (CoreExpr -> CoreExpr)
476 cpr_reconstruct ty cpr_info
477 = mk_cpr_let (ty,cpr_info) `thenUs` \(res_id, tup_ids, reconstruct_exp) ->
478 returnUs (\worker -> Case worker (mkWildId $ worker_type tup_ids)
479 [(DataCon $ unboxedTupleCon $ length tup_ids,
480 tup_ids, reconstruct_exp $ Var res_id)])
483 worker_type ids = mkTyConApp (unboxedTupleTyCon (length ids)) (map idType ids)
486 mk_cpr_let :: (Type, CprInfo) ->
487 UniqSM (CoreBndr, -- Binder for this component of result
488 [CoreBndr], -- Binders which will appear in worker's result
489 CoreExpr -> CoreExpr) -- Code to produce structured result.
490 mk_cpr_let (ty, NoCPRInfo)
491 -- this component will appear explicitly in the unboxed tuple.
492 = getUniqueUs `thenUs` \id_uniq ->
494 id_id = mk_ww_local id_uniq ty
496 returnUs (id_id, [id_id], id)
498 mk_cpr_let (ty, cpr_info@(CPRInfo ci_args))
499 | isNewTyCon tycon -- a new type: must coerce the argument to this type
500 = ASSERT ( null $ tail inst_con_arg_tys )
501 mk_cpr_let (head inst_con_arg_tys, cpr_info)
502 `thenUs` \(arg, tup, exp) ->
503 getUniqueUs `thenUs` \id_uniq ->
504 let id_id = mk_ww_local id_uniq ty
505 new_exp = \var -> exp (Let (NonRec id_id (Note (Coerce ty (idType arg)) (Var arg))) var)
507 returnUs (id_id, tup, new_exp)
509 | otherwise -- a data type
510 -- reconstruct components then apply data con
511 = mapUs mk_cpr_let (zip inst_con_arg_tys ci_args)
512 `thenUs` \sub_builds ->
513 getUniqueUs `thenUs` \id_uniq ->
514 let id_id = mk_ww_local id_uniq ty
515 (args, tup, exp) = unzip3 sub_builds
516 con_app = mkConApp data_con $ (map Type tycon_arg_tys) ++ (map Var args)
518 new_exp = \var -> foldl (\e f -> f e) (Let (NonRec id_id con_app) var) exp
520 returnUs (id_id, new_tup, new_exp)
522 (data_con, tycon, tycon_arg_tys, inst_con_arg_tys) = splitType "mk_cpr_let" ty
524 splitType :: String -> Type -> (DataCon, TyCon, [Type], [Type])
525 splitType fname ty = (data_con, tycon, tycon_arg_tys, dataConArgTys data_con tycon_arg_tys)
527 (data_con, tycon, tycon_arg_tys)
528 = case (splitAlgTyConApp_maybe ty) of
529 Just (arg_tycon, tycon_arg_tys, [data_con]) ->
530 -- The main event: a single-constructor data type
531 (data_con, arg_tycon, tycon_arg_tys)
533 Just (_, _, data_cons) ->
534 pprPanic (fname ++ ":")
535 (text "not one constr (interface files not consistent/up to date?)"
539 pprPanic (fname ++ ":")
540 (text "not a datatype" $$ ppr ty)
544 %************************************************************************
546 \subsection{Utilities}
548 %************************************************************************
552 mk_absent_let arg body
553 | not (isUnLiftedType arg_ty)
554 = Let (NonRec arg (mkTyApps (Var aBSENT_ERROR_ID) [arg_ty])) body
556 = panic "WwLib: haven't done mk_absent_let for primitives yet"
560 mk_unpk_case NewType arg unpk_args boxing_con boxing_tycon body
561 -- A newtype! Use a coercion not a case
562 = ASSERT( null other_args )
563 Case (Note (Coerce (idType unpk_arg) (idType arg)) (Var arg))
567 (unpk_arg:other_args) = unpk_args
569 mk_unpk_case DataType arg unpk_args boxing_con boxing_tycon body
571 = Case (Var arg) arg [(DataCon boxing_con, unpk_args, body)]
573 mk_pk_let NewType arg boxing_con con_tys unpk_args body
574 = ASSERT( null other_args )
575 Let (NonRec arg (Note (Coerce (idType arg) (idType unpk_arg)) (Var unpk_arg))) body
577 (unpk_arg:other_args) = unpk_args
579 mk_pk_let DataType arg boxing_con con_tys unpk_args body
580 = Let (NonRec arg (Con (DataCon boxing_con) con_args)) body
582 con_args = map Type con_tys ++ map Var unpk_args
585 mk_ww_local uniq ty = mkSysLocal SLIT("ww") uniq ty
588 mk_unboxed_tuple :: [(CoreExpr, Type)] -> (CoreExpr, Type)
589 mk_unboxed_tuple contents
590 = (mkConApp (unboxedTupleCon (length contents))
591 (map (Type . snd) contents ++
593 mkTyConApp (unboxedTupleTyCon (length contents))