rET_SMALL, rET_BIG,
rET_VEC_SMALL, rET_VEC_BIG
)
-import Constants ( mIN_UPD_SIZE )
+import Constants ( mIN_UPD_SIZE, wORD_SIZE )
import CLabel ( CLabel, mkReturnInfoLabel, mkReturnPtLabel,
mkClosureTblLabel, mkClosureLabel,
- moduleRegdLabel, labelDynamic )
+ labelDynamic, mkSplitMarkerLabel )
import ClosureInfo ( infoTableLabelFromCI, entryLabelFromCI,
fastLabelFromCI, closureUpdReqd,
staticClosureNeedsLink
)
import Literal ( Literal(..), word2IntLit )
-import Maybes ( maybeToBool )
-import PrimOp ( primOpNeedsWrapper, PrimOp(..) )
+import Maybes ( Maybe012(..), maybeToBool )
+import StgSyn ( StgOp(..) )
+import MachOp ( MachOp(..), resultRepsOfMachOp )
import PrimRep ( isFloatingRep, PrimRep(..) )
-import StixInfo ( genCodeInfoTable, genBitmapInfoTable )
+import StixInfo ( genCodeInfoTable, genBitmapInfoTable,
+ livenessIsSmall, bitmapToIntegers )
import StixMacro ( macroCode, checkCode )
-import StixPrim ( primCode, amodeToStix, amodeToStix' )
+import StixPrim ( foreignCallCode, amodeToStix, amodeToStix' )
import Outputable ( pprPanic, ppr )
import UniqSupply ( returnUs, thenUs, mapUs, getUniqueUs, UniqSM )
import Util ( naturalMergeSortLe )
import Panic ( panic )
import TyCon ( tyConDataCons )
import DataCon ( dataConWrapId )
-import BitSet ( intBS )
import Name ( NamedThing(..) )
-import Char ( ord )
-import CmdLineOpts ( opt_Static )
+import CmdLineOpts ( opt_Static, opt_EnsureSplittableC )
+import Outputable ( assertPanic )
+
+-- DEBUGGING ONLY
+--import IOExts ( trace )
+--import Outputable ( showSDoc )
+--import MachOp ( pprMachOp )
+
\end{code}
For each independent chunk of AbstractC code, we generate a list of
performed locally within the chunk.
\begin{code}
-genCodeAbstractC :: AbstractC -> UniqSM [StixTree]
+genCodeAbstractC :: AbstractC -> UniqSM [StixStmt]
genCodeAbstractC absC
= gentopcode absC
a2stix' = amodeToStix'
volsaves = volatileSaves
volrestores = volatileRestores
- p2stix = primCode
macro_code = macroCode
-- real code follows... ---------
\end{code}
gentopcode stmt@(CRetVector lbl _ _ _)
= genCodeVecTbl stmt `thenUs` \ code ->
- returnUs (StSegment TextSegment : code [StLabel lbl])
+ returnUs (StSegment TextSegment
+ : code [StLabel lbl, vtbl_post_label_word])
+ where
+ -- We put a dummy word after the vtbl label so as to ensure the label
+ -- is in the same (Text) section as the vtbl it labels. This is critical
+ -- for ensuring the GC works correctly, although GC crashes due to
+ -- misclassification are much more likely to show up in the interactive
+ -- system than in compile code. For details see comment near line 1164
+ -- of ghc/driver/mangler/ghc-asm.lprl, which contains an analogous fix for
+ -- the mangled via-C route.
+ vtbl_post_label_word = StData PtrRep [StInt 0]
gentopcode stmt@(CRetDirect uniq absC srt liveness)
= gencode absC `thenUs` \ code ->
where
lbl_info = mkReturnInfoLabel uniq
lbl_ret = mkReturnPtLabel uniq
- closure_type = case liveness of
- LvSmall _ -> rET_SMALL
- LvLarge _ -> rET_BIG
+ closure_type = if livenessIsSmall liveness then rET_SMALL else rET_BIG
gentopcode stmt@(CClosureInfoAndCode cl_info slow Nothing _)
, StData DataPtrRep (map mk_StCLbl_for_SRT closures)
]
where
- mk_StCLbl_for_SRT :: CLabel -> StixTree
+ mk_StCLbl_for_SRT :: CLabel -> StixExpr
mk_StCLbl_for_SRT label
| labelDynamic label
- = StIndex CharRep (StCLbl label) (StInt 1)
+ = StIndex Int8Rep (StCLbl label) (StInt 1)
| otherwise
= StCLbl label
gentopcode stmt@(CBitmap lbl mask)
- = returnUs [ StSegment TextSegment
- , StLabel lbl
- , StData WordRep (StInt (toInteger (length mask)) :
- map (StInt . toInteger . intBS) mask)
- ]
+ = returnUs $ case bitmapToIntegers mask of
+ mask'@(_:_:_) ->
+ [ StSegment TextSegment
+ , StLabel lbl
+ , StData WordRep (map StInt (toInteger (length mask') : mask'))
+ ]
+ _ -> []
gentopcode stmt@(CClosureTbl tycon)
= returnUs [ StSegment TextSegment
: StData IntRep [StInt 0]
: StSegment TextSegment
: StLabel lbl
- : StCondJump tmp_lbl (StPrim IntNeOp
+ : StCondJump tmp_lbl (StMachOp MO_Nat_Ne
[StInd IntRep (StCLbl flag_lbl),
StInt 0])
- : StAssign IntRep (StInd IntRep (StCLbl flag_lbl)) (StInt 1)
+ : StAssignMem IntRep (StCLbl flag_lbl) (StInt 1)
: code
[ StLabel tmp_lbl
- , StAssign PtrRep stgSp
- (StIndex PtrRep stgSp (StInt (-1)))
- , StJump (StInd WordRep stgSp)
+ , StAssignReg PtrRep stgSp
+ (StIndex PtrRep (StReg stgSp) (StInt (-1)))
+ , StJump NoDestInfo (StInd WordRep (StReg stgSp))
])
gentopcode absC
returnUs (\xs -> vectbl : itbl xs)
where
vectbl = StData PtrRep (reverse (map a2stix amodes))
- closure_type = case liveness of
- LvSmall _ -> rET_VEC_SMALL
- LvLarge _ -> rET_VEC_BIG
+ closure_type = if livenessIsSmall liveness then rET_VEC_SMALL else rET_VEC_BIG
\end{code}
= returnUs (\xs -> table ++ xs)
where
table = StData PtrRep [StCLbl (infoTableLabelFromCI cl_info)] :
- map (\amode -> StData (getAmodeRep amode) [a2stix amode]) amodes ++
+ map do_one_amode amodes ++
[StData PtrRep (padding_wds ++ static_link)]
- -- always at least one padding word: this is the static link field
- -- for the garbage collector.
- padding_wds = if closureUpdReqd cl_info then
- take (max 0 (mIN_UPD_SIZE - length amodes)) zeros
- else
- []
+ do_one_amode amode
+ = StData (promote_to_word (getAmodeRep amode)) [a2stix amode]
- static_link | staticClosureNeedsLink cl_info = [StInt 0]
- | otherwise = []
+ -- We need to promote any item smaller than a word to a word
+ promote_to_word pk
+ | sizeOf pk >= sizeOf IntRep = pk
+ | otherwise = IntRep
+
+ upd_reqd = closureUpdReqd cl_info
+
+ padding_wds
+ | upd_reqd = take (max 0 (mIN_UPD_SIZE - length amodes)) zeros
+ | otherwise = []
+
+ static_link | upd_reqd || staticClosureNeedsLink cl_info = [StInt 0]
+ | otherwise = []
zeros = StInt 0 : zeros
\end{code}
-Split markers are a NOP in this land.
+Split markers just insert a __stg_split_marker, which is caught by the
+split-mangler later on and used to split the assembly into chunks.
\begin{code}
- gencode CSplitMarker = returnUs id
+ gencode CSplitMarker
+ | opt_EnsureSplittableC = returnUs (\xs -> StLabel mkSplitMarkerLabel : xs)
+ | otherwise = returnUs id
\end{code}
gencode c2 `thenUs` \ b2 ->
returnUs (b1 . b2)
+ gencode (CSequential stuff)
+ = foo stuff
+ where
+ foo [] = returnUs id
+ foo (s:ss) = gencode s `thenUs` \ stix ->
+ foo ss `thenUs` \ stixes ->
+ returnUs (stix . stixes)
+
\end{code}
Initialising closure headers in the heap...a fairly complex ordeal if
\begin{code}
- gencode (CInitHdr cl_info reg_rel _)
+ gencode (CInitHdr cl_info reg_rel _ _)
= let
lhs = a2stix reg_rel
lbl = infoTableLabelFromCI cl_info
in
- returnUs (\xs -> StAssign PtrRep (StInd PtrRep lhs) (StCLbl lbl) : xs)
+ returnUs (\xs -> StAssignMem PtrRep lhs (StCLbl lbl) : xs)
\end{code}
lhs' = a2stix lhs
rhs' = a2stix' rhs
in
- returnUs (\xs -> StAssign pk' lhs' rhs' : xs)
+ returnUs (\xs -> mkStAssign pk' lhs' rhs' : xs)
\end{code}
\begin{code}
gencode (CJump dest)
- = returnUs (\xs -> StJump (a2stix dest) : xs)
+ = returnUs (\xs -> StJump NoDestInfo (a2stix dest) : xs)
gencode (CFallThrough (CLbl lbl _))
= returnUs (\xs -> StFallThrough lbl : xs)
gencode (CReturn dest DirectReturn)
- = returnUs (\xs -> StJump (a2stix dest) : xs)
+ = returnUs (\xs -> StJump NoDestInfo (a2stix dest) : xs)
gencode (CReturn table (StaticVectoredReturn n))
- = returnUs (\xs -> StJump dest : xs)
+ = returnUs (\xs -> StJump NoDestInfo dest : xs)
where
dest = StInd PtrRep (StIndex PtrRep (a2stix table)
(StInt (toInteger (-n-fixedItblSize-1))))
gencode (CReturn table (DynamicVectoredReturn am))
- = returnUs (\xs -> StJump dest : xs)
+ = returnUs (\xs -> StJump NoDestInfo dest : xs)
where
dest = StInd PtrRep (StIndex PtrRep (a2stix table) dyn_off)
- dyn_off = StPrim IntSubOp [StPrim IntNegOp [a2stix am],
- StInt (toInteger (fixedItblSize+1))]
+ dyn_off = StMachOp MO_Nat_Sub [StMachOp MO_NatS_Neg [a2stix am],
+ StInt (toInteger (fixedItblSize+1))]
\end{code}
Now the PrimOps, some of which may need caller-saves register wrappers.
\begin{code}
+ gencode (COpStmt results (StgFCallOp fcall _) args vols)
+ = ASSERT( null vols )
+ foreignCallCode (nonVoid results) fcall (nonVoid args)
+
+ gencode (COpStmt results (StgPrimOp op) args vols)
+ = panic "AbsCStixGen.gencode: un-translated PrimOp"
+
+ -- Translate out array indexing primops right here, so that
+ -- individual targets don't have to deal with them
+
+ gencode (CMachOpStmt (Just1 r1) (MO_ReadOSBI off_w rep) [base,index] vols)
+ = returnUs (\xs ->
+ mkStAssign
+ rep
+ (a2stix r1)
+ (StInd rep (StMachOp MO_Nat_Add
+ [StIndex rep (a2stix base) (a2stix index),
+ StInt (toInteger (off_w * wORD_SIZE))]))
+ : xs
+ )
- gencode (COpStmt results op args vols)
- -- ToDo (ADR?): use that liveness mask
- | primOpNeedsWrapper op
- = let
- saves = volsaves vols
- restores = volrestores vols
+ gencode (CMachOpStmt Just0 (MO_WriteOSBI off_w rep) [base,index,val] vols)
+ = returnUs (\xs ->
+ StAssignMem
+ rep
+ (StMachOp MO_Nat_Add
+ [StIndex rep (a2stix base) (a2stix index),
+ StInt (toInteger (off_w * wORD_SIZE))])
+ (a2stix val)
+ : xs
+ )
+
+ -- Gruesome cases for multiple-result primops
+ gencode (CMachOpStmt (Just2 r1 r2) mop [arg1, arg2] vols)
+ | mop `elem` [MO_NatS_AddC, MO_NatS_SubC, MO_NatS_MulC]
+ = getUniqueUs `thenUs` \ u1 ->
+ getUniqueUs `thenUs` \ u2 ->
+ let vr1 = StixVReg u1 IntRep
+ vr2 = StixVReg u2 IntRep
+ r1s = a2stix r1
+ r2s = a2stix r2
in
- p2stix (nonVoid results) op (nonVoid args)
- `thenUs` \ code ->
- returnUs (\xs -> saves ++ code (restores ++ xs))
+ returnUs (\xs ->
+ StAssignMachOp (Just2 vr1 vr2) mop [a2stix arg1, a2stix arg2]
+ : mkStAssign IntRep r1s (StReg (StixTemp vr1))
+ : mkStAssign IntRep r2s (StReg (StixTemp vr2))
+ : xs
+ )
- | otherwise = p2stix (nonVoid results) op (nonVoid args)
- where
- nonVoid = filter ((/= VoidRep) . getAmodeRep)
+ -- Ordinary MachOps are passed through unchanged.
+ gencode (CMachOpStmt (Just1 r1) mop args vols)
+ = let (Just1 rep) = resultRepsOfMachOp mop
+ in
+ returnUs (\xs ->
+ mkStAssign rep (a2stix r1)
+ (StMachOp mop (map a2stix args))
+ : xs
+ )
\end{code}
Now the dreaded conditional jump.
gencode (CCallProfCCMacro macro _)
= returnUs (\xs -> StComment macro : xs)
+ gencode CCallTypedef{} = returnUs id
+
gencode other
= pprPanic "AbsCStixGen.gencode" (dumpRealC other)
+
+ nonVoid = filter ((/= VoidRep) . getAmodeRep)
\end{code}
Here, we generate a jump table if there are more than four (integer)
\begin{code}
intTag :: Literal -> Integer
- intTag (MachChar c) = toInteger (ord c)
+ intTag (MachChar c) = toInteger c
intTag (MachInt i) = i
intTag (MachWord w) = intTag (word2IntLit (MachWord w))
intTag _ = panic "intTag"
highest = if floating then targetMaxDouble else targetMaxInt
in
(
- if not floating && choices > 4 && highTag - lowTag < toInteger (2 * choices) then
+ if not floating && choices > 4
+ && highTag - lowTag < toInteger (2 * choices)
+ then
mkJumpTable am' sortedAlts lowTag highTag udlbl
else
mkBinaryTree am' floating sortedAlts choices lowest highest udlbl
)
- `thenUs` \ alt_code ->
+ `thenUs` \ alt_code ->
gencode absC `thenUs` \ dflt_code ->
returnUs (\xs -> alt_code (StLabel udlbl : dflt_code (StLabel ujlbl : xs)))
mkJumpTable am alts lowTag highTag dflt
= getUniqLabelNCG `thenUs` \ utlbl ->
mapUs genLabel alts `thenUs` \ branches ->
- let cjmpLo = StCondJump dflt (StPrim IntLtOp [am, StInt (toInteger lowTag)])
- cjmpHi = StCondJump dflt (StPrim IntGtOp [am, StInt (toInteger highTag)])
+ let cjmpLo = StCondJump dflt (StMachOp MO_NatS_Lt [am, StInt (toInteger lowTag)])
+ cjmpHi = StCondJump dflt (StMachOp MO_NatS_Gt [am, StInt (toInteger highTag)])
- offset = StPrim IntSubOp [am, StInt lowTag]
+ offset = StMachOp MO_Nat_Sub [am, StInt lowTag]
+ dsts = DestInfo (dflt : map fst branches)
- jump = StJump (StInd PtrRep (StIndex PtrRep (StCLbl utlbl) offset))
+ jump = StJump dsts (StInd PtrRep (StIndex PtrRep (StCLbl utlbl) offset))
tlbl = StLabel utlbl
table = StData PtrRep (mkTable branches [lowTag..highTag] [])
in
| rangeOfOne = gencode alt
| otherwise
= let tag' = a2stix (CLit tag)
- cmpOp = if floating then DoubleNeOp else IntNeOp
- test = StPrim cmpOp [am, tag']
+ cmpOp = if floating then MO_Dbl_Ne else MO_Nat_Ne
+ test = StMachOp cmpOp [am, tag']
cjmp = StCondJump udlbl test
in
gencode alt `thenUs` \ alt_code ->
mkBinaryTree am floating alts choices lowTag highTag udlbl
= getUniqLabelNCG `thenUs` \ uhlbl ->
let tag' = a2stix (CLit splitTag)
- cmpOp = if floating then DoubleGeOp else IntGeOp
- test = StPrim cmpOp [am, tag']
+ cmpOp = if floating then MO_Dbl_Ge else MO_NatS_Ge
+ test = StMachOp cmpOp [am, tag']
cjmp = StCondJump uhlbl test
in
mkBinaryTree am floating alts_lo half lowTag splitTag udlbl
getUniqLabelNCG `thenUs` \ utlbl ->
let discrim' = a2stix discrim
tag' = a2stix (CLit tag)
- cmpOp = if (isFloatingRep (getAmodeRep discrim)) then DoubleNeOp else IntNeOp
- test = StPrim cmpOp [discrim', tag']
+ cmpOp = if (isFloatingRep (getAmodeRep discrim)) then MO_Dbl_Ne else MO_Nat_Ne
+ test = StMachOp cmpOp [discrim', tag']
cjmp = StCondJump utlbl test
dest = StLabel utlbl
join = StLabel ujlbl
gencode deflt `thenUs` \ dflt_code ->
returnUs (\xs -> cjmp : alt_code (dest : dflt_code (join : xs)))
-mkJoin :: AbstractC -> CLabel -> AbstractC
+mkJoin :: AbstractC -> CLabel -> AbstractC
mkJoin code lbl
| mightFallThrough code = mkAbsCStmts code (CJump (CLbl lbl PtrRep))
| otherwise = code