2 % (c) The University of Glasgow 2000
4 \section[ByteCodeGen]{Generate bytecode from Core}
7 module ByteCodeGen ( byteCodeGen, assembleBCO ) where
9 #include "HsVersions.h"
12 import Name ( Name, getName )
13 import Id ( Id, idType, isDataConId_maybe )
14 import OrdList ( OrdList, consOL, snocOL, appOL, unitOL,
15 nilOL, toOL, concatOL, fromOL )
16 import FiniteMap ( FiniteMap, addListToFM, listToFM,
17 addToFM, lookupFM, fmToList, emptyFM )
19 import PprCore ( pprCoreExpr, pprCoreAlt )
20 import Literal ( Literal(..) )
21 import PrimRep ( PrimRep(..) )
22 import CoreFVs ( freeVars )
23 import Type ( typePrimRep )
24 import DataCon ( DataCon, dataConTag, fIRST_TAG, dataConTyCon )
25 import TyCon ( tyConFamilySize )
26 import Util ( zipEqual, zipWith4Equal, naturalMergeSortLe, nOfThem )
27 import Var ( isTyVar )
28 import VarSet ( VarSet, varSetElems )
29 import PrimRep ( getPrimRepSize, isFollowableRep )
30 import Constants ( wORD_SIZE )
32 import Foreign ( Addr, Word16, Word32, nullAddr )
34 import MutableArray ( readWord32Array,
35 newFloatArray, writeFloatArray,
36 newDoubleArray, writeDoubleArray,
37 newIntArray, writeIntArray,
38 newAddrArray, writeAddrArray )
44 byteCodeGen :: [CoreBind] -> [ProtoBCO Name]
46 = let flatBinds = concatMap getBind binds
47 getBind (NonRec bndr rhs) = [(bndr, freeVars rhs)]
48 getBind (Rec binds) = [(bndr, freeVars rhs) | (bndr,rhs) <- binds]
49 final_state = runBc (BcM_State [] 0)
50 (mapBc schemeR flatBinds `thenBc_` returnBc ())
53 BcM_State bcos final_ctr -> bcos
57 %************************************************************************
59 \subsection{Bytecodes, and Outputery.}
61 %************************************************************************
68 -- Messing with the stack
70 | PUSH_L Int{-offset-}
79 | SLIDE Int{-this many-} Int{-down by this much-}
80 -- To do with the heap
82 | MKAP Int{-place ptr to heap this far down stack-} Int{-# words-}
83 | UNPACK Int -- unpack N ptr words from t.o.s Constr
84 | UNPACK_I Int -- unpack and tag an Int, from t.o.s Constr @ offset
85 | UNPACK_F Int -- unpack and tag a Float, from t.o.s Constr @ offset
86 | UNPACK_D Int -- unpack and tag a Double, from t.o.s Constr @ offset
88 -- For doing case trees
90 | TESTLT_I Int LocalLabel
91 | TESTEQ_I Int LocalLabel
92 | TESTLT_F Float LocalLabel
93 | TESTEQ_F Float LocalLabel
94 | TESTLT_D Double LocalLabel
95 | TESTEQ_D Double LocalLabel
96 | TESTLT_P Int LocalLabel
97 | TESTEQ_P Int LocalLabel
99 -- To Infinity And Beyond
102 instance Outputable BCInstr where
103 ppr (ARGCHECK n) = text "ARGCHECK" <+> int n
104 ppr (PUSH_L offset) = text "PUSH_L " <+> int offset
105 ppr (PUSH_G nm) = text "PUSH_G " <+> ppr nm
106 ppr (PUSH_AS nm) = text "PUSH_AS " <+> ppr nm
107 ppr (PUSHT_I i) = text "PUSHT_I " <+> int i
108 ppr (SLIDE n d) = text "SLIDE " <+> int n <+> int d
109 ppr (ALLOC sz) = text "ALLOC " <+> int sz
110 ppr (MKAP offset sz) = text "MKAP " <+> int offset <+> int sz
111 ppr (UNPACK sz) = text "UNPACK " <+> int sz
112 ppr (UNPACK_I sz) = text "UNPACK_I" <+> int sz
113 ppr (UNPACK_F sz) = text "UNPACK_F" <+> int sz
114 ppr (UNPACK_D sz) = text "UNPACK_D" <+> int sz
115 ppr (PACK dcon sz) = text "PACK " <+> ppr dcon <+> ppr sz
116 ppr (LABEL lab) = text "__" <> int lab <> colon
117 ppr (TESTLT_I i lab) = text "TESTLT_I" <+> int i <+> text "__" <> int lab
118 ppr (TESTEQ_I i lab) = text "TESTEQ_I" <+> int i <+> text "__" <> int lab
119 ppr (TESTLT_F f lab) = text "TESTLT_F" <+> float f <+> text "__" <> int lab
120 ppr (TESTEQ_F f lab) = text "TESTEQ_F" <+> float f <+> text "__" <> int lab
121 ppr (TESTLT_D d lab) = text "TESTLT_D" <+> double d <+> text "__" <> int lab
122 ppr (TESTEQ_D d lab) = text "TESTEQ_D" <+> double d <+> text "__" <> int lab
123 ppr (TESTLT_P i lab) = text "TESTLT_P" <+> int i <+> text "__" <> int lab
124 ppr (TESTEQ_P i lab) = text "TESTEQ_P" <+> int i <+> text "__" <> int lab
125 ppr CASEFAIL = text "CASEFAIL"
126 ppr ENTER = text "ENTER"
128 pprAltCode discrs_n_codes
129 = vcat (map f discrs_n_codes)
130 where f (discr, code) = ppr discr <> colon <+> vcat (map ppr (fromOL code))
132 instance Outputable a => Outputable (ProtoBCO a) where
133 ppr (ProtoBCO name instrs origin)
134 = (text "ProtoBCO" <+> ppr name <> colon)
135 $$ nest 6 (vcat (map ppr (fromOL instrs)))
137 Left alts -> vcat (map (pprCoreAlt.deAnnAlt) alts)
138 Right rhs -> pprCoreExpr (deAnnotate rhs)
141 %************************************************************************
143 \subsection{Compilation schema for the bytecode generator.}
145 %************************************************************************
149 type BCInstrList = OrdList BCInstr
152 = ProtoBCO a -- name, in some sense
153 BCInstrList -- instrs
154 -- what the BCO came from
155 (Either [AnnAlt Id VarSet]
159 type Sequel = Int -- back off to this depth before ENTER
161 -- Maps Ids to the offset from the stack _base_ so we don't have
162 -- to mess with it after each push/pop.
163 type BCEnv = FiniteMap Id Int -- To find vars on the stack
167 -- Compile code for the right hand side of a let binding.
168 -- Park the resulting BCO in the monad. Also requires the
169 -- variable to which this value was bound, so as to give the
170 -- resulting BCO a name.
171 schemeR :: (Id, AnnExpr Id VarSet) -> BcM ()
172 schemeR (nm, rhs) = schemeR_wrk rhs nm (collect [] rhs)
174 collect xs (_, AnnLam x e)
175 = collect (if isTyVar x then xs else (x:xs)) e
176 collect xs not_lambda
177 = (reverse xs, not_lambda)
179 schemeR_wrk original_body nm (args, body)
180 = let fvs = filter (not.isTyVar) (varSetElems (fst original_body))
181 all_args = fvs ++ reverse args
182 szsw_args = map taggedIdSizeW all_args
183 szw_args = sum szsw_args
184 p_init = listToFM (zip all_args (mkStackOffsets 0 szsw_args))
185 argcheck = if null args then nilOL else unitOL (ARGCHECK szw_args)
187 schemeE szw_args 0 p_init body `thenBc` \ body_code ->
188 emitBc (ProtoBCO (getName nm) (appOL argcheck body_code) (Right original_body))
190 -- Let szsw be the sizes in words of some items pushed onto the stack,
191 -- which has initial depth d'. Return the values which the stack environment
192 -- should map these items to.
193 mkStackOffsets :: Int -> [Int] -> [Int]
194 mkStackOffsets original_depth szsw
195 = map (subtract 1) (tail (scanl (+) original_depth szsw))
197 -- Compile code to apply the given expression to the remaining args
198 -- on the stack, returning a HNF.
199 schemeE :: Int -> Sequel -> BCEnv -> AnnExpr Id VarSet -> BcM BCInstrList
201 -- Delegate tail-calls to schemeT.
202 schemeE d s p e@(fvs, AnnApp f a)
203 = returnBc (schemeT (should_args_be_tagged e) d s 0 p (fvs, AnnApp f a))
204 schemeE d s p e@(fvs, AnnVar v)
205 = returnBc (schemeT (should_args_be_tagged e) d s 0 p (fvs, AnnVar v))
207 schemeE d s p (fvs, AnnLet binds b)
208 = let (xs,rhss) = case binds of AnnNonRec x rhs -> ([x],[rhs])
209 AnnRec xs_n_rhss -> unzip xs_n_rhss
211 fvss = map (filter (not.isTyVar).varSetElems.fst) rhss
212 sizes = map (\rhs_fvs -> 1 + sum (map taggedIdSizeW rhs_fvs)) fvss
214 -- This p', d' defn is safe because all the items being pushed
215 -- are ptrs, so all have size 1. d' and p' reflect the stack
216 -- after the closures have been allocated in the heap (but not
217 -- filled in), and pointers to them parked on the stack.
218 p' = addListToFM p (zipE xs (mkStackOffsets d (nOfThem n 1)))
221 infos = zipE4 fvss sizes xs [n, n-1 .. 1]
222 zipE = zipEqual "schemeE"
223 zipE4 = zipWith4Equal "schemeE" (\a b c d -> (a,b,c,d))
225 -- ToDo: don't build thunks for things with no free variables
226 buildThunk dd ([], size, id, off)
227 = PUSH_G (getName id)
228 `consOL` unitOL (MKAP (off+size-1) size)
229 buildThunk dd ((fv:fvs), size, id, off)
230 = case pushAtom True dd p' (AnnVar fv) of
231 (push_code, pushed_szw)
233 buildThunk (dd+pushed_szw) (fvs, size, id, off)
235 thunkCode = concatOL (map (buildThunk d') infos)
236 allocCode = toOL (map ALLOC sizes)
238 schemeE d' s p' b `thenBc` \ bodyCode ->
239 mapBc schemeR (zip xs rhss) `thenBc_`
240 returnBc (allocCode `appOL` thunkCode `appOL` bodyCode)
243 schemeE d s p (fvs, AnnCase scrut bndr alts)
245 -- Top of stack is the return itbl, as usual.
246 -- underneath it is the pointer to the alt_code BCO.
247 -- When an alt is entered, it assumes the returned value is
248 -- on top of the itbl.
251 -- Env and depth in which to compile the alts, not including
252 -- any vars bound by the alts themselves
253 d' = d + ret_frame_sizeW + taggedIdSizeW bndr
254 p' = addToFM p bndr (d' - 1)
257 = case typePrimRep (idType bndr) of
258 IntRep -> False ; FloatRep -> False ; DoubleRep -> False
260 other -> pprPanic "ByteCodeGen.schemeE" (ppr other)
262 -- given an alt, return a discr and code for it.
263 codeAlt alt@(discr, binds_f, rhs)
265 = let binds_r = reverse binds_f
266 binds_r_szsw = map untaggedIdSizeW binds_r
267 binds_szw = sum binds_r_szsw
269 p' (zip binds_r (mkStackOffsets d' binds_r_szsw))
271 unpack_code = mkUnpackCode 0 (map (typePrimRep.idType) binds_f)
272 in schemeE d'' s p'' rhs `thenBc` \ rhs_code ->
273 returnBc (my_discr alt, unpack_code `appOL` rhs_code)
275 = ASSERT(null binds_f)
276 schemeE d' s p' rhs `thenBc` \ rhs_code ->
277 returnBc (my_discr alt, rhs_code)
279 my_discr (DEFAULT, binds, rhs) = NoDiscr
280 my_discr (DataAlt dc, binds, rhs) = DiscrP (dataConTag dc)
281 my_discr (LitAlt l, binds, rhs)
282 = case l of MachInt i -> DiscrI (fromInteger i)
283 MachFloat r -> DiscrF (fromRational r)
284 MachDouble r -> DiscrD (fromRational r)
287 | not isAlgCase = Nothing
289 = case [dc | (DataAlt dc, _, _) <- alts] of
291 (dc:_) -> Just (tyConFamilySize (dataConTyCon dc))
294 mapBc codeAlt alts `thenBc` \ alt_stuff ->
295 mkMultiBranch maybe_ncons alt_stuff `thenBc` \ alt_final ->
297 alt_bco_name = getName bndr
298 alt_bco = ProtoBCO alt_bco_name alt_final (Left alts)
300 schemeE (d + ret_frame_sizeW)
301 (d + ret_frame_sizeW) p scrut `thenBc` \ scrut_code ->
303 emitBc alt_bco `thenBc_`
304 returnBc (PUSH_AS alt_bco_name `consOL` scrut_code)
307 schemeE d s p (fvs, AnnNote note body)
311 = pprPanic "ByteCodeGen.schemeE: unhandled case"
312 (pprCoreExpr (deAnnotate other))
315 -- Compile code to do a tail call. Doesn't need to be monadic.
316 schemeT :: Bool -- do tagging?
317 -> Int -- Stack depth
318 -> Sequel -- Sequel depth
319 -> Int -- # arg words so far
320 -> BCEnv -- stack env
321 -> AnnExpr Id VarSet -> BCInstrList
323 schemeT enTag d s narg_words p (_, AnnApp f a)
325 AnnType _ -> schemeT enTag d s narg_words p f
327 -> let (push, arg_words) = pushAtom enTag d p (snd a)
329 `appOL` schemeT enTag (d+arg_words) s (narg_words+arg_words) p f
331 schemeT enTag d s narg_words p (_, AnnVar f)
332 | Just con <- isDataConId_maybe f
333 = ASSERT(enTag == False)
334 PACK con narg_words `consOL` (mkSLIDE 1 (d-s-1) `snocOL` ENTER)
336 = ASSERT(enTag == True)
337 let (push, arg_words) = pushAtom True d p (AnnVar f)
339 `appOL` mkSLIDE (narg_words+arg_words) (d - s - narg_words)
343 = if d == 0 then nilOL else unitOL (SLIDE n d)
345 should_args_be_tagged (_, AnnVar v)
346 = case isDataConId_maybe v of
347 Just dcon -> False; Nothing -> True
348 should_args_be_tagged (_, AnnApp f a)
349 = should_args_be_tagged f
350 should_args_be_tagged (_, other)
351 = panic "should_args_be_tagged: tail call to non-con, non-var"
354 -- Make code to unpack a constructor onto the stack, adding
355 -- tags for the unboxed bits. Takes the PrimReps of the constructor's
356 -- arguments, and a travelling offset along the *constructor*.
357 mkUnpackCode :: Int -> [PrimRep] -> BCInstrList
358 mkUnpackCode off [] = nilOL
359 mkUnpackCode off (r:rs)
361 = let (rs_ptr, rs_nptr) = span isFollowableRep (r:rs)
362 ptrs_szw = sum (map untaggedSizeW rs_ptr)
363 in ASSERT(ptrs_szw == length rs_ptr)
364 UNPACK ptrs_szw `consOL` mkUnpackCode (off+ptrs_szw) rs_nptr
367 IntRep -> UNPACK_I off `consOL` theRest
368 FloatRep -> UNPACK_F off `consOL` theRest
369 DoubleRep -> UNPACK_D off `consOL` theRest
371 theRest = mkUnpackCode (off+untaggedSizeW r) rs
373 -- Push an atom onto the stack, returning suitable code & number of
374 -- stack words used. Pushes it either tagged or untagged, since
375 -- pushAtom is used to set up the stack prior to copying into the
376 -- heap for both APs (requiring tags) and constructors (which don't).
378 -- NB this means NO GC between pushing atoms for a constructor and
379 -- copying them into the heap. It probably also means that
380 -- tail calls MUST be of the form atom{atom ... atom} since if the
381 -- expression head was allowed to be arbitrary, there could be GC
382 -- in between pushing the arg atoms and completing the head.
383 -- (not sure; perhaps the allocate/doYouWantToGC interface means this
384 -- isn't a problem; but only if arbitrary graph construction for the
385 -- head doesn't leave this BCO, since GC might happen at the start of
386 -- each BCO (we consult doYouWantToGC there).
388 -- Blargh. JRS 001206
390 -- NB (further) that the env p must map each variable to the highest-
391 -- numbered stack slot for it. For example, if the stack has depth 4
392 -- and we tagged-ly push (v :: Int#) on it, the value will be in stack[4],
393 -- the tag in stack[5], the stack will have depth 6, and p must map v to
394 -- 5 and not to 4. Stack locations are numbered from zero, so a depth
395 -- 6 stack has valid words 0 .. 5.
397 pushAtom tagged d p (AnnVar v)
398 = let str = "\npushAtom " ++ showSDocDebug (ppr v) ++ ", depth = " ++ show d
400 showSDocDebug (nest 4 (vcat (map ppr (fmToList p))))
402 showSDoc (nest 4 (vcat (map ppr (fromOL (fst result)))))
403 ++ "\nendPushAtom " ++ showSDocDebug (ppr v)
404 str' = if str == str then str else str
407 = case lookupBCEnv_maybe p v of
408 Just d_v -> (toOL (nOfThem nwords (PUSH_L (d-d_v+sz_t-2))), sz_t)
409 Nothing -> ASSERT(sz_t == 1) (unitOL (PUSH_G nm), sz_t)
412 sz_t = taggedIdSizeW v
413 sz_u = untaggedIdSizeW v
414 nwords = if tagged then sz_t else sz_u
419 pushAtom True d p (AnnLit lit)
421 MachInt i -> (unitOL (PUSHT_I (fromInteger i)), taggedSizeW IntRep)
422 MachFloat r -> (unitOL (PUSHT_F (fromRational r)), taggedSizeW FloatRep)
423 MachDouble r -> (unitOL (PUSHT_D (fromRational r)), taggedSizeW DoubleRep)
425 pushAtom False d p (AnnLit lit)
427 MachInt i -> (unitOL (PUSHU_I (fromInteger i)), untaggedSizeW IntRep)
428 MachFloat r -> (unitOL (PUSHU_F (fromRational r)), untaggedSizeW FloatRep)
429 MachDouble r -> (unitOL (PUSHU_D (fromRational r)), untaggedSizeW DoubleRep)
431 pushAtom tagged d p other
432 = pprPanic "ByteCodeGen.pushAtom"
433 (pprCoreExpr (deAnnotate (undefined, other)))
436 -- Given a bunch of alts code and their discrs, do the donkey work
437 -- of making a multiway branch using a switch tree.
438 -- What a load of hassle!
439 mkMultiBranch :: Maybe Int -- # datacons in tycon, if alg alt
440 -- a hint; generates better code
441 -- Nothing is always safe
442 -> [(Discr, BCInstrList)]
444 mkMultiBranch maybe_ncons raw_ways
445 = let d_way = filter (isNoDiscr.fst) raw_ways
446 notd_ways = naturalMergeSortLe
447 (\w1 w2 -> leAlt (fst w1) (fst w2))
448 (filter (not.isNoDiscr.fst) raw_ways)
450 mkTree :: [(Discr, BCInstrList)] -> Discr -> Discr -> BcM BCInstrList
451 mkTree [] range_lo range_hi = returnBc the_default
453 mkTree [val] range_lo range_hi
454 | range_lo `eqAlt` range_hi
457 = getLabelBc `thenBc` \ label_neq ->
458 returnBc (mkTestEQ (fst val) label_neq
460 `appOL` unitOL (LABEL label_neq)
461 `appOL` the_default))
463 mkTree vals range_lo range_hi
464 = let n = length vals `div` 2
465 vals_lo = take n vals
466 vals_hi = drop n vals
467 v_mid = fst (head vals_hi)
469 getLabelBc `thenBc` \ label_geq ->
470 mkTree vals_lo range_lo (dec v_mid) `thenBc` \ code_lo ->
471 mkTree vals_hi v_mid range_hi `thenBc` \ code_hi ->
472 returnBc (mkTestLT v_mid label_geq
474 `appOL` unitOL (LABEL label_geq)
478 = case d_way of [] -> unitOL CASEFAIL
481 -- None of these will be needed if there are no non-default alts
482 (mkTestLT, mkTestEQ, init_lo, init_hi)
484 = panic "mkMultiBranch: awesome foursome"
486 = case fst (head notd_ways) of {
487 DiscrI _ -> ( \(DiscrI i) fail_label -> TESTLT_I i fail_label,
488 \(DiscrI i) fail_label -> TESTEQ_I i fail_label,
491 DiscrF _ -> ( \(DiscrF f) fail_label -> TESTLT_F f fail_label,
492 \(DiscrF f) fail_label -> TESTEQ_F f fail_label,
495 DiscrD _ -> ( \(DiscrD d) fail_label -> TESTLT_D d fail_label,
496 \(DiscrD d) fail_label -> TESTEQ_D d fail_label,
499 DiscrP _ -> ( \(DiscrP i) fail_label -> TESTLT_P i fail_label,
500 \(DiscrP i) fail_label -> TESTEQ_P i fail_label,
505 (algMinBound, algMaxBound)
506 = case maybe_ncons of
507 Just n -> (fIRST_TAG, fIRST_TAG + n - 1)
508 Nothing -> (minBound, maxBound)
510 (DiscrI i1) `eqAlt` (DiscrI i2) = i1 == i2
511 (DiscrF f1) `eqAlt` (DiscrF f2) = f1 == f2
512 (DiscrD d1) `eqAlt` (DiscrD d2) = d1 == d2
513 (DiscrP i1) `eqAlt` (DiscrP i2) = i1 == i2
514 NoDiscr `eqAlt` NoDiscr = True
517 (DiscrI i1) `leAlt` (DiscrI i2) = i1 <= i2
518 (DiscrF f1) `leAlt` (DiscrF f2) = f1 <= f2
519 (DiscrD d1) `leAlt` (DiscrD d2) = d1 <= d2
520 (DiscrP i1) `leAlt` (DiscrP i2) = i1 <= i2
521 NoDiscr `leAlt` NoDiscr = True
524 isNoDiscr NoDiscr = True
527 dec (DiscrI i) = DiscrI (i-1)
528 dec (DiscrP i) = DiscrP (i-1)
529 dec other = other -- not really right, but if you
530 -- do cases on floating values, you'll get what you deserve
532 -- same snotty comment applies to the following
540 mkTree notd_ways init_lo init_hi
544 %************************************************************************
546 \subsection{Supporting junk for the compilation schemes}
548 %************************************************************************
552 -- Describes case alts
560 instance Outputable Discr where
561 ppr (DiscrI i) = int i
562 ppr (DiscrF f) = text (show f)
563 ppr (DiscrD d) = text (show d)
564 ppr (DiscrP i) = int i
565 ppr NoDiscr = text "DEF"
568 -- Find things in the BCEnv (the what's-on-the-stack-env)
569 -- See comment preceding pushAtom for precise meaning of env contents
570 lookupBCEnv :: BCEnv -> Id -> Int
572 = case lookupFM env nm of
573 Nothing -> pprPanic "lookupBCEnv"
574 (ppr nm $$ char ' ' $$ vcat (map ppr (fmToList env)))
577 lookupBCEnv_maybe :: BCEnv -> Id -> Maybe Int
578 lookupBCEnv_maybe = lookupFM
581 -- When I push one of these on the stack, how much does Sp move by?
582 taggedSizeW :: PrimRep -> Int
584 | isFollowableRep pr = 1
585 | otherwise = 1{-the tag-} + getPrimRepSize pr
588 -- The plain size of something, without tag.
589 untaggedSizeW :: PrimRep -> Int
591 | isFollowableRep pr = 1
592 | otherwise = getPrimRepSize pr
595 taggedIdSizeW, untaggedIdSizeW :: Id -> Int
596 taggedIdSizeW = taggedSizeW . typePrimRep . idType
597 untaggedIdSizeW = untaggedSizeW . typePrimRep . idType
601 %************************************************************************
603 \subsection{The bytecode generator's monad}
605 %************************************************************************
609 = BcM_State { bcos :: [ProtoBCO Name], -- accumulates completed BCOs
610 nextlabel :: Int } -- for generating local labels
612 type BcM result = BcM_State -> (result, BcM_State)
614 mkBcM_State :: [ProtoBCO Name] -> Int -> BcM_State
615 mkBcM_State = BcM_State
617 runBc :: BcM_State -> BcM () -> BcM_State
618 runBc init_st m = case m init_st of { (r,st) -> st }
620 thenBc :: BcM a -> (a -> BcM b) -> BcM b
622 = case expr st of { (result, st') -> cont result st' }
624 thenBc_ :: BcM a -> BcM b -> BcM b
626 = case expr st of { (result, st') -> cont st' }
628 returnBc :: a -> BcM a
629 returnBc result st = (result, st)
631 mapBc :: (a -> BcM b) -> [a] -> BcM [b]
632 mapBc f [] = returnBc []
634 = f x `thenBc` \ r ->
635 mapBc f xs `thenBc` \ rs ->
638 emitBc :: ProtoBCO Name -> BcM ()
640 = ((), st{bcos = bco : bcos st})
642 getLabelBc :: BcM Int
644 = (nextlabel st, st{nextlabel = 1 + nextlabel st})
648 %************************************************************************
650 \subsection{The bytecode assembler}
652 %************************************************************************
654 The object format for bytecodes is: 16 bits for the opcode, and 16 for
655 each field -- so the code can be considered a sequence of 16-bit ints.
656 Each field denotes either a stack offset or number of items on the
657 stack (eg SLIDE), and index into the pointer table (eg PUSH_G), an
658 index into the literal table (eg PUSH_I/D/L), or a bytecode address in
662 -- An (almost) assembled BCO.
663 data BCO a = BCO [Word16] -- instructions
664 [Word32] -- literal pool
665 [a] -- Names or HValues
667 -- Top level assembler fn.
668 assembleBCO :: ProtoBCO Name -> BCO Name
669 assembleBCO (ProtoBCO nm instrs_ordlist origin)
671 -- pass 1: collect up the offsets of the local labels
672 instrs = fromOL instrs_ordlist
673 label_env = mkLabelEnv emptyFM 0 instrs
675 mkLabelEnv env i_offset [] = env
676 mkLabelEnv env i_offset (i:is)
678 = case i of LABEL n -> addToFM env n i_offset ; _ -> env
679 in mkLabelEnv new_env (i_offset + instrSizeB i) is
682 = case lookupFM label_env lab of
683 Just bco_offset -> bco_offset
684 Nothing -> pprPanic "assembleBCO.findLabel" (int lab)
686 -- pass 2: generate the instruction, ptr and nonptr bits
687 (insnW16s, litW32s, ptrs) = mkBits findLabel [] 0 [] 0 [] 0 instrs
689 BCO insnW16s litW32s ptrs
692 -- This is where all the action is (pass 2 of the assembler)
693 mkBits :: (Int -> Int) -- label finder
694 -> [Word16] -> Int -- reverse acc instr bits
695 -> [Word32] -> Int -- reverse acc literal bits
696 -> [Name] -> Int -- reverse acc ptrs
697 -> [BCInstr] -- insns!
698 -> ([Word16], [Word32], [Name])
700 mkBits findLabel r_is n_is r_lits n_lits r_ptrs n_ptrs []
701 = (reverse r_is, reverse r_lits, reverse r_ptrs)
702 mkBits findLabel r_is n_is r_lits n_lits r_ptrs n_ptrs (instr:instrs)
704 ARGCHECK n -> boring2 i_ARGCHECK n
705 PUSH_L off -> boring2 i_PUSH_L off
706 PUSH_G nm -> exciting2_P i_PUSH_G n_ptrs nm
707 PUSHT_I i -> exciting2_I i_PUSHT_I n_lits i
708 PUSHT_F f -> exciting2_F i_PUSHT_F n_lits f
709 PUSHT_D d -> exciting2_D i_PUSHT_D n_lits d
710 PUSHU_I i -> exciting2_I i_PUSHU_I n_lits i
711 PUSHU_F f -> exciting2_F i_PUSHU_F n_lits f
712 PUSHU_D d -> exciting2_D i_PUSHU_D n_lits d
713 SLIDE n by -> boring3 i_SLIDE n by
714 ALLOC n -> boring2 i_ALLOC n
715 MKAP off sz -> boring3 i_MKAP off sz
716 UNPACK n -> boring2 i_UNPACK n
717 PACK dcon sz -> exciting3_A i_PACK sz n_lits nullAddr {-findItbl dcon-}
719 TESTLT_I i l -> exciting3_I i_TESTLT_I n_lits (findLabel l) i
720 TESTEQ_I i l -> exciting3_I i_TESTEQ_I n_lits (findLabel l) i
721 TESTLT_F f l -> exciting3_F i_TESTLT_F n_lits (findLabel l) f
722 TESTEQ_F f l -> exciting3_F i_TESTEQ_F n_lits (findLabel l) f
723 TESTLT_D d l -> exciting3_D i_TESTLT_D n_lits (findLabel l) d
724 TESTEQ_D d l -> exciting3_D i_TESTEQ_D n_lits (findLabel l) d
725 TESTLT_P i l -> exciting3_I i_TESTLT_P n_lits (findLabel l) i
726 TESTEQ_P i l -> exciting3_I i_TESTEQ_P n_lits (findLabel l) i
727 CASEFAIL -> boring1 i_CASEFAIL
728 ENTER -> boring1 i_ENTER
730 r_mkILit = reverse . mkILit
731 r_mkFLit = reverse . mkFLit
732 r_mkDLit = reverse . mkDLit
733 r_mkALit = reverse . mkALit
739 = mkBits findLabel r_is n_is r_lits n_lits r_ptrs n_ptrs instrs
741 = mkBits findLabel (mkw i1 : r_is) (n_is+1)
742 r_lits n_lits r_ptrs n_ptrs instrs
744 = mkBits findLabel (mkw i2 : mkw i1 : r_is) (n_is+2)
745 r_lits n_lits r_ptrs n_ptrs instrs
747 = mkBits findLabel (mkw i3 : mkw i2 : mkw i1 : r_is) (n_is+3)
748 r_lits n_lits r_ptrs n_ptrs instrs
751 = mkBits findLabel (mkw i2 : mkw i1 : r_is) (n_is+2) r_lits n_lits
752 (p:r_ptrs) (n_ptrs+1) instrs
753 exciting3_P i1 i2 i3 p
754 = mkBits findLabel (mkw i3 : mkw i2 : mkw i1 : r_is) (n_is+3) r_lits n_lits
755 (p:r_ptrs) (n_ptrs+1) instrs
758 = mkBits findLabel (mkw i2 : mkw i1 : r_is) (n_is+2)
759 (r_mkILit i ++ r_lits) (n_lits + intLitSz32s)
761 exciting3_I i1 i2 i3 i
762 = mkBits findLabel (mkw i3 : mkw i2 : mkw i1 : r_is) (n_is+3)
763 (r_mkILit i ++ r_lits) (n_lits + intLitSz32s)
767 = mkBits findLabel (mkw i2 : mkw i1 : r_is) (n_is+2)
768 (r_mkFLit f ++ r_lits) (n_lits + floatLitSz32s)
770 exciting3_F i1 i2 i3 f
771 = mkBits findLabel (mkw i3 : mkw i2 : mkw i1 : r_is) (n_is+3)
772 (r_mkFLit f ++ r_lits) (n_lits + floatLitSz32s)
776 = mkBits findLabel (mkw i2 : mkw i1 : r_is) (n_is+2)
777 (r_mkDLit d ++ r_lits) (n_lits + doubleLitSz32s)
779 exciting3_D i1 i2 i3 d
780 = mkBits findLabel (mkw i3 : mkw i2 : mkw i1 : r_is) (n_is+3)
781 (r_mkDLit d ++ r_lits) (n_lits + doubleLitSz32s)
784 exciting3_A i1 i2 i3 d
785 = mkBits findLabel (mkw i3 : mkw i2 : mkw i1 : r_is) (n_is+3)
786 (r_mkALit d ++ r_lits) (n_lits + addrLitSz32s)
790 -- The size in bytes of an instruction.
791 instrSizeB :: BCInstr -> Int
821 -- Sizes of Int, Float and Double literals, in units of 32-bitses
822 intLitSz32s, floatLitSz32s, doubleLitSz32s, addrLitSz32s :: Int
823 intLitSz32s = wORD_SIZE `div` 4
824 floatLitSz32s = 1 -- Assume IEEE floats
826 addrLitSz32s = intLitSz32s
828 -- Make lists of 32-bit words for literals, so that when the
829 -- words are placed in memory at increasing addresses, the
830 -- bit pattern is correct for the host's word size and endianness.
831 mkILit :: Int -> [Word32]
832 mkFLit :: Float -> [Word32]
833 mkDLit :: Double -> [Word32]
834 mkALit :: Addr -> [Word32]
838 arr <- newFloatArray ((0::Int),0)
839 writeFloatArray arr 0 f
840 w0 <- readWord32Array arr 0
846 arr <- newDoubleArray ((0::Int),0)
847 writeDoubleArray arr 0 d
848 w0 <- readWord32Array arr 0
849 w1 <- readWord32Array arr 1
856 arr <- newIntArray ((0::Int),0)
857 writeIntArray arr 0 i
858 w0 <- readWord32Array arr 0
863 arr <- newIntArray ((0::Int),0)
864 writeIntArray arr 0 i
865 w0 <- readWord32Array arr 0
866 w1 <- readWord32Array arr 1
873 arr <- newAddrArray ((0::Int),0)
874 writeAddrArray arr 0 a
875 w0 <- readWord32Array arr 0
880 arr <- newAddrArray ((0::Int),0)
881 writeAddrArray arr 0 a
882 w0 <- readWord32Array arr 0
883 w1 <- readWord32Array arr 1
889 #include "../rts/Bytecodes.h"
891 i_ARGCHECK = (bci_ARGCHECK :: Int)
892 i_PUSH_L = (bci_PUSH_L :: Int)
893 i_PUSH_G = (bci_PUSH_G :: Int)
894 i_PUSH_AS = (bci_PUSH_AS :: Int)
895 i_PUSHT_I = (bci_PUSHT_I :: Int)
896 i_PUSHT_F = (bci_PUSHT_F :: Int)
897 i_PUSHT_D = (bci_PUSHT_D :: Int)
898 i_PUSHU_I = (bci_PUSHU_I :: Int)
899 i_PUSHU_F = (bci_PUSHU_F :: Int)
900 i_PUSHU_D = (bci_PUSHU_D :: Int)
901 i_SLIDE = (bci_SLIDE :: Int)
902 i_ALLOC = (bci_ALLOC :: Int)
903 i_MKAP = (bci_MKAP :: Int)
904 i_UNPACK = (bci_UNPACK :: Int)
905 i_PACK = (bci_PACK :: Int)
906 i_LABEL = (bci_LABEL :: Int)
907 i_TESTLT_I = (bci_TESTLT_I :: Int)
908 i_TESTEQ_I = (bci_TESTEQ_I :: Int)
909 i_TESTLT_F = (bci_TESTLT_F :: Int)
910 i_TESTEQ_F = (bci_TESTEQ_F :: Int)
911 i_TESTLT_D = (bci_TESTLT_D :: Int)
912 i_TESTEQ_D = (bci_TESTEQ_D :: Int)
913 i_TESTLT_P = (bci_TESTLT_P :: Int)
914 i_TESTEQ_P = (bci_TESTEQ_P :: Int)
915 i_CASEFAIL = (bci_CASEFAIL :: Int)
916 i_ENTER = (bci_ENTER :: Int)