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