2 % (c) The GRASP/AQUA Project, Glasgow University, 1993-1996
4 \section[MagicUFs]{Magic unfoldings that the simplifier knows about}
7 #include "HsVersions.h"
10 MagicUnfoldingFun, -- absolutely abstract
13 applyMagicUnfoldingFun
17 #if defined(__GLASGOW_HASKELL__) && __GLASGOW_HASKELL__ <= 201
18 IMPORT_DELOOPER(IdLoop) -- paranoia checking
21 import Id ( addInlinePragma )
23 import SimplEnv ( SimplEnv )
24 import SimplMonad ( SYN_IE(SmplM), SimplCount )
25 import Type ( mkFunTys )
26 import TysWiredIn ( mkListTy )
27 import Unique ( Unique{-instances-} )
28 import Util ( assoc, zipWith3Equal, nOfThem, panic )
31 %************************************************************************
33 \subsection{Types, etc., for magic-unfolding functions}
35 %************************************************************************
38 data MagicUnfoldingFun
39 = MUF ( SimplEnv -- state of play in simplifier...
40 -- (note: we can get simplifier switches
42 -> [CoreArg] -- arguments
43 -> Maybe (SmplM CoreExpr))
44 -- Just result, or Nothing
47 Give us a value's @Unique@, we'll give you back the corresponding MUF.
49 mkMagicUnfoldingFun :: Unique -> MagicUnfoldingFun
51 mkMagicUnfoldingFun tag
52 = assoc "mkMagicUnfoldingFun" magic_UFs_table tag
54 magic_UFs_table = panic "MagicUFs.magic_UFs_table:ToDo"
57 Give us an MUF and stuff to apply it to, and we'll give you back the
60 applyMagicUnfoldingFun
64 -> Maybe (SmplM CoreExpr)
66 applyMagicUnfoldingFun (MUF fun) env args = fun env args
69 %************************************************************************
71 \subsection{The table of actual magic unfoldings}
73 %************************************************************************
78 magic_UFs_table :: [(FAST_STRING, MagicUnfoldingFun)]
81 = [(SLIT("augment"), MUF augment_fun),
82 (SLIT("build"), MUF build_fun),
83 (SLIT("foldl"), MUF foldl_fun),
84 (SLIT("foldr"), MUF foldr_fun),
85 (SLIT("unpackFoldrPS__"), MUF unpack_foldr_fun),
86 (SLIT("unpackAppendPS__"), MUF unpack_append_fun)]
89 %************************************************************************
91 \subsubsection{Unfolding function for @append@}
93 %************************************************************************
96 -- First build, the way we express our lists.
100 -> Maybe (SmplM CoreExpr)
101 build_fun env [TypeArg ty,ValArg (VarArg e)]
102 | switchIsSet env SimplDoInlineFoldrBuild
106 ourCons = CoTyApp (Var consDataCon) ty
107 ourNil = CoTyApp (Var nilDataCon) ty
109 result = newIds [ mkFunTys [ty, tyL] tyL, tyL ] `thenSmpl` \ [c,n] ->
110 returnSmpl(Let (NonRec c ourCons)
111 (Let (NonRec n ourNil)
112 (App (App (CoTyApp (Var e) tyL) (VarArg c)) (VarArg n)))
114 -- ToDo: add `build' without an argument instance.
115 -- This is strange, because of g's type.
116 build_fun env _ = ASSERT (not (switchIsSet env SimplDoInlineFoldrBuild))
121 augment_fun :: SimplEnv
123 -> Maybe (SmplM CoreExpr)
125 augment_fun env [TypeArg ty,ValArg (VarArg e),ValArg nil]
126 | switchIsSet env SimplDoInlineFoldrBuild
130 ourCons = CoTyApp (Var consDataCon) ty
131 result = newId (mkFunTys [ty, tyL] tyL) `thenSmpl` \ c ->
132 returnSmpl (Let (NonRec c ourCons)
133 (App (App (CoTyApp (Var e) tyL) (VarArg c)) nil))
134 -- ToDo: add `build' without an argument instance.
135 -- This is strange, because of g's type.
137 augment_fun env _ = ASSERT (not (switchIsSet env SimplDoInlineFoldrBuild))
141 Now foldr, the way we consume lists.
144 foldr_fun :: SimplEnv
146 -> Maybe (SmplM CoreExpr)
148 foldr_fun env (TypeArg ty1:TypeArg ty2:ValArg arg_k:ValArg arg_z:rest_args)
149 | do_fb_red && isConsFun env arg_k && isNilForm env arg_z
150 -- foldr (:) [] ==> id
151 -- this transformation is *always* benificial
152 -- cf. foldr (:) [] (build g) == g (:) []
153 -- with foldr (:) [] (build g) == build g
154 -- after unfolding build, they are the same thing.
155 = Just (tick Foldr_Cons_Nil `thenSmpl_`
156 newId (mkListTy ty1) `thenSmpl` \ x ->
157 returnSmpl({-trace "foldr (:) []"-} (mkGenApp (Lam x (Var x)) rest_args))
160 do_fb_red = switchIsSet env SimplDoFoldrBuild
162 foldr_fun env (TypeArg ty1:TypeArg ty2:ValArg arg_k:ValArg arg_z:ValArg arg_list:rest_args)
163 | do_fb_red && isNilForm env arg_list
165 -- again another short cut, helps with unroling of constant lists
166 = Just (tick Foldr_Nil `thenSmpl_`
167 returnSmpl (argToExpr arg_z)
170 | do_fb_red && arg_list_isBuildForm
171 -- foldr k z (build g) ==> g k z
172 -- this next line *is* the foldr/build rule proper.
173 = Just (tick FoldrBuild `thenSmpl_`
174 returnSmpl (mkGenApp (Var g) (TypeArg ty2:ValArg arg_k:ValArg arg_z:rest_args))
177 | do_fb_red && arg_list_isAugmentForm
178 -- foldr k z (augment g h) ==> let v = foldr k z h in g k v
179 -- this next line *is* the foldr/augment rule proper.
180 = Just (tick FoldrAugment `thenSmpl_`
181 newId ty2 `thenSmpl` \ v ->
183 Let (NonRec v (mkGenApp (Var foldrId)
184 [TypeArg ty1,TypeArg ty2,
188 (mkGenApp (Var g') (TypeArg ty2:ValArg arg_k:ValArg (VarArg v):rest_args)))
191 | do_fb_red && arg_list_isListForm
192 -- foldr k z (a:b:c:rest) =
193 -- (\ f -> f a (f b (f c (foldr f z rest)))) k rest_args
194 -- NB: 'k' is used just one by foldr, but 'f' is used many
195 -- times inside the list structure. This means that
196 -- 'f' needs to be inside a lambda, to make sure the simplifier
200 -- f a (f b (f c (foldr f z rest)))
202 -- let ele_1 = foldr f z rest
207 = Just (tick Foldr_List `thenSmpl_`
209 mkFunTys [ty1, ty2] ty2 :
210 nOfThem (length the_list) ty2
211 ) `thenSmpl` \ (f_id:ele_id1:ele_ids) ->
215 (mkGenApp (Var foldrId)
216 [TypeArg ty1,TypeArg ty2,
217 ValArg (VarArg f_id),
220 rest_binds = zipWith3Equal "Foldr:rest_binds"
221 (\ e v e' -> NonRec e (mkRhs v e'))
223 (reverse (tail the_list))
224 (init (ele_id1:ele_ids))
225 mkRhs v e = App (App (Var f_id) v) (VarArg e)
228 (mkRhs (head the_list) (last (ele_id1:ele_ids)))
229 (fst_bind:rest_binds)
231 returnSmpl (mkGenApp (Lam f_id core_list) (ValArg arg_k:rest_args))
237 | do_fb_red && arg_list_isStringForm -- ok, its a string!
238 -- foldr f z "foo" => unpackFoldrPS__ f z "foo"#
239 = Just (tick Str_FoldrStr `thenSmpl_`
240 returnSmpl (mkGenApp (Var unpackCStringFoldrId)
242 ValArg (LitArg (MachStr str_val)):
248 do_fb_red = switchIsSet env SimplDoFoldrBuild
250 arg_list_isStringForm = maybeToBool stringForm
251 stringForm = getStringForm env arg_list
252 (Just str_val) = stringForm
254 arg_list_isBuildForm = maybeToBool buildForm
255 buildForm = getBuildForm env arg_list
258 arg_list_isAugmentForm = maybeToBool augmentForm
259 augmentForm = getAugmentForm env arg_list
260 (Just (g',h)) = augmentForm
262 arg_list_isListForm = maybeToBool listForm
263 listForm = getListForm env arg_list
264 (Just (the_list,the_tl)) = listForm
266 arg_list_isAppendForm = maybeToBool appendForm
267 appendForm = getAppendForm env arg_list
268 (Just (xs,ys)) = appendForm
271 foldr_fun env (TypeArg ty1:TypeArg ty2:ValArg arg_k:rest_args)
272 | doing_inlining && isConsFun env arg_k && not dont_fold_back_append
273 -- foldr (:) z xs = xs ++ z
274 = Just (tick Foldr_Cons `thenSmpl_`
275 newIds [ty2,mkListTy ty1] `thenSmpl` \ [z,x] ->
277 (Lam z (Lam x (mkGenApp
285 | doing_inlining && (isInterestingArg env arg_k
286 || isConsFun env arg_k)
292 -- (a:b) -> f a (h b)
296 -- tick FoldrInline `thenSmpl_`
299 mkListTy ty1, -- b :: [t1]
301 mkListTy ty1, -- x :: t1
302 mkFunTys [mkListTy ty1] ty2,
304 mkFunTys [ty1, ty2] ty2,
308 ] `thenSmpl` \ [a,b,v,x,h,f,z,xs] ->
310 h_rhs = (Lam x (Case (Var x)
312 [(nilDataCon,[],argToExpr (VarArg z)),
313 (consDataCon,[a,b],body)]
315 body = Let (NonRec v (App (Var h) (VarArg b)))
316 (App (App (argToExpr (VarArg f))
322 (Lam f (Lam z (Lam xs
323 (Let (Rec [(h,h_rhs)])
324 (App (Var h) (VarArg xs))))))
325 (ValArg arg_k:rest_args))
328 doing_inlining = switchIsSet env SimplDoInlineFoldrBuild
329 dont_fold_back_append = switchIsSet env SimplDontFoldBackAppend
331 foldr_fun _ _ = Nothing
333 isConsFun :: SimplEnv -> CoreArg -> Bool
334 isConsFun env (VarArg v)
335 = case lookupUnfolding env v of
336 SimpleUnfolding _ (Lam (x,_) (Lam (y,_) (Con con tys [VarArg x',VarArg y']))) _
337 | con == consDataCon && x==x' && y==y'
338 -> ASSERT ( length tys == 1 ) True
340 isConsFun env _ = False
342 isNilForm :: SimplEnv -> CoreArg -> Bool
343 isNilForm env (VarArg v)
344 = case lookupUnfolding env v of
345 SimpleUnfolding _ (CoTyApp (Var id) _) _ | id == nilDataCon -> True
346 SimpleUnfolding _ (Lit (NoRepStr s)) _ | _NULL_ s -> True
348 isNilForm env _ = False
350 getBuildForm :: SimplEnv -> CoreArg -> Maybe Id
351 getBuildForm env (VarArg v)
352 = case lookupUnfolding env v of
353 SimpleUnfolding False _ _ _ -> Nothing
354 -- not allowed to inline :-(
355 SimpleUnfolding _ (App (CoTyApp (Var bld) _) (VarArg g)) _
356 | bld == buildId -> Just g
357 SimpleUnfolding _ (App (App (CoTyApp (Var bld) _)
359 | bld == augmentId && isNilForm env h -> Just g
361 getBuildForm env _ = Nothing
365 getAugmentForm :: SimplEnv -> CoreArg -> Maybe (Id,CoreArg)
366 getAugmentForm env (VarArg v)
367 = case lookupUnfolding env v of
368 SimpleUnfolding False _ _ _ -> Nothing
369 -- not allowed to inline :-(
370 SimpleUnfolding _ (App (App (CoTyApp (Var bld) _)
372 | bld == augmentId -> Just (g,h)
374 getAugmentForm env _ = Nothing
376 getStringForm :: SimplEnv -> CoreArg -> Maybe FAST_STRING
377 getStringForm env (LitArg (NoRepStr str)) = Just str
378 getStringForm env _ = Nothing
381 getAppendForm :: SimplEnv -> CoreArg -> Maybe (GenCoreAtom Id,GenCoreAtom Id)
382 getAppendForm env (VarArg v) =
383 case lookupUnfolding env v of
384 SimpleUnfolding False _ _ _ -> Nothing -- not allowed to inline :-(
385 SimpleUnfolding _ (App (App (App (CoTyApp (CoTyApp (Var fld) _) _) con) ys) xs) _
386 | fld == foldrId && isConsFun env con -> Just (xs,ys)
388 getAppendForm env _ = Nothing
392 -- this gets a list of the form a : b : c : d and returns ([a,b,c],d)
393 -- it natuarally follows that [a,b,c] => ([a,b,c],e), where e = []
399 -> Maybe ([CoreArg],CoreArg)
400 getListForm env (VarArg v)
401 = case lookupUnfolding env v of
402 SimpleUnfolding _ (Con id [ty_arg,head,tail]) _
403 | id == consDataCon ->
404 case getListForm env tail of
405 Nothing -> Just ([head],tail)
406 Just (lst,new_tail) -> Just (head:lst,new_tail)
408 getListForm env _ = Nothing
410 isInterestingArg :: SimplEnv -> CoreArg -> Bool
411 isInterestingArg env (VarArg v)
412 = case lookupUnfolding env v of
413 SimpleUnfolding False _ _ UnfoldNever -> False
414 SimpleUnfolding _ exp guide -> True
416 isInterestingArg env _ = False
418 foldl_fun env (TypeArg ty1:TypeArg ty2:ValArg arg_k:ValArg arg_z:ValArg arg_list:rest_args)
419 | do_fb_red && isNilForm env arg_list
421 -- again another short cut, helps with unroling of constant lists
422 = Just (tick Foldl_Nil `thenSmpl_`
423 returnSmpl (argToExpr arg_z)
426 | do_fb_red && arg_list_isBuildForm
427 -- foldl t1 t2 k z (build t3 g) ==>
428 -- let c {- INLINE -} = \ b g' a -> g' (f a b)
429 -- n {- INLINE -} = \ a -> a
431 -- this next line *is* the foldr/build rule proper.
432 = Just(tick FoldlBuild `thenSmpl_`
433 -- c :: t2 -> (t1 -> t1) -> t1 -> t1
436 {- pre_c -} mkFunTys [ty2, mkFunTys [ty1] ty1, ty1] ty1,
437 {- pre_n -} mkFunTys [ty1] ty1,
439 {- g' -} mkFunTys [ty1] ty1,
443 ] `thenSmpl` \ [pre_c,
452 c = addInlinePragma pre_c
453 c_rhs = Lam b (Lam g' (Lam a
454 (Let (NonRec t (App (App (argToExpr arg_k) (VarArg a)) (VarArg b)))
455 (App (Var g') (VarArg t)))))
456 n = addInlinePragma pre_n
457 n_rhs = Lam a' (Var a')
459 returnSmpl (Let (NonRec c c_rhs) $
460 Let (NonRec n n_rhs) $
462 (TypeArg (mkFunTys [ty1] ty1):ValArg (VarArg c):ValArg (VarArg n)
463 :ValArg arg_z:rest_args))
466 | do_fb_red && arg_list_isAugmentForm
467 -- foldl t1 t2 k z (augment t3 g h) ==>
468 -- let c {- INLINE -} = \ b g' a -> g' (f a b)
469 -- n {- INLINE -} = \ a -> a
470 -- r {- INLINE -} = foldr t2 (t1 -> t1) c n h
472 -- this next line *is* the foldr/build rule proper.
473 = Just (tick FoldlAugment `thenSmpl_`
474 -- c :: t2 -> (t1 -> t1) -> t1 -> t1
477 {- pre_c -} mkFunTys [ty2, mkFunTys [ty1] ty1, ty1] ty1,
478 {- pre_n -} mkFunTys [ty1] ty1,
479 {- pre_r -} mkFunTys [ty1] ty1,
481 {- g_ -} mkFunTys [ty1] ty1,
485 ] `thenSmpl` \ [pre_c,
495 c = addInlinePragma pre_c
496 c_rhs = Lam b (Lam g_ (Lam a
497 (Let (NonRec t (App (App (argToExpr arg_k) (VarArg a)) (VarArg b)))
498 (App (Var g_) (VarArg t)))))
499 n = addInlinePragma pre_n
500 n_rhs = Lam a' (Var a')
501 r = addInlinePragma pre_r
502 r_rhs = mkGenApp (Var foldrId)
503 [TypeArg ty2,TypeArg (mkFunTys [ty1] ty1),
508 returnSmpl (Let (NonRec c c_rhs) $
509 Let (NonRec n n_rhs) $
510 Let (NonRec r r_rhs) $
512 (TypeArg (mkFunTys [ty1] ty1):ValArg (VarArg c):ValArg (VarArg r)
513 :ValArg arg_z:rest_args))
516 | do_fb_red && arg_list_isListForm
517 -- foldl k z (a:b:c:rest) =
518 -- (\ f -> foldl f (f (f (f z a) b) c) rest) k rest_args
519 -- NB: 'k' is used just one by foldr, but 'f' is used many
520 -- times inside the list structure. This means that
521 -- 'f' needs to be inside a lambda, to make sure the simplifier
525 -- foldl f (f (f (f z a) b) c) rest
526 -- f a (f b (f c (foldr f z rest)))
531 -- in foldl f ele_3 rest
533 = Just (tick Foldl_List `thenSmpl_`
535 mkFunTys [ty1, ty2] ty1 :
536 nOfThem (length the_list) ty1
537 ) `thenSmpl` \ (f_id:ele_ids) ->
539 rest_binds = zipWith3Equal "foldl:rest_binds"
540 (\ e v e' -> NonRec e (mkRhs v e'))
542 the_list -- :: [CoreArg]
543 (init (arg_z:map VarArg ele_ids)) -- :: [CoreArg]
544 mkRhs v e = App (App (Var f_id) e) v
546 last_bind = mkGenApp (Var foldlId)
547 [TypeArg ty1,TypeArg ty2,
548 ValArg (VarArg f_id),
549 ValArg (VarArg (last ele_ids)),
556 returnSmpl (mkGenApp (Lam f_id core_list)
557 (ValArg arg_k:rest_args))
561 do_fb_red = switchIsSet env SimplDoFoldrBuild
563 arg_list_isAugmentForm = maybeToBool augmentForm
564 augmentForm = getAugmentForm env arg_list
565 (Just (g',h)) = augmentForm
567 arg_list_isBuildForm = maybeToBool buildForm
568 buildForm = getBuildForm env arg_list
571 arg_list_isListForm = maybeToBool listForm
572 listForm = getListForm env arg_list
573 (Just (the_list,the_tl)) = listForm
576 arg_list_isAppendForm = maybeToBool appendForm
577 appendForm = getAppendForm env arg_list
578 (Just (xs,ys)) = appendForm
581 foldl_fun env (TypeArg ty1:TypeArg ty2:ValArg arg_k:rest_args)
582 | doing_inlining && (isInterestingArg env arg_k
583 || isConsFun env arg_k)
589 -- (a:b) -> h b (f r a)
594 -- tick FoldrInline `thenSmpl_`
597 mkListTy ty2, -- b :: [t1]
599 mkListTy ty2, -- x :: t1
600 mkFunTys [mkListTy ty2, ty1] ty1,
601 -- h :: [t2] -> t1 -> t1
602 mkFunTys [ty1, ty2] ty1,
607 ] `thenSmpl` \ [a,b,v,x,h,f,z,xs,r] ->
609 h_rhs = (Lam x (Lam r (Case (Var x))
611 [(nilDataCon,[],argToExpr (VarArg r)),
612 (consDataCon,[a,b],body)]
614 body = Let (NonRec v (App (App (Var f) (VarArg r))
616 (App (App (argToExpr (VarArg h))
622 (Lam f (Lam z (Lam xs
623 (Let (Rec [(h,h_rhs)])
624 (App (App (Var h) (VarArg xs))
626 (ValArg arg_k:rest_args))
629 doing_inlining = switchIsSet env SimplDoInlineFoldrBuild
631 foldl_fun env _ = Nothing
637 -- Foldr unpackFoldr "str"# (:) stuff ==> unpackAppend "str"#
639 unpack_foldr_fun env [TypeArg ty,ValArg str,ValArg arg_k,ValArg arg_z]
640 | switchIsSet env SimplDoFoldrBuild && isConsFun env arg_k
641 = Just (tick Str_UnpackCons `thenSmpl_`
642 returnSmpl (mkGenApp (Var unpackCStringAppendId)
646 unpack_foldr_fun env _ = Nothing
648 unpack_append_fun env
649 [ValArg (LitArg (MachStr str_val)),ValArg arg_z]
650 | switchIsSet env SimplDoFoldrBuild && isNilForm env arg_z
651 = Just (tick Str_UnpackNil `thenSmpl_`
652 returnSmpl (Lit (NoRepStr str_val))
654 unpack_append_fun env _ = Nothing