2 % (c) The GRASP/AQUA Project, Glasgow University, 1993-1996
4 \section[WwLib]{A library for the ``worker/wrapper'' back-end to the strictness analyser}
7 #include "HsVersions.h"
12 mkWwBodies, mAX_WORKER_ARGS,
14 -- our friendly worker/wrapper monad:
16 returnWw, thenWw, mapWw,
17 getUniqueWw, uniqSMtoWwM
19 -- and to make the interface self-sufficient...
24 import PrelInfo ( aBSENT_ERROR_ID )
26 import Id ( mkWorkerId, mkSysLocal, idType,
27 getInstantiatedDataConSig, getIdInfo,
28 replaceIdInfo, addIdStrictness, DataCon(..)
30 import IdInfo -- lots of things
31 import Maybes ( maybeToBool, Maybe(..), MaybeErr )
33 import SrcLoc ( mkUnknownSrcLoc )
34 import Type ( mkTyVarTy, mkFunTys, isPrimType,
35 maybeDataTyCon, quantifyTy
43 quantifyTy = panic "WwLib.quantifyTy"
46 %************************************************************************
48 \subsection[datatype-WwLib]{@WwBinding@: a datatype for worker/wrapper-ing}
50 %************************************************************************
52 In the worker/wrapper stuff, we want to carry around @CoreBindings@ in
53 an ``intermediate form'' that can later be turned into a \tr{let} or
54 \tr{case} (depending on strictness info).
59 | WwCase (CoreExpr -> CoreExpr)
60 -- the "case" will be a "strict let" of the form:
65 -- (instead of "let <blah> = rhs in body")
67 -- The expr you pass to the function is "body" (the
68 -- expression that goes "in the corner").
71 %************************************************************************
73 \subsection[mkWrapperAndWorker]{@mkWrapperAndWorker@}
75 %************************************************************************
77 ************ WARNING ******************
78 these comments are rather out of date
79 *****************************************
81 @mkWrapperAndWorker@ is given:
84 The {\em original function} \tr{f}, of the form:
86 f = /\ tyvars -> \ args -> body
88 The original-binder \tr{f}, the \tr{tyvars}, \tr{args}, and \tr{body}
91 We use the Id \tr{f} mostly to get its type.
94 Strictness information about \tr{f}, in the form of a list of
101 @mkWrapperAndWorker@ produces (A BIT OUT-OF-DATE...):
104 Maybe @Nothing@: no worker/wrappering going on in this case. This can
105 happen (a)~if the strictness info says that there is nothing
106 interesting to do or (b)~if *any* of the argument types corresponding
107 to ``active'' arg postitions is abstract or will be to the outside
108 world (i.e., {\em this} module can see the constructors, but nobody
109 else will be able to). An ``active'' arg position is one which the
110 wrapper has to unpack. An importing module can't do this unpacking,
111 so it simply has to give up and call the wrapper only.
114 Maybe \tr{Just (wrapper_Id, wrapper_body, worker_Id, worker_body)}.
116 The @wrapper_Id@ is just the one that was passed in, with its
117 strictness IdInfo updated.
120 The \tr{body} of the original function may not be given (i.e., it's
121 BOTTOM), in which case you'd jolly well better not tug on the
124 Here's an example. The original function is:
126 g :: forall a . Int -> [a] -> a
128 g = /\ a -> \ x ys ->
134 From this, we want to produce:
136 -- wrapper (an unfolding)
137 g :: forall a . Int -> [a] -> a
139 g = /\ a -> \ x ys ->
141 I# x# -> g.wrk a x# ys
142 -- call the worker; don't forget the type args!
145 g.wrk :: forall a . Int# -> [a] -> a
147 g.wrk = /\ a -> \ x# ys ->
151 case x of -- note: body of g moved intact
156 Something we have to be careful about: Here's an example:
158 -- "f" strictness: U(P)U(P)
159 f (I# a) (I# b) = a +# b
161 g = f -- "g" strictness same as "f"
163 \tr{f} will get a worker all nice and friendly-like; that's good.
164 {\em But we don't want a worker for \tr{g}}, even though it has the
165 same strictness as \tr{f}. Doing so could break laziness, at best.
167 Consequently, we insist that the number of strictness-info items is
168 exactly the same as the number of lambda-bound arguments. (This is
169 probably slightly paranoid, but OK in practice.) If it isn't the
170 same, we ``revise'' the strictness info, so that we won't propagate
171 the unusable strictness-info into the interfaces.
173 ==========================
175 Here's the real fun... The wrapper's ``deconstructing'' of arguments
176 and the worker's putting them back together again are ``duals'' in
179 What we do is walk along the @Demand@ list, producing two
180 expressions (one for wrapper, one for worker...), each with a ``hole''
181 in it, where we will later plug in more information. For our previous
182 example, the expressions-with-HOLES are:
186 I# x# -> <<HOLE>> x# ys
194 (Actually, we add the lambda-bound arguments at the end...) (The big
195 Lambdas are added on the front later.)
199 :: Type -- Type of the *body* of the orig
200 -- function; i.e. /\ tyvars -> \ vars -> body
201 -> [TyVar] -- Type lambda vars of original function
202 -> [Id] -- Args of original function
203 -> [Demand] -- Strictness info for those args
205 -> UniqSM (Maybe -- Nothing iff (a) no interesting split possible
206 -- (b) any unpack on abstract type
207 (Id -> CoreExpr, -- Wrapper expr w/
208 -- hole for worker id
209 CoreExpr -> CoreExpr, -- Worker expr w/ hole
210 -- for original fn body
211 StrictnessInfo, -- Worker strictness info
212 Type -> Type) -- Worker type w/ hole
213 ) -- for type of original fn body
216 mkWwBodies body_ty tyvars args arg_infos
217 = ASSERT(length args == length arg_infos)
218 -- or you can get disastrous user/definer-module mismatches
219 if (all_absent_args_and_unboxed_value body_ty arg_infos)
220 then returnUs Nothing
223 mk_ww_arg_processing args arg_infos (mAX_WORKER_ARGS - nonAbsentArgs arg_infos)
224 `thenUsMaybe` \ (wrap_frag, work_args_info, work_frag) ->
226 (work_args, wrkr_demands) = unzip work_args_info
228 wrkr_strictness = mkStrictnessInfo wrkr_demands Nothing -- no worker-of-worker...
230 wrapper_w_hole = \ worker_id ->
233 mkCoTyApps (Var worker_id) (map mkTyVarTy tyvars)
236 worker_w_hole = \ orig_body ->
237 mkLam tyvars work_args (
241 worker_ty_w_hole = \ body_ty ->
242 snd (quantifyTy tyvars (
243 mkFunTys (map idType work_args) body_ty
246 returnUs (Just (wrapper_w_hole, worker_w_hole, wrkr_strictness, worker_ty_w_hole))
248 -- "all_absent_args_and_unboxed_value":
249 -- check for the obscure case of "\ x y z ... -> body" where
250 -- (a) *all* of the args x, y, z,... are absent, and
251 -- (b) the type of body is unboxed
252 -- If these conditions are true, we must *not* play worker/wrapper games!
254 all_absent_args_and_unboxed_value body_ty arg_infos
255 = not (null arg_infos)
256 && all is_absent_arg arg_infos
257 && isPrimType body_ty
259 is_absent_arg (WwLazy True) = True
260 is_absent_arg _ = False
263 Important: mk_ww_arg_processing doesn't check
264 for an "interesting" split. It just races ahead and makes the
265 split, even if there's no unpacking at all. This is important for
266 when it calls itself recursively.
268 It returns Nothing only if it encounters an abstract type in mid-flight.
271 mAX_WORKER_ARGS :: Int -- ToDo: set via flag
272 mAX_WORKER_ARGS = 6 -- Hmm... but this is an everything-must-
273 -- be-compiled-with-the-same-val thing...
276 :: [Id] -- Args of original function
277 -> [Demand] -- Strictness info for those args
278 -- must be at least as long as args
280 -> Int -- Number of extra args we are prepared to add.
281 -- This prevents over-eager unpacking, leading
282 -- to huge-arity functions.
284 -> UniqSM (Maybe -- Nothing iff any unpack on abstract type
285 (CoreExpr -> CoreExpr, -- Wrapper expr w/
286 -- hole for worker id
288 [(Id,Demand)], -- Worker's args
289 -- and their strictness info
290 CoreExpr -> CoreExpr) -- Worker body expr w/ hole
291 ) -- for original fn body
293 mk_ww_arg_processing [] _ _ = returnUs (Just (id, [], id))
295 mk_ww_arg_processing (arg : args) (WwLazy True : infos) max_extra_args
297 -- So, finish args to the right...
298 --pprTrace "Absent; num_wrkr_args=" (ppInt num_wrkr_args) (
302 mk_ww_arg_processing args infos max_extra_args
303 -- we've already discounted for absent args,
304 -- so we don't change max_extra_args
305 `thenUsMaybe` \ (wrap_rest, work_args_info, work_rest) ->
307 -- wrapper doesn't pass this arg to worker:
310 \ hole -> wrap_rest hole,
313 work_args_info, -- NB: no argument added
314 \ hole -> mk_absent_let arg arg_ty (work_rest hole)
318 mk_absent_let arg arg_ty body
319 = if not (isPrimType arg_ty) then
320 Let (NonRec arg (mkCoTyApp (Var aBSENT_ERROR_ID) arg_ty)) body
321 else -- quite horrible
322 panic "WwLib: haven't done mk_absent_let for primitives yet"
325 mk_ww_arg_processing (arg : args) (WwUnpack cmpnt_infos : infos) max_extra_args
326 | new_max_extra_args > 0 -- Check that we are prepared to add arguments
327 = -- this is the complicated one.
328 --pprTrace "Unpack; num_wrkr_args=" (ppCat [ppInt num_wrkr_args, ppStr "; new_max=", ppInt new_num_wrkr_args, ppStr "; arg=", ppr PprDebug arg, ppr PprDebug (WwUnpack cmpnt_infos)]) (
329 case maybeDataTyCon arg_ty of
331 Nothing -> -- Not a data type
332 panic "mk_ww_arg_processing: not datatype"
334 Just (_, _, []) -> -- An abstract type
335 -- We have to give up on the whole idea
337 Just (_, _, (_:_:_)) -> -- Two or more constructors; that's odd
338 panic "mk_ww_arg_processing: multi-constr"
340 Just (arg_tycon, tycon_arg_tys, [data_con]) ->
341 -- The main event: a single-constructor data type
344 (_,inst_con_arg_tys,_)
345 = getInstantiatedDataConSig data_con tycon_arg_tys
347 getUniques (length inst_con_arg_tys) `thenUs` \ uniqs ->
350 unpk_args = zipWithEqual
351 (\ u t -> mkSysLocal SLIT("upk") u t mkUnknownSrcLoc)
352 uniqs inst_con_arg_tys
354 -- In processing the rest, push the sub-component args
355 -- and infos on the front of the current bunch
356 mk_ww_arg_processing (unpk_args ++ args) (cmpnt_infos ++ infos) new_max_extra_args
357 `thenUsMaybe` \ (wrap_rest, work_args_info, work_rest) ->
360 -- wrapper: unpack the value
361 \ hole -> mk_unpk_case arg unpk_args
365 -- worker: expect the unpacked value;
366 -- reconstruct the orig value with a "let"
368 \ hole -> work_rest (mk_pk_let arg data_con tycon_arg_tys unpk_args hole)
376 + 1 -- We won't pass the original arg now
377 - nonAbsentArgs cmpnt_infos -- But we will pass an arg for each cmpt
379 mk_unpk_case arg unpk_args boxing_con boxing_tycon body
381 AlgAlts [(boxing_con, unpk_args, body)]
385 mk_pk_let arg boxing_con con_tys unpk_args body
386 = Let (NonRec arg (Con boxing_con con_tys [VarArg a | a <- unpk_args]))
389 mk_ww_arg_processing (arg : args) (arg_demand : infos) max_extra_args
391 = -- For all others at the moment, we just
392 -- pass them to the worker unchanged.
393 --pprTrace "Other; num_wrkr_args=" (ppCat [ppInt num_wrkr_args, ppStr ";arg=", ppr PprDebug arg, ppr PprDebug arg_demand]) (
395 -- Finish args to the right...
396 mk_ww_arg_processing args infos max_extra_args
397 `thenUsMaybe` \ (wrap_rest, work_args_info, work_rest) ->
401 \ hole -> wrap_rest (App hole (VarArg arg)),
404 (arg, arg_demand) : work_args_info,
405 \ hole -> work_rest hole
410 %************************************************************************
412 \subsection[monad-WwLib]{Simple monad for worker/wrapper}
414 %************************************************************************
416 In this monad, we thread a @UniqueSupply@, and we carry a
417 @GlobalSwitch@-lookup function downwards.
422 -> (GlobalSwitch -> Bool)
425 {-# INLINE thenWw #-}
426 {-# INLINE returnWw #-}
428 returnWw :: a -> WwM a
429 thenWw :: WwM a -> (a -> WwM b) -> WwM b
430 mapWw :: (a -> WwM b) -> [a] -> WwM [b]
432 returnWw expr ns sw = expr
435 = case splitUniqSupply us of { (s1, s2) ->
436 case (m s1 sw_chk) of { m_res ->
439 mapWw f [] = returnWw []
441 = f x `thenWw` \ x' ->
442 mapWw f xs `thenWw` \ xs' ->
447 getUniqueWw :: WwM Unique
448 uniqSMtoWwM :: UniqSM a -> WwM a
450 getUniqueWw us sw_chk = getUnique us
452 uniqSMtoWwM u_obj us sw_chk = u_obj us
454 thenUsMaybe :: UniqSM (Maybe a) -> (a -> UniqSM (Maybe b)) -> UniqSM (Maybe b)
456 = m `thenUs` \ result ->
458 Nothing -> returnUs Nothing