remove empty dir
[ghc-hetmet.git] / ghc / compiler / simplCore / SATMonad.lhs
1 %
2 % (c) The GRASP/AQUA Project, Glasgow University, 1992-1998
3 %
4 %************************************************************************
5 %*                                                                      *
6 \section[SATMonad]{The Static Argument Transformation pass Monad}
7 %*                                                                      *
8 %************************************************************************
9
10 96/03: We aren't using the static-argument transformation right now.
11
12 \begin{code}
13 module SATMonad where
14
15 #include "HsVersions.h"
16
17 import Panic            ( panic )
18
19 junk_from_SATMonad = panic "SATMonad.junk"
20
21 {- LATER: to end of file:
22
23 module SATMonad (
24         SATInfo(..), updSAEnv,
25         SatM(..), initSAT, emptyEnvSAT,
26         returnSAT, thenSAT, thenSAT_, mapSAT, getSATInfo, newSATName,
27         getArgLists, Arg(..), insSAEnv, saTransform,
28
29         SATEnv(..), isStatic, dropStatics
30     ) where
31
32 import Type             ( mkTyVarTy, mkSigmaTy,
33                           splitSigmaTy, splitFunTys,
34                           glueTyArgs, substTy,
35                           InstTyEnv(..)
36                         )
37 import MkId             ( mkSysLocal )
38 import Id               ( idType, idName, mkLocalId )
39 import UniqSupply
40 import Util
41
42 infixr 9 `thenSAT`, `thenSAT_`
43 \end{code}
44
45 %************************************************************************
46 %*                                                                      *
47 \subsection{Static Argument Transformation Environment}
48 %*                                                                      *
49 %************************************************************************
50
51 \begin{code}
52 type SATEnv = IdEnv SATInfo
53
54 type SATInfo = ([Arg Type],[Arg Id])
55
56 data Arg a = Static a | NotStatic
57     deriving Eq
58
59 delOneFromSAEnv v us env
60   = ((), delVarEnv env v)
61
62 updSAEnv :: Maybe (Id,SATInfo) -> SatM ()
63 updSAEnv Nothing
64   = returnSAT ()
65 updSAEnv (Just (b,(tyargs,args)))
66   = getSATInfo b      `thenSAT` (\ r ->
67     case r of
68       Nothing              -> returnSAT ()
69       Just (tyargs',args') -> delOneFromSAEnv b `thenSAT_`
70                               insSAEnv b (checkArgs tyargs tyargs',
71                                           checkArgs args args')
72     )
73
74 checkArgs as [] = notStatics (length as)
75 checkArgs [] as = notStatics (length as)
76 checkArgs (a:as) (a':as') | a == a' = a:checkArgs as as'
77 checkArgs (_:as) (_:as') = NotStatic:checkArgs as as'
78
79 notStatics :: Int -> [Arg a]
80 notStatics n = nOfThem n NotStatic
81
82 insSAEnv :: Id -> SATInfo -> SatM ()
83 insSAEnv b info us env
84   = ((), extendVarEnv env b info)
85 \end{code}
86
87 %************************************************************************
88 %*                                                                      *
89 \subsection{Static Argument Transformation Monad}
90 %*                                                                      *
91 %************************************************************************
92
93 Two items of state to thread around: a UniqueSupply and a SATEnv.
94
95 \begin{code}
96 type SatM result
97   =  UniqSupply -> SATEnv -> (result, SATEnv)
98
99 initSAT :: SatM a -> UniqSupply -> a
100
101 initSAT f us = fst (f us emptyVarEnv)
102
103 thenSAT m k us env
104   = case splitUniqSupply us     of { (s1, s2) ->
105     case m s1 env               of { (m_result, menv) ->
106     k m_result s2 menv }}
107
108 thenSAT_ m k us env
109   = case splitUniqSupply us     of { (s1, s2) ->
110     case m s1 env               of { (_, menv) ->
111     k s2 menv }}
112
113 emptyEnvSAT :: SatM ()
114 emptyEnvSAT us _ = ((), emptyVarEnv)
115
116 returnSAT v us env = (v, env)
117
118 mapSAT f []     = returnSAT []
119 mapSAT f (x:xs)
120   = f x         `thenSAT` \ x'  ->
121     mapSAT f xs `thenSAT` \ xs' ->
122     returnSAT (x':xs')
123 \end{code}
124
125 %************************************************************************
126 %*                                                                      *
127 \subsection{Utility Functions}
128 %*                                                                      *
129 %************************************************************************
130
131 \begin{code}
132 getSATInfo :: Id -> SatM (Maybe SATInfo)
133 getSATInfo var us env
134   = (lookupVarEnv env var, env)
135
136 newSATName :: Id -> Type -> SatM Id
137 newSATName id ty us env
138   = case (getUnique us) of { unique ->
139     let
140         new_name = mkCompoundName SLIT("$sat") unique (idName id)
141     in
142     (mkLocalId new_name ty, env) }
143
144 getArgLists :: CoreExpr -> ([Arg Type],[Arg Id])
145 getArgLists expr
146   = let
147         (tvs, lambda_bounds, body) = collectBinders expr
148     in
149     ([ Static (mkTyVarTy tv) | tv <- tvs ],
150      [ Static v              | v <- lambda_bounds ])
151
152 dropArgs :: CoreExpr -> CoreExpr
153 dropArgs (Lam   _ e)    = dropArgs e
154 dropArgs (CoTyLam _ e)  = dropArgs e
155 dropArgs e              = e
156 \end{code}
157
158 We implement saTransform using shadowing of binders, that is
159 we transform
160 map = \f as -> case as of
161                  [] -> []
162                  (a':as') -> let x = f a'
163                                  y = map f as'
164                              in x:y
165 to
166 map = \f as -> let map = \f as -> map' as
167                in let rec map' = \as -> case as of
168                                           [] -> []
169                                           (a':as') -> let x = f a'
170                                                           y = map f as'
171                                                       in x:y
172                   in map' as
173
174 the inner map should get inlined and eliminated.
175 \begin{code}
176 saTransform :: Id -> CoreExpr -> SatM CoreBinding
177 saTransform binder rhs
178   = getSATInfo binder `thenSAT` \ r ->
179     case r of
180       -- [Andre] test: do it only if we have more than one static argument.
181       --Just (tyargs,args) | any isStatic args
182       Just (tyargs,args) | (filter isStatic args) `lengthExceeds` 1
183         -> newSATName binder (new_ty tyargs args)  `thenSAT` \ binder' ->
184            mkNewRhs binder binder' tyargs args rhs `thenSAT` \ new_rhs ->
185            trace ("SAT "++ show (length (filter isStatic args))) (
186            returnSAT (NonRec binder new_rhs)
187            )
188       _ -> returnSAT (Rec [(binder, rhs)])
189   where
190     mkNewRhs binder binder' tyargs args rhs
191       = let
192             non_static_args :: [Id]
193             non_static_args
194                = get_nsa args (snd (getArgLists rhs))
195                where
196                  get_nsa :: [Arg a] -> [Arg a] -> [a]
197                  get_nsa [] _ = []
198                  get_nsa _ [] = []
199                  get_nsa (NotStatic:args) (Static v:as) = v:get_nsa args as
200                  get_nsa (_:args)         (_:as)        =   get_nsa args as
201
202             local_body = foldl App (Var binder')
203                                 [VarArg a | a <- non_static_args]
204
205             nonrec_rhs = origLams local_body
206
207             -- HACK! The following is a fake SysLocal binder with
208             --  *the same* unique as binder.
209             -- the reason for this is the following:
210             -- this binder *will* get inlined but if it happen to be
211             -- a top level binder it is never removed as dead code,
212             -- therefore we have to remove that information (of it being
213             -- top-level or exported somehow.)
214             -- A better fix is to use binder directly but with the TopLevel
215             -- tag (or Exported tag) modified.
216             fake_binder = mkSysLocal SLIT("sat")
217                             (getUnique binder)
218                             (idType binder)
219             rec_body = mkValLam non_static_args
220                                ( Let (NonRec fake_binder nonrec_rhs)
221                                  {-in-} (dropArgs rhs))
222         in
223         returnSAT (
224             origLams (Let (Rec [(binder',rec_body)]) {-in-} local_body)
225         )
226       where
227         origLams = origLams' rhs
228                  where
229                    origLams' (Lam v e)     e' = Lam   v  (origLams' e e')
230                    origLams' (CoTyLam ty e)  e' = CoTyLam ty (origLams' e e')
231                    origLams' _               e' = e'
232
233     new_ty tyargs args
234       = substTy (mk_inst_tyenv tyargs tv_tmpl)
235                       (mkSigmaTy tv_tmpl' dict_tys' tau_ty')
236       where
237         -- get type info for the local function:
238         (tv_tmpl, dict_tys, tau_ty) = (splitSigmaTy . idType) binder
239         (reg_arg_tys, res_type)     = splitFunTys tau_ty
240
241         -- now, we drop the ones that are
242         -- static, that is, the ones we will not pass to the local function
243         tv_tmpl'     = dropStatics tyargs tv_tmpl
244
245         (args1, args2) = splitAtList dict_tys args
246         dict_tys'    = dropStatics args1 dict_tys
247         reg_arg_tys' = dropStatics args2 reg_arg_tys
248
249         tau_ty'      = glueTyArgs reg_arg_tys' res_type
250
251         mk_inst_tyenv []                    _ = emptyVarEnv
252         mk_inst_tyenv (Static s:args) (t:ts)  = extendVarEnv (mk_inst_tyenv args ts) t s
253         mk_inst_tyenv (_:args)      (_:ts)    = mk_inst_tyenv args ts
254
255 dropStatics [] t = t
256 dropStatics (Static _:args) (t:ts) = dropStatics args ts
257 dropStatics (_:args)        (t:ts) = t:dropStatics args ts
258
259 isStatic :: Arg a -> Bool
260 isStatic NotStatic = False
261 isStatic _         = True
262 -}
263 \end{code}