2 % (c) The AQUA Project, Glasgow University, 1993-1998
7 CodeSegment(..), StixReg(..), StixTree(..), StixTreeList,
8 pprStixTrees, pprStixTree, ppStixReg,
9 stixCountTempUses, stixSubst,
10 DestInfo(..), hasDestInfo,
12 stgBaseReg, stgNode, stgSp, stgSu, stgSpLim,
13 stgHp, stgHpLim, stgTagReg, stgR9, stgR10,
14 stgCurrentTSO, stgCurrentNursery,
16 fixedHS, arrWordsHS, arrPtrsHS,
18 NatM, initNat, thenNat, returnNat,
19 mapNat, mapAndUnzipNat, mapAccumLNat,
20 getUniqueNat, getDeltaNat, setDeltaNat,
21 NatM_State, mkNatM_State,
22 uniqOfNatM_State, deltaOfNatM_State,
24 getUniqLabelNCG, getNatLabelNCG,
28 #include "HsVersions.h"
30 import Ratio ( Rational )
31 import IOExts ( unsafePerformIO )
32 import IO ( hPutStrLn, stderr )
34 import AbsCSyn ( node, tagreg, MagicId(..) )
35 import ForeignCall ( CCallConv )
36 import CLabel ( mkAsmTempLabel, CLabel, pprCLabel )
37 import PrimRep ( PrimRep(..) )
38 import PrimOp ( PrimOp )
39 import Unique ( Unique )
40 import SMRep ( fixedHdrSize, arrWordsHdrSize, arrPtrsHdrSize )
41 import UniqSupply ( UniqSupply, splitUniqSupply, uniqFromSupply,
42 UniqSM, thenUs, returnUs, getUniqueUs )
47 Here is the tag at the nodes of our @StixTree@. Notice its
48 relationship with @PrimOp@ in prelude/PrimOp.
52 = -- Segment (text or data)
56 -- We can tag the leaves with constants/immediates.
58 | StInt Integer -- ** add Kind at some point
61 | StString FAST_STRING
62 | StCLbl CLabel -- labels that we might index into
64 -- Abstract registers of various kinds
68 -- A typed offset from a base location
70 | StIndex PrimRep StixTree StixTree -- kind, base, offset
72 -- An indirection from an address to its contents.
74 | StInd PrimRep StixTree
76 -- Assignment is typed to determine size and register placement
78 | StAssign PrimRep StixTree StixTree -- dst, src
80 -- A simple assembly label that we might jump to.
84 -- A function header and footer
89 -- An unconditional jump. This instruction may or may not jump
90 -- out of the register allocation domain (basic block, more or
91 -- less). For correct register allocation when this insn is used
92 -- to jump through a jump table, we optionally allow a list of
93 -- the exact targets to be attached, so that the allocator can
94 -- easily construct the exact flow edges leaving this insn.
95 -- Dynamic targets are allowed.
97 | StJump DestInfo StixTree
99 -- A fall-through, from slow to fast
101 | StFallThrough CLabel
103 -- A conditional jump. This instruction can be non-terminal :-)
104 -- Only static, local, forward labels are allowed
106 | StCondJump CLabel StixTree
108 -- Raw data (as in an info table).
110 | StData PrimRep [StixTree]
112 -- Primitive Operations
114 | StPrim PrimOp [StixTree]
116 -- Calls to C functions
118 | StCall FAST_STRING CCallConv PrimRep [StixTree]
120 -- A volatile memory scratch array, which is allocated
121 -- relative to the stack pointer. It is an array of
122 -- ptr/word/int sized things. Do not expect to be preserved
123 -- beyond basic blocks or over a ccall. Current max size
124 -- is 6, used in StixInteger.
128 -- Assembly-language comments
130 | StComment FAST_STRING
133 -- used by insnFuture in RegAllocInfo.lhs
135 = NoDestInfo -- no supplied dests; infer from context
136 | DestInfo [CLabel] -- precisely these dests and no others
138 hasDestInfo NoDestInfo = False
139 hasDestInfo (DestInfo _) = True
141 pprDests :: DestInfo -> SDoc
142 pprDests NoDestInfo = text "NoDestInfo"
143 pprDests (DestInfo dsts) = brack (hsep (map pprCLabel dsts))
146 pprStixTrees :: [StixTree] -> SDoc
149 vcat (map pprStixTree ts),
154 paren t = char '(' <> t <> char ')'
155 brack t = char '[' <> t <> char ']'
157 pprStixTree :: StixTree -> SDoc
160 StSegment cseg -> paren (ppCodeSegment cseg)
161 StInt i -> paren (integer i)
162 StFloat rat -> paren (text "Float" <+> rational rat)
163 StDouble rat -> paren (text "Double" <+> rational rat)
164 StString str -> paren (text "Str `" <> ptext str <> char '\'')
165 StComment str -> paren (text "Comment" <+> ptext str)
166 StCLbl lbl -> pprCLabel lbl
167 StReg reg -> ppStixReg reg
168 StIndex k b o -> paren (pprStixTree b <+> char '+' <>
169 ppr k <+> pprStixTree o)
170 StInd k t -> ppr k <> char '[' <> pprStixTree t <> char ']'
171 StAssign k d s -> pprStixTree d <> text " :=" <> ppr k
172 <> text " " <> pprStixTree s
173 StLabel ll -> pprCLabel ll <+> char ':'
174 StFunBegin ll -> char ' ' $$ paren (text "FunBegin" <+> pprCLabel ll)
175 StFunEnd ll -> paren (text "FunEnd" <+> pprCLabel ll)
176 StJump dsts t -> paren (text "Jump" <+> pprDests dsts <+> pprStixTree t)
177 StFallThrough ll -> paren (text "FallThru" <+> pprCLabel ll)
178 StCondJump l t -> paren (text "JumpC" <+> pprCLabel l
180 StData k ds -> paren (text "Data" <+> ppr k <+>
181 hsep (map pprStixTree ds))
182 StPrim op ts -> paren (text "Prim" <+> ppr op <+>
183 hsep (map pprStixTree ts))
185 -> paren (text "Call" <+> ptext nm <+>
187 hsep (map pprStixTree args))
188 StScratchWord i -> text "ScratchWord" <> paren (int i)
191 Stix registers can have two forms. They {\em may} or {\em may not}
192 map to real, machine-level registers.
196 = StixMagicId MagicId -- Regs which are part of the abstract machine model
198 | StixTemp Unique PrimRep -- "Regs" which model local variables (CTemps) in
201 ppStixReg (StixMagicId mid)
203 ppStixReg (StixTemp u pr)
204 = hcat [text "Temp(", ppr u, ppr pr, char ')']
207 ppMId BaseReg = text "BaseReg"
208 ppMId (VanillaReg kind n) = hcat [ppr kind, text "IntReg(",
209 int (iBox n), char ')']
210 ppMId (FloatReg n) = hcat [text "FltReg(", int (iBox n), char ')']
211 ppMId (DoubleReg n) = hcat [text "DblReg(", int (iBox n), char ')']
212 ppMId (LongReg kind n) = hcat [ppr kind, text "LongReg(",
213 int (iBox n), char ')']
216 ppMId SpLim = text "SpLim"
218 ppMId HpLim = text "HpLim"
219 ppMId CurCostCentre = text "CCC"
220 ppMId VoidReg = text "VoidReg"
223 We hope that every machine supports the idea of data segment and text
224 segment (or that it has no segments at all, and we can lump these
228 data CodeSegment = DataSegment | TextSegment | RoDataSegment deriving (Eq, Show)
229 ppCodeSegment = text . show
231 type StixTreeList = [StixTree] -> [StixTree]
234 Stix Trees for STG registers:
236 stgBaseReg, stgNode, stgSp, stgSu, stgSpLim, stgHp, stgHpLim
239 stgBaseReg = StReg (StixMagicId BaseReg)
240 stgNode = StReg (StixMagicId node)
241 stgTagReg = StReg (StixMagicId tagreg)
242 stgSp = StReg (StixMagicId Sp)
243 stgSu = StReg (StixMagicId Su)
244 stgSpLim = StReg (StixMagicId SpLim)
245 stgHp = StReg (StixMagicId Hp)
246 stgHpLim = StReg (StixMagicId HpLim)
247 stgCurrentTSO = StReg (StixMagicId CurrentTSO)
248 stgCurrentNursery = StReg (StixMagicId CurrentNursery)
249 stgR9 = StReg (StixMagicId (VanillaReg WordRep (_ILIT 9)))
250 stgR10 = StReg (StixMagicId (VanillaReg WordRep (_ILIT 10)))
252 getNatLabelNCG :: NatM CLabel
254 = getUniqueNat `thenNat` \ u ->
255 returnNat (mkAsmTempLabel u)
257 getUniqLabelNCG :: UniqSM CLabel
259 = getUniqueUs `thenUs` \ u ->
260 returnUs (mkAsmTempLabel u)
262 fixedHS = StInt (toInteger fixedHdrSize)
263 arrWordsHS = StInt (toInteger arrWordsHdrSize)
264 arrPtrsHS = StInt (toInteger arrPtrsHdrSize)
267 Stix optimisation passes may wish to find out how many times a
268 given temporary appears in a tree, so as to be able to decide
269 whether or not to inline the assignment's RHS at usage site(s).
272 stixCountTempUses :: Unique -> StixTree -> Int
273 stixCountTempUses u t
274 = let qq = stixCountTempUses u
279 StixTemp uu pr -> if u == uu then 1 else 0
282 StIndex pk t1 t2 -> qq t1 + qq t2
284 StAssign pk t1 t2 -> qq t1 + qq t2
285 StJump dsts t1 -> qq t1
286 StCondJump lbl t1 -> qq t1
287 StData pk ts -> sum (map qq ts)
288 StPrim op ts -> sum (map qq ts)
289 StCall nm cconv pk ts -> sum (map qq ts)
305 stixSubst :: Unique -> StixTree -> StixTree -> StixTree
306 stixSubst u new_u in_this_tree
307 = stixMapUniques f in_this_tree
309 f :: Unique -> Maybe StixTree
310 f uu = if uu == u then Just new_u else Nothing
313 stixMapUniques :: (Unique -> Maybe StixTree) -> StixTree -> StixTree
315 = let qq = stixMapUniques f
326 StIndex pk t1 t2 -> StIndex pk (qq t1) (qq t2)
327 StInd pk t1 -> StInd pk (qq t1)
328 StAssign pk t1 t2 -> StAssign pk (qq t1) (qq t2)
329 StJump dsts t1 -> StJump dsts (qq t1)
330 StCondJump lbl t1 -> StCondJump lbl (qq t1)
331 StData pk ts -> StData pk (map qq ts)
332 StPrim op ts -> StPrim op (map qq ts)
333 StCall nm cconv pk ts -> StCall nm cconv pk (map qq ts)
350 data NatM_State = NatM_State UniqSupply Int
351 type NatM result = NatM_State -> (result, NatM_State)
353 mkNatM_State :: UniqSupply -> Int -> NatM_State
354 mkNatM_State = NatM_State
356 uniqOfNatM_State (NatM_State us delta) = us
357 deltaOfNatM_State (NatM_State us delta) = delta
360 initNat :: NatM_State -> NatM a -> (a, NatM_State)
361 initNat init_st m = case m init_st of { (r,st) -> (r,st) }
363 thenNat :: NatM a -> (a -> NatM b) -> NatM b
365 = case expr st of { (result, st') -> cont result st' }
367 returnNat :: a -> NatM a
368 returnNat result st = (result, st)
370 mapNat :: (a -> NatM b) -> [a] -> NatM [b]
371 mapNat f [] = returnNat []
373 = f x `thenNat` \ r ->
374 mapNat f xs `thenNat` \ rs ->
377 mapAndUnzipNat :: (a -> NatM (b,c)) -> [a] -> NatM ([b],[c])
378 mapAndUnzipNat f [] = returnNat ([],[])
379 mapAndUnzipNat f (x:xs)
380 = f x `thenNat` \ (r1, r2) ->
381 mapAndUnzipNat f xs `thenNat` \ (rs1, rs2) ->
382 returnNat (r1:rs1, r2:rs2)
384 mapAccumLNat :: (acc -> x -> NatM (acc, y))
391 mapAccumLNat f b (x:xs)
392 = f b x `thenNat` \ (b__2, x__2) ->
393 mapAccumLNat f b__2 xs `thenNat` \ (b__3, xs__2) ->
394 returnNat (b__3, x__2:xs__2)
397 getUniqueNat :: NatM Unique
398 getUniqueNat (NatM_State us delta)
399 = case splitUniqSupply us of
400 (us1,us2) -> (uniqFromSupply us1, (NatM_State us2 delta))
402 getDeltaNat :: NatM Int
403 getDeltaNat st@(NatM_State us delta)
406 setDeltaNat :: Int -> NatM ()
407 setDeltaNat delta (NatM_State us _)
408 = ((), NatM_State us delta)
411 Giving up in a not-too-inelegant way.
414 ncgPrimopMoan :: String -> SDoc -> a
415 ncgPrimopMoan msg pp_rep
419 "You've fallen across an unimplemented case in GHC's native code generation\n" ++
420 "machinery. You can work around this for the time being by compiling\n" ++
421 "this module via the C route, by giving the flag -fvia-C.\n" ++
422 "The panic below contains information, intended for the GHC implementors,\n" ++
423 "about the exact place where GHC gave up. Please send it to us\n" ++
424 "at glasgow-haskell-bugs@haskell.org, so as to encourage us to fix this.\n"