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, wORD_SIZE )
25 import CLabel ( CLabel, mkReturnInfoLabel, mkReturnPtLabel,
26 mkClosureTblLabel, mkClosureLabel,
27 labelDynamic, mkSplitMarkerLabel )
28 import ClosureInfo ( infoTableLabelFromCI, entryLabelFromCI,
29 closureLabelFromCI, fastLabelFromCI
31 import Literal ( Literal(..), word2IntLit )
32 import Maybes ( maybeToBool )
33 import StgSyn ( StgOp(..) )
34 import MachOp ( MachOp(..), resultRepsOfMachOp )
35 import PrimRep ( isFloatingRep, is64BitRep,
36 PrimRep(..), getPrimRepArrayElemSize )
37 import StixInfo ( genCodeInfoTable, genBitmapInfoTable,
38 livenessIsSmall, bitmapToIntegers )
39 import StixMacro ( macroCode, checkCode )
40 import StixPrim ( foreignCallCode, amodeToStix, amodeToStix' )
41 import Outputable ( pprPanic, ppr )
42 import UniqSupply ( returnUs, thenUs, mapUs, getUniqueUs, UniqSM )
43 import Util ( naturalMergeSortLe )
44 import Panic ( panic )
45 import TyCon ( tyConDataCons )
46 import DataCon ( dataConWrapId )
47 import Name ( NamedThing(..) )
48 import CmdLineOpts ( opt_Static, opt_EnsureSplittableC )
49 import Outputable ( assertPanic )
52 --import IOExts ( trace )
53 --import Outputable ( showSDoc )
54 --import MachOp ( pprMachOp )
58 For each independent chunk of AbstractC code, we generate a list of
59 @StixTree@s, where each tree corresponds to a single Stix instruction.
60 We leave the chunks separated so that register allocation can be
61 performed locally within the chunk.
64 genCodeAbstractC :: AbstractC -> UniqSM [StixStmt]
70 a2stix' = amodeToStix'
71 volsaves = volatileSaves
72 volrestores = volatileRestores
73 macro_code = macroCode
74 -- real code follows... ---------
77 Here we handle top-level things, like @CCodeBlock@s and
87 gentopcode (CCodeBlock lbl absC)
88 = gencode absC `thenUs` \ code ->
89 returnUs (StSegment TextSegment : StFunBegin lbl : code [StFunEnd lbl])
91 gentopcode stmt@(CStaticClosure closure_info _ _)
92 = genCodeStaticClosure stmt `thenUs` \ code ->
95 then StSegment DataSegment
96 : StLabel lbl : code []
97 else StSegment DataSegment
98 : StData PtrRep [StInt 0] -- DLLised world, need extra zero word
99 : StLabel lbl : code []
102 lbl = closureLabelFromCI closure_info
104 gentopcode stmt@(CRetVector lbl _ _ _)
105 = genCodeVecTbl stmt `thenUs` \ code ->
106 returnUs (StSegment TextSegment
107 : code [StLabel lbl, vtbl_post_label_word])
109 -- We put a dummy word after the vtbl label so as to ensure the label
110 -- is in the same (Text) section as the vtbl it labels. This is critical
111 -- for ensuring the GC works correctly, although GC crashes due to
112 -- misclassification are much more likely to show up in the interactive
113 -- system than in compile code. For details see comment near line 1164
114 -- of ghc/driver/mangler/ghc-asm.lprl, which contains an analogous fix
115 -- for the mangled via-C route.
116 vtbl_post_label_word = StData PtrRep [StInt 0]
118 gentopcode stmt@(CRetDirect uniq absC srt liveness)
119 = gencode absC `thenUs` \ code ->
120 genBitmapInfoTable liveness srt closure_type False `thenUs` \ itbl ->
121 returnUs (StSegment TextSegment :
122 itbl (StLabel lbl_info : StLabel lbl_ret : code []))
124 lbl_info = mkReturnInfoLabel uniq
125 lbl_ret = mkReturnPtLabel uniq
126 closure_type = if livenessIsSmall liveness then rET_SMALL else rET_BIG
128 gentopcode stmt@(CClosureInfoAndCode cl_info slow Nothing _)
131 = genCodeInfoTable stmt `thenUs` \ itbl ->
132 returnUs (StSegment TextSegment : itbl [])
135 = genCodeInfoTable stmt `thenUs` \ itbl ->
136 gencode slow `thenUs` \ slow_code ->
137 returnUs (StSegment TextSegment : itbl (StFunBegin slow_lbl :
138 slow_code [StFunEnd slow_lbl]))
140 slow_is_empty = not (maybeToBool (nonemptyAbsC slow))
141 slow_lbl = entryLabelFromCI cl_info
143 gentopcode stmt@(CClosureInfoAndCode cl_info slow (Just fast) _) =
144 -- ToDo: what if this is empty? ------------------------^^^^
145 genCodeInfoTable stmt `thenUs` \ itbl ->
146 gencode slow `thenUs` \ slow_code ->
147 gencode fast `thenUs` \ fast_code ->
148 returnUs (StSegment TextSegment : itbl (StFunBegin slow_lbl :
149 slow_code (StFunEnd slow_lbl : StFunBegin fast_lbl :
150 fast_code [StFunEnd fast_lbl])))
152 slow_lbl = entryLabelFromCI cl_info
153 fast_lbl = fastLabelFromCI cl_info
155 gentopcode stmt@(CSRT lbl closures)
156 = returnUs [ StSegment TextSegment
158 , StData DataPtrRep (map mk_StCLbl_for_SRT closures)
161 mk_StCLbl_for_SRT :: CLabel -> StixExpr
162 mk_StCLbl_for_SRT label
164 = StIndex Int8Rep (StCLbl label) (StInt 1)
168 gentopcode stmt@(CBitmap lbl mask)
169 = returnUs $ case bitmapToIntegers mask of
171 [ StSegment TextSegment
173 , StData WordRep (map StInt (toInteger (length mask') : mask'))
177 gentopcode stmt@(CClosureTbl tycon)
178 = returnUs [ StSegment TextSegment
179 , StLabel (mkClosureTblLabel tycon)
180 , StData DataPtrRep (map (StCLbl . mkClosureLabel . getName . dataConWrapId)
181 (tyConDataCons tycon) )
184 gentopcode stmt@(CModuleInitBlock lbl absC)
185 = gencode absC `thenUs` \ code ->
186 getUniqLabelNCG `thenUs` \ tmp_lbl ->
187 getUniqLabelNCG `thenUs` \ flag_lbl ->
188 returnUs ( StSegment DataSegment
190 : StData IntRep [StInt 0]
191 : StSegment TextSegment
193 : StCondJump tmp_lbl (StMachOp MO_Nat_Ne
194 [StInd IntRep (StCLbl flag_lbl),
196 : StAssignMem IntRep (StCLbl flag_lbl) (StInt 1)
199 , StAssignReg PtrRep stgSp
200 (StIndex PtrRep (StReg stgSp) (StInt (-1)))
201 , StJump NoDestInfo (StInd WordRep (StReg stgSp))
205 = gencode absC `thenUs` \ code ->
206 returnUs (StSegment TextSegment : code [])
213 -> UniqSM StixTreeList
215 genCodeVecTbl (CRetVector lbl amodes srt liveness)
216 = genBitmapInfoTable liveness srt closure_type True `thenUs` \itbl ->
217 returnUs (\xs -> vectbl : itbl xs)
219 vectbl = StData PtrRep (reverse (map a2stix amodes))
220 closure_type = if livenessIsSmall liveness then rET_VEC_SMALL else rET_VEC_BIG
228 -> UniqSM StixTreeList
230 genCodeStaticClosure (CStaticClosure cl_info cost_centre amodes)
231 = returnUs (\xs -> table ++ xs)
233 table = StData PtrRep [StCLbl (infoTableLabelFromCI cl_info)] :
234 map do_one_amode amodes
237 = StData (promote_to_word (getAmodeRep amode)) [a2stix amode]
239 -- We need to promote any item smaller than a word to a word
241 | getPrimRepArrayElemSize pk >= getPrimRepArrayElemSize IntRep = pk
245 Now the individual AbstractC statements.
251 -> UniqSM StixTreeList
255 @AbsCNop@s just disappear.
259 gencode AbsCNop = returnUs id
263 Split markers just insert a __stg_split_marker, which is caught by the
264 split-mangler later on and used to split the assembly into chunks.
269 | opt_EnsureSplittableC = returnUs (\xs -> StLabel mkSplitMarkerLabel : xs)
270 | otherwise = returnUs id
274 AbstractC instruction sequences are handled individually, and the
275 resulting StixTreeLists are joined together.
279 gencode (AbsCStmts c1 c2)
280 = gencode c1 `thenUs` \ b1 ->
281 gencode c2 `thenUs` \ b2 ->
284 gencode (CSequential stuff)
288 foo (s:ss) = gencode s `thenUs` \ stix ->
289 foo ss `thenUs` \ stixes ->
290 returnUs (stix . stixes)
294 Initialising closure headers in the heap...a fairly complex ordeal if
295 done properly. For now, we just set the info pointer, but we should
296 really take a peek at the flags to determine whether or not there are
297 other things to be done (setting cost centres, age headers, global
302 gencode (CInitHdr cl_info reg_rel _ _)
305 lbl = infoTableLabelFromCI cl_info
307 returnUs (\xs -> StAssignMem PtrRep lhs (StCLbl lbl) : xs)
315 gencode (CCheck macro args assts)
316 = gencode assts `thenUs` \assts_stix ->
317 checkCode macro args assts_stix
321 Assignment, the curse of von Neumann, is the center of the code we
322 produce. In most cases, the type of the assignment is determined
323 by the type of the destination. However, when the destination can
324 have mixed types, the type of the assignment is ``StgWord'' (we use
325 PtrRep for lack of anything better). Think: do we also want a cast
326 of the source? Be careful about floats/doubles.
330 gencode (CAssign lhs rhs)
334 = let -- This is a Hack. Should be cleaned up.
336 pk' | ncg_target_is_32bit && is64BitRep lhs_rep
339 = if mixedTypeLocn lhs && not (isFloatingRep lhs_rep)
345 returnUs (\xs -> mkStAssign pk' lhs' rhs' : xs)
347 lhs_rep = getAmodeRep lhs
351 Unconditional jumps, including the special ``enter closure'' operation.
352 Note that the new entry convention requires that we load the InfoPtr (R2)
353 with the address of the info table before jumping to the entry code for Node.
355 For a vectored return, we must subtract the size of the info table to
356 get at the return vector. This depends on the size of the info table,
357 which varies depending on whether we're profiling etc.
362 = returnUs (\xs -> StJump NoDestInfo (a2stix dest) : xs)
364 gencode (CFallThrough (CLbl lbl _))
365 = returnUs (\xs -> StFallThrough lbl : xs)
367 gencode (CReturn dest DirectReturn)
368 = returnUs (\xs -> StJump NoDestInfo (a2stix dest) : xs)
370 gencode (CReturn table (StaticVectoredReturn n))
371 = returnUs (\xs -> StJump NoDestInfo dest : xs)
373 dest = StInd PtrRep (StIndex PtrRep (a2stix table)
374 (StInt (toInteger (-n-fixedItblSize-1))))
376 gencode (CReturn table (DynamicVectoredReturn am))
377 = returnUs (\xs -> StJump NoDestInfo dest : xs)
379 dest = StInd PtrRep (StIndex PtrRep (a2stix table) dyn_off)
380 dyn_off = StMachOp MO_Nat_Sub [StMachOp MO_NatS_Neg [a2stix am],
381 StInt (toInteger (fixedItblSize+1))]
385 Now the PrimOps, some of which may need caller-saves register wrappers.
388 gencode (COpStmt results (StgFCallOp fcall _) args vols)
389 = ASSERT( null vols )
390 foreignCallCode (nonVoid results) fcall (nonVoid args)
392 gencode (COpStmt results (StgPrimOp op) args vols)
393 = panic "AbsCStixGen.gencode: un-translated PrimOp"
395 -- Translate out array indexing primops right here, so that
396 -- individual targets don't have to deal with them
398 gencode (CMachOpStmt (Just r1) (MO_ReadOSBI off_w rep) [base,index] vols)
403 (StInd rep (StMachOp MO_Nat_Add
404 [StIndex rep (a2stix base) (a2stix index),
405 StInt (toInteger (off_w * wORD_SIZE))]))
409 -- Ordinary MachOps are passed through unchanged.
410 gencode (CMachOpStmt Nothing (MO_WriteOSBI off_w rep) [base,index,val] vols)
415 [StIndex rep (a2stix base) (a2stix index),
416 StInt (toInteger (off_w * wORD_SIZE))])
421 gencode (CMachOpStmt (Just r1) mop args vols)
422 = case resultRepsOfMachOp mop of
425 mkStAssign rep (a2stix r1)
426 (StMachOp mop (map a2stix args))
431 Now the dreaded conditional jump.
433 Now the if statement. Almost *all* flow of control are of this form.
435 if (am==lit) { absC } else { absCdef }
449 gencode (CSwitch discrim alts deflt)
453 [(tag,alt_code)] -> case maybe_empty_deflt of
454 Nothing -> gencode alt_code
455 Just dc -> mkIfThenElse discrim tag alt_code dc
457 [(tag1@(MachInt i1), alt_code1),
458 (tag2@(MachInt i2), alt_code2)]
459 | deflt_is_empty && i1 == 0 && i2 == 1
460 -> mkIfThenElse discrim tag1 alt_code1 alt_code2
461 | deflt_is_empty && i1 == 1 && i2 == 0
462 -> mkIfThenElse discrim tag2 alt_code2 alt_code1
464 -- If the @discrim@ is simple, then this unfolding is safe.
465 other | simple_discrim -> mkSimpleSwitches discrim alts deflt
467 -- Otherwise, we need to do a bit of work.
468 other -> getUniqueUs `thenUs` \ u ->
470 (CAssign (CTemp u pk) discrim)
471 (CSwitch (CTemp u pk) alts deflt))
474 maybe_empty_deflt = nonemptyAbsC deflt
475 deflt_is_empty = case maybe_empty_deflt of
479 pk = getAmodeRep discrim
481 simple_discrim = case discrim of
489 Finally, all of the disgusting AbstractC macros.
493 gencode (CMacroStmt macro args) = macro_code macro args
495 gencode (CCallProfCtrMacro macro _)
496 = returnUs (\xs -> StComment macro : xs)
498 gencode (CCallProfCCMacro macro _)
499 = returnUs (\xs -> StComment macro : xs)
501 gencode CCallTypedef{} = returnUs id
504 = pprPanic "AbsCStixGen.gencode" (dumpRealC other)
506 nonVoid = filter ((/= VoidRep) . getAmodeRep)
509 Here, we generate a jump table if there are more than four (integer)
510 alternatives and the jump table occupancy is greater than 50%.
511 Otherwise, we generate a binary comparison tree. (Perhaps this could
516 intTag :: Literal -> Integer
517 intTag (MachChar c) = toInteger c
518 intTag (MachInt i) = i
519 intTag (MachWord w) = intTag (word2IntLit (MachWord w))
520 intTag _ = panic "intTag"
522 fltTag :: Literal -> Rational
524 fltTag (MachFloat f) = f
525 fltTag (MachDouble d) = d
526 fltTag x = pprPanic "fltTag" (ppr x)
530 :: CAddrMode -> [(Literal,AbstractC)] -> AbstractC
531 -> UniqSM StixTreeList
533 mkSimpleSwitches am alts absC
534 = getUniqLabelNCG `thenUs` \ udlbl ->
535 getUniqLabelNCG `thenUs` \ ujlbl ->
537 joinedAlts = map (\ (tag,code) -> (tag, mkJoin code ujlbl)) alts
538 sortedAlts = naturalMergeSortLe leAlt joinedAlts
539 -- naturalMergeSortLe, because we often get sorted alts to begin with
541 lowTag = intTag (fst (head sortedAlts))
542 highTag = intTag (fst (last sortedAlts))
544 -- lowest and highest possible values the discriminant could take
545 lowest = if floating then targetMinDouble else targetMinInt
546 highest = if floating then targetMaxDouble else targetMaxInt
549 if not floating && choices > 4
550 && highTag - lowTag < toInteger (2 * choices)
552 mkJumpTable am' sortedAlts lowTag highTag udlbl
554 mkBinaryTree am' floating sortedAlts choices lowest highest udlbl
556 `thenUs` \ alt_code ->
557 gencode absC `thenUs` \ dflt_code ->
559 returnUs (\xs -> alt_code (StLabel udlbl : dflt_code (StLabel ujlbl : xs)))
562 floating = isFloatingRep (getAmodeRep am)
563 choices = length alts
565 (x@(MachChar _),_) `leAlt` (y,_) = intTag x <= intTag y
566 (x@(MachInt _), _) `leAlt` (y,_) = intTag x <= intTag y
567 (x@(MachWord _), _) `leAlt` (y,_) = intTag x <= intTag y
568 (x,_) `leAlt` (y,_) = fltTag x <= fltTag y
572 We use jump tables when doing an integer switch on a relatively dense
573 list of alternatives. We expect to be given a list of alternatives,
574 sorted by tag, and a range of values for which we are to generate a
575 table. Of course, the tags of the alternatives should lie within the
576 indicated range. The alternatives need not cover the range; a default
577 target is provided for the missing alternatives.
579 If a join is necessary after the switch, the alternatives should
580 already finish with a jump to the join point.
585 :: StixTree -- discriminant
586 -> [(Literal, AbstractC)] -- alternatives
587 -> Integer -- low tag
588 -> Integer -- high tag
589 -> CLabel -- default label
590 -> UniqSM StixTreeList
593 mkJumpTable am alts lowTag highTag dflt
594 = getUniqLabelNCG `thenUs` \ utlbl ->
595 mapUs genLabel alts `thenUs` \ branches ->
596 let cjmpLo = StCondJump dflt (StMachOp MO_NatS_Lt [am, StInt (toInteger lowTag)])
597 cjmpHi = StCondJump dflt (StMachOp MO_NatS_Gt [am, StInt (toInteger highTag)])
599 offset = StMachOp MO_Nat_Sub [am, StInt lowTag]
600 dsts = DestInfo (dflt : map fst branches)
602 jump = StJump dsts (StInd PtrRep (StIndex PtrRep (StCLbl utlbl) offset))
604 table = StData PtrRep (mkTable branches [lowTag..highTag] [])
606 mapUs mkBranch branches `thenUs` \ alts ->
608 returnUs (\xs -> cjmpLo : cjmpHi : jump :
609 StSegment DataSegment : tlbl : table :
610 StSegment TextSegment : foldr1 (.) alts xs)
613 genLabel x = getUniqLabelNCG `thenUs` \ lbl -> returnUs (lbl, x)
615 mkBranch (lbl,(_,alt)) =
616 gencode alt `thenUs` \ alt_code ->
617 returnUs (\xs -> StLabel lbl : alt_code xs)
619 mkTable _ [] tbl = reverse tbl
620 mkTable [] (x:xs) tbl = mkTable [] xs (StCLbl dflt : tbl)
621 mkTable alts@((lbl,(tag,_)):rest) (x:xs) tbl
622 | intTag tag == x = mkTable rest xs (StCLbl lbl : tbl)
623 | otherwise = mkTable alts xs (StCLbl dflt : tbl)
627 We generate binary comparison trees when a jump table is inappropriate.
628 We expect to be given a list of alternatives, sorted by tag, and for
629 convenience, the length of the alternative list. We recursively break
630 the list in half and do a comparison on the first tag of the second half
631 of the list. (Odd lists are broken so that the second half of the list
632 is longer.) We can handle either integer or floating kind alternatives,
633 so long as they are not mixed. (We assume that the type of the discriminant
634 determines the type of the alternatives.)
636 As with the jump table approach, if a join is necessary after the switch, the
637 alternatives should already finish with a jump to the join point.
642 :: StixTree -- discriminant
643 -> Bool -- floating point?
644 -> [(Literal, AbstractC)] -- alternatives
645 -> Int -- number of choices
646 -> Literal -- low tag
647 -> Literal -- high tag
648 -> CLabel -- default code label
649 -> UniqSM StixTreeList
652 mkBinaryTree am floating [(tag,alt)] _ lowTag highTag udlbl
653 | rangeOfOne = gencode alt
655 = let tag' = a2stix (CLit tag)
656 cmpOp = if floating then MO_Dbl_Ne else MO_Nat_Ne
657 test = StMachOp cmpOp [am, tag']
658 cjmp = StCondJump udlbl test
660 gencode alt `thenUs` \ alt_code ->
661 returnUs (\xs -> cjmp : alt_code xs)
664 rangeOfOne = not floating && intTag lowTag + 1 >= intTag highTag
665 -- When there is only one possible tag left in range, we skip the comparison
667 mkBinaryTree am floating alts choices lowTag highTag udlbl
668 = getUniqLabelNCG `thenUs` \ uhlbl ->
669 let tag' = a2stix (CLit splitTag)
670 cmpOp = if floating then MO_Dbl_Ge else MO_NatS_Ge
671 test = StMachOp cmpOp [am, tag']
672 cjmp = StCondJump uhlbl test
674 mkBinaryTree am floating alts_lo half lowTag splitTag udlbl
675 `thenUs` \ lo_code ->
676 mkBinaryTree am floating alts_hi (choices - half) splitTag highTag udlbl
677 `thenUs` \ hi_code ->
679 returnUs (\xs -> cjmp : lo_code (StLabel uhlbl : hi_code xs))
682 half = choices `div` 2
683 (alts_lo, alts_hi) = splitAt half alts
684 splitTag = fst (head alts_hi)
691 :: CAddrMode -- discriminant
693 -> AbstractC -- if-part
694 -> AbstractC -- else-part
695 -> UniqSM StixTreeList
698 mkIfThenElse discrim tag alt deflt
699 = getUniqLabelNCG `thenUs` \ ujlbl ->
700 getUniqLabelNCG `thenUs` \ utlbl ->
701 let discrim' = a2stix discrim
702 tag' = a2stix (CLit tag)
703 cmpOp = if (isFloatingRep (getAmodeRep discrim)) then MO_Dbl_Ne else MO_Nat_Ne
704 test = StMachOp cmpOp [discrim', tag']
705 cjmp = StCondJump utlbl test
709 gencode (mkJoin alt ujlbl) `thenUs` \ alt_code ->
710 gencode deflt `thenUs` \ dflt_code ->
711 returnUs (\xs -> cjmp : alt_code (dest : dflt_code (join : xs)))
714 mkJoin :: AbstractC -> CLabel -> AbstractC
716 | mightFallThrough code = mkAbsCStmts code (CJump (CLbl lbl PtrRep))
720 %---------------------------------------------------------------------------
722 This answers the question: Can the code fall through to the next
723 line(s) of code? This errs towards saying True if it can't choose,
724 because it is used for eliminating needless jumps. In other words, if
725 you might possibly {\em not} jump, then say yes to falling through.
728 mightFallThrough :: AbstractC -> Bool
730 mightFallThrough absC = ft absC True
732 ft AbsCNop if_empty = if_empty
734 ft (CJump _) if_empty = False
735 ft (CReturn _ _) if_empty = False
736 ft (CSwitch _ alts deflt) if_empty
737 = ft deflt if_empty ||
738 or [ft alt if_empty | (_,alt) <- alts]
740 ft (AbsCStmts c1 c2) if_empty = ft c2 (ft c1 if_empty)
741 ft _ if_empty = if_empty
743 {- Old algorithm, which called nonemptyAbsC for every subexpression! =========
744 fallThroughAbsC (AbsCStmts c1 c2)
745 = case nonemptyAbsC c2 of
746 Nothing -> fallThroughAbsC c1
747 Just x -> fallThroughAbsC x
748 fallThroughAbsC (CJump _) = False
749 fallThroughAbsC (CReturn _ _) = False
750 fallThroughAbsC (CSwitch _ choices deflt)
751 = (not (isEmptyAbsC deflt) && fallThroughAbsC deflt)
752 || or (map (fallThroughAbsC . snd) choices)
753 fallThroughAbsC other = True
755 isEmptyAbsC :: AbstractC -> Bool
756 isEmptyAbsC = not . maybeToBool . nonemptyAbsC
757 ================= End of old, quadratic, algorithm -}