2 % (c) The AQUA Project, Glasgow University, 1993-1998
7 CodeSegment(..), StixReg(..), StixExpr(..), StixVReg(..),
8 StixStmt(..), mkStAssign, StixStmtList,
9 pprStixStmts, pprStixStmt, pprStixExpr, pprStixReg,
10 stixStmt_CountTempUses, stixStmt_Subst,
11 liftStrings, repOfStixExpr,
12 DestInfo(..), hasDestInfo,
14 stgBaseReg, stgNode, stgSp, stgSu, stgSpLim,
15 stgHp, stgHpLim, stgHpAlloc, stgTagReg, stgR9, stgR10,
16 stgCurrentTSO, stgCurrentNursery,
18 fixedHS, arrWordsHS, arrPtrsHS,
20 NatM, initNat, thenNat, returnNat,
21 mapNat, mapAndUnzipNat, mapAccumLNat,
22 getUniqueNat, getDeltaNat, setDeltaNat,
23 NatM_State, mkNatM_State,
24 uniqOfNatM_State, deltaOfNatM_State,
26 getUniqLabelNCG, getNatLabelNCG,
29 -- Information about the target arch
33 #include "HsVersions.h"
35 import Ratio ( Rational )
36 import IOExts ( unsafePerformIO )
37 import IO ( hPutStrLn, stderr )
39 import AbsCSyn ( node, tagreg, MagicId(..) )
40 import AbsCUtils ( magicIdPrimRep )
41 import ForeignCall ( CCallConv )
42 import CLabel ( mkAsmTempLabel, CLabel, pprCLabel )
43 import PrimRep ( PrimRep(..) )
44 import MachOp ( MachOp(..), pprMachOp, resultRepsOfMachOp )
45 import Unique ( Unique )
46 import SMRep ( fixedHdrSize, arrWordsHdrSize, arrPtrsHdrSize )
47 import UniqSupply ( UniqSupply, splitUniqSupply, uniqFromSupply,
48 UniqSM, thenUs, returnUs, getUniqueUs )
49 import Maybes ( Maybe012(..), maybe012ToList )
50 import Constants ( wORD_SIZE )
55 Two types, StixStmt and StixValue, define Stix.
59 -- Non-value trees; ones executed for their side-effect.
62 = -- Directive for the assembler to change segment
65 -- Assembly-language comments
66 | StComment FAST_STRING
68 -- Assignments are typed to determine size and register placement.
69 -- Assign a value to a StixReg
70 | StAssignReg PrimRep StixReg StixExpr
72 -- Assign a value to memory. First tree indicates the address to be
73 -- assigned to, so there is an implicit dereference here.
74 | StAssignMem PrimRep StixExpr StixExpr -- dst, src
76 -- Do a machine op which generates multiple values, and assign
77 -- the results to the lvalues stated here.
78 | StAssignMachOp (Maybe012 StixVReg) MachOp [StixExpr]
80 -- A simple assembly label that we might jump to.
83 -- A function header and footer
87 -- An unconditional jump. This instruction may or may not jump
88 -- out of the register allocation domain (basic block, more or
89 -- less). For correct register allocation when this insn is used
90 -- to jump through a jump table, we optionally allow a list of
91 -- the exact targets to be attached, so that the allocator can
92 -- easily construct the exact flow edges leaving this insn.
93 -- Dynamic targets are allowed.
94 | StJump DestInfo StixExpr
96 -- A fall-through, from slow to fast
97 | StFallThrough CLabel
99 -- A conditional jump. This instruction can be non-terminal :-)
100 -- Only static, local, forward labels are allowed
101 | StCondJump CLabel StixExpr
103 -- Raw data (as in an info table).
104 | StData PrimRep [StixExpr]
105 -- String which has been lifted to the top level (sigh).
106 | StDataString FAST_STRING
108 -- A value computed only for its side effects; result is discarded
109 -- (A handy trapdoor to allow CCalls with no results to appear as
111 | StVoidable StixExpr
114 -- Helper fn to make Stix assignment statements where the
115 -- lvalue masquerades as a StixExpr. A kludge that should
116 -- be done away with.
117 mkStAssign :: PrimRep -> StixExpr -> StixExpr -> StixStmt
118 mkStAssign rep (StReg reg) rhs
119 = StAssignReg rep reg rhs
120 mkStAssign rep (StInd rep' addr) rhs
121 | rep `isCloseEnoughTo` rep'
122 = StAssignMem rep addr rhs
124 = --pprPanic "Stix.mkStAssign: mismatched reps" (ppr rep <+> ppr rep')
125 --trace ("Stix.mkStAssign: mismatched reps: " ++ showSDoc (ppr rep <+> ppr rep')) (
126 StAssignMem rep addr rhs
129 isCloseEnoughTo r1 r2
130 = r1 == r2 || (wordIsh r1 && wordIsh r2)
132 = rep `elem` [IntRep, WordRep, PtrRep, AddrRep, CodePtrRep,
133 RetRep, ArrayRep, PrimPtrRep, StableNameRep, BCORep]
134 -- determined by looking at PrimRep.showPrimRep
136 -- Stix trees which denote a value.
139 StInt Integer -- ** add Kind at some point
142 | StString FAST_STRING
143 | StCLbl CLabel -- labels that we might index into
145 -- Abstract registers of various kinds
148 -- A typed offset from a base location
149 | StIndex PrimRep StixExpr StixExpr -- kind, base, offset
151 -- An indirection from an address to its contents.
152 | StInd PrimRep StixExpr
154 -- Primitive Operations
155 | StMachOp MachOp [StixExpr]
157 -- Calls to C functions
158 | StCall FAST_STRING CCallConv PrimRep [StixExpr]
161 -- What's the PrimRep of the value denoted by this StixExpr?
162 repOfStixExpr :: StixExpr -> PrimRep
163 repOfStixExpr (StInt _) = IntRep
164 repOfStixExpr (StFloat _) = FloatRep
165 repOfStixExpr (StDouble _) = DoubleRep
166 repOfStixExpr (StString _) = PtrRep
167 repOfStixExpr (StCLbl _) = PtrRep
168 repOfStixExpr (StReg reg) = repOfStixReg reg
169 repOfStixExpr (StIndex _ _ _) = PtrRep
170 repOfStixExpr (StInd rep _) = rep
171 repOfStixExpr (StCall target conv retrep args) = retrep
172 repOfStixExpr (StMachOp mop args)
173 = case resultRepsOfMachOp mop of
175 other -> pprPanic "repOfStixExpr:StMachOp" (pprMachOp mop)
178 -- used by insnFuture in RegAllocInfo.lhs
180 = NoDestInfo -- no supplied dests; infer from context
181 | DestInfo [CLabel] -- precisely these dests and no others
183 hasDestInfo NoDestInfo = False
184 hasDestInfo (DestInfo _) = True
186 pprDests :: DestInfo -> SDoc
187 pprDests NoDestInfo = text "NoDestInfo"
188 pprDests (DestInfo dsts) = brackets (hsep (map pprCLabel dsts))
191 pprStixStmts :: [StixStmt] -> SDoc
194 vcat (map pprStixStmt ts),
200 pprStixExpr :: StixExpr -> SDoc
203 StCLbl lbl -> pprCLabel lbl
204 StInt i -> (if i < 0 then parens else id) (integer i)
205 StFloat rat -> parens (text "Float" <+> rational rat)
206 StDouble rat -> parens (text "Double" <+> rational rat)
207 StString str -> parens (text "Str `" <> ptext str <> char '\'')
208 StIndex k b o -> parens (pprStixExpr b <+> char '+' <>
209 ppr k <+> pprStixExpr o)
210 StInd k t -> ppr k <> char '[' <> pprStixExpr t <> char ']'
211 StReg reg -> pprStixReg reg
212 StMachOp op args -> pprMachOp op
213 <> parens (hsep (punctuate comma (map pprStixExpr args)))
215 -> parens (text "Call" <+> ptext nm <+>
217 hsep (map pprStixExpr args))
219 pprStixStmt :: StixStmt -> SDoc
222 StSegment cseg -> parens (ppCodeSegment cseg)
223 StComment str -> parens (text "Comment" <+> ptext str)
224 StAssignReg pr reg rhs
225 -> pprStixReg reg <> text " :=" <> ppr pr
226 <> text " " <> pprStixExpr rhs
227 StAssignMem pr addr rhs
228 -> ppr pr <> char '[' <> pprStixExpr addr <> char ']'
229 <> text " :=" <> ppr pr
230 <> text " " <> pprStixExpr rhs
231 StAssignMachOp lhss mop args
232 -> parens (hcat (punctuate comma (
233 map pprStixVReg (maybe012ToList lhss)
237 <> parens (hsep (punctuate comma (map pprStixExpr args)))
238 StLabel ll -> pprCLabel ll <+> char ':'
239 StFunBegin ll -> char ' ' $$ parens (text "FunBegin" <+> pprCLabel ll)
240 StFunEnd ll -> parens (text "FunEnd" <+> pprCLabel ll)
241 StJump dsts t -> parens (text "Jump" <+> pprDests dsts <+> pprStixExpr t)
242 StFallThrough ll -> parens (text "FallThru" <+> pprCLabel ll)
243 StCondJump l t -> parens (text "JumpC" <+> pprCLabel l
245 StData k ds -> parens (text "Data" <+> ppr k <+>
246 hsep (map pprStixExpr ds))
247 StDataString str -> parens (text "DataString" <+> ppr str)
248 StVoidable expr -> text "(void)" <+> pprStixExpr expr
251 Stix registers can have two forms. They {\em may} or {\em may not}
252 map to real, machine-level registers.
256 = StixMagicId MagicId -- Regs which are part of the abstract machine model
258 | StixTemp StixVReg -- "Regs" which model local variables (CTemps) in
261 pprStixReg (StixMagicId mid) = ppMId mid
262 pprStixReg (StixTemp temp) = pprStixVReg temp
264 repOfStixReg (StixTemp (StixVReg u pr)) = pr
265 repOfStixReg (StixMagicId mid) = magicIdPrimRep mid
268 = StixVReg Unique PrimRep
270 pprStixVReg (StixVReg u pr) = hcat [text "VReg(", ppr u, colon, ppr pr, char ')']
274 ppMId BaseReg = text "BaseReg"
275 ppMId (VanillaReg kind n) = hcat [ppr kind, text "IntReg(",
276 int (iBox n), char ')']
277 ppMId (FloatReg n) = hcat [text "FltReg(", int (iBox n), char ')']
278 ppMId (DoubleReg n) = hcat [text "DblReg(", int (iBox n), char ')']
279 ppMId (LongReg kind n) = hcat [ppr kind, text "LongReg(",
280 int (iBox n), char ')']
283 ppMId SpLim = text "SpLim"
285 ppMId HpLim = text "HpLim"
286 ppMId CurCostCentre = text "CCC"
287 ppMId VoidReg = text "VoidReg"
290 We hope that every machine supports the idea of data segment and text
291 segment (or that it has no segments at all, and we can lump these
301 ppCodeSegment = text . show
303 type StixStmtList = [StixStmt] -> [StixStmt]
306 Stix Trees for STG registers:
308 stgBaseReg, stgNode, stgSp, stgSu, stgSpLim, stgHp, stgHpLim
311 stgBaseReg = StixMagicId BaseReg
312 stgNode = StixMagicId node
313 stgTagReg = StixMagicId tagreg
314 stgSp = StixMagicId Sp
315 stgSu = StixMagicId Su
316 stgSpLim = StixMagicId SpLim
317 stgHp = StixMagicId Hp
318 stgHpLim = StixMagicId HpLim
319 stgHpAlloc = StixMagicId HpAlloc
320 stgCurrentTSO = StixMagicId CurrentTSO
321 stgCurrentNursery = StixMagicId CurrentNursery
322 stgR9 = StixMagicId (VanillaReg WordRep (_ILIT 9))
323 stgR10 = StixMagicId (VanillaReg WordRep (_ILIT 10))
325 getNatLabelNCG :: NatM CLabel
327 = getUniqueNat `thenNat` \ u ->
328 returnNat (mkAsmTempLabel u)
330 getUniqLabelNCG :: UniqSM CLabel
332 = getUniqueUs `thenUs` \ u ->
333 returnUs (mkAsmTempLabel u)
335 fixedHS = StInt (toInteger fixedHdrSize)
336 arrWordsHS = StInt (toInteger arrWordsHdrSize)
337 arrPtrsHS = StInt (toInteger arrPtrsHdrSize)
340 Stix optimisation passes may wish to find out how many times a
341 given temporary appears in a tree, so as to be able to decide
342 whether or not to inline the assignment's RHS at usage site(s).
345 stixExpr_CountTempUses :: Unique -> StixExpr -> Int
346 stixExpr_CountTempUses u t
347 = let qs = stixStmt_CountTempUses u
348 qe = stixExpr_CountTempUses u
349 qr = stixReg_CountTempUses u
353 StIndex pk t1 t2 -> qe t1 + qe t2
355 StMachOp mop ts -> sum (map qe ts)
356 StCall nm cconv pk ts -> sum (map qe ts)
363 stixStmt_CountTempUses :: Unique -> StixStmt -> Int
364 stixStmt_CountTempUses u t
365 = let qe = stixExpr_CountTempUses u
366 qr = stixReg_CountTempUses u
367 qv = stixVReg_CountTempUses u
370 StAssignReg pk reg rhs -> qr reg + qe rhs
371 StAssignMem pk addr rhs -> qe addr + qe rhs
372 StJump dsts t1 -> qe t1
373 StCondJump lbl t1 -> qe t1
374 StData pk ts -> sum (map qe ts)
375 StAssignMachOp lhss mop args
376 -> sum (map qv (maybe012ToList lhss)) + sum (map qe args)
377 StVoidable expr -> qe expr
386 stixReg_CountTempUses u reg
388 StixTemp vreg -> stixVReg_CountTempUses u vreg
391 stixVReg_CountTempUses u (StixVReg uu pr)
392 = if u == uu then 1 else 0
395 If we do decide to inline a temporary binding, the following functions
399 stixStmt_Subst :: Unique -> StixExpr -> StixStmt -> StixStmt
400 stixStmt_Subst u new_u in_this_tree
401 = stixStmt_MapUniques f in_this_tree
403 f :: Unique -> Maybe StixExpr
404 f uu = if uu == u then Just new_u else Nothing
407 stixExpr_MapUniques :: (Unique -> Maybe StixExpr) -> StixExpr -> StixExpr
408 stixExpr_MapUniques f t
409 = let qe = stixExpr_MapUniques f
410 qs = stixStmt_MapUniques f
411 qr = stixReg_MapUniques f
414 StReg reg -> case qr reg of
417 StIndex pk t1 t2 -> StIndex pk (qe t1) (qe t2)
418 StInd pk t1 -> StInd pk (qe t1)
419 StMachOp mop args -> StMachOp mop (map qe args)
420 StCall nm cconv pk ts -> StCall nm cconv pk (map qe ts)
427 stixStmt_MapUniques :: (Unique -> Maybe StixExpr) -> StixStmt -> StixStmt
428 stixStmt_MapUniques f t
429 = let qe = stixExpr_MapUniques f
430 qs = stixStmt_MapUniques f
431 qr = stixReg_MapUniques f
432 qv = stixVReg_MapUniques f
434 doMopLhss Just0 = Just0
438 other -> doMopLhss_panic
439 doMopLhss (Just2 r1 r2)
440 = case (qv r1, qv r2) of
441 (Nothing, Nothing) -> Just2 r1 r2
442 other -> doMopLhss_panic
443 -- Because the StixRegs processed by doMopLhss are lvalues, they
444 -- absolutely shouldn't be mapped to a StixExpr;
445 -- hence we panic if they do. Same deal for StAssignReg below.
447 = panic "stixStmt_MapUniques:doMopLhss"
450 StAssignReg pk reg rhs
452 Nothing -> StAssignReg pk reg (qe rhs)
453 Just xx -> panic "stixStmt_MapUniques:StAssignReg"
454 StAssignMem pk addr rhs -> StAssignMem pk (qe addr) (qe rhs)
455 StJump dsts t1 -> StJump dsts (qe t1)
456 StCondJump lbl t1 -> StCondJump lbl (qe t1)
457 StData pk ts -> StData pk (map qe ts)
458 StVoidable expr -> StVoidable (qe expr)
459 StAssignMachOp lhss mop args
460 -> StAssignMachOp (doMopLhss lhss) mop (map qe args)
470 stixReg_MapUniques :: (Unique -> Maybe StixExpr) -> StixReg -> Maybe StixExpr
471 stixReg_MapUniques f reg
473 StixMagicId mid -> Nothing
474 StixTemp vreg -> stixVReg_MapUniques f vreg
476 stixVReg_MapUniques :: (Unique -> Maybe StixExpr) -> StixVReg -> Maybe StixExpr
477 stixVReg_MapUniques f (StixVReg uu pr)
482 -- Lift StStrings out of top-level StDatas, putting them at the end of
483 -- the block, and replacing them with StCLbls which refer to the lifted-out strings.
484 {- Motivation for this hackery provided by the following bug:
488 (Data P_ Addr.A#_static_info)
489 (Data StgAddr (Str `alalal'))
494 .global Bogon_ping_closure
496 .long Addr_Azh_static_info
507 ie, the Str is planted in-line, when what we really meant was to place
508 a _reference_ to the string there. liftStrings will lift out all such
509 strings in top-level data and place them at the end of the block.
511 This is still a rather half-baked solution -- to do the job entirely right
512 would mean a complete traversal of all the Stixes, but there's currently no
513 real need for it, and it would be slow. Also, potentially there could be
514 literal types other than strings which need lifting out?
517 liftStrings :: [StixStmt] -> UniqSM [StixStmt]
519 = liftStrings_wrk stmts [] []
521 liftStrings_wrk :: [StixStmt] -- originals
522 -> [StixStmt] -- (reverse) originals with strings lifted out
523 -> [(CLabel, FAST_STRING)] -- lifted strs, and their new labels
526 -- First, examine the original trees and lift out strings in top-level StDatas.
527 liftStrings_wrk (st:sts) acc_stix acc_strs
530 -> lift datas acc_strs `thenUs` \ (datas_done, acc_strs1) ->
531 liftStrings_wrk sts ((StData sz datas_done):acc_stix) acc_strs1
533 -> liftStrings_wrk sts (other:acc_stix) acc_strs
535 -- Handle a top-level StData
536 lift [] acc_strs = returnUs ([], acc_strs)
538 = lift ds acc_strs `thenUs` \ (ds_done, acc_strs1) ->
541 -> getUniqueUs `thenUs` \ unq ->
542 let lbl = mkAsmTempLabel unq in
543 returnUs ((StCLbl lbl):ds_done, ((lbl,s):acc_strs1))
545 -> returnUs (other:ds_done, acc_strs1)
547 -- When we've run out of original trees, emit the lifted strings.
548 liftStrings_wrk [] acc_stix acc_strs
549 = returnUs (reverse acc_stix ++ concatMap f acc_strs)
551 f (lbl,str) = [StSegment RoDataSegment,
554 StSegment TextSegment]
560 data NatM_State = NatM_State UniqSupply Int
561 type NatM result = NatM_State -> (result, NatM_State)
563 mkNatM_State :: UniqSupply -> Int -> NatM_State
564 mkNatM_State = NatM_State
566 uniqOfNatM_State (NatM_State us delta) = us
567 deltaOfNatM_State (NatM_State us delta) = delta
570 initNat :: NatM_State -> NatM a -> (a, NatM_State)
571 initNat init_st m = case m init_st of { (r,st) -> (r,st) }
573 thenNat :: NatM a -> (a -> NatM b) -> NatM b
575 = case expr st of { (result, st') -> cont result st' }
577 returnNat :: a -> NatM a
578 returnNat result st = (result, st)
580 mapNat :: (a -> NatM b) -> [a] -> NatM [b]
581 mapNat f [] = returnNat []
583 = f x `thenNat` \ r ->
584 mapNat f xs `thenNat` \ rs ->
587 mapAndUnzipNat :: (a -> NatM (b,c)) -> [a] -> NatM ([b],[c])
588 mapAndUnzipNat f [] = returnNat ([],[])
589 mapAndUnzipNat f (x:xs)
590 = f x `thenNat` \ (r1, r2) ->
591 mapAndUnzipNat f xs `thenNat` \ (rs1, rs2) ->
592 returnNat (r1:rs1, r2:rs2)
594 mapAccumLNat :: (acc -> x -> NatM (acc, y))
601 mapAccumLNat f b (x:xs)
602 = f b x `thenNat` \ (b__2, x__2) ->
603 mapAccumLNat f b__2 xs `thenNat` \ (b__3, xs__2) ->
604 returnNat (b__3, x__2:xs__2)
607 getUniqueNat :: NatM Unique
608 getUniqueNat (NatM_State us delta)
609 = case splitUniqSupply us of
610 (us1,us2) -> (uniqFromSupply us1, (NatM_State us2 delta))
612 getDeltaNat :: NatM Int
613 getDeltaNat st@(NatM_State us delta)
616 setDeltaNat :: Int -> NatM ()
617 setDeltaNat delta (NatM_State us _)
618 = ((), NatM_State us delta)
621 Giving up in a not-too-inelegant way.
624 ncgPrimopMoan :: String -> SDoc -> a
625 ncgPrimopMoan msg pp_rep
629 "You've fallen across an unimplemented case in GHC's native code generation\n" ++
630 "machinery. You can work around this for the time being by compiling\n" ++
631 "this module via the C route, by giving the flag -fvia-C.\n" ++
632 "The panic below contains information, intended for the GHC implementors,\n" ++
633 "about the exact place where GHC gave up. Please send it to us\n" ++
634 "at glasgow-haskell-bugs@haskell.org, so as to encourage us to fix this.\n"
641 Information about the target.
645 ncg_target_is_32bit :: Bool
646 ncg_target_is_32bit | wORD_SIZE == 4 = True
647 | wORD_SIZE == 8 = False