[project @ 2000-12-07 11:00:43 by sewardj]
[ghc-hetmet.git] / ghc / compiler / ghci / ByteCodeGen.lhs
1 %
2 % (c) The University of Glasgow 2000
3 %
4 \section[ByteCodeGen]{Generate bytecode from Core}
5
6 \begin{code}
7 module ByteCodeGen ( byteCodeGen, assembleBCO ) where
8
9 #include "HsVersions.h"
10
11 import Outputable
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 )
18 import CoreSyn
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 )
25 import Util             ( zipEqual, zipWith4Equal, naturalMergeSortLe )
26 import VarSet           ( VarSet, varSetElems )
27 import PrimRep          ( getPrimRepSize, isFollowableRep )
28 import Constants        ( wORD_SIZE )
29
30 import Foreign          ( Addr, Word16, Word32, nullAddr )
31 import ST               ( runST )
32 import MutableArray     ( readWord32Array,
33                           newFloatArray, writeFloatArray,
34                           newDoubleArray, writeDoubleArray,
35                           newIntArray, writeIntArray,
36                           newAddrArray, writeAddrArray )
37 \end{code}
38
39 Entry point.
40
41 \begin{code}
42 byteCodeGen :: [CoreBind] -> [ProtoBCO Name]
43 byteCodeGen binds
44    = let flatBinds = concatMap getBind binds
45          getBind (NonRec bndr rhs) = [(bndr, freeVars rhs)]
46          getBind (Rec binds)       = [(bndr, freeVars rhs) | (bndr,rhs) <- binds]
47          final_state = runBc (BcM_State [] 0) 
48                              (mapBc schemeR flatBinds `thenBc_` returnBc ())
49      in  
50          case final_state of
51             BcM_State bcos final_ctr -> bcos
52 \end{code}
53
54
55 %************************************************************************
56 %*                                                                      *
57 \subsection{Bytecodes, and Outputery.}
58 %*                                                                      *
59 %************************************************************************
60
61 \begin{code}
62
63 type LocalLabel = Int
64
65 data BCInstr
66    -- Messing with the stack
67    = ARGCHECK  Int
68    | PUSH_L    Int{-size-} Int{-offset-}
69    | PUSH_G    Name
70    | PUSHT_I   Int
71    | PUSHT_F   Float
72    | PUSHT_D   Double
73    | PUSHU_I   Int
74    | PUSHU_F   Float
75    | PUSHU_D   Double
76    | SLIDE     Int{-this many-} Int{-down by this much-}
77    -- To do with the heap
78    | ALLOC     Int
79    | MKAP      Int{-place ptr to heap this far down stack-} Int{-# words-}
80    | UNPACK    Int
81    | PACK      DataCon Int
82    -- For doing case trees
83    | LABEL     LocalLabel
84    | TESTLT_I  Int    LocalLabel
85    | TESTEQ_I  Int    LocalLabel
86    | TESTLT_F  Float  LocalLabel
87    | TESTEQ_F  Float  LocalLabel
88    | TESTLT_D  Double LocalLabel
89    | TESTEQ_D  Double LocalLabel
90    | TESTLT_P  Int    LocalLabel
91    | TESTEQ_P  Int    LocalLabel
92    | CASEFAIL
93    -- To Infinity And Beyond
94    | ENTER
95
96 instance Outputable BCInstr where
97    ppr (ARGCHECK n)          = text "ARGCHECK" <+> int n
98    ppr (PUSH_L sz offset)    = text "PUSH_L  " <+> int sz <+> int offset
99    ppr (PUSH_G nm)           = text "PUSH_G  " <+> ppr nm
100    ppr (PUSHT_I i)           = text "PUSHT_I " <+> int i
101    ppr (SLIDE n d)           = text "SLIDE   " <+> int n <+> int d
102    ppr (ALLOC sz)            = text "ALLOC   " <+> int sz
103    ppr (MKAP offset sz)      = text "MKAP    " <+> int offset <+> int sz
104    ppr (UNPACK sz)           = text "UNPACK  " <+> int sz
105    ppr (PACK dcon sz)        = text "PACK    " <+> ppr dcon <+> ppr sz
106    ppr ENTER                 = text "ENTER"
107
108 pprAltCode discrs_n_codes
109    = vcat (map f discrs_n_codes)
110      where f (discr, code) = ppr discr <> colon <+> vcat (map ppr (fromOL code))
111
112 instance Outputable a => Outputable (ProtoBCO a) where
113    ppr (ProtoBCO name instrs origin)
114       = (text "ProtoBCO" <+> ppr name <> colon)
115         $$ nest 6 (vcat (map ppr (fromOL instrs)))
116         $$ case origin of
117               Left alts -> vcat (map (pprCoreAlt.deAnnAlt) alts)
118               Right rhs -> pprCoreExpr (deAnnotate rhs)
119 \end{code}
120
121 %************************************************************************
122 %*                                                                      *
123 \subsection{Compilation schema for the bytecode generator.}
124 %*                                                                      *
125 %************************************************************************
126
127 \begin{code}
128
129 type BCInstrList = OrdList BCInstr
130
131 data ProtoBCO a 
132    = ProtoBCO a                         -- name, in some sense
133               BCInstrList               -- instrs
134                                         -- what the BCO came from
135               (Either [AnnAlt Id VarSet]
136                       (AnnExpr Id VarSet))
137
138
139 type Sequel = Int       -- back off to this depth before ENTER
140
141 -- Maps Ids to the offset from the stack _base_ so we don't have
142 -- to mess with it after each push/pop.
143 type BCEnv = FiniteMap Id Int   -- To find vars on the stack
144
145
146
147 -- Compile code for the right hand side of a let binding.
148 -- Park the resulting BCO in the monad.  Also requires the
149 -- variable to which this value was bound, so as to give the
150 -- resulting BCO a name.
151 schemeR :: (Id, AnnExpr Id VarSet) -> BcM ()
152 schemeR (nm, rhs) = schemeR_wrk nm (collect [] rhs)
153
154 collect xs (_, AnnLam x e) = collect (x:xs) e
155 collect xs not_lambda      = (reverse xs, not_lambda)
156
157 schemeR_wrk nm (args, body)
158    = let fvs       = fst body
159          all_args  = varSetElems fvs ++ args
160          szsw_args = map taggedIdSizeW all_args
161          szw_args  = sum szsw_args
162          p_init    = listToFM (zip all_args (scanl (+) 0 szsw_args))
163          argcheck  = if null args then nilOL else unitOL (ARGCHECK szw_args)
164      in
165      schemeE szw_args 0 p_init body             `thenBc` \ body_code ->
166      emitBc (ProtoBCO (getName nm) (appOL argcheck body_code) (Right body))
167
168
169 -- Compile code to apply the given expression to the remaining args
170 -- on the stack, returning a HNF.
171 schemeE :: Int -> Sequel -> BCEnv -> AnnExpr Id VarSet -> BcM BCInstrList
172
173 -- Delegate tail-calls to schemeT.
174 schemeE d s p e@(fvs, AnnApp f a) 
175    = returnBc (schemeT (should_args_be_tagged e) d s 0 p (fvs, AnnApp f a))
176 schemeE d s p e@(fvs, AnnVar v)
177    = returnBc (schemeT (should_args_be_tagged e) d s 0 p (fvs, AnnVar v))
178
179 schemeE d s p (fvs, AnnLet binds b)
180    = let (xs,rhss) = case binds of AnnNonRec x rhs  -> ([x],[rhs])
181                                    AnnRec xs_n_rhss -> unzip xs_n_rhss
182      in
183      mapBc schemeR (zip xs rhss)                        `thenBc_`
184      let n     = length xs
185          fvss  = map (varSetElems.fst) rhss
186          sizes = map (\rhs_fvs -> 1 + sum (map taggedIdSizeW rhs_fvs)) fvss
187          p'    = addListToFM p (zipE xs [d .. d+n-1])
188          d'    = d + n
189          infos = zipE4 fvss sizes xs [n, n-1 .. 1]
190          zipE  = zipEqual "schemeE"
191          zipE4 = zipWith4Equal "schemeE" (\a b c d -> (a,b,c,d))
192
193          -- ToDo: don't build thunks for things with no free variables
194          buildThunk (fvs, size, id, off)
195             = case unzip (map (pushAtom True d' p . AnnVar) (reverse fvs)) of
196                 (push_codes, pushed_szsw) 
197                    -> ASSERT(sum pushed_szsw == size - 1)
198                             (toOL push_codes `snocOL` PUSH_G (getName id) 
199                                              `appOL` unitOL (MKAP off size))
200
201          thunkCode = concatOL (map buildThunk infos)
202          allocCode = toOL (map ALLOC sizes)
203      in
204      schemeE d' s p' b                                  `thenBc` \ bodyCode ->
205      mapBc schemeR (zip xs rhss)                        `thenBc` \_ ->
206      returnBc (allocCode `appOL` thunkCode `appOL` bodyCode)
207
208
209 schemeE d s p (fvs, AnnCase scrut bndr alts)
210    = let
211         -- Top of stack is the return itbl, as usual.
212         -- underneath it is the pointer to the alt_code BCO.
213         -- When an alt is entered, it assumes the returned value is
214         -- on top of the itbl.
215         ret_frame_sizeW = 2
216
217         -- Env and depth in which to compile the alts, not including
218         -- any vars bound by the alts themselves
219         d' = d + ret_frame_sizeW + taggedIdSizeW bndr
220         p' = addToFM p bndr d'
221
222         isAlgCase
223            = case typePrimRep (idType bndr) of
224                 IntRep -> False ; FloatRep -> False ; DoubleRep -> False
225                 PtrRep -> True
226                 other  -> pprPanic "ByteCodeGen.schemeE" (ppr other)
227
228         -- given an alt, return a discr and code for it.
229         codeAlt alt@(discr, binds, rhs)
230            | isAlgCase 
231            = let binds_szsw = map untaggedIdSizeW binds
232                  binds_szw  = sum binds_szsw
233                  p'' = addListToFM p' (zip binds (scanl (+) d' binds_szsw))
234                  d'' = d' + binds_szw
235              in schemeE d'' s p'' rhs   `thenBc` \ rhs_code -> 
236                 returnBc (my_discr alt, UNPACK binds_szw `consOL` rhs_code)
237            | otherwise 
238            = ASSERT(null binds) 
239              schemeE d' s p' rhs        `thenBc` \ rhs_code ->
240              returnBc (my_discr alt, rhs_code)
241
242         my_discr (DEFAULT, binds, rhs)  = NoDiscr
243         my_discr (DataAlt dc, binds, rhs) = DiscrP (dataConTag dc - fIRST_TAG)
244         my_discr (LitAlt l, binds, rhs)
245            = case l of MachInt i     -> DiscrI (fromInteger i)
246                        MachFloat r   -> DiscrF (fromRational r)
247                        MachDouble r  -> DiscrD (fromRational r)
248
249      in 
250      mapBc codeAlt alts                                 `thenBc` \ alt_stuff ->
251      mkMultiBranch alt_stuff                            `thenBc` \ alt_final ->
252      let 
253          alt_bco_name = getName bndr
254          alt_bco      = ProtoBCO alt_bco_name alt_final (Left alts)
255      in
256      schemeE (d + ret_frame_sizeW) 
257              (d + ret_frame_sizeW) p scrut              `thenBc` \ scrut_code ->
258
259      emitBc alt_bco                                     `thenBc_`
260      returnBc (PUSH_G alt_bco_name `consOL` scrut_code)
261
262
263 -- Compile code to do a tail call.  Doesn't need to be monadic.
264 schemeT :: Bool         -- do tagging?
265         -> Int          -- Stack depth
266         -> Sequel       -- Sequel depth
267         -> Int          -- # arg words so far
268         -> BCEnv        -- stack env
269         -> AnnExpr Id VarSet -> BCInstrList
270
271 schemeT enTag d s narg_words p (_, AnnApp f a) 
272    = let (push, arg_words) = pushAtom enTag d p (snd a)
273      in push 
274         `consOL` schemeT enTag (d+arg_words) s (narg_words+arg_words) p f
275
276 schemeT enTag d s narg_words p (_, AnnVar f)
277    | Just con <- isDataConId_maybe f
278    = ASSERT(enTag == False)
279      PACK con narg_words `consOL` SLIDE 1 (d-s-1) `consOL` unitOL ENTER
280    | otherwise
281    = ASSERT(enTag == True)
282      let (push, arg_words) = pushAtom True d p (AnnVar f)
283      in push 
284         `consOL` SLIDE (narg_words+arg_words) (d - s - narg_words)
285         `consOL` unitOL ENTER
286
287 should_args_be_tagged (_, AnnVar v)
288    = case isDataConId_maybe v of
289         Just dcon -> False; Nothing -> True
290 should_args_be_tagged (_, AnnApp f a)
291    = should_args_be_tagged f
292 should_args_be_tagged (_, other)
293    = panic "should_args_be_tagged: tail call to non-con, non-var"
294
295 -- Push an atom onto the stack, returning suitable code & number of
296 -- stack words used.  Pushes it either tagged or untagged, since 
297 -- pushAtom is used to set up the stack prior to copying into the
298 -- heap for both APs (requiring tags) and constructors (which don't).
299 --
300 -- NB this means NO GC between pushing atoms for a constructor and
301 -- copying them into the heap.  It probably also means that 
302 -- tail calls MUST be of the form atom{atom ... atom} since if the
303 -- expression head was allowed to be arbitrary, there could be GC
304 -- in between pushing the arg atoms and completing the head.
305 -- (not sure; perhaps the allocate/doYouWantToGC interface means this
306 -- isn't a problem; but only if arbitrary graph construction for the
307 -- head doesn't leave this BCO, since GC might happen at the start of
308 -- each BCO (we consult doYouWantToGC there).
309 --
310 -- Blargh.  JRS 001206
311 --
312 pushAtom True{-tagged-} d p (AnnVar v) 
313    = case lookupBCEnv_maybe p v of
314         Just offset -> (PUSH_L sz offset, sz)
315         Nothing     -> ASSERT(sz == 1) (PUSH_G nm, sz)
316      where
317         nm = getName v
318         sz = taggedIdSizeW v
319
320 pushAtom False{-not tagged-} d p (AnnVar v) 
321    = case lookupBCEnv_maybe p v of
322         Just offset -> (PUSH_L sz (offset+1), sz-1)
323         Nothing     -> ASSERT(sz == 1) (PUSH_G nm, sz)
324      where
325         nm = getName v
326         sz = untaggedIdSizeW v
327
328 pushAtom True d p (AnnLit lit)
329    = case lit of
330         MachInt i    -> (PUSHT_I (fromInteger i),  taggedSizeW IntRep)
331         MachFloat r  -> (PUSHT_F (fromRational r), taggedSizeW FloatRep)
332         MachDouble r -> (PUSHT_D (fromRational r), taggedSizeW DoubleRep)
333
334 pushAtom False d p (AnnLit lit)
335    = case lit of
336         MachInt i    -> (PUSHU_I (fromInteger i),  untaggedSizeW IntRep)
337         MachFloat r  -> (PUSHU_F (fromRational r), untaggedSizeW FloatRep)
338         MachDouble r -> (PUSHU_D (fromRational r), untaggedSizeW DoubleRep)
339
340
341 -- Given a bunch of alts code and their discrs, do the donkey work
342 -- of making a multiway branch using a switch tree.
343 -- What a load of hassle!
344 mkMultiBranch :: [(Discr, BCInstrList)] -> BcM BCInstrList
345 mkMultiBranch raw_ways
346    = let d_way     = filter (isNoDiscr.fst) raw_ways
347          notd_ways = naturalMergeSortLe 
348                         (\w1 w2 -> leAlt (fst w1) (fst w2))
349                         (filter (not.isNoDiscr.fst) raw_ways)
350
351          mkTree :: [(Discr, BCInstrList)] -> Discr -> Discr -> BcM BCInstrList
352          mkTree [] range_lo range_hi = returnBc the_default
353
354          mkTree [val] range_lo range_hi
355             | range_lo `eqAlt` range_hi 
356             = returnBc (snd val)
357             | otherwise
358             = getLabelBc                                `thenBc` \ label_neq ->
359               returnBc (mkTestEQ (fst val) label_neq 
360                         `consOL` (snd val
361                         `appOL`   unitOL (LABEL label_neq)
362                         `appOL`   the_default))
363
364          mkTree vals range_lo range_hi
365             = let n = length vals `div` 2
366                   vals_lo = take n vals
367                   vals_hi = drop n vals
368                   v_mid = fst (head vals_hi)
369               in
370               getLabelBc                                `thenBc` \ label_geq ->
371               mkTree vals_lo range_lo (dec v_mid)       `thenBc` \ code_lo ->
372               mkTree vals_hi v_mid range_hi             `thenBc` \ code_hi ->
373               returnBc (mkTestLT v_mid label_geq
374                         `consOL` (code_lo
375                         `appOL`   unitOL (LABEL label_geq)
376                         `appOL`   code_hi))
377  
378          the_default 
379             = case d_way of [] -> unitOL CASEFAIL
380                             [(_, def)] -> def
381
382          -- None of these will be needed if there are no non-default alts
383          (mkTestLT, mkTestEQ, init_lo, init_hi)
384             | null notd_ways
385             = panic "mkMultiBranch: awesome foursome"
386             | otherwise
387             = case fst (head notd_ways) of {
388               DiscrI _ -> ( \(DiscrI i) fail_label -> TESTLT_I i fail_label,
389                             \(DiscrI i) fail_label -> TESTEQ_I i fail_label,
390                             DiscrI minBound,
391                             DiscrI maxBound );
392               DiscrF _ -> ( \(DiscrF f) fail_label -> TESTLT_F f fail_label,
393                             \(DiscrF f) fail_label -> TESTEQ_F f fail_label,
394                             DiscrF minF,
395                             DiscrF maxF );
396               DiscrD _ -> ( \(DiscrD d) fail_label -> TESTLT_D d fail_label,
397                             \(DiscrD d) fail_label -> TESTEQ_D d fail_label,
398                             DiscrD minD,
399                             DiscrD maxD );
400               DiscrP _ -> ( \(DiscrP i) fail_label -> TESTLT_P i fail_label,
401                             \(DiscrP i) fail_label -> TESTEQ_P i fail_label,
402                             DiscrP minBound,
403                             DiscrP maxBound )
404               }
405
406          (DiscrI i1) `eqAlt` (DiscrI i2) = i1 == i2
407          (DiscrF f1) `eqAlt` (DiscrF f2) = f1 == f2
408          (DiscrD d1) `eqAlt` (DiscrD d2) = d1 == d2
409          (DiscrP i1) `eqAlt` (DiscrP i2) = i1 == i2
410          NoDiscr     `eqAlt` NoDiscr     = True
411          _           `eqAlt` _           = False
412
413          (DiscrI i1) `leAlt` (DiscrI i2) = i1 <= i2
414          (DiscrF f1) `leAlt` (DiscrF f2) = f1 <= f2
415          (DiscrD d1) `leAlt` (DiscrD d2) = d1 <= d2
416          (DiscrP i1) `leAlt` (DiscrP i2) = i1 <= i2
417          NoDiscr     `leAlt` NoDiscr     = True
418          _           `leAlt` _           = False
419
420          isNoDiscr NoDiscr = True
421          isNoDiscr _       = False
422
423          dec (DiscrI i) = DiscrI (i-1)
424          dec (DiscrP i) = DiscrP (i-1)
425          dec other      = other         -- not really right, but if you
426                 -- do cases on floating values, you'll get what you deserve
427
428          -- same snotty comment applies to the following
429          minF, maxF :: Float
430          minD, maxD :: Double
431          minF = -1.0e37
432          maxF =  1.0e37
433          minD = -1.0e308
434          maxD =  1.0e308
435      in
436          mkTree notd_ways init_lo init_hi
437
438 \end{code}
439
440 %************************************************************************
441 %*                                                                      *
442 \subsection{Supporting junk for the compilation schemes}
443 %*                                                                      *
444 %************************************************************************
445
446 \begin{code}
447
448 -- Describes case alts
449 data Discr 
450    = DiscrI Int
451    | DiscrF Float
452    | DiscrD Double
453    | DiscrP Int
454    | NoDiscr
455
456 instance Outputable Discr where
457    ppr (DiscrI i) = int i
458    ppr (DiscrF f) = text (show f)
459    ppr (DiscrD d) = text (show d)
460    ppr (DiscrP i) = int i
461    ppr NoDiscr    = text "DEF"
462
463
464 -- Find things in the BCEnv (the what's-on-the-stack-env)
465 lookupBCEnv :: BCEnv -> Id -> Int
466 lookupBCEnv env nm
467    = case lookupFM env nm of
468         Nothing -> pprPanic "lookupBCEnv" 
469                             (ppr nm $$ char ' ' $$ vcat (map ppr (fmToList env)))
470         Just xx -> xx
471
472 lookupBCEnv_maybe :: BCEnv -> Id -> Maybe Int
473 lookupBCEnv_maybe = lookupFM
474
475
476 -- When I push one of these on the stack, how much does Sp move by?
477 taggedSizeW :: PrimRep -> Int
478 taggedSizeW pr
479    | isFollowableRep pr = 1
480    | otherwise          = 1{-the tag-} + getPrimRepSize pr
481
482
483 -- The plain size of something, without tag.
484 untaggedSizeW :: PrimRep -> Int
485 untaggedSizeW pr
486    | isFollowableRep pr = 1
487    | otherwise          = getPrimRepSize pr
488
489
490 taggedIdSizeW, untaggedIdSizeW :: Id -> Int
491 taggedIdSizeW   = taggedSizeW   . typePrimRep . idType
492 untaggedIdSizeW = untaggedSizeW . typePrimRep . idType
493
494 \end{code}
495
496 %************************************************************************
497 %*                                                                      *
498 \subsection{The bytecode generator's monad}
499 %*                                                                      *
500 %************************************************************************
501
502 \begin{code}
503 data BcM_State 
504    = BcM_State { bcos      :: [ProtoBCO Name],  -- accumulates completed BCOs
505                  nextlabel :: Int }             -- for generating local labels
506
507 type BcM result = BcM_State -> (result, BcM_State)
508
509 mkBcM_State :: [ProtoBCO Name] -> Int -> BcM_State
510 mkBcM_State = BcM_State
511
512 runBc :: BcM_State -> BcM () -> BcM_State
513 runBc init_st m = case m init_st of { (r,st) -> st }
514
515 thenBc :: BcM a -> (a -> BcM b) -> BcM b
516 thenBc expr cont st
517   = case expr st of { (result, st') -> cont result st' }
518
519 thenBc_ :: BcM a -> BcM b -> BcM b
520 thenBc_ expr cont st
521   = case expr st of { (result, st') -> cont st' }
522
523 returnBc :: a -> BcM a
524 returnBc result st = (result, st)
525
526 mapBc :: (a -> BcM b) -> [a] -> BcM [b]
527 mapBc f []     = returnBc []
528 mapBc f (x:xs)
529   = f x          `thenBc` \ r  ->
530     mapBc f xs   `thenBc` \ rs ->
531     returnBc (r:rs)
532
533 emitBc :: ProtoBCO Name -> BcM ()
534 emitBc bco st
535    = ((), st{bcos = bco : bcos st})
536
537 getLabelBc :: BcM Int
538 getLabelBc st
539    = (nextlabel st, st{nextlabel = 1 + nextlabel st})
540
541 \end{code}
542
543 %************************************************************************
544 %*                                                                      *
545 \subsection{The bytecode assembler}
546 %*                                                                      *
547 %************************************************************************
548
549 The object format for bytecodes is: 16 bits for the opcode, and 16 for
550 each field -- so the code can be considered a sequence of 16-bit ints.
551 Each field denotes either a stack offset or number of items on the
552 stack (eg SLIDE), and index into the pointer table (eg PUSH_G), an
553 index into the literal table (eg PUSH_I/D/L), or a bytecode address in
554 this BCO.
555
556 \begin{code}
557 -- An (almost) assembled BCO.
558 data BCO a = BCO [Word16]       -- instructions
559                  [Word32]       -- literal pool
560                  [a]            -- Names or HValues
561
562 -- Top level assembler fn.
563 assembleBCO :: ProtoBCO Name -> BCO Name
564 assembleBCO (ProtoBCO nm instrs_ordlist origin)
565    = let
566          -- pass 1: collect up the offsets of the local labels
567          instrs = fromOL instrs_ordlist
568          label_env = mkLabelEnv emptyFM 0 instrs
569
570          mkLabelEnv env i_offset [] = env
571          mkLabelEnv env i_offset (i:is)
572             = let new_env 
573                      = case i of LABEL n -> addToFM env n i_offset ; _ -> env
574               in  mkLabelEnv new_env (i_offset + instrSizeB i) is
575
576          findLabel lab
577             = case lookupFM label_env lab of
578                  Just bco_offset -> bco_offset
579                  Nothing -> pprPanic "assembleBCO.findLabel" (int lab)
580
581          -- pass 2: generate the instruction, ptr and nonptr bits
582          (insnW16s, litW32s, ptrs) = mkBits findLabel [] 0 [] 0 [] 0 instrs
583      in
584          BCO insnW16s litW32s ptrs
585
586
587 -- This is where all the action is (pass 2 of the assembler)
588 mkBits :: (Int -> Int)          -- label finder
589        -> [Word16] -> Int       -- reverse acc instr bits
590        -> [Word32] -> Int       -- reverse acc literal bits
591        -> [Name] -> Int         -- reverse acc ptrs
592        -> [BCInstr]             -- insns!
593        -> ([Word16], [Word32], [Name])
594
595 mkBits findLabel r_is n_is r_lits n_lits r_ptrs n_ptrs []
596    = (reverse r_is, reverse r_lits, reverse r_ptrs)
597 mkBits findLabel r_is n_is r_lits n_lits r_ptrs n_ptrs (instr:instrs)
598    = case instr of
599         ARGCHECK  n    -> boring2 i_ARGCHECK n
600         PUSH_L    sz off -> boring3 i_PUSH_L sz off
601         PUSH_G    nm   -> exciting2_P i_PUSH_G n_ptrs nm
602         PUSHT_I   i    -> exciting2_I i_PUSHT_I n_lits i
603         PUSHT_F   f    -> exciting2_F i_PUSHT_F n_lits f
604         PUSHT_D   d    -> exciting2_D i_PUSHT_D n_lits d
605         PUSHU_I   i    -> exciting2_I i_PUSHU_I n_lits i
606         PUSHU_F   f    -> exciting2_F i_PUSHU_F n_lits f
607         PUSHU_D   d    -> exciting2_D i_PUSHU_D n_lits d
608         SLIDE     n by -> boring3 i_SLIDE n by
609         ALLOC     n    -> boring2 i_ALLOC n
610         MKAP      off sz -> boring3 i_MKAP off sz
611         UNPACK    n    -> boring2 i_UNPACK n
612         PACK      dcon sz -> exciting3_A i_PACK sz n_lits nullAddr {-findItbl dcon-}
613         LABEL     lab  -> nop
614         TESTLT_I  i l  -> exciting3_I i_TESTLT_I n_lits (findLabel l) i
615         TESTEQ_I  i l  -> exciting3_I i_TESTEQ_I n_lits (findLabel l) i
616         TESTLT_F  f l  -> exciting3_F i_TESTLT_F n_lits (findLabel l) f
617         TESTEQ_F  f l  -> exciting3_F i_TESTEQ_F n_lits (findLabel l) f
618         TESTLT_D  d l  -> exciting3_D i_TESTLT_D n_lits (findLabel l) d
619         TESTEQ_D  d l  -> exciting3_D i_TESTEQ_D n_lits (findLabel l) d
620         TESTLT_P  i l  -> exciting3_I i_TESTLT_P n_lits (findLabel l) i
621         TESTEQ_P  i l  -> exciting3_I i_TESTEQ_P n_lits (findLabel l) i
622         CASEFAIL       -> boring1 i_CASEFAIL
623         ENTER          -> boring1 i_ENTER
624      where
625         r_mkILit = reverse . mkILit
626         r_mkFLit = reverse . mkFLit
627         r_mkDLit = reverse . mkDLit
628         r_mkALit = reverse . mkALit
629
630         mkw :: Int -> Word16
631         mkw = fromIntegral
632
633         nop
634            = mkBits findLabel r_is n_is r_lits n_lits r_ptrs n_ptrs instrs
635         boring1 i1
636            = mkBits findLabel (mkw i1 : r_is) (n_is+1) 
637                     r_lits n_lits r_ptrs n_ptrs instrs
638         boring2 i1 i2 
639            = mkBits findLabel (mkw i2 : mkw i1 : r_is) (n_is+2) 
640                     r_lits n_lits r_ptrs n_ptrs instrs
641         boring3 i1 i2 i3
642            = mkBits findLabel (mkw i3 : mkw i2 : mkw i1 : r_is) (n_is+3) 
643                     r_lits n_lits r_ptrs n_ptrs instrs
644
645         exciting2_P i1 i2 p
646            = mkBits findLabel (mkw i2 : mkw i1 : r_is) (n_is+2) r_lits n_lits
647                     (p:r_ptrs) (n_ptrs+1) instrs
648         exciting3_P i1 i2 i3 p
649            = mkBits findLabel (mkw i3 : mkw i2 : mkw i1 : r_is) (n_is+3) r_lits n_lits
650                     (p:r_ptrs) (n_ptrs+1) instrs
651
652         exciting2_I i1 i2 i
653            = mkBits findLabel (mkw i2 : mkw i1 : r_is) (n_is+2) 
654                     (r_mkILit i ++ r_lits) (n_lits + intLitSz32s)
655                     r_ptrs n_ptrs instrs
656         exciting3_I i1 i2 i3 i
657            = mkBits findLabel (mkw i3 : mkw i2 : mkw i1 : r_is) (n_is+3) 
658                     (r_mkILit i ++ r_lits) (n_lits + intLitSz32s)
659                     r_ptrs n_ptrs instrs
660
661         exciting2_F i1 i2 f
662            = mkBits findLabel (mkw i2 : mkw i1 : r_is) (n_is+2) 
663                     (r_mkFLit f ++ r_lits) (n_lits + floatLitSz32s)
664                     r_ptrs n_ptrs instrs
665         exciting3_F i1 i2 i3 f
666            = mkBits findLabel (mkw i3 : mkw i2 : mkw i1 : r_is) (n_is+3) 
667                     (r_mkFLit f ++ r_lits) (n_lits + floatLitSz32s)
668                     r_ptrs n_ptrs instrs
669
670         exciting2_D i1 i2 d
671            = mkBits findLabel (mkw i2 : mkw i1 : r_is) (n_is+2) 
672                     (r_mkDLit d ++ r_lits) (n_lits + doubleLitSz32s)
673                     r_ptrs n_ptrs instrs
674         exciting3_D i1 i2 i3 d
675            = mkBits findLabel (mkw i3 : mkw i2 : mkw i1 : r_is) (n_is+3) 
676                     (r_mkDLit d ++ r_lits) (n_lits + doubleLitSz32s)
677                     r_ptrs n_ptrs instrs
678
679         exciting3_A i1 i2 i3 d
680            = mkBits findLabel (mkw i3 : mkw i2 : mkw i1 : r_is) (n_is+3) 
681                     (r_mkALit d ++ r_lits) (n_lits + addrLitSz32s)
682                     r_ptrs n_ptrs instrs
683
684
685 -- The size in bytes of an instruction.
686 instrSizeB :: BCInstr -> Int
687 instrSizeB instr
688    = case instr of
689         ARGCHECK _   -> 4
690         PUSH_L   _ _ -> 6
691         PUSH_G   _   -> 4
692         PUSHT_I  _   -> 4
693         PUSHT_F  _   -> 4
694         PUSHT_D  _   -> 4
695         PUSHU_I  _   -> 4
696         PUSHU_F  _   -> 4
697         PUSHU_D  _   -> 4
698         SLIDE    _ _ -> 6
699         ALLOC    _   -> 4
700         MKAP     _ _ -> 6
701         UNPACK   _   -> 4
702         PACK     _ _ -> 6
703         LABEL    _   -> 4
704         TESTLT_I _ _ -> 6
705         TESTEQ_I _ _ -> 6
706         TESTLT_F _ _ -> 6
707         TESTEQ_F _ _ -> 6
708         TESTLT_D _ _ -> 6
709         TESTEQ_D _ _ -> 6
710         TESTLT_P _ _ -> 6
711         TESTEQ_P _ _ -> 6
712         CASEFAIL     -> 2
713         ENTER        -> 2
714
715
716 -- Sizes of Int, Float and Double literals, in units of 32-bitses
717 intLitSz32s, floatLitSz32s, doubleLitSz32s, addrLitSz32s :: Int
718 intLitSz32s    = wORD_SIZE `div` 4
719 floatLitSz32s  = 1      -- Assume IEEE floats
720 doubleLitSz32s = 2
721 addrLitSz32s   = intLitSz32s
722
723 -- Make lists of 32-bit words for literals, so that when the
724 -- words are placed in memory at increasing addresses, the
725 -- bit pattern is correct for the host's word size and endianness.
726 mkILit :: Int    -> [Word32]
727 mkFLit :: Float  -> [Word32]
728 mkDLit :: Double -> [Word32]
729 mkALit :: Addr   -> [Word32]
730
731 mkFLit f
732    = runST (do
733         arr <- newFloatArray ((0::Int),0)
734         writeFloatArray arr 0 f
735         w0 <- readWord32Array arr 0
736         return [w0]
737      )
738
739 mkDLit d
740    = runST (do
741         arr <- newDoubleArray ((0::Int),0)
742         writeDoubleArray arr 0 d
743         w0 <- readWord32Array arr 0
744         w1 <- readWord32Array arr 1
745         return [w0,w1]
746      )
747
748 mkILit i
749    | wORD_SIZE == 4
750    = runST (do
751         arr <- newIntArray ((0::Int),0)
752         writeIntArray arr 0 i
753         w0 <- readWord32Array arr 0
754         return [w0]
755      )
756    | wORD_SIZE == 8
757    = runST (do
758         arr <- newIntArray ((0::Int),0)
759         writeIntArray arr 0 i
760         w0 <- readWord32Array arr 0
761         w1 <- readWord32Array arr 1
762         return [w0,w1]
763      )
764    
765 mkALit a
766    | wORD_SIZE == 4
767    = runST (do
768         arr <- newAddrArray ((0::Int),0)
769         writeAddrArray arr 0 a
770         w0 <- readWord32Array arr 0
771         return [w0]
772      )
773    | wORD_SIZE == 8
774    = runST (do
775         arr <- newAddrArray ((0::Int),0)
776         writeAddrArray arr 0 a
777         w0 <- readWord32Array arr 0
778         w1 <- readWord32Array arr 1
779         return [w0,w1]
780      )
781    
782
783
784 #include "../rts/Bytecodes.h"
785
786 i_ARGCHECK = (bci_ARGCHECK :: Int)
787 i_PUSH_L   = (bci_PUSH_L   :: Int)
788 i_PUSH_G   = (bci_PUSH_G   :: Int)
789 i_PUSHT_I  = (bci_PUSHT_I  :: Int)
790 i_PUSHT_F  = (bci_PUSHT_F  :: Int)
791 i_PUSHT_D  = (bci_PUSHT_D  :: Int)
792 i_PUSHU_I  = (bci_PUSHU_I  :: Int)
793 i_PUSHU_F  = (bci_PUSHU_F  :: Int)
794 i_PUSHU_D  = (bci_PUSHU_D  :: Int)
795 i_SLIDE    = (bci_SLIDE    :: Int)
796 i_ALLOC    = (bci_ALLOC    :: Int)
797 i_MKAP     = (bci_MKAP     :: Int)
798 i_UNPACK   = (bci_UNPACK   :: Int)
799 i_PACK     = (bci_PACK     :: Int)
800 i_LABEL    = (bci_LABEL    :: Int)
801 i_TESTLT_I = (bci_TESTLT_I :: Int)
802 i_TESTEQ_I = (bci_TESTEQ_I :: Int)
803 i_TESTLT_F = (bci_TESTLT_F :: Int)
804 i_TESTEQ_F = (bci_TESTEQ_F :: Int)
805 i_TESTLT_D = (bci_TESTLT_D :: Int)
806 i_TESTEQ_D = (bci_TESTEQ_D :: Int)
807 i_TESTLT_P = (bci_TESTLT_P :: Int)
808 i_TESTEQ_P = (bci_TESTEQ_P :: Int)
809 i_CASEFAIL = (bci_CASEFAIL :: Int)
810 i_ENTER    = (bci_ENTER    :: Int)
811
812 \end{code}