2 % (c) The GRASP/AQUA Project, Glasgow University, 1993-1995
4 \section[SpecMonad]{Monad for the Specialiser}
7 #include "HsVersions.h"
15 import Outputable -- ToDo: these may be removable...
20 import CmdLineOpts ( GlobalSwitch(..) )
21 import CoreLift ( mkLiftedId, liftExpr, bindUnlift, applyBindUnlifts )
25 import InstEnv ( lookupClassInstAtSimpleType )
26 import Maybes ( catMaybes, firstJust, maybeToBool, Maybe(..) )
27 import TyVarEnv -- ( growTyVarEnvList, nullTyVarEnv, TyVarEnv, TypeEnv(..) )
35 %************************************************************************
37 \subsection[cloning-binders]{The Specialising IdEnv and CloneInfo}
39 %************************************************************************
41 @SpecIdEnv@ maps old Ids to their new "clone". There are three cases:
43 1) (NoLift CoLitAtom l) : an Id which is bound to a literal
45 2) (NoLift CoLitAtom l) : an Id bound to a "new" Id
46 The new Id is a possibly-type-specialised clone of the original
48 3) Lifted lifted_id unlifted_id :
50 This indicates that the original Id has been specialised to an
51 unboxed value which must be lifted (see "Unboxed bindings" above)
52 @unlifted_id@ is the unboxed clone of the original Id
53 @lifted_id@ is a *lifted* version of the original Id
55 When you lookup Ids which are Lifted, you have to insert a case
56 expression to un-lift the value (done with @bindUnlift@)
58 You also have to insert a case to lift the value in the binding
59 (done with @liftExpr@)
63 type SpecIdEnv = IdEnv CloneInfo
66 = NoLift PlainCoreAtom -- refers to cloned id or literal
68 | Lifted Id -- lifted, cloned id
69 Id -- unlifted, cloned id
73 %************************************************************************
75 \subsection[monad-Specialise]{Monad used in specialisation}
77 %************************************************************************
81 inherited: control flags and
82 recordInst functions with flags cached
84 environment mapping tyvars to types
85 environment mapping Ids to Atoms
87 threaded in and out: unique supply
91 = (GlobalSwitch -> Bool)
97 initSM m sw_chker uniqs
98 = m sw_chker nullTyVarEnv nullIdEnv uniqs
100 returnSM :: a -> SpecM a
101 thenSM :: SpecM a -> (a -> SpecM b) -> SpecM b
102 fixSM :: (a -> SpecM a) -> SpecM a
104 thenSM m k sw_chkr tvenv idenv us
105 = case splitUniqSupply us of { (s1, s2) ->
106 case (m sw_chkr tvenv idenv s1) of { r ->
107 k r sw_chkr tvenv idenv s2 }}
109 returnSM r sw_chkr tvenv idenv us = r
111 fixSM k sw_chkr tvenv idenv us
114 r = k r sw_chkr tvenv idenv us -- Recursive in r!
119 getSwitchCheckerSM sw_chkr tvenv idenv us = sw_chkr
122 The only interesting bit is figuring out the type of the SpecId!
125 newSpecIds :: [Id] -- The id of which to make a specialised version
126 -> [Maybe UniType] -- Specialise to these types
127 -> Int -- No of dicts to specialise
130 newSpecIds new_ids maybe_tys dicts_to_ignore sw_chkr tvenv idenv us
131 = [ mkSpecId uniq id maybe_tys (spec_id_ty id) (selectIdInfoForSpecId id)
132 | (id,uniq) <- new_ids `zip` uniqs ]
134 uniqs = getSUniques (length new_ids) us
135 spec_id_ty id = specialiseTy (getIdUniType id) maybe_tys dicts_to_ignore
137 newTyVars :: Int -> SpecM [TyVar]
138 newTyVars n sw_chkr tvenv idenv us
139 = map mkPolySysTyVar uniqs
141 uniqs = getSUniques n us
144 @cloneLambdaOrCaseBinders@ and @cloneLetBinders@ take a bunch of
145 binders, and build ``clones'' for them. The clones differ from the
146 originals in three ways:
148 (a) they have a fresh unique
149 (b) they have the current type environment applied to their type
150 (c) for Let binders which have been specialised to unboxed values
151 the clone will have a lifted type
153 As well as returning the list of cloned @Id@s they also return a list of
154 @CloneInfo@s which the original binders should be bound to.
157 cloneLambdaOrCaseBinders :: [Id] -- Old binders
158 -> SpecM ([Id], [CloneInfo]) -- New ones
160 cloneLambdaOrCaseBinders old_ids sw_chkr tvenv idenv us
162 uniqs = getSUniques (length old_ids) us
164 unzip (zipWith clone_it old_ids uniqs)
167 = (new_id, NoLift (CoVarAtom new_id))
169 new_id = applyTypeEnvToId tvenv (mkIdWithNewUniq old_id uniq)
171 cloneLetBinders :: Bool -- Top level ?
173 -> [Id] -- Old binders
174 -> SpecM ([Id], [CloneInfo]) -- New ones
176 cloneLetBinders top_lev is_rec old_ids sw_chkr tvenv idenv us
178 uniqs = getSUniques (2 * length old_ids) us
180 unzip (clone_them old_ids uniqs)
182 clone_them [] [] = []
184 clone_them (old_id:olds) (u1:u2:uniqs)
187 NoLift (CoVarAtom old_id)) : clone_rest
189 -- Don't clone if it is a top-level thing. Why not?
190 -- (a) we don't want to change the uniques
191 -- on such things (see TopLevId in Id.lhs)
192 -- (b) we don't have to be paranoid about name capture
193 -- (c) the thing is polymorphic so no need to subst
196 = if (is_rec && isUnboxedDataType new_ty && not (isUnboxedDataType old_ty))
198 Lifted lifted_id unlifted_id) : clone_rest
200 NoLift (CoVarAtom new_id)) : clone_rest
203 clone_rest = clone_them olds uniqs
205 new_id = applyTypeEnvToId tvenv (mkIdWithNewUniq old_id u1)
206 new_ty = getIdUniType new_id
207 old_ty = getIdUniType old_id
209 (lifted_id, unlifted_id) = mkLiftedId new_id u2
212 cloneTyVarSM :: TyVar -> SpecM TyVar
214 cloneTyVarSM old_tyvar sw_chkr tvenv idenv us
218 cloneTyVar old_tyvar uniq -- new_tyvar
220 bindId :: Id -> CloneInfo -> SpecM thing -> SpecM thing
222 bindId id val specm sw_chkr tvenv idenv us
223 = specm sw_chkr tvenv (addOneToIdEnv idenv id val) us
225 bindIds :: [Id] -> [CloneInfo] -> SpecM thing -> SpecM thing
227 bindIds olds news specm sw_chkr tvenv idenv us
228 = specm sw_chkr tvenv (growIdEnvList idenv (zip olds news)) us
230 bindSpecIds :: [Id] -- Old
231 -> [(CloneInfo)] -- New
232 -> [[Maybe SpecInfo]] -- Corresponding specialisations
233 -- Each sub-list corresponds to a different type,
234 -- and contains one Maybe spec_info for each id
238 bindSpecIds olds clones spec_infos specm sw_chkr tvenv idenv us
239 = specm sw_chkr tvenv (growIdEnvList idenv old_to_clone) us
241 old_to_clone = mk_old_to_clone olds clones spec_infos
243 -- The important thing here is that we are *lazy* in spec_infos
244 mk_old_to_clone [] [] _ = []
245 mk_old_to_clone (old:rest_olds) (clone:rest_clones) spec_infos
246 = (old, add_spec_info clone) :
247 mk_old_to_clone rest_olds rest_clones spec_infos_rest
249 add_spec_info (NoLift (CoVarAtom new))
250 = NoLift (CoVarAtom (new `addIdSpecialisation`
251 (mkSpecEnv spec_infos_this_id)))
253 = lifted -- no specialised instances for unboxed lifted values
255 spec_infos_this_id = catMaybes (map head spec_infos)
256 spec_infos_rest = map tail spec_infos
259 bindTyVar :: TyVar -> UniType -> SpecM thing -> SpecM thing
261 bindTyVar tyvar ty specm sw_chkr tvenv idenv us
262 = specm sw_chkr (growTyVarEnvList tvenv [(tyvar,ty)]) idenv us
266 lookupId :: Id -> SpecM CloneInfo
268 lookupId id sw_chkr tvenv idenv us
269 = case lookupIdEnv idenv id of
270 Nothing -> NoLift (CoVarAtom id)
275 specTy :: UniType -> SpecM UniType -- Apply the current type envt to the type
277 specTy ty sw_chkr tvenv idenv us
278 = applyTypeEnvToTy tvenv ty
282 liftId :: Id -> SpecM (Id, Id)
283 liftId id sw_chkr tvenv idenv us
290 In other monads these @mapSM@ things are usually called @listM@.
291 I think @mapSM@ is a much better name. The `2' and `3' variants are
292 when you want to return two or three results, and get at them
293 separately. It saves you having to do an (unzip stuff) right after.
296 mapSM :: (a -> SpecM b) -> [a] -> SpecM [b]
297 mapAndUnzipSM :: (a -> SpecM (b1, b2)) -> [a] -> SpecM ([b1],[b2])
298 mapAndUnzip3SM :: (a -> SpecM (b1, b2, b3)) -> [a] -> SpecM ([b1],[b2],[b3])
299 mapAndUnzip4SM :: (a -> SpecM (b1, b2, b3, b4)) -> [a] -> SpecM ([b1],[b2],[b3],[b4])
301 mapSM f [] = returnSM []
302 mapSM f (x:xs) = f x `thenSM` \ r ->
303 mapSM f xs `thenSM` \ rs ->
306 mapAndUnzipSM f [] = returnSM ([],[])
307 mapAndUnzipSM f (x:xs) = f x `thenSM` \ (r1, r2) ->
308 mapAndUnzipSM f xs `thenSM` \ (rs1,rs2) ->
309 returnSM ((r1:rs1),(r2:rs2))
311 mapAndUnzip3SM f [] = returnSM ([],[],[])
312 mapAndUnzip3SM f (x:xs) = f x `thenSM` \ (r1,r2,r3) ->
313 mapAndUnzip3SM f xs `thenSM` \ (rs1,rs2,rs3) ->
314 returnSM ((r1:rs1),(r2:rs2),(r3:rs3))
316 mapAndUnzip4SM f [] = returnSM ([],[],[],[])
317 mapAndUnzip4SM f (x:xs) = f x `thenSM` \ (r1,r2,r3,r4) ->
318 mapAndUnzip4SM f xs `thenSM` \ (rs1,rs2,rs3,rs4) ->
319 returnSM ((r1:rs1),(r2:rs2),(r3:rs3),(r4:rs4))