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 ( retItblSize )
21 import CLabel ( CLabel, mkReturnInfoLabel, mkReturnPtLabel,
22 mkClosureTblLabel, mkClosureLabel,
23 labelDynamic, mkSplitMarkerLabel )
25 import Literal ( Literal(..), word2IntLit )
26 import StgSyn ( StgOp(..) )
27 import MachOp ( MachOp(..), resultRepOfMachOp )
28 import PrimRep ( isFloatingRep, is64BitRep,
29 PrimRep(..), getPrimRepSizeInBytes )
30 import StixMacro ( macroCode, checkCode )
31 import StixPrim ( foreignCallCode, amodeToStix, amodeToStix' )
32 import Outputable ( pprPanic, ppr )
33 import UniqSupply ( returnUs, thenUs, mapUs, getUniqueUs, UniqSM )
34 import Util ( naturalMergeSortLe )
35 import Panic ( panic )
36 import TyCon ( tyConDataCons )
37 import Constants ( wORD_SIZE, bITMAP_BITS_SHIFT )
38 import Name ( NamedThing(..) )
39 import CmdLineOpts ( opt_Static, opt_EnsureSplittableC )
40 import Outputable ( assertPanic )
41 import BitSet ( BitSet, intBS )
44 --import TRACE ( trace )
45 --import Outputable ( showSDoc )
46 --import MachOp ( pprMachOp )
48 #include "nativeGen/NCG.h"
51 For each independent chunk of AbstractC code, we generate a list of
52 @StixTree@s, where each tree corresponds to a single Stix instruction.
53 We leave the chunks separated so that register allocation can be
54 performed locally within the chunk.
57 genCodeAbstractC :: AbstractC -> UniqSM [StixStmt]
63 a2stix' = amodeToStix'
64 volsaves = volatileSaves
65 volrestores = volatileRestores
66 macro_code = macroCode
67 -- real code follows... ---------
70 Here we handle top-level things, like @CCodeBlock@s and
80 gentopcode (CCodeBlock lbl absC)
81 = gencode absC `thenUs` \ code ->
82 returnUs (StSegment TextSegment : StFunBegin lbl : code [StFunEnd lbl])
84 gentopcode stmt@(CStaticClosure lbl closure_info _ _)
85 = genCodeStaticClosure stmt `thenUs` \ code ->
88 then StSegment DataSegment
89 : StLabel lbl : code []
90 else StSegment DataSegment
91 : StData PtrRep [StInt 0] -- DLLised world, need extra zero word
92 : StLabel lbl : code []
95 gentopcode stmt@(CRetVector lbl amodes srt liveness)
96 = returnUs ( StSegment TextSegment
102 table = map amodeToStix (mkVecInfoTable amodes srt liveness)
104 gentopcode stmt@(CRetDirect uniq absC srt liveness)
105 = gencode absC `thenUs` \ code ->
106 returnUs ( StSegment TextSegment
107 : StData PtrRep table
112 info_lbl = mkReturnInfoLabel uniq
113 ret_lbl = mkReturnPtLabel uniq
114 table = map amodeToStix (mkRetInfoTable ret_lbl srt liveness)
116 gentopcode stmt@(CClosureInfoAndCode cl_info entry)
117 = gencode entry `thenUs` \ slow_code ->
118 returnUs ( StSegment TextSegment
119 : StData PtrRep table
121 : StFunBegin entry_lbl
122 : slow_code [StFunEnd entry_lbl])
124 entry_lbl = entryLabelFromCI cl_info
125 info_lbl = infoTableLabelFromCI cl_info
126 table = map amodeToStix (mkInfoTable cl_info)
128 gentopcode stmt@(CSRT lbl closures)
129 = returnUs [ StSegment TextSegment
131 , StData DataPtrRep (map mk_StCLbl_for_SRT closures)
134 mk_StCLbl_for_SRT :: CLabel -> StixExpr
135 mk_StCLbl_for_SRT label
137 = StIndex Int8Rep (StCLbl label) (StInt 1)
141 gentopcode stmt@(CBitmap l@(Liveness lbl size mask))
144 [ StSegment TextSegment
146 , StData WordRep (map StInt (toInteger size : bitmapToIntegers mask))
151 -- ToDo: translate out bitmaps earlier, like info tables
152 isBigLiveness (Liveness _ size _) = size > mAX_SMALL_BITMAP_SIZE
153 mAX_SMALL_BITMAP_SIZE = (wORD_SIZE * 8) - bITMAP_BITS_SHIFT
155 gentopcode stmt@(CClosureTbl tycon)
156 = returnUs [ StSegment TextSegment
157 , StLabel (mkClosureTblLabel tycon)
158 , StData DataPtrRep (map (StCLbl . mkClosureLabel . getName)
159 (tyConDataCons tycon) )
162 gentopcode stmt@(CModuleInitBlock plain_lbl lbl absC)
163 = gencode absC `thenUs` \ code ->
164 getUniqLabelNCG `thenUs` \ tmp_lbl ->
165 getUniqLabelNCG `thenUs` \ flag_lbl ->
166 returnUs ( StSegment DataSegment
168 : StData IntRep [StInt 0]
169 : StSegment TextSegment
171 : StJump NoDestInfo (StCLbl lbl)
173 : StCondJump tmp_lbl (StMachOp MO_Nat_Ne
174 [StInd IntRep (StCLbl flag_lbl),
176 : StAssignMem IntRep (StCLbl flag_lbl) (StInt 1)
179 , StAssignReg PtrRep stgSp
180 (StIndex PtrRep (StReg stgSp) (StInt (-1)))
181 , StJump NoDestInfo (StInd WordRep (StReg stgSp))
185 = gencode absC `thenUs` \ code ->
186 returnUs (StSegment TextSegment : code [])
193 -> UniqSM StixTreeList
195 genCodeStaticClosure (CStaticClosure lbl cl_info cost_centre amodes)
196 = returnUs (\xs -> table ++ xs)
198 table = StData PtrRep [StCLbl (infoTableLabelFromCI cl_info)] :
199 foldr do_one_amode [] amodes
201 do_one_amode amode rest
202 | rep == VoidRep = rest
203 | otherwise = StData (promote_to_word rep) [a2stix amode] : rest
205 rep = getAmodeRep amode
207 -- We need to promote any item smaller than a word to a word
209 | getPrimRepSizeInBytes pk >= getPrimRepSizeInBytes IntRep = pk
213 Now the individual AbstractC statements.
219 -> UniqSM StixTreeList
223 @AbsCNop@s just disappear.
227 gencode AbsCNop = returnUs id
231 Split markers just insert a __stg_split_marker, which is caught by the
232 split-mangler later on and used to split the assembly into chunks.
237 | opt_EnsureSplittableC = returnUs (\xs -> StLabel mkSplitMarkerLabel : xs)
238 | otherwise = returnUs id
242 AbstractC instruction sequences are handled individually, and the
243 resulting StixTreeLists are joined together.
247 gencode (AbsCStmts c1 c2)
248 = gencode c1 `thenUs` \ b1 ->
249 gencode c2 `thenUs` \ b2 ->
252 gencode (CSequential stuff)
256 foo (s:ss) = gencode s `thenUs` \ stix ->
257 foo ss `thenUs` \ stixes ->
258 returnUs (stix . stixes)
262 Initialising closure headers in the heap...a fairly complex ordeal if
263 done properly. For now, we just set the info pointer, but we should
264 really take a peek at the flags to determine whether or not there are
265 other things to be done (setting cost centres, age headers, global
270 gencode (CInitHdr cl_info reg_rel _ _)
273 lbl = infoTableLabelFromCI cl_info
275 returnUs (\xs -> StAssignMem PtrRep lhs (StCLbl lbl) : xs)
283 gencode (CCheck macro args assts)
284 = gencode assts `thenUs` \assts_stix ->
285 checkCode macro args assts_stix
289 Assignment, the curse of von Neumann, is the center of the code we
290 produce. In most cases, the type of the assignment is determined
291 by the type of the destination. However, when the destination can
292 have mixed types, the type of the assignment is ``StgWord'' (we use
293 PtrRep for lack of anything better). Think: do we also want a cast
294 of the source? Be careful about floats/doubles.
298 gencode (CAssign lhs rhs)
302 = let -- This is a Hack. Should be cleaned up.
304 pk' | ncg_target_is_32bit && is64BitRep lhs_rep
307 = if mixedTypeLocn lhs && not (isFloatingRep lhs_rep)
313 returnUs (\xs -> mkStAssign pk' lhs' rhs' : xs)
315 lhs_rep = getAmodeRep lhs
319 Unconditional jumps, including the special ``enter closure'' operation.
320 Note that the new entry convention requires that we load the InfoPtr (R2)
321 with the address of the info table before jumping to the entry code for Node.
323 For a vectored return, we must subtract the size of the info table to
324 get at the return vector. This depends on the size of the info table,
325 which varies depending on whether we're profiling etc.
330 = returnUs (\xs -> StJump NoDestInfo (a2stix dest) : xs)
332 gencode (CFallThrough (CLbl lbl _))
333 = returnUs (\xs -> StFallThrough lbl : xs)
335 gencode (CReturn dest DirectReturn)
336 = returnUs (\xs -> StJump NoDestInfo (a2stix dest) : xs)
338 gencode (CReturn table (StaticVectoredReturn n))
339 = returnUs (\xs -> StJump NoDestInfo dest : xs)
341 dest = StInd PtrRep (StIndex PtrRep (a2stix table)
342 (StInt (toInteger (-n-retItblSize-1))))
344 gencode (CReturn table (DynamicVectoredReturn am))
345 = returnUs (\xs -> StJump NoDestInfo dest : xs)
347 dest = StInd PtrRep (StIndex PtrRep (a2stix table) dyn_off)
348 dyn_off = StMachOp MO_Nat_Sub [StMachOp MO_NatS_Neg [a2stix am],
349 StInt (toInteger (retItblSize+1))]
353 Now the PrimOps, some of which may need caller-saves register wrappers.
356 gencode (COpStmt results (StgFCallOp fcall _) args vols)
357 = ASSERT( null vols )
358 foreignCallCode (nonVoid results) fcall (nonVoid args)
360 gencode (COpStmt results (StgPrimOp op) args vols)
361 = panic "AbsCStixGen.gencode: un-translated PrimOp"
363 gencode (CMachOpStmt res mop args vols)
364 = returnUs (\xs -> mkStAssign (resultRepOfMachOp mop) (a2stix res)
365 (StMachOp mop (map a2stix args))
370 Now the dreaded conditional jump.
372 Now the if statement. Almost *all* flow of control are of this form.
374 if (am==lit) { absC } else { absCdef }
388 gencode (CSwitch discrim alts deflt)
392 [(tag,alt_code)] -> case maybe_empty_deflt of
393 Nothing -> gencode alt_code
394 Just dc -> mkIfThenElse discrim tag alt_code dc
396 [(tag1@(MachInt i1), alt_code1),
397 (tag2@(MachInt i2), alt_code2)]
398 | deflt_is_empty && i1 == 0 && i2 == 1
399 -> mkIfThenElse discrim tag1 alt_code1 alt_code2
400 | deflt_is_empty && i1 == 1 && i2 == 0
401 -> mkIfThenElse discrim tag2 alt_code2 alt_code1
403 -- If the @discrim@ is simple, then this unfolding is safe.
404 other | simple_discrim -> mkSimpleSwitches discrim alts deflt
406 -- Otherwise, we need to do a bit of work.
407 other -> getUniqueUs `thenUs` \ u ->
409 (CAssign (CTemp u pk) discrim)
410 (CSwitch (CTemp u pk) alts deflt))
413 maybe_empty_deflt = nonemptyAbsC deflt
414 deflt_is_empty = case maybe_empty_deflt of
418 pk = getAmodeRep discrim
420 simple_discrim = case discrim of
428 Finally, all of the disgusting AbstractC macros.
432 gencode (CMacroStmt macro args) = macro_code macro args
434 gencode (CCallProfCtrMacro macro _)
435 = returnUs (\xs -> StComment macro : xs)
437 gencode (CCallProfCCMacro macro _)
438 = returnUs (\xs -> StComment macro : xs)
440 gencode CCallTypedef{} = returnUs id
443 = pprPanic "AbsCStixGen.gencode" (dumpRealC other)
445 nonVoid = filter ((/= VoidRep) . getAmodeRep)
448 Here, we generate a jump table if there are more than four (integer)
449 alternatives and the jump table occupancy is greater than 50%.
450 Otherwise, we generate a binary comparison tree. (Perhaps this could
455 intTag :: Literal -> Integer
456 intTag (MachChar c) = toInteger c
457 intTag (MachInt i) = i
458 intTag (MachWord w) = intTag (word2IntLit (MachWord w))
459 intTag _ = panic "intTag"
461 fltTag :: Literal -> Rational
463 fltTag (MachFloat f) = f
464 fltTag (MachDouble d) = d
465 fltTag x = pprPanic "fltTag" (ppr x)
469 :: CAddrMode -> [(Literal,AbstractC)] -> AbstractC
470 -> UniqSM StixTreeList
472 mkSimpleSwitches am alts absC
473 = getUniqLabelNCG `thenUs` \ udlbl ->
474 getUniqLabelNCG `thenUs` \ ujlbl ->
476 joinedAlts = map (\ (tag,code) -> (tag, mkJoin code ujlbl)) alts
477 sortedAlts = naturalMergeSortLe leAlt joinedAlts
478 -- naturalMergeSortLe, because we often get sorted alts to begin with
480 lowTag = intTag (fst (head sortedAlts))
481 highTag = intTag (fst (last sortedAlts))
483 -- lowest and highest possible values the discriminant could take
484 lowest = if floating then targetMinDouble else targetMinInt
485 highest = if floating then targetMaxDouble else targetMaxInt
488 if not floating && choices > 4
489 && highTag - lowTag < toInteger (2 * choices)
491 mkJumpTable am' sortedAlts lowTag highTag udlbl
493 mkBinaryTree am' floating sortedAlts choices lowest highest udlbl
495 `thenUs` \ alt_code ->
496 gencode absC `thenUs` \ dflt_code ->
498 returnUs (\xs -> alt_code (StLabel udlbl : dflt_code (StLabel ujlbl : xs)))
501 floating = isFloatingRep (getAmodeRep am)
502 choices = length alts
504 (x@(MachChar _),_) `leAlt` (y,_) = intTag x <= intTag y
505 (x@(MachInt _), _) `leAlt` (y,_) = intTag x <= intTag y
506 (x@(MachWord _), _) `leAlt` (y,_) = intTag x <= intTag y
507 (x,_) `leAlt` (y,_) = fltTag x <= fltTag y
511 We use jump tables when doing an integer switch on a relatively dense
512 list of alternatives. We expect to be given a list of alternatives,
513 sorted by tag, and a range of values for which we are to generate a
514 table. Of course, the tags of the alternatives should lie within the
515 indicated range. The alternatives need not cover the range; a default
516 target is provided for the missing alternatives.
518 If a join is necessary after the switch, the alternatives should
519 already finish with a jump to the join point.
524 :: StixTree -- discriminant
525 -> [(Literal, AbstractC)] -- alternatives
526 -> Integer -- low tag
527 -> Integer -- high tag
528 -> CLabel -- default label
529 -> UniqSM StixTreeList
532 mkJumpTable am alts lowTag highTag dflt
533 = getUniqLabelNCG `thenUs` \ utlbl ->
534 mapUs genLabel alts `thenUs` \ branches ->
535 let cjmpLo = StCondJump dflt (StMachOp MO_NatS_Lt [am, StInt (toInteger lowTag)])
536 cjmpHi = StCondJump dflt (StMachOp MO_NatS_Gt [am, StInt (toInteger highTag)])
538 offset = StMachOp MO_Nat_Sub [am, StInt lowTag]
539 dsts = DestInfo (dflt : map fst branches)
541 jump = StJump dsts (StInd PtrRep (StIndex PtrRep (StCLbl utlbl) offset))
543 table = StData PtrRep (mkTable branches [lowTag..highTag] [])
545 mapUs mkBranch branches `thenUs` \ alts ->
547 returnUs (\xs -> cjmpLo : cjmpHi : jump :
548 StSegment DataSegment : tlbl : table :
549 StSegment TextSegment : foldr1 (.) alts xs)
552 genLabel x = getUniqLabelNCG `thenUs` \ lbl -> returnUs (lbl, x)
554 mkBranch (lbl,(_,alt)) =
555 gencode alt `thenUs` \ alt_code ->
556 returnUs (\xs -> StLabel lbl : alt_code xs)
558 mkTable _ [] tbl = reverse tbl
559 mkTable [] (x:xs) tbl = mkTable [] xs (StCLbl dflt : tbl)
560 mkTable alts@((lbl,(tag,_)):rest) (x:xs) tbl
561 | intTag tag == x = mkTable rest xs (StCLbl lbl : tbl)
562 | otherwise = mkTable alts xs (StCLbl dflt : tbl)
566 We generate binary comparison trees when a jump table is inappropriate.
567 We expect to be given a list of alternatives, sorted by tag, and for
568 convenience, the length of the alternative list. We recursively break
569 the list in half and do a comparison on the first tag of the second half
570 of the list. (Odd lists are broken so that the second half of the list
571 is longer.) We can handle either integer or floating kind alternatives,
572 so long as they are not mixed. (We assume that the type of the discriminant
573 determines the type of the alternatives.)
575 As with the jump table approach, if a join is necessary after the switch, the
576 alternatives should already finish with a jump to the join point.
581 :: StixTree -- discriminant
582 -> Bool -- floating point?
583 -> [(Literal, AbstractC)] -- alternatives
584 -> Int -- number of choices
585 -> Literal -- low tag
586 -> Literal -- high tag
587 -> CLabel -- default code label
588 -> UniqSM StixTreeList
591 mkBinaryTree am floating [(tag,alt)] _ lowTag highTag udlbl
592 | rangeOfOne = gencode alt
594 = let tag' = a2stix (CLit tag)
595 cmpOp = if floating then MO_Dbl_Ne else MO_Nat_Ne
596 test = StMachOp cmpOp [am, tag']
597 cjmp = StCondJump udlbl test
599 gencode alt `thenUs` \ alt_code ->
600 returnUs (\xs -> cjmp : alt_code xs)
603 rangeOfOne = not floating && intTag lowTag + 1 >= intTag highTag
604 -- When there is only one possible tag left in range, we skip the comparison
606 mkBinaryTree am floating alts choices lowTag highTag udlbl
607 = getUniqLabelNCG `thenUs` \ uhlbl ->
608 let tag' = a2stix (CLit splitTag)
609 cmpOp = if floating then MO_Dbl_Ge else MO_NatS_Ge
610 test = StMachOp cmpOp [am, tag']
611 cjmp = StCondJump uhlbl test
613 mkBinaryTree am floating alts_lo half lowTag splitTag udlbl
614 `thenUs` \ lo_code ->
615 mkBinaryTree am floating alts_hi (choices - half) splitTag highTag udlbl
616 `thenUs` \ hi_code ->
618 returnUs (\xs -> cjmp : lo_code (StLabel uhlbl : hi_code xs))
621 half = choices `div` 2
622 (alts_lo, alts_hi) = splitAt half alts
623 splitTag = fst (head alts_hi)
630 :: CAddrMode -- discriminant
632 -> AbstractC -- if-part
633 -> AbstractC -- else-part
634 -> UniqSM StixTreeList
637 mkIfThenElse discrim tag alt deflt
638 = getUniqLabelNCG `thenUs` \ ujlbl ->
639 getUniqLabelNCG `thenUs` \ utlbl ->
640 let discrim' = a2stix discrim
641 tag' = a2stix (CLit tag)
642 cmpOp = if (isFloatingRep (getAmodeRep discrim)) then MO_Dbl_Ne else MO_Nat_Ne
643 test = StMachOp cmpOp [discrim', tag']
644 cjmp = StCondJump utlbl test
648 gencode (mkJoin alt ujlbl) `thenUs` \ alt_code ->
649 gencode deflt `thenUs` \ dflt_code ->
650 returnUs (\xs -> cjmp : alt_code (dest : dflt_code (join : xs)))
653 mkJoin :: AbstractC -> CLabel -> AbstractC
655 | mightFallThrough code = mkAbsCStmts code (CJump (CLbl lbl PtrRep))
659 %---------------------------------------------------------------------------
662 bitmapToIntegers :: [BitSet] -> [Integer]
663 bitmapToIntegers = bundle . map (toInteger . intBS)
665 #if BYTES_PER_WORD == 4
669 bundle is = case splitAt (BYTES_PER_WORD/4) is of
671 ( foldr1 (\x y -> x + 4294967296 * y)
672 [x `mod` 4294967296 | x <- these]
678 %---------------------------------------------------------------------------
680 This answers the question: Can the code fall through to the next
681 line(s) of code? This errs towards saying True if it can't choose,
682 because it is used for eliminating needless jumps. In other words, if
683 you might possibly {\em not} jump, then say yes to falling through.
686 mightFallThrough :: AbstractC -> Bool
688 mightFallThrough absC = ft absC True
690 ft AbsCNop if_empty = if_empty
692 ft (CJump _) if_empty = False
693 ft (CReturn _ _) if_empty = False
694 ft (CSwitch _ alts deflt) if_empty
695 = ft deflt if_empty ||
696 or [ft alt if_empty | (_,alt) <- alts]
698 ft (AbsCStmts c1 c2) if_empty = ft c2 (ft c1 if_empty)
699 ft _ if_empty = if_empty
701 {- Old algorithm, which called nonemptyAbsC for every subexpression! =========
702 fallThroughAbsC (AbsCStmts c1 c2)
703 = case nonemptyAbsC c2 of
704 Nothing -> fallThroughAbsC c1
705 Just x -> fallThroughAbsC x
706 fallThroughAbsC (CJump _) = False
707 fallThroughAbsC (CReturn _ _) = False
708 fallThroughAbsC (CSwitch _ choices deflt)
709 = (not (isEmptyAbsC deflt) && fallThroughAbsC deflt)
710 || or (map (fallThroughAbsC . snd) choices)
711 fallThroughAbsC other = True
713 isEmptyAbsC :: AbstractC -> Bool
714 isEmptyAbsC = not . maybeToBool . nonemptyAbsC
715 ================= End of old, quadratic, algorithm -}