2 % (c) The AQUA Project, Glasgow University, 1993-1998
6 module AbsCStixGen ( genCodeAbstractC ) where
8 #include "HsVersions.h"
10 import Ratio ( Rational )
16 import AbsCUtils ( getAmodeRep, mixedTypeLocn,
17 nonemptyAbsC, mkAbsCStmts
19 import PprAbsC ( dumpRealC )
20 import SMRep ( fixedItblSize,
22 rET_VEC_SMALL, rET_VEC_BIG
24 import Constants ( mIN_UPD_SIZE )
25 import CLabel ( CLabel, mkReturnInfoLabel, mkReturnPtLabel,
26 mkClosureTblLabel, mkClosureLabel,
27 moduleRegdLabel, labelDynamic,
29 import ClosureInfo ( infoTableLabelFromCI, entryLabelFromCI,
30 fastLabelFromCI, closureUpdReqd,
31 staticClosureNeedsLink
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(..) )
49 import CmdLineOpts ( opt_Static, opt_EnsureSplittableC )
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.
58 genCodeAbstractC :: AbstractC -> UniqSM [StixTree]
64 a2stix' = amodeToStix'
65 volsaves = volatileSaves
66 volrestores = volatileRestores
68 macro_code = macroCode
69 -- real code follows... ---------
72 Here we handle top-level things, like @CCodeBlock@s and
82 gentopcode (CCodeBlock lbl absC)
83 = gencode absC `thenUs` \ code ->
84 returnUs (StSegment TextSegment : StFunBegin lbl : code [StFunEnd lbl])
86 gentopcode stmt@(CStaticClosure lbl _ _ _)
87 = genCodeStaticClosure stmt `thenUs` \ code ->
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 []
97 gentopcode stmt@(CRetVector lbl _ _ _)
98 = genCodeVecTbl stmt `thenUs` \ code ->
99 returnUs (StSegment TextSegment : code [StLabel lbl])
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 []))
107 lbl_info = mkReturnInfoLabel uniq
108 lbl_ret = mkReturnPtLabel uniq
109 closure_type = case liveness of
110 LvSmall _ -> rET_SMALL
113 gentopcode stmt@(CClosureInfoAndCode cl_info slow Nothing _)
116 = genCodeInfoTable stmt `thenUs` \ itbl ->
117 returnUs (StSegment TextSegment : itbl [])
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]))
125 slow_is_empty = not (maybeToBool (nonemptyAbsC slow))
126 slow_lbl = entryLabelFromCI cl_info
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])))
137 slow_lbl = entryLabelFromCI cl_info
138 fast_lbl = fastLabelFromCI cl_info
140 gentopcode stmt@(CSRT lbl closures)
141 = returnUs [ StSegment TextSegment
143 , StData DataPtrRep (map mk_StCLbl_for_SRT closures)
146 mk_StCLbl_for_SRT :: CLabel -> StixTree
147 mk_StCLbl_for_SRT label
149 = StIndex Int8Rep (StCLbl label) (StInt 1)
153 gentopcode stmt@(CBitmap lbl mask)
154 = returnUs [ StSegment TextSegment
156 , StData WordRep (StInt (toInteger (length mask)) :
157 map (StInt . toInteger . intBS) mask)
160 gentopcode stmt@(CClosureTbl tycon)
161 = returnUs [ StSegment TextSegment
162 , StLabel (mkClosureTblLabel tycon)
163 , StData DataPtrRep (map (StCLbl . mkClosureLabel . getName . dataConWrapId)
164 (tyConDataCons tycon) )
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
173 : StData IntRep [StInt 0]
174 : StSegment TextSegment
176 : StCondJump tmp_lbl (StPrim IntNeOp
177 [StInd IntRep (StCLbl flag_lbl),
179 : StAssign IntRep (StInd IntRep (StCLbl flag_lbl)) (StInt 1)
182 , StAssign PtrRep stgSp
183 (StIndex PtrRep stgSp (StInt (-1)))
184 , StJump (StInd WordRep stgSp)
188 = gencode absC `thenUs` \ code ->
189 returnUs (StSegment TextSegment : code [])
196 -> UniqSM StixTreeList
198 genCodeVecTbl (CRetVector lbl amodes srt liveness)
199 = genBitmapInfoTable liveness srt closure_type True `thenUs` \itbl ->
200 returnUs (\xs -> vectbl : itbl xs)
202 vectbl = StData PtrRep (reverse (map a2stix amodes))
203 closure_type = case liveness of
204 LvSmall _ -> rET_VEC_SMALL
205 LvLarge _ -> rET_VEC_BIG
213 -> UniqSM StixTreeList
215 genCodeStaticClosure (CStaticClosure _ cl_info cost_centre amodes)
216 = returnUs (\xs -> table ++ xs)
218 table = StData PtrRep [StCLbl (infoTableLabelFromCI cl_info)] :
219 map do_one_amode amodes ++
220 [StData PtrRep (padding_wds ++ static_link)]
223 = StData (promote_to_word (getAmodeRep amode)) [a2stix amode]
225 -- We need to promote any item smaller than a word to a word
226 promote_to_word Int8Rep = IntRep
227 promote_to_word CharRep = IntRep
228 promote_to_word other = other
230 -- always at least one padding word: this is the static link field
231 -- for the garbage collector.
232 padding_wds = if closureUpdReqd cl_info then
233 take (max 0 (mIN_UPD_SIZE - length amodes)) zeros
237 static_link | staticClosureNeedsLink cl_info = [StInt 0]
240 zeros = StInt 0 : zeros
243 -- Watch out for VoidKinds...cf. PprAbsC
245 | getAmodeRep item == VoidRep = StInt 0
246 | otherwise = a2stix item
251 Now the individual AbstractC statements.
257 -> UniqSM StixTreeList
261 @AbsCNop@s just disappear.
265 gencode AbsCNop = returnUs id
269 Split markers just insert a __stg_split_marker, which is caught by the
270 split-mangler later on and used to split the assembly into chunks.
275 | opt_EnsureSplittableC = returnUs (\xs -> StLabel mkSplitMarkerLabel : xs)
276 | otherwise = returnUs id
280 AbstractC instruction sequences are handled individually, and the
281 resulting StixTreeLists are joined together.
285 gencode (AbsCStmts c1 c2)
286 = gencode c1 `thenUs` \ b1 ->
287 gencode c2 `thenUs` \ b2 ->
292 Initialising closure headers in the heap...a fairly complex ordeal if
293 done properly. For now, we just set the info pointer, but we should
294 really take a peek at the flags to determine whether or not there are
295 other things to be done (setting cost centres, age headers, global
300 gencode (CInitHdr cl_info reg_rel _)
303 lbl = infoTableLabelFromCI cl_info
305 returnUs (\xs -> StAssign PtrRep (StInd PtrRep lhs) (StCLbl lbl) : xs)
313 gencode (CCheck macro args assts)
314 = gencode assts `thenUs` \assts_stix ->
315 checkCode macro args assts_stix
319 Assignment, the curse of von Neumann, is the center of the code we
320 produce. In most cases, the type of the assignment is determined
321 by the type of the destination. However, when the destination can
322 have mixed types, the type of the assignment is ``StgWord'' (we use
323 PtrRep for lack of anything better). Think: do we also want a cast
324 of the source? Be careful about floats/doubles.
328 gencode (CAssign lhs rhs)
329 | getAmodeRep lhs == VoidRep = returnUs id
331 = let pk = getAmodeRep lhs
332 pk' = if mixedTypeLocn lhs && not (isFloatingRep pk) then IntRep else pk
336 returnUs (\xs -> StAssign pk' lhs' rhs' : xs)
340 Unconditional jumps, including the special ``enter closure'' operation.
341 Note that the new entry convention requires that we load the InfoPtr (R2)
342 with the address of the info table before jumping to the entry code for Node.
344 For a vectored return, we must subtract the size of the info table to
345 get at the return vector. This depends on the size of the info table,
346 which varies depending on whether we're profiling etc.
351 = returnUs (\xs -> StJump (a2stix dest) : xs)
353 gencode (CFallThrough (CLbl lbl _))
354 = returnUs (\xs -> StFallThrough lbl : xs)
356 gencode (CReturn dest DirectReturn)
357 = returnUs (\xs -> StJump (a2stix dest) : xs)
359 gencode (CReturn table (StaticVectoredReturn n))
360 = returnUs (\xs -> StJump dest : xs)
362 dest = StInd PtrRep (StIndex PtrRep (a2stix table)
363 (StInt (toInteger (-n-fixedItblSize-1))))
365 gencode (CReturn table (DynamicVectoredReturn am))
366 = returnUs (\xs -> StJump dest : xs)
368 dest = StInd PtrRep (StIndex PtrRep (a2stix table) dyn_off)
369 dyn_off = StPrim IntSubOp [StPrim IntNegOp [a2stix am],
370 StInt (toInteger (fixedItblSize+1))]
374 Now the PrimOps, some of which may need caller-saves register wrappers.
378 gencode (COpStmt results op args vols)
379 -- ToDo (ADR?): use that liveness mask
380 | primOpNeedsWrapper op
382 saves = volsaves vols
383 restores = volrestores vols
385 p2stix (nonVoid results) op (nonVoid args)
387 returnUs (\xs -> saves ++ code (restores ++ xs))
389 | otherwise = p2stix (nonVoid results) op (nonVoid args)
391 nonVoid = filter ((/= VoidRep) . getAmodeRep)
395 Now the dreaded conditional jump.
397 Now the if statement. Almost *all* flow of control are of this form.
399 if (am==lit) { absC } else { absCdef }
413 gencode (CSwitch discrim alts deflt)
417 [(tag,alt_code)] -> case maybe_empty_deflt of
418 Nothing -> gencode alt_code
419 Just dc -> mkIfThenElse discrim tag alt_code dc
421 [(tag1@(MachInt i1), alt_code1),
422 (tag2@(MachInt i2), alt_code2)]
423 | deflt_is_empty && i1 == 0 && i2 == 1
424 -> mkIfThenElse discrim tag1 alt_code1 alt_code2
425 | deflt_is_empty && i1 == 1 && i2 == 0
426 -> mkIfThenElse discrim tag2 alt_code2 alt_code1
428 -- If the @discrim@ is simple, then this unfolding is safe.
429 other | simple_discrim -> mkSimpleSwitches discrim alts deflt
431 -- Otherwise, we need to do a bit of work.
432 other -> getUniqueUs `thenUs` \ u ->
434 (CAssign (CTemp u pk) discrim)
435 (CSwitch (CTemp u pk) alts deflt))
438 maybe_empty_deflt = nonemptyAbsC deflt
439 deflt_is_empty = case maybe_empty_deflt of
443 pk = getAmodeRep discrim
445 simple_discrim = case discrim of
453 Finally, all of the disgusting AbstractC macros.
457 gencode (CMacroStmt macro args) = macro_code macro args
459 gencode (CCallProfCtrMacro macro _)
460 = returnUs (\xs -> StComment macro : xs)
462 gencode (CCallProfCCMacro macro _)
463 = returnUs (\xs -> StComment macro : xs)
466 = pprPanic "AbsCStixGen.gencode" (dumpRealC other)
469 Here, we generate a jump table if there are more than four (integer)
470 alternatives and the jump table occupancy is greater than 50%.
471 Otherwise, we generate a binary comparison tree. (Perhaps this could
476 intTag :: Literal -> Integer
477 intTag (MachChar c) = toInteger c
478 intTag (MachInt i) = i
479 intTag (MachWord w) = intTag (word2IntLit (MachWord w))
480 intTag _ = panic "intTag"
482 fltTag :: Literal -> Rational
484 fltTag (MachFloat f) = f
485 fltTag (MachDouble d) = d
486 fltTag x = pprPanic "fltTag" (ppr x)
490 :: CAddrMode -> [(Literal,AbstractC)] -> AbstractC
491 -> UniqSM StixTreeList
493 mkSimpleSwitches am alts absC
494 = getUniqLabelNCG `thenUs` \ udlbl ->
495 getUniqLabelNCG `thenUs` \ ujlbl ->
497 joinedAlts = map (\ (tag,code) -> (tag, mkJoin code ujlbl)) alts
498 sortedAlts = naturalMergeSortLe leAlt joinedAlts
499 -- naturalMergeSortLe, because we often get sorted alts to begin with
501 lowTag = intTag (fst (head sortedAlts))
502 highTag = intTag (fst (last sortedAlts))
504 -- lowest and highest possible values the discriminant could take
505 lowest = if floating then targetMinDouble else targetMinInt
506 highest = if floating then targetMaxDouble else targetMaxInt
509 if not floating && choices > 4 && highTag - lowTag < toInteger (2 * choices) then
510 mkJumpTable am' sortedAlts lowTag highTag udlbl
512 mkBinaryTree am' floating sortedAlts choices lowest highest udlbl
514 `thenUs` \ alt_code ->
515 gencode absC `thenUs` \ dflt_code ->
517 returnUs (\xs -> alt_code (StLabel udlbl : dflt_code (StLabel ujlbl : xs)))
520 floating = isFloatingRep (getAmodeRep am)
521 choices = length alts
523 (x@(MachChar _),_) `leAlt` (y,_) = intTag x <= intTag y
524 (x@(MachInt _), _) `leAlt` (y,_) = intTag x <= intTag y
525 (x@(MachWord _), _) `leAlt` (y,_) = intTag x <= intTag y
526 (x,_) `leAlt` (y,_) = fltTag x <= fltTag y
530 We use jump tables when doing an integer switch on a relatively dense
531 list of alternatives. We expect to be given a list of alternatives,
532 sorted by tag, and a range of values for which we are to generate a
533 table. Of course, the tags of the alternatives should lie within the
534 indicated range. The alternatives need not cover the range; a default
535 target is provided for the missing alternatives.
537 If a join is necessary after the switch, the alternatives should
538 already finish with a jump to the join point.
543 :: StixTree -- discriminant
544 -> [(Literal, AbstractC)] -- alternatives
545 -> Integer -- low tag
546 -> Integer -- high tag
547 -> CLabel -- default label
548 -> UniqSM StixTreeList
551 mkJumpTable am alts lowTag highTag dflt
552 = getUniqLabelNCG `thenUs` \ utlbl ->
553 mapUs genLabel alts `thenUs` \ branches ->
554 let cjmpLo = StCondJump dflt (StPrim IntLtOp [am, StInt (toInteger lowTag)])
555 cjmpHi = StCondJump dflt (StPrim IntGtOp [am, StInt (toInteger highTag)])
557 offset = StPrim IntSubOp [am, StInt lowTag]
559 jump = StJump (StInd PtrRep (StIndex PtrRep (StCLbl utlbl) offset))
561 table = StData PtrRep (mkTable branches [lowTag..highTag] [])
563 mapUs mkBranch branches `thenUs` \ alts ->
565 returnUs (\xs -> cjmpLo : cjmpHi : jump :
566 StSegment DataSegment : tlbl : table :
567 StSegment TextSegment : foldr1 (.) alts xs)
570 genLabel x = getUniqLabelNCG `thenUs` \ lbl -> returnUs (lbl, x)
572 mkBranch (lbl,(_,alt)) =
573 gencode alt `thenUs` \ alt_code ->
574 returnUs (\xs -> StLabel lbl : alt_code xs)
576 mkTable _ [] tbl = reverse tbl
577 mkTable [] (x:xs) tbl = mkTable [] xs (StCLbl dflt : tbl)
578 mkTable alts@((lbl,(tag,_)):rest) (x:xs) tbl
579 | intTag tag == x = mkTable rest xs (StCLbl lbl : tbl)
580 | otherwise = mkTable alts xs (StCLbl dflt : tbl)
584 We generate binary comparison trees when a jump table is inappropriate.
585 We expect to be given a list of alternatives, sorted by tag, and for
586 convenience, the length of the alternative list. We recursively break
587 the list in half and do a comparison on the first tag of the second half
588 of the list. (Odd lists are broken so that the second half of the list
589 is longer.) We can handle either integer or floating kind alternatives,
590 so long as they are not mixed. (We assume that the type of the discriminant
591 determines the type of the alternatives.)
593 As with the jump table approach, if a join is necessary after the switch, the
594 alternatives should already finish with a jump to the join point.
599 :: StixTree -- discriminant
600 -> Bool -- floating point?
601 -> [(Literal, AbstractC)] -- alternatives
602 -> Int -- number of choices
603 -> Literal -- low tag
604 -> Literal -- high tag
605 -> CLabel -- default code label
606 -> UniqSM StixTreeList
609 mkBinaryTree am floating [(tag,alt)] _ lowTag highTag udlbl
610 | rangeOfOne = gencode alt
612 = let tag' = a2stix (CLit tag)
613 cmpOp = if floating then DoubleNeOp else IntNeOp
614 test = StPrim cmpOp [am, tag']
615 cjmp = StCondJump udlbl test
617 gencode alt `thenUs` \ alt_code ->
618 returnUs (\xs -> cjmp : alt_code xs)
621 rangeOfOne = not floating && intTag lowTag + 1 >= intTag highTag
622 -- When there is only one possible tag left in range, we skip the comparison
624 mkBinaryTree am floating alts choices lowTag highTag udlbl
625 = getUniqLabelNCG `thenUs` \ uhlbl ->
626 let tag' = a2stix (CLit splitTag)
627 cmpOp = if floating then DoubleGeOp else IntGeOp
628 test = StPrim cmpOp [am, tag']
629 cjmp = StCondJump uhlbl test
631 mkBinaryTree am floating alts_lo half lowTag splitTag udlbl
632 `thenUs` \ lo_code ->
633 mkBinaryTree am floating alts_hi (choices - half) splitTag highTag udlbl
634 `thenUs` \ hi_code ->
636 returnUs (\xs -> cjmp : lo_code (StLabel uhlbl : hi_code xs))
639 half = choices `div` 2
640 (alts_lo, alts_hi) = splitAt half alts
641 splitTag = fst (head alts_hi)
648 :: CAddrMode -- discriminant
650 -> AbstractC -- if-part
651 -> AbstractC -- else-part
652 -> UniqSM StixTreeList
655 mkIfThenElse discrim tag alt deflt
656 = getUniqLabelNCG `thenUs` \ ujlbl ->
657 getUniqLabelNCG `thenUs` \ utlbl ->
658 let discrim' = a2stix discrim
659 tag' = a2stix (CLit tag)
660 cmpOp = if (isFloatingRep (getAmodeRep discrim)) then DoubleNeOp else IntNeOp
661 test = StPrim cmpOp [discrim', tag']
662 cjmp = StCondJump utlbl test
666 gencode (mkJoin alt ujlbl) `thenUs` \ alt_code ->
667 gencode deflt `thenUs` \ dflt_code ->
668 returnUs (\xs -> cjmp : alt_code (dest : dflt_code (join : xs)))
670 mkJoin :: AbstractC -> CLabel -> AbstractC
673 | mightFallThrough code = mkAbsCStmts code (CJump (CLbl lbl PtrRep))
677 %---------------------------------------------------------------------------
679 This answers the question: Can the code fall through to the next
680 line(s) of code? This errs towards saying True if it can't choose,
681 because it is used for eliminating needless jumps. In other words, if
682 you might possibly {\em not} jump, then say yes to falling through.
685 mightFallThrough :: AbstractC -> Bool
687 mightFallThrough absC = ft absC True
689 ft AbsCNop if_empty = if_empty
691 ft (CJump _) if_empty = False
692 ft (CReturn _ _) if_empty = False
693 ft (CSwitch _ alts deflt) if_empty
694 = ft deflt if_empty ||
695 or [ft alt if_empty | (_,alt) <- alts]
697 ft (AbsCStmts c1 c2) if_empty = ft c2 (ft c1 if_empty)
698 ft _ if_empty = if_empty
700 {- Old algorithm, which called nonemptyAbsC for every subexpression! =========
701 fallThroughAbsC (AbsCStmts c1 c2)
702 = case nonemptyAbsC c2 of
703 Nothing -> fallThroughAbsC c1
704 Just x -> fallThroughAbsC x
705 fallThroughAbsC (CJump _) = False
706 fallThroughAbsC (CReturn _ _) = False
707 fallThroughAbsC (CSwitch _ choices deflt)
708 = (not (isEmptyAbsC deflt) && fallThroughAbsC deflt)
709 || or (map (fallThroughAbsC . snd) choices)
710 fallThroughAbsC other = True
712 isEmptyAbsC :: AbstractC -> Bool
713 isEmptyAbsC = not . maybeToBool . nonemptyAbsC
714 ================= End of old, quadratic, algorithm -}