[project @ 2000-07-03 14:59:25 by simonmar]
[ghc-hetmet.git] / ghc / compiler / nativeGen / AbsCStixGen.lhs
1 %
2 % (c) The AQUA Project, Glasgow University, 1993-1998
3 %
4
5 \begin{code}
6 module AbsCStixGen ( genCodeAbstractC ) where
7
8 #include "HsVersions.h"
9
10 import Ratio    ( Rational )
11
12 import AbsCSyn
13 import Stix
14 import MachMisc
15
16 import AbsCUtils        ( getAmodeRep, mixedTypeLocn,
17                           nonemptyAbsC, mkAbsCStmts
18                         )
19 import PprAbsC          ( dumpRealC )
20 import SMRep            ( fixedItblSize, 
21                           rET_SMALL, rET_BIG, 
22                           rET_VEC_SMALL, rET_VEC_BIG 
23                         )
24 import Constants        ( mIN_UPD_SIZE )
25 import CLabel           ( CLabel, mkReturnInfoLabel, mkReturnPtLabel,
26                           mkClosureTblLabel, mkClosureLabel,
27                           moduleRegdLabel, labelDynamic,
28                           mkSplitMarkerLabel )
29 import ClosureInfo      ( infoTableLabelFromCI, entryLabelFromCI,
30                           fastLabelFromCI, closureUpdReqd,
31                           staticClosureNeedsLink
32                         )
33 import Literal          ( Literal(..), word2IntLit )
34 import Maybes           ( maybeToBool )
35 import PrimOp           ( primOpNeedsWrapper, PrimOp(..) )
36 import PrimRep          ( isFloatingRep, PrimRep(..) )
37 import StixInfo         ( genCodeInfoTable, genBitmapInfoTable )
38 import StixMacro        ( macroCode, checkCode )
39 import StixPrim         ( primCode, amodeToStix, amodeToStix' )
40 import Outputable       ( pprPanic, ppr )
41 import UniqSupply       ( returnUs, thenUs, mapUs, getUniqueUs, UniqSM )
42 import Util             ( naturalMergeSortLe )
43 import Panic            ( panic )
44 import TyCon            ( tyConDataCons )
45 import DataCon          ( dataConWrapId )
46 import BitSet           ( intBS )
47 import Name             ( NamedThing(..) )
48 import Char             ( ord )
49 import CmdLineOpts      ( opt_Static )
50 \end{code}
51
52 For each independent chunk of AbstractC code, we generate a list of
53 @StixTree@s, where each tree corresponds to a single Stix instruction.
54 We leave the chunks separated so that register allocation can be
55 performed locally within the chunk.
56
57 \begin{code}
58 genCodeAbstractC :: AbstractC -> UniqSM [StixTree]
59
60 genCodeAbstractC absC
61   = gentopcode absC
62  where
63  a2stix      = amodeToStix
64  a2stix'     = amodeToStix'
65  volsaves    = volatileSaves
66  volrestores = volatileRestores
67  p2stix      = primCode
68  macro_code  = macroCode
69  -- real code follows... ---------
70 \end{code}
71
72 Here we handle top-level things, like @CCodeBlock@s and
73 @CClosureInfoTable@s.
74
75 \begin{code}
76  {-
77  genCodeTopAbsC
78     :: AbstractC
79     -> UniqSM [StixTree]
80  -}
81
82  gentopcode (CCodeBlock lbl absC)
83   = gencode absC                                `thenUs` \ code ->
84     returnUs (StSegment TextSegment : StFunBegin lbl : code [StFunEnd lbl])
85
86  gentopcode stmt@(CStaticClosure lbl _ _ _)
87   = genCodeStaticClosure stmt                   `thenUs` \ code ->
88     returnUs (
89        if   opt_Static
90        then StSegment DataSegment 
91             : StLabel lbl : code []
92        else StSegment DataSegment 
93             : StData PtrRep [StInt 0] -- DLLised world, need extra zero word
94             : StLabel lbl : code []
95     )
96
97  gentopcode stmt@(CRetVector lbl _ _ _)
98   = genCodeVecTbl stmt                          `thenUs` \ code ->
99     returnUs (StSegment TextSegment : code [StLabel lbl])
100
101  gentopcode stmt@(CRetDirect uniq absC srt liveness)
102   = gencode absC                                       `thenUs` \ code ->
103     genBitmapInfoTable liveness srt closure_type False `thenUs` \ itbl ->
104     returnUs (StSegment TextSegment : 
105               itbl (StLabel lbl_info : StLabel lbl_ret : code []))
106   where 
107         lbl_info = mkReturnInfoLabel uniq
108         lbl_ret  = mkReturnPtLabel uniq
109         closure_type = case liveness of
110                          LvSmall _ -> rET_SMALL
111                          LvLarge _ -> rET_BIG
112
113  gentopcode stmt@(CClosureInfoAndCode cl_info slow Nothing _)
114
115   | slow_is_empty
116   = genCodeInfoTable stmt               `thenUs` \ itbl ->
117     returnUs (StSegment TextSegment : itbl [])
118
119   | otherwise
120   = genCodeInfoTable stmt               `thenUs` \ itbl ->
121     gencode slow                        `thenUs` \ slow_code ->
122     returnUs (StSegment TextSegment : itbl (StFunBegin slow_lbl :
123               slow_code [StFunEnd slow_lbl]))
124   where
125     slow_is_empty = not (maybeToBool (nonemptyAbsC slow))
126     slow_lbl = entryLabelFromCI cl_info
127
128  gentopcode stmt@(CClosureInfoAndCode cl_info slow (Just fast) _) =
129  -- ToDo: what if this is empty? ------------------------^^^^
130     genCodeInfoTable stmt               `thenUs` \ itbl ->
131     gencode slow                        `thenUs` \ slow_code ->
132     gencode fast                        `thenUs` \ fast_code ->
133     returnUs (StSegment TextSegment : itbl (StFunBegin slow_lbl :
134               slow_code (StFunEnd slow_lbl : StFunBegin fast_lbl :
135               fast_code [StFunEnd fast_lbl])))
136   where
137     slow_lbl = entryLabelFromCI cl_info
138     fast_lbl = fastLabelFromCI cl_info
139
140  gentopcode stmt@(CSRT lbl closures)
141   = returnUs [ StSegment TextSegment 
142              , StLabel lbl 
143              , StData DataPtrRep (map mk_StCLbl_for_SRT closures)
144              ]
145     where
146        mk_StCLbl_for_SRT :: CLabel -> StixTree
147        mk_StCLbl_for_SRT label
148           | labelDynamic label
149           = StIndex CharRep (StCLbl label) (StInt 1)
150           | otherwise
151           = StCLbl label
152
153  gentopcode stmt@(CBitmap lbl mask)
154   = returnUs [ StSegment TextSegment 
155              , StLabel lbl 
156              , StData WordRep (StInt (toInteger (length mask)) : 
157                                 map  (StInt . toInteger . intBS) mask)
158              ]
159
160  gentopcode stmt@(CClosureTbl tycon)
161   = returnUs [ StSegment TextSegment
162              , StLabel (mkClosureTblLabel tycon)
163              , StData DataPtrRep (map (StCLbl . mkClosureLabel . getName . dataConWrapId) 
164                                       (tyConDataCons tycon) )
165              ]
166
167  gentopcode stmt@(CModuleInitBlock lbl absC)
168   = gencode absC                        `thenUs` \ code ->
169     getUniqLabelNCG                     `thenUs` \ tmp_lbl ->
170     getUniqLabelNCG                     `thenUs` \ flag_lbl ->
171     returnUs ( StSegment DataSegment
172              : StLabel flag_lbl
173              : StData IntRep [StInt 0]
174              : StSegment TextSegment
175              : StLabel lbl
176              : StCondJump tmp_lbl (StPrim IntNeOp       
177                                      [StInd IntRep (StCLbl flag_lbl),
178                                       StInt 0])
179              : StAssign IntRep (StInd IntRep (StCLbl flag_lbl)) (StInt 1)
180              : code 
181              [ StLabel tmp_lbl
182              , StAssign PtrRep stgSp
183                         (StIndex PtrRep stgSp (StInt (-1)))
184              , StJump (StInd WordRep stgSp)
185              ])
186
187  gentopcode absC
188   = gencode absC                                `thenUs` \ code ->
189     returnUs (StSegment TextSegment : code [])
190 \end{code}
191
192 \begin{code}
193  {-
194  genCodeVecTbl
195     :: AbstractC
196     -> UniqSM StixTreeList
197  -}
198  genCodeVecTbl (CRetVector lbl amodes srt liveness)
199   = genBitmapInfoTable liveness srt closure_type True `thenUs` \itbl ->
200     returnUs (\xs -> vectbl : itbl xs)
201   where
202     vectbl = StData PtrRep (reverse (map a2stix amodes))
203     closure_type = case liveness of
204                     LvSmall _ -> rET_VEC_SMALL
205                     LvLarge _ -> rET_VEC_BIG
206
207 \end{code}
208
209 \begin{code}
210  {-
211  genCodeStaticClosure
212     :: AbstractC
213     -> UniqSM StixTreeList
214  -}
215  genCodeStaticClosure (CStaticClosure _ cl_info cost_centre amodes)
216   = returnUs (\xs -> table ++ xs)
217   where
218     table = StData PtrRep [StCLbl (infoTableLabelFromCI cl_info)] : 
219             map (\amode -> StData (getAmodeRep amode) [a2stix amode]) amodes ++
220             [StData PtrRep (padding_wds ++ static_link)]
221
222     -- always at least one padding word: this is the static link field
223     -- for the garbage collector.
224     padding_wds = if closureUpdReqd cl_info then
225                         take (max 0 (mIN_UPD_SIZE - length amodes)) zeros
226                   else
227                         []
228
229     static_link | staticClosureNeedsLink cl_info = [StInt 0]
230                 | otherwise                      = []
231
232     zeros = StInt 0 : zeros
233
234     {- needed??? --SDM
235         -- Watch out for VoidKinds...cf. PprAbsC
236     amodeZeroVoid item
237       | getAmodeRep item == VoidRep = StInt 0
238       | otherwise = a2stix item
239     -}
240
241 \end{code}
242
243 Now the individual AbstractC statements.
244
245 \begin{code}
246  {-
247  gencode
248     :: AbstractC
249     -> UniqSM StixTreeList
250  -}
251 \end{code}
252
253 @AbsCNop@s just disappear.
254
255 \begin{code}
256
257  gencode AbsCNop = returnUs id
258
259 \end{code}
260
261 Split markers just insert a __stg_split_marker, which is caught by the
262 split-mangler later on and used to split the assembly into chunks.
263
264 \begin{code}
265
266  gencode CSplitMarker = returnUs (\xs -> StLabel mkSplitMarkerLabel : xs)
267
268 \end{code}
269
270 AbstractC instruction sequences are handled individually, and the
271 resulting StixTreeLists are joined together.
272
273 \begin{code}
274
275  gencode (AbsCStmts c1 c2)
276   = gencode c1                          `thenUs` \ b1 ->
277     gencode c2                          `thenUs` \ b2 ->
278     returnUs (b1 . b2)
279
280 \end{code}
281
282 Initialising closure headers in the heap...a fairly complex ordeal if
283 done properly.  For now, we just set the info pointer, but we should
284 really take a peek at the flags to determine whether or not there are
285 other things to be done (setting cost centres, age headers, global
286 addresses, etc.)
287
288 \begin{code}
289
290  gencode (CInitHdr cl_info reg_rel _)
291   = let
292         lhs = a2stix reg_rel
293         lbl = infoTableLabelFromCI cl_info
294     in
295         returnUs (\xs -> StAssign PtrRep (StInd PtrRep lhs) (StCLbl lbl) : xs)
296
297 \end{code}
298
299 Heap/Stack Checks.
300
301 \begin{code}
302
303  gencode (CCheck macro args assts)
304   = gencode assts `thenUs` \assts_stix ->
305     checkCode macro args assts_stix
306
307 \end{code}
308
309 Assignment, the curse of von Neumann, is the center of the code we
310 produce.  In most cases, the type of the assignment is determined
311 by the type of the destination.  However, when the destination can
312 have mixed types, the type of the assignment is ``StgWord'' (we use
313 PtrRep for lack of anything better).  Think:  do we also want a cast
314 of the source?  Be careful about floats/doubles.
315
316 \begin{code}
317
318  gencode (CAssign lhs rhs)
319   | getAmodeRep lhs == VoidRep = returnUs id
320   | otherwise
321   = let pk = getAmodeRep lhs
322         pk' = if mixedTypeLocn lhs && not (isFloatingRep pk) then IntRep else pk
323         lhs' = a2stix lhs
324         rhs' = a2stix' rhs
325     in
326         returnUs (\xs -> StAssign pk' lhs' rhs' : xs)
327
328 \end{code}
329
330 Unconditional jumps, including the special ``enter closure'' operation.
331 Note that the new entry convention requires that we load the InfoPtr (R2)
332 with the address of the info table before jumping to the entry code for Node.
333
334 For a vectored return, we must subtract the size of the info table to
335 get at the return vector.  This depends on the size of the info table,
336 which varies depending on whether we're profiling etc.
337
338 \begin{code}
339
340  gencode (CJump dest)
341   = returnUs (\xs -> StJump (a2stix dest) : xs)
342
343  gencode (CFallThrough (CLbl lbl _))
344   = returnUs (\xs -> StFallThrough lbl : xs)
345
346  gencode (CReturn dest DirectReturn)
347   = returnUs (\xs -> StJump (a2stix dest) : xs)
348
349  gencode (CReturn table (StaticVectoredReturn n))
350   = returnUs (\xs -> StJump dest : xs)
351   where
352     dest = StInd PtrRep (StIndex PtrRep (a2stix table)
353                                   (StInt (toInteger (-n-fixedItblSize-1))))
354
355  gencode (CReturn table (DynamicVectoredReturn am))
356   = returnUs (\xs -> StJump dest : xs)
357   where
358     dest = StInd PtrRep (StIndex PtrRep (a2stix table) dyn_off)
359     dyn_off = StPrim IntSubOp [StPrim IntNegOp [a2stix am], 
360                                StInt (toInteger (fixedItblSize+1))]
361
362 \end{code}
363
364 Now the PrimOps, some of which may need caller-saves register wrappers.
365
366 \begin{code}
367
368  gencode (COpStmt results op args vols)
369   -- ToDo (ADR?): use that liveness mask
370   | primOpNeedsWrapper op
371   = let
372         saves = volsaves vols
373         restores = volrestores vols
374     in
375         p2stix (nonVoid results) op (nonVoid args)
376                                                         `thenUs` \ code ->
377         returnUs (\xs -> saves ++ code (restores ++ xs))
378
379   | otherwise = p2stix (nonVoid results) op (nonVoid args)
380     where
381         nonVoid = filter ((/= VoidRep) . getAmodeRep)
382
383 \end{code}
384
385 Now the dreaded conditional jump.
386
387 Now the if statement.  Almost *all* flow of control are of this form.
388 @
389         if (am==lit) { absC } else { absCdef }
390 @
391         =>
392 @
393         IF am = lit GOTO l1:
394         absC
395         jump l2:
396    l1:
397         absCdef
398    l2:
399 @
400
401 \begin{code}
402
403  gencode (CSwitch discrim alts deflt)
404   = case alts of
405       [] -> gencode deflt
406
407       [(tag,alt_code)] -> case maybe_empty_deflt of
408                                 Nothing -> gencode alt_code
409                                 Just dc -> mkIfThenElse discrim tag alt_code dc
410
411       [(tag1@(MachInt i1), alt_code1),
412        (tag2@(MachInt i2), alt_code2)]
413         | deflt_is_empty && i1 == 0 && i2 == 1
414         -> mkIfThenElse discrim tag1 alt_code1 alt_code2
415         | deflt_is_empty && i1 == 1 && i2 == 0
416         -> mkIfThenElse discrim tag2 alt_code2 alt_code1
417
418         -- If the @discrim@ is simple, then this unfolding is safe.
419       other | simple_discrim -> mkSimpleSwitches discrim alts deflt
420
421         -- Otherwise, we need to do a bit of work.
422       other ->  getUniqueUs                       `thenUs` \ u ->
423                 gencode (AbsCStmts
424                 (CAssign (CTemp u pk) discrim)
425                 (CSwitch (CTemp u pk) alts deflt))
426
427   where
428     maybe_empty_deflt = nonemptyAbsC deflt
429     deflt_is_empty = case maybe_empty_deflt of
430                         Nothing -> True
431                         Just _  -> False
432
433     pk = getAmodeRep discrim
434
435     simple_discrim = case discrim of
436                         CReg _    -> True
437                         CTemp _ _ -> True
438                         other     -> False
439 \end{code}
440
441
442
443 Finally, all of the disgusting AbstractC macros.
444
445 \begin{code}
446
447  gencode (CMacroStmt macro args) = macro_code macro args
448
449  gencode (CCallProfCtrMacro macro _)
450   = returnUs (\xs -> StComment macro : xs)
451
452  gencode (CCallProfCCMacro macro _)
453   = returnUs (\xs -> StComment macro : xs)
454
455  gencode other
456   = pprPanic "AbsCStixGen.gencode" (dumpRealC other)
457 \end{code}
458
459 Here, we generate a jump table if there are more than four (integer)
460 alternatives and the jump table occupancy is greater than 50%.
461 Otherwise, we generate a binary comparison tree.  (Perhaps this could
462 be tuned.)
463
464 \begin{code}
465
466  intTag :: Literal -> Integer
467  intTag (MachChar c)  = toInteger (ord c)
468  intTag (MachInt i)   = i
469  intTag (MachWord w)  = intTag (word2IntLit (MachWord w))
470  intTag _             = panic "intTag"
471
472  fltTag :: Literal -> Rational
473
474  fltTag (MachFloat f)  = f
475  fltTag (MachDouble d) = d
476  fltTag x              = pprPanic "fltTag" (ppr x)
477
478  {-
479  mkSimpleSwitches
480     :: CAddrMode -> [(Literal,AbstractC)] -> AbstractC
481     -> UniqSM StixTreeList
482  -}
483  mkSimpleSwitches am alts absC
484   = getUniqLabelNCG                                     `thenUs` \ udlbl ->
485     getUniqLabelNCG                                     `thenUs` \ ujlbl ->
486     let am' = a2stix am
487         joinedAlts = map (\ (tag,code) -> (tag, mkJoin code ujlbl)) alts
488         sortedAlts = naturalMergeSortLe leAlt joinedAlts
489                      -- naturalMergeSortLe, because we often get sorted alts to begin with
490
491         lowTag = intTag (fst (head sortedAlts))
492         highTag = intTag (fst (last sortedAlts))
493
494         -- lowest and highest possible values the discriminant could take
495         lowest = if floating then targetMinDouble else targetMinInt
496         highest = if floating then targetMaxDouble else targetMaxInt
497     in
498         (
499         if not floating && choices > 4 && highTag - lowTag < toInteger (2 * choices) then
500             mkJumpTable am' sortedAlts lowTag highTag udlbl
501         else
502             mkBinaryTree am' floating sortedAlts choices lowest highest udlbl
503         )
504                                                         `thenUs` \ alt_code ->
505         gencode absC                            `thenUs` \ dflt_code ->
506
507         returnUs (\xs -> alt_code (StLabel udlbl : dflt_code (StLabel ujlbl : xs)))
508
509     where
510         floating = isFloatingRep (getAmodeRep am)
511         choices = length alts
512
513         (x@(MachChar _),_)  `leAlt` (y,_) = intTag x <= intTag y
514         (x@(MachInt _), _)  `leAlt` (y,_) = intTag x <= intTag y
515         (x@(MachWord _), _) `leAlt` (y,_) = intTag x <= intTag y
516         (x,_)               `leAlt` (y,_) = fltTag x <= fltTag y
517
518 \end{code}
519
520 We use jump tables when doing an integer switch on a relatively dense
521 list of alternatives.  We expect to be given a list of alternatives,
522 sorted by tag, and a range of values for which we are to generate a
523 table.  Of course, the tags of the alternatives should lie within the
524 indicated range.  The alternatives need not cover the range; a default
525 target is provided for the missing alternatives.
526
527 If a join is necessary after the switch, the alternatives should
528 already finish with a jump to the join point.
529
530 \begin{code}
531  {-
532  mkJumpTable
533     :: StixTree                 -- discriminant
534     -> [(Literal, AbstractC)]   -- alternatives
535     -> Integer                  -- low tag
536     -> Integer                  -- high tag
537     -> CLabel                   -- default label
538     -> UniqSM StixTreeList
539  -}
540
541  mkJumpTable am alts lowTag highTag dflt
542   = getUniqLabelNCG                                     `thenUs` \ utlbl ->
543     mapUs genLabel alts                                 `thenUs` \ branches ->
544     let cjmpLo = StCondJump dflt (StPrim IntLtOp [am, StInt (toInteger lowTag)])
545         cjmpHi = StCondJump dflt (StPrim IntGtOp [am, StInt (toInteger highTag)])
546
547         offset = StPrim IntSubOp [am, StInt lowTag]
548
549         jump = StJump (StInd PtrRep (StIndex PtrRep (StCLbl utlbl) offset))
550         tlbl = StLabel utlbl
551         table = StData PtrRep (mkTable branches [lowTag..highTag] [])
552     in
553         mapUs mkBranch branches                         `thenUs` \ alts ->
554
555         returnUs (\xs -> cjmpLo : cjmpHi : jump :
556                          StSegment DataSegment : tlbl : table :
557                          StSegment TextSegment : foldr1 (.) alts xs)
558
559     where
560         genLabel x = getUniqLabelNCG `thenUs` \ lbl -> returnUs (lbl, x)
561
562         mkBranch (lbl,(_,alt)) =
563             gencode alt                         `thenUs` \ alt_code ->
564             returnUs (\xs -> StLabel lbl : alt_code xs)
565
566         mkTable _  []     tbl = reverse tbl
567         mkTable [] (x:xs) tbl = mkTable [] xs (StCLbl dflt : tbl)
568         mkTable alts@((lbl,(tag,_)):rest) (x:xs) tbl
569           | intTag tag == x = mkTable rest xs (StCLbl lbl : tbl)
570           | otherwise = mkTable alts xs (StCLbl dflt : tbl)
571
572 \end{code}
573
574 We generate binary comparison trees when a jump table is inappropriate.
575 We expect to be given a list of alternatives, sorted by tag, and for
576 convenience, the length of the alternative list.  We recursively break
577 the list in half and do a comparison on the first tag of the second half
578 of the list.  (Odd lists are broken so that the second half of the list
579 is longer.)  We can handle either integer or floating kind alternatives,
580 so long as they are not mixed.  (We assume that the type of the discriminant
581 determines the type of the alternatives.)
582
583 As with the jump table approach, if a join is necessary after the switch, the
584 alternatives should already finish with a jump to the join point.
585
586 \begin{code}
587  {-
588  mkBinaryTree
589     :: StixTree                 -- discriminant
590     -> Bool                     -- floating point?
591     -> [(Literal, AbstractC)]   -- alternatives
592     -> Int                      -- number of choices
593     -> Literal                  -- low tag
594     -> Literal                  -- high tag
595     -> CLabel                   -- default code label
596     -> UniqSM StixTreeList
597  -}
598
599  mkBinaryTree am floating [(tag,alt)] _ lowTag highTag udlbl
600   | rangeOfOne = gencode alt
601   | otherwise
602   = let tag' = a2stix (CLit tag)
603         cmpOp = if floating then DoubleNeOp else IntNeOp
604         test = StPrim cmpOp [am, tag']
605         cjmp = StCondJump udlbl test
606     in
607         gencode alt                             `thenUs` \ alt_code ->
608         returnUs (\xs -> cjmp : alt_code xs)
609
610     where
611         rangeOfOne = not floating && intTag lowTag + 1 >= intTag highTag
612         -- When there is only one possible tag left in range, we skip the comparison
613
614  mkBinaryTree am floating alts choices lowTag highTag udlbl
615   = getUniqLabelNCG                                     `thenUs` \ uhlbl ->
616     let tag' = a2stix (CLit splitTag)
617         cmpOp = if floating then DoubleGeOp else IntGeOp
618         test = StPrim cmpOp [am, tag']
619         cjmp = StCondJump uhlbl test
620     in
621         mkBinaryTree am floating alts_lo half lowTag splitTag udlbl
622                                                         `thenUs` \ lo_code ->
623         mkBinaryTree am floating alts_hi (choices - half) splitTag highTag udlbl
624                                                         `thenUs` \ hi_code ->
625
626         returnUs (\xs -> cjmp : lo_code (StLabel uhlbl : hi_code xs))
627
628     where
629         half = choices `div` 2
630         (alts_lo, alts_hi) = splitAt half alts
631         splitTag = fst (head alts_hi)
632
633 \end{code}
634
635 \begin{code}
636  {-
637  mkIfThenElse
638     :: CAddrMode            -- discriminant
639     -> Literal              -- tag
640     -> AbstractC            -- if-part
641     -> AbstractC            -- else-part
642     -> UniqSM StixTreeList
643  -}
644
645  mkIfThenElse discrim tag alt deflt
646   = getUniqLabelNCG                                     `thenUs` \ ujlbl ->
647     getUniqLabelNCG                                     `thenUs` \ utlbl ->
648     let discrim' = a2stix discrim
649         tag' = a2stix (CLit tag)
650         cmpOp = if (isFloatingRep (getAmodeRep discrim)) then DoubleNeOp else IntNeOp
651         test = StPrim cmpOp [discrim', tag']
652         cjmp = StCondJump utlbl test
653         dest = StLabel utlbl
654         join = StLabel ujlbl
655     in
656         gencode (mkJoin alt ujlbl)              `thenUs` \ alt_code ->
657         gencode deflt                           `thenUs` \ dflt_code ->
658         returnUs (\xs -> cjmp : alt_code (dest : dflt_code (join : xs)))
659
660 mkJoin :: AbstractC -> CLabel -> AbstractC
661
662 mkJoin code lbl
663   | mightFallThrough code = mkAbsCStmts code (CJump (CLbl lbl PtrRep))
664   | otherwise = code
665 \end{code}
666
667 %---------------------------------------------------------------------------
668
669 This answers the question: Can the code fall through to the next
670 line(s) of code?  This errs towards saying True if it can't choose,
671 because it is used for eliminating needless jumps.  In other words, if
672 you might possibly {\em not} jump, then say yes to falling through.
673
674 \begin{code}
675 mightFallThrough :: AbstractC -> Bool
676
677 mightFallThrough absC = ft absC True
678  where
679   ft AbsCNop       if_empty = if_empty
680
681   ft (CJump _)       if_empty = False
682   ft (CReturn _ _)   if_empty = False
683   ft (CSwitch _ alts deflt) if_empty
684         = ft deflt if_empty ||
685           or [ft alt if_empty | (_,alt) <- alts]
686
687   ft (AbsCStmts c1 c2) if_empty = ft c2 (ft c1 if_empty)
688   ft _ if_empty = if_empty
689
690 {- Old algorithm, which called nonemptyAbsC for every subexpression! =========
691 fallThroughAbsC (AbsCStmts c1 c2)
692   = case nonemptyAbsC c2 of
693         Nothing -> fallThroughAbsC c1
694         Just x -> fallThroughAbsC x
695 fallThroughAbsC (CJump _)        = False
696 fallThroughAbsC (CReturn _ _)    = False
697 fallThroughAbsC (CSwitch _ choices deflt)
698   = (not (isEmptyAbsC deflt) && fallThroughAbsC deflt)
699     || or (map (fallThroughAbsC . snd) choices)
700 fallThroughAbsC other            = True
701
702 isEmptyAbsC :: AbstractC -> Bool
703 isEmptyAbsC = not . maybeToBool . nonemptyAbsC
704 ================= End of old, quadratic, algorithm -}
705 \end{code}