[project @ 1996-01-08 20:28:12 by partain]
[ghc-hetmet.git] / ghc / compiler / simplCore / MagicUFs.lhs
diff --git a/ghc/compiler/simplCore/MagicUFs.lhs b/ghc/compiler/simplCore/MagicUFs.lhs
new file mode 100644 (file)
index 0000000..371c0a7
--- /dev/null
@@ -0,0 +1,525 @@
+%
+% (c) The GRASP/AQUA Project, Glasgow University, 1993-1995
+%
+\section[MagicUFs]{Magic unfoldings that the simplifier knows about}
+
+\begin{code}
+#include "HsVersions.h"
+
+module MagicUFs (
+        MagicUnfoldingFun,  -- absolutely abstract
+
+        mkMagicUnfoldingFun,
+        applyMagicUnfoldingFun,
+        
+        CoreArg, PlainCoreArg(..), CoreAtom, PlainCoreAtom(..),
+        CoreExpr, PlainCoreExpr(..), Id, Maybe, SimplEnv,
+       SplitUniqSupply, TickType, UniType,
+       SmplM(..), SimplCount
+    ) where
+
+IMPORT_Trace            -- ToDo: not sure why this is being used
+
+import AbsPrel          ( foldlId, foldrId, buildId,
+                          nilDataCon, consDataCon, mkListTy, mkFunTy,
+                          unpackCStringAppendId
+                        )
+import AbsUniType       ( splitTypeWithDictsAsArgs, TyVarTemplate )
+import BasicLit         ( BasicLit(..) )
+import CmdLineOpts      ( SimplifierSwitch(..), switchIsOn, SwitchResult )
+import Id
+import IdInfo
+import Maybes           ( Maybe(..), maybeToBool )
+import Outputable
+import PlainCore
+import Pretty
+import SimplEnv
+import SimplMonad
+import TaggedCore
+import Util
+\end{code}
+
+%************************************************************************
+%*                                                                      *
+\subsection{Types, etc., for magic-unfolding functions}
+%*                                                                      *
+%************************************************************************
+
+\begin{code}
+data MagicUnfoldingFun
+  = MUF ( SimplEnv              -- state of play in simplifier...
+                                -- (note: we can get simplifier switches
+                                -- from the SimplEnv)
+        -> [PlainCoreArg]       -- arguments
+        -> SmplM (Maybe PlainCoreExpr))
+                                -- Just result, or Nothing
+\end{code}
+
+Give us a string tag, we'll give you back the corresponding MUF.
+\begin{code}
+mkMagicUnfoldingFun :: FAST_STRING -> MagicUnfoldingFun
+
+mkMagicUnfoldingFun tag
+  = assoc ("mkMagicUnfoldingFun:"  ++ _UNPK_ tag) magic_UFs_table tag
+\end{code}
+
+Give us an MUF and stuff to apply it to, and we'll give you back the
+answer.
+\begin{code}
+applyMagicUnfoldingFun
+        :: MagicUnfoldingFun
+        -> SimplEnv
+        -> [PlainCoreArg]
+        -> SmplM (Maybe PlainCoreExpr)
+
+applyMagicUnfoldingFun (MUF fun) env args = fun env args
+\end{code}
+
+%************************************************************************
+%*                                                                      *
+\subsection{The table of actual magic unfoldings}
+%*                                                                      *
+%************************************************************************
+
+\begin{code}
+magic_UFs_table :: [(FAST_STRING, MagicUnfoldingFun)]
+
+magic_UFs_table
+  = [(SLIT("build"),  MUF build_fun),
+     (SLIT("foldl"),  MUF foldl_fun),
+     (SLIT("foldr"),  MUF foldr_fun) ]
+\end{code}
+
+%************************************************************************
+%*                                                                      *
+\subsubsection{Unfolding function for @append@}
+%*                                                                      *
+%************************************************************************
+
+\begin{code}
+-- First build, the way we express our lists.
+
+build_fun :: SimplEnv
+          -> [PlainCoreArg]
+          -> SmplM (Maybe PlainCoreExpr)
+build_fun env [TypeArg ty,ValArg (CoVarAtom e)] 
+       | switchIsSet env SimplDoInlineFoldrBuild =
+        let
+                tyL     = mkListTy ty
+                ourCons = mkCoTyApp (CoVar consDataCon) ty
+                ourNil  = mkCoTyApp (CoVar nilDataCon) ty
+        in
+        newIds  [ ty `mkFunTy` (tyL `mkFunTy` tyL),
+                  tyL ]                 `thenSmpl` \ [c,n] ->
+        returnSmpl(Just (CoLet (CoNonRec c ourCons)
+                        (CoLet (CoNonRec n ourNil)
+                         (CoApp (CoApp (mkCoTyApp (CoVar e) tyL) (CoVarAtom c)) (CoVarAtom n)))))
+-- ToDo: add `build' without an argument instance.
+-- This is strange, because of g's type.
+build_fun env _ = 
+       ASSERT (not (switchIsSet env SimplDoInlineFoldrBuild))
+       returnSmpl Nothing
+
+-- Now foldr, the way we consume lists.
+
+foldr_fun :: SimplEnv
+          -> [PlainCoreArg]
+          -> SmplM (Maybe PlainCoreExpr)
+{-
+foldr_fun env _ 
+  | trace "HEHJDHF!" False = error "NEVER" 
+-}
+foldr_fun env (TypeArg ty1:TypeArg ty2:ValArg arg_k:ValArg arg_z:rest_args)
+  | isConsFun env arg_k && isNilForm env arg_z
+  =     -- foldr (:) [] ==> id
+       -- this transformation is *always* benificial
+       -- cf.  foldr (:) [] (build g) == g (:) []
+       -- with foldr (:) [] (build g) == build g
+       -- after unfolding build, they are the same thing.
+     tick FoldrConsNil                 `thenSmpl_` 
+     newId (mkListTy ty1)              `thenSmpl` \ x ->
+     returnSmpl({-trace "foldr (:) []"-} (Just (applyToArgs (CoLam [x] (CoVar x)) rest_args)))
+
+foldr_fun env (TypeArg ty1:TypeArg ty2:ValArg arg_k:ValArg arg_z:ValArg arg_list:rest_args)
+ | do_fb_red && isNilForm env arg_list
+  =     -- foldr f z [] = z
+       -- again another short cut, helps with unroling of constant lists
+    tick Foldr_Nil     `thenSmpl_`
+    returnSmpl (Just (atomToExpr arg_z))
+
+  | do_fb_red && arg_list_isBuildForm 
+  =     -- foldr k z (build g) ==> g k z
+       -- this next line *is* the foldr/build rule proper.
+    tick FoldrBuild    `thenSmpl_`
+    returnSmpl (Just (applyToArgs (CoVar g) (TypeArg ty2:ValArg arg_k:ValArg arg_z:rest_args)))
+
+  | do_fb_red && arg_list_isAppendForm 
+  =     -- foldr k z (foldr (:) ys xs) <args> ==> foldr k (foldr k z ys) xs <args>
+       -- this unfolds foldr one into foldr
+    tick FoldrFoldr    `thenSmpl_`
+    newId ty2  `thenSmpl` \ other_foldr ->
+       let
+           inner_foldr = applyToArgs (CoVar foldrId) 
+                       [TypeArg ty1,TypeArg ty2,
+                        ValArg arg_k,ValArg arg_z,ValArg ys]
+           outer_foldr = applyToArgs (CoVar foldrId) 
+                       ([TypeArg ty1,TypeArg ty2,
+                        ValArg arg_k,ValArg (CoVarAtom other_foldr),ValArg xs]
+                       ++ rest_args)
+       in returnSmpl (Just (CoLet (CoNonRec other_foldr inner_foldr) outer_foldr))
+
+ | do_fb_red && arg_list_isListForm
+ =      -- foldr k z (a:b:c:rest) = 
+       --      (\ f -> f a (f b (f c (foldr f z rest)))) k rest_args
+       -- NB: 'k' is used just one by foldr, but 'f' is used many
+       -- times inside the list structure. This means that
+       -- 'f' needs to be inside a lambda, to make sure the simplifier
+       -- realises this.
+       -- 
+       -- The structure of     
+       --       f a (f b (f c (foldr f z rest)))
+       -- in core becomes:
+       --      let ele_1 = foldr f z rest
+       --          ele_2 = f c ele_1
+       --          ele_3 = f b ele_2
+       --      in f a ele_3
+       --
+  tick Foldr_List      `thenSmpl_`
+  newIds ( 
+               ty1 `mkFunTy` (ty2 `mkFunTy` ty2) :
+               take (length the_list) (repeat ty2)
+       )                       `thenSmpl` \ (f_id:ele_id1:ele_ids) ->
+  let
+       fst_bind = CoNonRec 
+                       ele_id1 
+                       (applyToArgs (CoVar foldrId) 
+                               [TypeArg ty1,TypeArg ty2,
+                                ValArg (CoVarAtom f_id),
+                                ValArg arg_z,
+                                ValArg the_tl])
+       --ToDo: look for a zipWith that checks for the same length of a 3 lists
+       rest_binds = zipWith3 
+                        (\ e v e' -> CoNonRec e (mkRhs v e'))
+                        ele_ids
+                        (reverse (tail the_list))
+                        (init (ele_id1:ele_ids))
+       mkRhs v e = CoApp (CoApp (CoVar f_id) v) (CoVarAtom e)
+       core_list = foldr
+                       CoLet 
+                       (mkRhs (head the_list) (last (ele_id1:ele_ids)))
+                       (fst_bind:rest_binds)
+  in
+       returnSmpl (Just (applyToArgs (CoLam [f_id] core_list)
+                                     (ValArg arg_k:rest_args)))
+
+ where
+   do_fb_red           = switchIsSet env SimplDoFoldrBuild
+
+   arg_list_isBuildForm = maybeToBool buildForm
+   buildForm            = getBuildForm env arg_list
+   (Just g)             = buildForm
+
+   arg_list_isListForm      = maybeToBool listForm
+   listForm                 = getListForm env arg_list
+   (Just (the_list,the_tl)) = listForm
+
+   arg_list_isAppendForm = maybeToBool appendForm
+   appendForm            = getAppendForm env arg_list
+   (Just (xs,ys))        = appendForm
+
+foldr_fun env (TypeArg ty1:TypeArg ty2:ValArg arg_k:rest_args)
+{- OLD:
+  | doing_inlining && isConsFun env arg_k 
+  =    -- foldr (:) z xs = xs ++ z              
+     tick FoldrCons    `thenSmpl_`
+     newIds [ty2,mkListTy ty1] `thenSmpl` \ [z,x] ->
+     returnSmpl (Just (applyToArgs 
+                        (CoLam [z,x] (applyToArgs 
+                                        (CoVar appendId) [
+                                                TypeArg ty1,
+                                                ValArg (CoVarAtom x),
+                                                ValArg (CoVarAtom z)]))
+                        rest_args))
+-}
+  | doing_inlining && (isInterestingArg env arg_k  
+                      || isConsFun env arg_k)
+  =   -- foldr k args =                         
+      --        (\ f z xs ->
+      --          letrec                                 
+      --             h x = case x of
+      --                   [] -> z
+      --                   (a:b) -> f a (h b)
+      --          in
+      --             h xs) k args
+      --
+     tick FoldrInline          `thenSmpl_`
+     newIds [
+                ty1,                    -- a :: t1
+                mkListTy ty1,           -- b :: [t1]
+                ty2,                    -- v :: t2
+                mkListTy ty1,           -- x :: t1
+                mkListTy ty1 `mkFunTy` ty2,
+                                        -- h :: [t1] -> t2
+                ty1 `mkFunTy` (ty2 `mkFunTy` ty2),
+                                        -- f
+                ty2,                    -- z
+                mkListTy ty1            -- xs
+                        ] `thenSmpl` \ [a,b,v,x,h,f,z,xs] ->
+           let
+             h_rhs = (CoLam [x] (CoCase (CoVar x)
+                      (CoAlgAlts
+                          [(nilDataCon,[],atomToExpr (CoVarAtom z)),
+                           (consDataCon,[a,b],body)]
+                       CoNoDefault)))
+             body = CoLet (CoNonRec v (CoApp (CoVar h) (CoVarAtom b)))
+                          (CoApp (CoApp (atomToExpr (CoVarAtom f))
+                                                  (CoVarAtom a))
+                                                    (CoVarAtom v))
+           in
+             returnSmpl (Just 
+                     (applyToArgs
+                         (CoLam [f,z,xs]
+                          (CoLet (CoRec [(h,h_rhs)]) 
+                                 (CoApp (CoVar h) (CoVarAtom xs))))
+                     (ValArg arg_k:rest_args)))
+   where
+       doing_inlining = switchIsSet env SimplDoInlineFoldrBuild 
+foldr_fun _ _ = returnSmpl Nothing
+
+isConsFun :: SimplEnv -> PlainCoreAtom -> Bool
+isConsFun env (CoVarAtom v) = 
+    case lookupUnfolding env v of
+        GeneralForm _ _ (CoLam [(x,_),(y,_)] 
+                        (CoCon con tys [CoVarAtom x',CoVarAtom y'])) _
+                        | con == consDataCon && x==x' && y==y'
+          -> ASSERT ( length tys == 1 ) True
+        _ -> False
+isConsFun env _ = False
+
+isNilForm :: SimplEnv -> PlainCoreAtom -> Bool
+isNilForm env (CoVarAtom v) = 
+    case lookupUnfolding env v of
+        GeneralForm _ _ (CoTyApp (CoVar id) _) _
+          | id == nilDataCon -> True
+        ConstructorForm id _ _
+          | id == nilDataCon   -> True
+        LiteralForm (NoRepStr s) | _NULL_ s -> True
+        _ -> False
+isNilForm env _ = False
+
+getBuildForm :: SimplEnv -> PlainCoreAtom -> Maybe Id
+getBuildForm env (CoVarAtom v) = 
+    case lookupUnfolding env v of
+        GeneralForm False _ _ _ -> Nothing     -- not allowed to inline :-(
+        GeneralForm _ _ (CoApp (CoTyApp (CoVar bld) _) (CoVarAtom g)) _
+          | bld == buildId -> Just g
+        _ -> Nothing
+getBuildForm env _ = Nothing
+
+getAppendForm :: SimplEnv -> PlainCoreAtom -> Maybe (CoreAtom Id,CoreAtom Id)
+getAppendForm env (CoVarAtom v) = 
+    case lookupUnfolding env v of
+        GeneralForm False _ _ _ -> Nothing     -- not allowed to inline :-(
+        GeneralForm _ _ (CoApp (CoApp (CoApp (CoTyApp (CoTyApp (CoVar fld) _) _) con) ys) xs) _
+          | fld == foldrId && isConsFun env con -> Just (xs,ys)
+        _ -> Nothing
+getAppendForm env _ = Nothing
+
+--
+-- this gets a list of the form a : b : c : d and returns ([a,b,c],d)
+-- it natuarally follows that [a,b,c] => ([a,b,c],e), where e = []
+--
+
+getListForm
+       :: SimplEnv 
+       -> PlainCoreAtom 
+       -> Maybe ([PlainCoreAtom],PlainCoreAtom)
+getListForm env (CoVarAtom v) = 
+    case lookupUnfolding env v of
+       ConstructorForm id _ [head,tail]
+          | id == consDataCon -> 
+               case getListForm env tail of
+                  Nothing -> Just ([head],tail)
+                  Just (lst,new_tail) -> Just (head:lst,new_tail)
+       _ -> Nothing
+getListForm env _ = Nothing
+
+isInterestingArg :: SimplEnv -> PlainCoreAtom -> Bool
+isInterestingArg env (CoVarAtom v) = 
+    case lookupUnfolding env v of
+       GeneralForm False _ _ UnfoldNever -> False
+       GeneralForm _ _ exp guide -> True
+       _ -> False
+isInterestingArg env _ = False
+
+foldl_fun env (TypeArg ty1:TypeArg ty2:ValArg arg_k:ValArg arg_z:ValArg arg_list:rest_args)
+ | do_fb_red && isNilForm env arg_list
+  =     -- foldl f z [] = z
+       -- again another short cut, helps with unroling of constant lists
+    tick Foldr_Nil     `thenSmpl_`
+    returnSmpl (Just (atomToExpr arg_z))
+
+  | do_fb_red && arg_list_isBuildForm 
+  =     -- foldl t1 t2 k z (build t3 g) ==> 
+       --                 let c {- INLINE -} = \ b g' a -> g' (f a b) 
+       --                     n {- INLINE -} = \ a -> a
+       --                 in g t1 c n z
+       -- this next line *is* the foldr/build rule proper.
+    tick FoldrBuild    `thenSmpl_`
+       -- c :: t2 -> (t1 -> t1) -> t1 -> t1
+       -- n :: t1 -> t1
+    newIds [
+       {- pre_c -}     ty2 `mkFunTy` ((ty1 `mkFunTy` ty1) `mkFunTy` (ty1 `mkFunTy` ty1)),
+       {- pre_n -}     ty1 `mkFunTy` ty1,
+       {- b -}         ty2,
+       {- g' -}        ty1 `mkFunTy` ty1, 
+       {- a -}         ty1,
+       {- a' -}        ty1,    
+       {- t -}         ty1
+       ]               `thenSmpl` \ [pre_c,
+                                     pre_n,
+                                     b,
+                                     g',
+                                     a,
+                                     a',
+                                     t] ->
+
+    let
+       c     = addIdUnfolding pre_c (iWantToBeINLINEd UnfoldAlways)
+       c_rhs = CoLam [b,g',a]
+                (CoLet (CoNonRec t (CoApp (CoApp (atomToExpr arg_k) (CoVarAtom a)) (CoVarAtom b)))
+                        (CoApp (CoVar g') (CoVarAtom t)))
+       n     = addIdUnfolding pre_n (iWantToBeINLINEd UnfoldAlways) 
+       n_rhs = CoLam [a'] (CoVar a')
+    in
+    returnSmpl (Just (CoLet (CoNonRec c c_rhs) (CoLet (CoNonRec n n_rhs) 
+                 (applyToArgs (CoVar g) 
+                     (TypeArg (ty1 `mkFunTy` ty1):ValArg (CoVarAtom c):ValArg (CoVarAtom n)
+                               :ValArg arg_z:rest_args)))))
+
+
+  | do_fb_red && arg_list_isAppendForm 
+  =     -- foldl k z (foldr (:) ys xs) <args> ==> foldl k (foldl k z xs) ys <args>
+       -- be caseful with for order of xs / ys
+    tick FoldrFoldr    `thenSmpl_`
+    newId ty1  `thenSmpl` \ other_foldl ->
+       let
+           inner_foldl = applyToArgs (CoVar foldlId) 
+                       [TypeArg ty1,TypeArg ty2,
+                        ValArg arg_k,ValArg arg_z,ValArg xs]
+           outer_foldl = applyToArgs (CoVar foldlId) 
+                       ([TypeArg ty1,TypeArg ty2,
+                        ValArg arg_k,ValArg (CoVarAtom other_foldl),ValArg ys]
+                       ++ rest_args)
+       in returnSmpl (Just (CoLet (CoNonRec other_foldl inner_foldl) outer_foldl))
+
+ | do_fb_red && arg_list_isListForm
+ =      -- foldl k z (a:b:c:rest) = 
+       --      (\ f -> foldl f (f (f (f z a) b) c) rest) k rest_args
+       -- NB: 'k' is used just one by foldr, but 'f' is used many
+       -- times inside the list structure. This means that
+       -- 'f' needs to be inside a lambda, to make sure the simplifier
+       -- realises this.
+       -- 
+       -- The structure of     
+       --       foldl f (f (f (f z a) b) c) rest
+       --       f a (f b (f c (foldr f z rest)))
+       -- in core becomes:
+       --      let ele_1 = f z a
+       --          ele_2 = f ele_1 b
+       --          ele_3 = f ele_2 c
+       --      in foldl f ele_3 rest
+       --
+  tick Foldr_List      `thenSmpl_`
+  newIds ( 
+               ty1 `mkFunTy` (ty2 `mkFunTy` ty1) :
+               take (length the_list) (repeat ty1)
+       )                       `thenSmpl` \ (f_id:ele_ids) ->
+  let
+       --ToDo: look for a zipWith that checks for the same length of a 3 lists
+       rest_binds = zipWith3 
+                        (\ e v e' -> CoNonRec e (mkRhs v e'))
+                        ele_ids                                -- :: [Id]
+                        the_list                               -- :: [PlainCoreAtom]
+                        (init (arg_z:map CoVarAtom ele_ids))   -- :: [PlainCoreAtom]
+       mkRhs v e = CoApp (CoApp (CoVar f_id) e) v
+
+       last_bind = applyToArgs (CoVar foldlId) 
+                               [TypeArg ty1,TypeArg ty2,
+                                ValArg (CoVarAtom f_id),
+                                ValArg (CoVarAtom (last ele_ids)),
+                                ValArg the_tl]
+       core_list = foldr
+                       CoLet 
+                       last_bind
+                       rest_binds
+  in
+       returnSmpl (Just (applyToArgs (CoLam [f_id] core_list)
+                                     (ValArg arg_k:rest_args)))
+
+ where
+   do_fb_red           = switchIsSet env SimplDoFoldrBuild
+
+   arg_list_isBuildForm = maybeToBool buildForm
+   buildForm            = getBuildForm env arg_list
+   (Just g)             = buildForm
+
+   arg_list_isListForm      = maybeToBool listForm
+   listForm                 = getListForm env arg_list
+   (Just (the_list,the_tl)) = listForm
+
+   arg_list_isAppendForm = maybeToBool appendForm
+   appendForm            = getAppendForm env arg_list
+   (Just (xs,ys))        = appendForm
+
+foldl_fun env (TypeArg ty1:TypeArg ty2:ValArg arg_k:rest_args)
+  | doing_inlining && (isInterestingArg env arg_k  
+                      || isConsFun env arg_k)
+  =   -- foldl k args =                         
+      --        (\ f z xs ->
+      --          letrec                                 
+      --             h x r = case x of
+      --                     []    -> r
+      --                     (a:b) -> h b (f r a)
+      --          in
+      --             h xs z) k args
+      --
+     tick FoldrInline                          `thenSmpl_`
+     newIds [
+                ty2,                    -- a :: t1
+                mkListTy ty2,           -- b :: [t1]
+                ty1,                    -- v :: t2
+                mkListTy ty2,           -- x :: t1
+                mkListTy ty2 `mkFunTy` (ty1 `mkFunTy` ty1),
+                                        -- h :: [t2] -> t1 -> t1
+                ty1 `mkFunTy` (ty2 `mkFunTy` ty1),
+                                        -- f
+                ty1,                    -- z
+                mkListTy ty2,           -- xs
+               ty1                     -- r
+                        ] `thenSmpl` \ [a,b,v,x,h,f,z,xs,r] ->
+           let
+             h_rhs = (CoLam [x,r] (CoCase (CoVar x)
+                      (CoAlgAlts
+                          [(nilDataCon,[],atomToExpr (CoVarAtom r)),
+                           (consDataCon,[a,b],body)]
+                       CoNoDefault)))
+             body = CoLet (CoNonRec v (CoApp (CoApp (CoVar f) (CoVarAtom r))
+                                                             (CoVarAtom a)))
+                          (CoApp (CoApp (atomToExpr (CoVarAtom h))
+                                                  (CoVarAtom b))
+                                                    (CoVarAtom v))
+           in
+             returnSmpl (Just 
+                     (applyToArgs
+                         (CoLam [f,z,xs]
+                          (CoLet (CoRec [(h,h_rhs)]) 
+                                 (CoApp (CoApp (CoVar h) (CoVarAtom xs)) 
+                                                        (CoVarAtom z))))
+                     (ValArg arg_k:rest_args)))
+   where
+       doing_inlining = switchIsSet env SimplDoInlineFoldrBuild 
+
+foldl_fun env _ = returnSmpl Nothing
+\end{code}
+