2 % (c) The GRASP/AQUA Project, Glasgow University, 1993-1996
4 \section[MagicUFs]{Magic unfoldings that the simplifier knows about}
8 MagicUnfoldingFun, -- absolutely abstract
11 applyMagicUnfoldingFun
14 #include "HsVersions.h"
16 import Id ( addInlinePragma )
18 import SimplEnv ( SimplEnv )
19 import SimplMonad ( SmplM, SimplCount )
20 import Type ( mkFunTys )
21 import TysWiredIn ( mkListTy )
22 import Unique ( Unique{-instances-} )
23 import Util ( assoc, zipWith3Equal, nOfThem, panic )
26 %************************************************************************
28 \subsection{Types, etc., for magic-unfolding functions}
30 %************************************************************************
33 data MagicUnfoldingFun
34 = MUF ( SimplEnv -- state of play in simplifier...
35 -- (note: we can get simplifier switches
37 -> [CoreArg] -- arguments
38 -> Maybe (SmplM CoreExpr))
39 -- Just result, or Nothing
42 Give us a value's @Unique@, we'll give you back the corresponding MUF.
44 mkMagicUnfoldingFun :: Unique -> MagicUnfoldingFun
46 mkMagicUnfoldingFun tag
47 = assoc "mkMagicUnfoldingFun" magic_UFs_table tag
49 magic_UFs_table = panic "MagicUFs.magic_UFs_table:ToDo"
52 Give us an MUF and stuff to apply it to, and we'll give you back the
55 applyMagicUnfoldingFun
59 -> Maybe (SmplM CoreExpr)
61 applyMagicUnfoldingFun (MUF fun) env args = fun env args
64 %************************************************************************
66 \subsection{The table of actual magic unfoldings}
68 %************************************************************************
73 magic_UFs_table :: [(FAST_STRING, MagicUnfoldingFun)]
76 = [(SLIT("augment"), MUF augment_fun),
77 (SLIT("build"), MUF build_fun),
78 (SLIT("foldl"), MUF foldl_fun),
79 (SLIT("foldr"), MUF foldr_fun),
80 (SLIT("unpackFoldrPS__"), MUF unpack_foldr_fun),
81 (SLIT("unpackAppendPS__"), MUF unpack_append_fun)]
84 %************************************************************************
86 \subsubsection{Unfolding function for @append@}
88 %************************************************************************
91 -- First build, the way we express our lists.
95 -> Maybe (SmplM CoreExpr)
96 build_fun env [TypeArg ty,ValArg (VarArg e)]
97 | switchIsSet env SimplDoInlineFoldrBuild
101 ourCons = CoTyApp (Var consDataCon) ty
102 ourNil = CoTyApp (Var nilDataCon) ty
104 result = newIds [ mkFunTys [ty, tyL] tyL, tyL ] `thenSmpl` \ [c,n] ->
105 returnSmpl(Let (NonRec c ourCons)
106 (Let (NonRec n ourNil)
107 (App (App (CoTyApp (Var e) tyL) (VarArg c)) (VarArg n)))
109 -- ToDo: add `build' without an argument instance.
110 -- This is strange, because of g's type.
111 build_fun env _ = ASSERT (not (switchIsSet env SimplDoInlineFoldrBuild))
116 augment_fun :: SimplEnv
118 -> Maybe (SmplM CoreExpr)
120 augment_fun env [TypeArg ty,ValArg (VarArg e),ValArg nil]
121 | switchIsSet env SimplDoInlineFoldrBuild
125 ourCons = CoTyApp (Var consDataCon) ty
126 result = newId (mkFunTys [ty, tyL] tyL) `thenSmpl` \ c ->
127 returnSmpl (Let (NonRec c ourCons)
128 (App (App (CoTyApp (Var e) tyL) (VarArg c)) nil))
129 -- ToDo: add `build' without an argument instance.
130 -- This is strange, because of g's type.
132 augment_fun env _ = ASSERT (not (switchIsSet env SimplDoInlineFoldrBuild))
136 Now foldr, the way we consume lists.
139 foldr_fun :: SimplEnv
141 -> Maybe (SmplM CoreExpr)
143 foldr_fun env (TypeArg ty1:TypeArg ty2:ValArg arg_k:ValArg arg_z:rest_args)
144 | do_fb_red && isConsFun env arg_k && isNilForm env arg_z
145 -- foldr (:) [] ==> id
146 -- this transformation is *always* benificial
147 -- cf. foldr (:) [] (build g) == g (:) []
148 -- with foldr (:) [] (build g) == build g
149 -- after unfolding build, they are the same thing.
150 = Just (tick Foldr_Cons_Nil `thenSmpl_`
151 newId (mkListTy ty1) `thenSmpl` \ x ->
152 returnSmpl({-trace "foldr (:) []"-} (mkGenApp (Lam x (Var x)) rest_args))
155 do_fb_red = switchIsSet env SimplDoFoldrBuild
157 foldr_fun env (TypeArg ty1:TypeArg ty2:ValArg arg_k:ValArg arg_z:ValArg arg_list:rest_args)
158 | do_fb_red && isNilForm env arg_list
160 -- again another short cut, helps with unroling of constant lists
161 = Just (tick Foldr_Nil `thenSmpl_`
162 returnSmpl (argToExpr arg_z)
165 | do_fb_red && arg_list_isBuildForm
166 -- foldr k z (build g) ==> g k z
167 -- this next line *is* the foldr/build rule proper.
168 = Just (tick FoldrBuild `thenSmpl_`
169 returnSmpl (mkGenApp (Var g) (TypeArg ty2:ValArg arg_k:ValArg arg_z:rest_args))
172 | do_fb_red && arg_list_isAugmentForm
173 -- foldr k z (augment g h) ==> let v = foldr k z h in g k v
174 -- this next line *is* the foldr/augment rule proper.
175 = Just (tick FoldrAugment `thenSmpl_`
176 newId ty2 `thenSmpl` \ v ->
178 Let (NonRec v (mkGenApp (Var foldrId)
179 [TypeArg ty1,TypeArg ty2,
183 (mkGenApp (Var g') (TypeArg ty2:ValArg arg_k:ValArg (VarArg v):rest_args)))
186 | do_fb_red && arg_list_isListForm
187 -- foldr k z (a:b:c:rest) =
188 -- (\ f -> f a (f b (f c (foldr f z rest)))) k rest_args
189 -- NB: 'k' is used just one by foldr, but 'f' is used many
190 -- times inside the list structure. This means that
191 -- 'f' needs to be inside a lambda, to make sure the simplifier
195 -- f a (f b (f c (foldr f z rest)))
197 -- let ele_1 = foldr f z rest
202 = Just (tick Foldr_List `thenSmpl_`
204 mkFunTys [ty1, ty2] ty2 :
205 nOfThem (length the_list) ty2
206 ) `thenSmpl` \ (f_id:ele_id1:ele_ids) ->
210 (mkGenApp (Var foldrId)
211 [TypeArg ty1,TypeArg ty2,
212 ValArg (VarArg f_id),
215 rest_binds = zipWith3Equal "Foldr:rest_binds"
216 (\ e v e' -> NonRec e (mkRhs v e'))
218 (reverse (tail the_list))
219 (init (ele_id1:ele_ids))
220 mkRhs v e = App (App (Var f_id) v) (VarArg e)
223 (mkRhs (head the_list) (last (ele_id1:ele_ids)))
224 (fst_bind:rest_binds)
226 returnSmpl (mkGenApp (Lam f_id core_list) (ValArg arg_k:rest_args))
232 | do_fb_red && arg_list_isStringForm -- ok, its a string!
233 -- foldr f z "foo" => unpackFoldrPS__ f z "foo"#
234 = Just (tick Str_FoldrStr `thenSmpl_`
235 returnSmpl (mkGenApp (Var unpackCStringFoldrId)
237 ValArg (LitArg (MachStr str_val)):
243 do_fb_red = switchIsSet env SimplDoFoldrBuild
245 arg_list_isStringForm = maybeToBool stringForm
246 stringForm = getStringForm env arg_list
247 (Just str_val) = stringForm
249 arg_list_isBuildForm = maybeToBool buildForm
250 buildForm = getBuildForm env arg_list
253 arg_list_isAugmentForm = maybeToBool augmentForm
254 augmentForm = getAugmentForm env arg_list
255 (Just (g',h)) = augmentForm
257 arg_list_isListForm = maybeToBool listForm
258 listForm = getListForm env arg_list
259 (Just (the_list,the_tl)) = listForm
261 arg_list_isAppendForm = maybeToBool appendForm
262 appendForm = getAppendForm env arg_list
263 (Just (xs,ys)) = appendForm
266 foldr_fun env (TypeArg ty1:TypeArg ty2:ValArg arg_k:rest_args)
267 | doing_inlining && isConsFun env arg_k && not dont_fold_back_append
268 -- foldr (:) z xs = xs ++ z
269 = Just (tick Foldr_Cons `thenSmpl_`
270 newIds [ty2,mkListTy ty1] `thenSmpl` \ [z,x] ->
272 (Lam z (Lam x (mkGenApp
280 | doing_inlining && (isInterestingArg env arg_k
281 || isConsFun env arg_k)
287 -- (a:b) -> f a (h b)
291 -- tick FoldrInline `thenSmpl_`
294 mkListTy ty1, -- b :: [t1]
296 mkListTy ty1, -- x :: t1
297 mkFunTys [mkListTy ty1] ty2,
299 mkFunTys [ty1, ty2] ty2,
303 ] `thenSmpl` \ [a,b,v,x,h,f,z,xs] ->
305 h_rhs = (Lam x (Case (Var x)
307 [(nilDataCon,[],argToExpr (VarArg z)),
308 (consDataCon,[a,b],body)]
310 body = Let (NonRec v (App (Var h) (VarArg b)))
311 (App (App (argToExpr (VarArg f))
317 (Lam f (Lam z (Lam xs
318 (Let (Rec [(h,h_rhs)])
319 (App (Var h) (VarArg xs))))))
320 (ValArg arg_k:rest_args))
323 doing_inlining = switchIsSet env SimplDoInlineFoldrBuild
324 dont_fold_back_append = switchIsSet env SimplDontFoldBackAppend
326 foldr_fun _ _ = Nothing
328 isConsFun :: SimplEnv -> CoreArg -> Bool
329 isConsFun env (VarArg v)
330 = case lookupUnfolding env v of
331 SimpleUnfolding _ (Lam (x,_) (Lam (y,_) (Con con tys [VarArg x',VarArg y']))) _
332 | con == consDataCon && x==x' && y==y'
333 -> ASSERT ( length tys == 1 ) True
335 isConsFun env _ = False
337 isNilForm :: SimplEnv -> CoreArg -> Bool
338 isNilForm env (VarArg v)
339 = case lookupUnfolding env v of
340 SimpleUnfolding _ (CoTyApp (Var id) _) _ | id == nilDataCon -> True
341 SimpleUnfolding _ (Lit (NoRepStr s)) _ | _NULL_ s -> True
343 isNilForm env _ = False
345 getBuildForm :: SimplEnv -> CoreArg -> Maybe Id
346 getBuildForm env (VarArg v)
347 = case lookupUnfolding env v of
348 SimpleUnfolding False _ _ _ -> Nothing
349 -- not allowed to inline :-(
350 SimpleUnfolding _ (App (CoTyApp (Var bld) _) (VarArg g)) _
351 | bld == buildId -> Just g
352 SimpleUnfolding _ (App (App (CoTyApp (Var bld) _)
354 | bld == augmentId && isNilForm env h -> Just g
356 getBuildForm env _ = Nothing
360 getAugmentForm :: SimplEnv -> CoreArg -> Maybe (Id,CoreArg)
361 getAugmentForm env (VarArg v)
362 = case lookupUnfolding env v of
363 SimpleUnfolding False _ _ _ -> Nothing
364 -- not allowed to inline :-(
365 SimpleUnfolding _ (App (App (CoTyApp (Var bld) _)
367 | bld == augmentId -> Just (g,h)
369 getAugmentForm env _ = Nothing
371 getStringForm :: SimplEnv -> CoreArg -> Maybe FAST_STRING
372 getStringForm env (LitArg (NoRepStr str)) = Just str
373 getStringForm env _ = Nothing
376 getAppendForm :: SimplEnv -> CoreArg -> Maybe (GenCoreAtom Id,GenCoreAtom Id)
377 getAppendForm env (VarArg v) =
378 case lookupUnfolding env v of
379 SimpleUnfolding False _ _ _ -> Nothing -- not allowed to inline :-(
380 SimpleUnfolding _ (App (App (App (CoTyApp (CoTyApp (Var fld) _) _) con) ys) xs) _
381 | fld == foldrId && isConsFun env con -> Just (xs,ys)
383 getAppendForm env _ = Nothing
387 -- this gets a list of the form a : b : c : d and returns ([a,b,c],d)
388 -- it natuarally follows that [a,b,c] => ([a,b,c],e), where e = []
394 -> Maybe ([CoreArg],CoreArg)
395 getListForm env (VarArg v)
396 = case lookupUnfolding env v of
397 SimpleUnfolding _ (Con id [ty_arg,head,tail]) _
398 | id == consDataCon ->
399 case getListForm env tail of
400 Nothing -> Just ([head],tail)
401 Just (lst,new_tail) -> Just (head:lst,new_tail)
403 getListForm env _ = Nothing
405 isInterestingArg :: SimplEnv -> CoreArg -> Bool
406 isInterestingArg env (VarArg v)
407 = case lookupUnfolding env v of
408 SimpleUnfolding False _ _ UnfoldNever -> False
409 SimpleUnfolding _ exp guide -> True
411 isInterestingArg env _ = False
413 foldl_fun env (TypeArg ty1:TypeArg ty2:ValArg arg_k:ValArg arg_z:ValArg arg_list:rest_args)
414 | do_fb_red && isNilForm env arg_list
416 -- again another short cut, helps with unroling of constant lists
417 = Just (tick Foldl_Nil `thenSmpl_`
418 returnSmpl (argToExpr arg_z)
421 | do_fb_red && arg_list_isBuildForm
422 -- foldl t1 t2 k z (build t3 g) ==>
423 -- let c {- INLINE -} = \ b g' a -> g' (f a b)
424 -- n {- INLINE -} = \ a -> a
426 -- this next line *is* the foldr/build rule proper.
427 = Just(tick FoldlBuild `thenSmpl_`
428 -- c :: t2 -> (t1 -> t1) -> t1 -> t1
431 {- pre_c -} mkFunTys [ty2, mkFunTys [ty1] ty1, ty1] ty1,
432 {- pre_n -} mkFunTys [ty1] ty1,
434 {- g' -} mkFunTys [ty1] ty1,
438 ] `thenSmpl` \ [pre_c,
447 c = addInlinePragma pre_c
448 c_rhs = Lam b (Lam g' (Lam a
449 (Let (NonRec t (App (App (argToExpr arg_k) (VarArg a)) (VarArg b)))
450 (App (Var g') (VarArg t)))))
451 n = addInlinePragma pre_n
452 n_rhs = Lam a' (Var a')
454 returnSmpl (Let (NonRec c c_rhs) $
455 Let (NonRec n n_rhs) $
457 (TypeArg (mkFunTys [ty1] ty1):ValArg (VarArg c):ValArg (VarArg n)
458 :ValArg arg_z:rest_args))
461 | do_fb_red && arg_list_isAugmentForm
462 -- foldl t1 t2 k z (augment t3 g h) ==>
463 -- let c {- INLINE -} = \ b g' a -> g' (f a b)
464 -- n {- INLINE -} = \ a -> a
465 -- r {- INLINE -} = foldr t2 (t1 -> t1) c n h
467 -- this next line *is* the foldr/build rule proper.
468 = Just (tick FoldlAugment `thenSmpl_`
469 -- c :: t2 -> (t1 -> t1) -> t1 -> t1
472 {- pre_c -} mkFunTys [ty2, mkFunTys [ty1] ty1, ty1] ty1,
473 {- pre_n -} mkFunTys [ty1] ty1,
474 {- pre_r -} mkFunTys [ty1] ty1,
476 {- g_ -} mkFunTys [ty1] ty1,
480 ] `thenSmpl` \ [pre_c,
490 c = addInlinePragma pre_c
491 c_rhs = Lam b (Lam g_ (Lam a
492 (Let (NonRec t (App (App (argToExpr arg_k) (VarArg a)) (VarArg b)))
493 (App (Var g_) (VarArg t)))))
494 n = addInlinePragma pre_n
495 n_rhs = Lam a' (Var a')
496 r = addInlinePragma pre_r
497 r_rhs = mkGenApp (Var foldrId)
498 [TypeArg ty2,TypeArg (mkFunTys [ty1] ty1),
503 returnSmpl (Let (NonRec c c_rhs) $
504 Let (NonRec n n_rhs) $
505 Let (NonRec r r_rhs) $
507 (TypeArg (mkFunTys [ty1] ty1):ValArg (VarArg c):ValArg (VarArg r)
508 :ValArg arg_z:rest_args))
511 | do_fb_red && arg_list_isListForm
512 -- foldl k z (a:b:c:rest) =
513 -- (\ f -> foldl f (f (f (f z a) b) c) rest) k rest_args
514 -- NB: 'k' is used just one by foldr, but 'f' is used many
515 -- times inside the list structure. This means that
516 -- 'f' needs to be inside a lambda, to make sure the simplifier
520 -- foldl f (f (f (f z a) b) c) rest
521 -- f a (f b (f c (foldr f z rest)))
526 -- in foldl f ele_3 rest
528 = Just (tick Foldl_List `thenSmpl_`
530 mkFunTys [ty1, ty2] ty1 :
531 nOfThem (length the_list) ty1
532 ) `thenSmpl` \ (f_id:ele_ids) ->
534 rest_binds = zipWith3Equal "foldl:rest_binds"
535 (\ e v e' -> NonRec e (mkRhs v e'))
537 the_list -- :: [CoreArg]
538 (init (arg_z:map VarArg ele_ids)) -- :: [CoreArg]
539 mkRhs v e = App (App (Var f_id) e) v
541 last_bind = mkGenApp (Var foldlId)
542 [TypeArg ty1,TypeArg ty2,
543 ValArg (VarArg f_id),
544 ValArg (VarArg (last ele_ids)),
551 returnSmpl (mkGenApp (Lam f_id core_list)
552 (ValArg arg_k:rest_args))
556 do_fb_red = switchIsSet env SimplDoFoldrBuild
558 arg_list_isAugmentForm = maybeToBool augmentForm
559 augmentForm = getAugmentForm env arg_list
560 (Just (g',h)) = augmentForm
562 arg_list_isBuildForm = maybeToBool buildForm
563 buildForm = getBuildForm env arg_list
566 arg_list_isListForm = maybeToBool listForm
567 listForm = getListForm env arg_list
568 (Just (the_list,the_tl)) = listForm
571 arg_list_isAppendForm = maybeToBool appendForm
572 appendForm = getAppendForm env arg_list
573 (Just (xs,ys)) = appendForm
576 foldl_fun env (TypeArg ty1:TypeArg ty2:ValArg arg_k:rest_args)
577 | doing_inlining && (isInterestingArg env arg_k
578 || isConsFun env arg_k)
584 -- (a:b) -> h b (f r a)
589 -- tick FoldrInline `thenSmpl_`
592 mkListTy ty2, -- b :: [t1]
594 mkListTy ty2, -- x :: t1
595 mkFunTys [mkListTy ty2, ty1] ty1,
596 -- h :: [t2] -> t1 -> t1
597 mkFunTys [ty1, ty2] ty1,
602 ] `thenSmpl` \ [a,b,v,x,h,f,z,xs,r] ->
604 h_rhs = (Lam x (Lam r (Case (Var x))
606 [(nilDataCon,[],argToExpr (VarArg r)),
607 (consDataCon,[a,b],body)]
609 body = Let (NonRec v (App (App (Var f) (VarArg r))
611 (App (App (argToExpr (VarArg h))
617 (Lam f (Lam z (Lam xs
618 (Let (Rec [(h,h_rhs)])
619 (App (App (Var h) (VarArg xs))
621 (ValArg arg_k:rest_args))
624 doing_inlining = switchIsSet env SimplDoInlineFoldrBuild
626 foldl_fun env _ = Nothing
632 -- Foldr unpackFoldr "str"# (:) stuff ==> unpackAppend "str"#
634 unpack_foldr_fun env [TypeArg ty,ValArg str,ValArg arg_k,ValArg arg_z]
635 | switchIsSet env SimplDoFoldrBuild && isConsFun env arg_k
636 = Just (tick Str_UnpackCons `thenSmpl_`
637 returnSmpl (mkGenApp (Var unpackCStringAppendId)
641 unpack_foldr_fun env _ = Nothing
643 unpack_append_fun env
644 [ValArg (LitArg (MachStr str_val)),ValArg arg_z]
645 | switchIsSet env SimplDoFoldrBuild && isNilForm env arg_z
646 = Just (tick Str_UnpackNil `thenSmpl_`
647 returnSmpl (Lit (NoRepStr str_val))
649 unpack_append_fun env _ = Nothing