2 % (c) The GRASP/AQUA Project, Glasgow University, 1993-1998
4 \section[MagicUFs]{Magic unfoldings that the simplifier knows about}
8 MagicUnfoldingFun, -- absolutely abstract
11 applyMagicUnfoldingFun
14 #include "HsVersions.h"
17 import SimplMonad ( SimplM, SimplCont )
18 import Type ( mkFunTys )
19 import TysWiredIn ( mkListTy )
20 import Unique ( Unique{-instances-} )
21 import Util ( assoc, zipWith3Equal, nOfThem )
22 import Panic ( panic )
25 %************************************************************************
27 \subsection{Types, etc., for magic-unfolding functions}
29 %************************************************************************
32 data MagicUnfoldingFun
33 = MUF ( SimplCont -> Maybe (SimplM CoreExpr))
34 -- Just result, or Nothing
37 Give us a value's @Unique@, we'll give you back the corresponding MUF.
39 mkMagicUnfoldingFun :: Unique -> MagicUnfoldingFun
41 mkMagicUnfoldingFun tag
42 = assoc "mkMagicUnfoldingFun" magic_UFs_table tag
44 magic_UFs_table = panic "MagicUFs.magic_UFs_table:ToDo"
47 Give us an MUF and stuff to apply it to, and we'll give you back the answer.
50 applyMagicUnfoldingFun
53 -> Maybe (SimplM CoreExpr)
55 applyMagicUnfoldingFun (MUF fun) cont = fun cont
58 %************************************************************************
60 \subsection{The table of actual magic unfoldings}
62 %************************************************************************
67 magic_UFs_table :: [(FAST_STRING, MagicUnfoldingFun)]
70 = [(SLIT("augment"), MUF augment_fun),
71 (SLIT("build"), MUF build_fun),
72 (SLIT("foldl"), MUF foldl_fun),
73 (SLIT("foldr"), MUF foldr_fun),
74 (SLIT("unpackFoldrPS__"), MUF unpack_foldr_fun),
75 (SLIT("unpackAppendPS__"), MUF unpack_append_fun)]
78 %************************************************************************
80 \subsubsection{Unfolding function for @append@}
82 %************************************************************************
85 -- First build, the way we express our lists.
89 -> Maybe (SimplM CoreExpr)
90 build_fun env [TypeArg ty,ValArg (VarArg e)]
91 | switchIsSet env SimplDoInlineFoldrBuild
95 ourCons = CoTyApp (Var consDataCon) ty
96 ourNil = CoTyApp (Var nilDataCon) ty
98 result = newIds [ mkFunTys [ty, tyL] tyL, tyL ] `thenSmpl` \ [c,n] ->
99 returnSmpl(Let (NonRec c ourCons)
100 (Let (NonRec n ourNil)
101 (App (App (CoTyApp (Var e) tyL) (VarArg c)) (VarArg n)))
103 -- ToDo: add `build' without an argument instance.
104 -- This is strange, because of g's type.
105 build_fun env _ = ASSERT (not (switchIsSet env SimplDoInlineFoldrBuild))
110 augment_fun :: SimplEnv
112 -> Maybe (SimplM CoreExpr)
114 augment_fun env [TypeArg ty,ValArg (VarArg e),ValArg nil]
115 | switchIsSet env SimplDoInlineFoldrBuild
119 ourCons = CoTyApp (Var consDataCon) ty
120 result = newId (mkFunTys [ty, tyL] tyL) `thenSmpl` \ c ->
121 returnSmpl (Let (NonRec c ourCons)
122 (App (App (CoTyApp (Var e) tyL) (VarArg c)) nil))
123 -- ToDo: add `build' without an argument instance.
124 -- This is strange, because of g's type.
126 augment_fun env _ = ASSERT (not (switchIsSet env SimplDoInlineFoldrBuild))
130 Now foldr, the way we consume lists.
133 foldr_fun :: SimplEnv
135 -> Maybe (SimplM CoreExpr)
137 foldr_fun env (TypeArg ty1:TypeArg ty2:ValArg arg_k:ValArg arg_z:rest_args)
138 | do_fb_red && isConsFun env arg_k && isNilForm env arg_z
139 -- foldr (:) [] ==> id
140 -- this transformation is *always* benificial
141 -- cf. foldr (:) [] (build g) == g (:) []
142 -- with foldr (:) [] (build g) == build g
143 -- after unfolding build, they are the same thing.
144 = Just (tick Foldr_Cons_Nil `thenSmpl_`
145 newId (mkListTy ty1) `thenSmpl` \ x ->
146 returnSmpl({-trace "foldr (:) []"-} (mkGenApp (Lam x (Var x)) rest_args))
149 do_fb_red = switchIsSet env SimplDoFoldrBuild
151 foldr_fun env (TypeArg ty1:TypeArg ty2:ValArg arg_k:ValArg arg_z:ValArg arg_list:rest_args)
152 | do_fb_red && isNilForm env arg_list
154 -- again another short cut, helps with unroling of constant lists
155 = Just (tick Foldr_Nil `thenSmpl_`
156 returnSmpl (argToExpr arg_z)
159 | do_fb_red && arg_list_isBuildForm
160 -- foldr k z (build g) ==> g k z
161 -- this next line *is* the foldr/build rule proper.
162 = Just (tick FoldrBuild `thenSmpl_`
163 returnSmpl (mkGenApp (Var g) (TypeArg ty2:ValArg arg_k:ValArg arg_z:rest_args))
166 | do_fb_red && arg_list_isAugmentForm
167 -- foldr k z (augment g h) ==> let v = foldr k z h in g k v
168 -- this next line *is* the foldr/augment rule proper.
169 = Just (tick FoldrAugment `thenSmpl_`
170 newId ty2 `thenSmpl` \ v ->
172 Let (NonRec v (mkGenApp (Var foldrId)
173 [TypeArg ty1,TypeArg ty2,
177 (mkGenApp (Var g') (TypeArg ty2:ValArg arg_k:ValArg (VarArg v):rest_args)))
180 | do_fb_red && arg_list_isListForm
181 -- foldr k z (a:b:c:rest) =
182 -- (\ f -> f a (f b (f c (foldr f z rest)))) k rest_args
183 -- NB: 'k' is used just one by foldr, but 'f' is used many
184 -- times inside the list structure. This means that
185 -- 'f' needs to be inside a lambda, to make sure the simplifier
189 -- f a (f b (f c (foldr f z rest)))
191 -- let ele_1 = foldr f z rest
196 = Just (tick Foldr_List `thenSmpl_`
198 mkFunTys [ty1, ty2] ty2 :
199 nOfThem (length the_list) ty2
200 ) `thenSmpl` \ (f_id:ele_id1:ele_ids) ->
204 (mkGenApp (Var foldrId)
205 [TypeArg ty1,TypeArg ty2,
206 ValArg (VarArg f_id),
209 rest_binds = zipWith3Equal "Foldr:rest_binds"
210 (\ e v e' -> NonRec e (mkRhs v e'))
212 (reverse (tail the_list))
213 (init (ele_id1:ele_ids))
214 mkRhs v e = App (App (Var f_id) v) (VarArg e)
217 (mkRhs (head the_list) (last (ele_id1:ele_ids)))
218 (fst_bind:rest_binds)
220 returnSmpl (mkGenApp (Lam f_id core_list) (ValArg arg_k:rest_args))
226 | do_fb_red && arg_list_isStringForm -- ok, its a string!
227 -- foldr f z "foo" => unpackFoldrPS__ f z "foo"#
228 = Just (tick Str_FoldrStr `thenSmpl_`
229 returnSmpl (mkGenApp (Var unpackCStringFoldrId)
231 ValArg (LitArg (MachStr str_val)):
237 do_fb_red = switchIsSet env SimplDoFoldrBuild
239 arg_list_isStringForm = maybeToBool stringForm
240 stringForm = getStringForm env arg_list
241 (Just str_val) = stringForm
243 arg_list_isBuildForm = maybeToBool buildForm
244 buildForm = getBuildForm env arg_list
247 arg_list_isAugmentForm = maybeToBool augmentForm
248 augmentForm = getAugmentForm env arg_list
249 (Just (g',h)) = augmentForm
251 arg_list_isListForm = maybeToBool listForm
252 listForm = getListForm env arg_list
253 (Just (the_list,the_tl)) = listForm
255 arg_list_isAppendForm = maybeToBool appendForm
256 appendForm = getAppendForm env arg_list
257 (Just (xs,ys)) = appendForm
260 foldr_fun env (TypeArg ty1:TypeArg ty2:ValArg arg_k:rest_args)
261 | doing_inlining && isConsFun env arg_k && not dont_fold_back_append
262 -- foldr (:) z xs = xs ++ z
263 = Just (tick Foldr_Cons `thenSmpl_`
264 newIds [ty2,mkListTy ty1] `thenSmpl` \ [z,x] ->
266 (Lam z (Lam x (mkGenApp
274 | doing_inlining && (isInterestingArg env arg_k
275 || isConsFun env arg_k)
281 -- (a:b) -> f a (h b)
285 -- tick FoldrInline `thenSmpl_`
288 mkListTy ty1, -- b :: [t1]
290 mkListTy ty1, -- x :: t1
291 mkFunTys [mkListTy ty1] ty2,
293 mkFunTys [ty1, ty2] ty2,
297 ] `thenSmpl` \ [a,b,v,x,h,f,z,xs] ->
299 h_rhs = (Lam x (Case (Var x)
301 [(nilDataCon,[],argToExpr (VarArg z)),
302 (consDataCon,[a,b],body)]
304 body = Let (NonRec v (App (Var h) (VarArg b)))
305 (App (App (argToExpr (VarArg f))
311 (Lam f (Lam z (Lam xs
312 (Let (Rec [(h,h_rhs)])
313 (App (Var h) (VarArg xs))))))
314 (ValArg arg_k:rest_args))
317 doing_inlining = switchIsSet env SimplDoInlineFoldrBuild
318 dont_fold_back_append = switchIsSet env SimplDontFoldBackAppend
320 foldr_fun _ _ = Nothing
322 isConsFun :: SimplEnv -> CoreArg -> Bool
323 isConsFun env (VarArg v)
324 = case lookupUnfolding env v of
325 SimpleUnfolding _ (Lam (x,_) (Lam (y,_) (Con con tys [VarArg x',VarArg y']))) _
326 | con == consDataCon && x==x' && y==y'
327 -> ASSERT ( length tys == 1 ) True
329 isConsFun env _ = False
331 isNilForm :: SimplEnv -> CoreArg -> Bool
332 isNilForm env (VarArg v)
333 = case lookupUnfolding env v of
334 SimpleUnfolding _ (CoTyApp (Var id) _) _ | id == nilDataCon -> True
335 SimpleUnfolding _ (Lit (NoRepStr s)) _ | _NULL_ s -> True
337 isNilForm env _ = False
339 getBuildForm :: SimplEnv -> CoreArg -> Maybe Id
340 getBuildForm env (VarArg v)
341 = case lookupUnfolding env v of
342 SimpleUnfolding False _ _ _ -> Nothing
343 -- not allowed to inline :-(
344 SimpleUnfolding _ (App (CoTyApp (Var bld) _) (VarArg g)) _
345 | bld == buildId -> Just g
346 SimpleUnfolding _ (App (App (CoTyApp (Var bld) _)
348 | bld == augmentId && isNilForm env h -> Just g
350 getBuildForm env _ = Nothing
354 getAugmentForm :: SimplEnv -> CoreArg -> Maybe (Id,CoreArg)
355 getAugmentForm env (VarArg v)
356 = case lookupUnfolding env v of
357 SimpleUnfolding False _ _ _ -> Nothing
358 -- not allowed to inline :-(
359 SimpleUnfolding _ (App (App (CoTyApp (Var bld) _)
361 | bld == augmentId -> Just (g,h)
363 getAugmentForm env _ = Nothing
365 getStringForm :: SimplEnv -> CoreArg -> Maybe FAST_STRING
366 getStringForm env (LitArg (NoRepStr str)) = Just str
367 getStringForm env _ = Nothing
370 getAppendForm :: SimplEnv -> CoreArg -> Maybe (GenCoreAtom Id,GenCoreAtom Id)
371 getAppendForm env (VarArg v) =
372 case lookupUnfolding env v of
373 SimpleUnfolding False _ _ _ -> Nothing -- not allowed to inline :-(
374 SimpleUnfolding _ (App (App (App (CoTyApp (CoTyApp (Var fld) _) _) con) ys) xs) _
375 | fld == foldrId && isConsFun env con -> Just (xs,ys)
377 getAppendForm env _ = Nothing
381 -- this gets a list of the form a : b : c : d and returns ([a,b,c],d)
382 -- it natuarally follows that [a,b,c] => ([a,b,c],e), where e = []
388 -> Maybe ([CoreArg],CoreArg)
389 getListForm env (VarArg v)
390 = case lookupUnfolding env v of
391 SimpleUnfolding _ (Con id [ty_arg,head,tail]) _
392 | id == consDataCon ->
393 case getListForm env tail of
394 Nothing -> Just ([head],tail)
395 Just (lst,new_tail) -> Just (head:lst,new_tail)
397 getListForm env _ = Nothing
399 isInterestingArg :: SimplEnv -> CoreArg -> Bool
400 isInterestingArg env (VarArg v)
401 = case lookupUnfolding env v of
402 SimpleUnfolding False _ _ UnfoldNever -> False
403 SimpleUnfolding _ exp guide -> True
405 isInterestingArg env _ = False
407 foldl_fun env (TypeArg ty1:TypeArg ty2:ValArg arg_k:ValArg arg_z:ValArg arg_list:rest_args)
408 | do_fb_red && isNilForm env arg_list
410 -- again another short cut, helps with unroling of constant lists
411 = Just (tick Foldl_Nil `thenSmpl_`
412 returnSmpl (argToExpr arg_z)
415 | do_fb_red && arg_list_isBuildForm
416 -- foldl t1 t2 k z (build t3 g) ==>
417 -- let c {- INLINE -} = \ b g' a -> g' (f a b)
418 -- n {- INLINE -} = \ a -> a
420 -- this next line *is* the foldr/build rule proper.
421 = Just(tick FoldlBuild `thenSmpl_`
422 -- c :: t2 -> (t1 -> t1) -> t1 -> t1
425 {- pre_c -} mkFunTys [ty2, mkFunTys [ty1] ty1, ty1] ty1,
426 {- pre_n -} mkFunTys [ty1] ty1,
428 {- g' -} mkFunTys [ty1] ty1,
432 ] `thenSmpl` \ [pre_c,
441 c = addInlinePragma pre_c
442 c_rhs = Lam b (Lam g' (Lam a
443 (Let (NonRec t (App (App (argToExpr arg_k) (VarArg a)) (VarArg b)))
444 (App (Var g') (VarArg t)))))
445 n = addInlinePragma pre_n
446 n_rhs = Lam a' (Var a')
448 returnSmpl (Let (NonRec c c_rhs) $
449 Let (NonRec n n_rhs) $
451 (TypeArg (mkFunTys [ty1] ty1):ValArg (VarArg c):ValArg (VarArg n)
452 :ValArg arg_z:rest_args))
455 | do_fb_red && arg_list_isAugmentForm
456 -- foldl t1 t2 k z (augment t3 g h) ==>
457 -- let c {- INLINE -} = \ b g' a -> g' (f a b)
458 -- n {- INLINE -} = \ a -> a
459 -- r {- INLINE -} = foldr t2 (t1 -> t1) c n h
461 -- this next line *is* the foldr/build rule proper.
462 = Just (tick FoldlAugment `thenSmpl_`
463 -- c :: t2 -> (t1 -> t1) -> t1 -> t1
466 {- pre_c -} mkFunTys [ty2, mkFunTys [ty1] ty1, ty1] ty1,
467 {- pre_n -} mkFunTys [ty1] ty1,
468 {- pre_r -} mkFunTys [ty1] ty1,
470 {- g_ -} mkFunTys [ty1] ty1,
474 ] `thenSmpl` \ [pre_c,
484 c = addInlinePragma pre_c
485 c_rhs = Lam b (Lam g_ (Lam a
486 (Let (NonRec t (App (App (argToExpr arg_k) (VarArg a)) (VarArg b)))
487 (App (Var g_) (VarArg t)))))
488 n = addInlinePragma pre_n
489 n_rhs = Lam a' (Var a')
490 r = addInlinePragma pre_r
491 r_rhs = mkGenApp (Var foldrId)
492 [TypeArg ty2,TypeArg (mkFunTys [ty1] ty1),
497 returnSmpl (Let (NonRec c c_rhs) $
498 Let (NonRec n n_rhs) $
499 Let (NonRec r r_rhs) $
501 (TypeArg (mkFunTys [ty1] ty1):ValArg (VarArg c):ValArg (VarArg r)
502 :ValArg arg_z:rest_args))
505 | do_fb_red && arg_list_isListForm
506 -- foldl k z (a:b:c:rest) =
507 -- (\ f -> foldl f (f (f (f z a) b) c) rest) k rest_args
508 -- NB: 'k' is used just one by foldr, but 'f' is used many
509 -- times inside the list structure. This means that
510 -- 'f' needs to be inside a lambda, to make sure the simplifier
514 -- foldl f (f (f (f z a) b) c) rest
515 -- f a (f b (f c (foldr f z rest)))
520 -- in foldl f ele_3 rest
522 = Just (tick Foldl_List `thenSmpl_`
524 mkFunTys [ty1, ty2] ty1 :
525 nOfThem (length the_list) ty1
526 ) `thenSmpl` \ (f_id:ele_ids) ->
528 rest_binds = zipWith3Equal "foldl:rest_binds"
529 (\ e v e' -> NonRec e (mkRhs v e'))
531 the_list -- :: [CoreArg]
532 (init (arg_z:map VarArg ele_ids)) -- :: [CoreArg]
533 mkRhs v e = App (App (Var f_id) e) v
535 last_bind = mkGenApp (Var foldlId)
536 [TypeArg ty1,TypeArg ty2,
537 ValArg (VarArg f_id),
538 ValArg (VarArg (last ele_ids)),
545 returnSmpl (mkGenApp (Lam f_id core_list)
546 (ValArg arg_k:rest_args))
550 do_fb_red = switchIsSet env SimplDoFoldrBuild
552 arg_list_isAugmentForm = maybeToBool augmentForm
553 augmentForm = getAugmentForm env arg_list
554 (Just (g',h)) = augmentForm
556 arg_list_isBuildForm = maybeToBool buildForm
557 buildForm = getBuildForm env arg_list
560 arg_list_isListForm = maybeToBool listForm
561 listForm = getListForm env arg_list
562 (Just (the_list,the_tl)) = listForm
565 arg_list_isAppendForm = maybeToBool appendForm
566 appendForm = getAppendForm env arg_list
567 (Just (xs,ys)) = appendForm
570 foldl_fun env (TypeArg ty1:TypeArg ty2:ValArg arg_k:rest_args)
571 | doing_inlining && (isInterestingArg env arg_k
572 || isConsFun env arg_k)
578 -- (a:b) -> h b (f r a)
583 -- tick FoldrInline `thenSmpl_`
586 mkListTy ty2, -- b :: [t1]
588 mkListTy ty2, -- x :: t1
589 mkFunTys [mkListTy ty2, ty1] ty1,
590 -- h :: [t2] -> t1 -> t1
591 mkFunTys [ty1, ty2] ty1,
596 ] `thenSmpl` \ [a,b,v,x,h,f,z,xs,r] ->
598 h_rhs = (Lam x (Lam r (Case (Var x))
600 [(nilDataCon,[],argToExpr (VarArg r)),
601 (consDataCon,[a,b],body)]
603 body = Let (NonRec v (App (App (Var f) (VarArg r))
605 (App (App (argToExpr (VarArg h))
611 (Lam f (Lam z (Lam xs
612 (Let (Rec [(h,h_rhs)])
613 (App (App (Var h) (VarArg xs))
615 (ValArg arg_k:rest_args))
618 doing_inlining = switchIsSet env SimplDoInlineFoldrBuild
620 foldl_fun env _ = Nothing
626 -- Foldr unpackFoldr "str"# (:) stuff ==> unpackAppend "str"#
628 unpack_foldr_fun env [TypeArg ty,ValArg str,ValArg arg_k,ValArg arg_z]
629 | switchIsSet env SimplDoFoldrBuild && isConsFun env arg_k
630 = Just (tick Str_UnpackCons `thenSmpl_`
631 returnSmpl (mkGenApp (Var unpackCStringAppendId)
635 unpack_foldr_fun env _ = Nothing
637 unpack_append_fun env
638 [ValArg (LitArg (MachStr str_val)),ValArg arg_z]
639 | switchIsSet env SimplDoFoldrBuild && isNilForm env arg_z
640 = Just (tick Str_UnpackNil `thenSmpl_`
641 returnSmpl (Lit (NoRepStr str_val))
643 unpack_append_fun env _ = Nothing