More CPP removal: pprDynamicLinkerAsmLabel in CLabel
[ghc.git] / compiler / codeGen / StgCmmMonad.hs
1 -----------------------------------------------------------------------------
2 --
3 -- Monad for Stg to C-- code generation
4 --
5 -- (c) The University of Glasgow 2004-2006
6 --
7 -----------------------------------------------------------------------------
8
9 module StgCmmMonad (
10 FCode, -- type
11
12 initC, thenC, thenFC, listCs, listFCs, mapCs, mapFCs,
13 returnFC, fixC, fixC_, nopC, whenC,
14 newUnique, newUniqSupply,
15
16 emit, emitDecl, emitProc, emitProcWithConvention, emitSimpleProc,
17
18 getCmm, cgStmtsToBlocks,
19 getCodeR, getCode, getHeapUsage,
20
21 forkClosureBody, forkStatics, forkAlts, forkProc, codeOnly,
22
23 ConTagZ,
24
25 Sequel(..),
26 withSequel, getSequel,
27
28 setSRTLabel, getSRTLabel,
29 setTickyCtrLabel, getTickyCtrLabel,
30
31 withUpdFrameOff, getUpdFrameOff, initUpdFrameOff,
32
33 HeapUsage(..), VirtualHpOffset, initHpUsage,
34 getHpUsage, setHpUsage, heapHWM,
35 setVirtHp, getVirtHp, setRealHp,
36
37 getModuleName,
38
39 -- ideally we wouldn't export these, but some other modules access internal state
40 getState, setState, getInfoDown, getDynFlags, getThisPackage,
41
42 -- more localised access to monad state
43 CgIdInfo(..), CgLoc(..),
44 getBinds, setBinds, getStaticBinds,
45
46 -- out of general friendliness, we also export ...
47 CgInfoDownwards(..), CgState(..) -- non-abstract
48 ) where
49
50 #include "HsVersions.h"
51
52 import Cmm
53 import StgCmmClosure
54 import DynFlags
55 import MkGraph
56 import BlockId
57 import CLabel
58 import SMRep
59 import Module
60 import Id
61 import VarEnv
62 import OrdList
63 import Unique
64 import UniqSupply
65 import FastString(sLit)
66 import Outputable
67
68 import Control.Monad
69 import Data.List
70 import Prelude hiding( sequence )
71 import qualified Prelude( sequence )
72
73 infixr 9 `thenC` -- Right-associative!
74 infixr 9 `thenFC`
75
76
77 --------------------------------------------------------
78 -- The FCode monad and its types
79 --------------------------------------------------------
80
81 newtype FCode a = FCode (CgInfoDownwards -> CgState -> (a, CgState))
82
83 instance Monad FCode where
84 (>>=) = thenFC
85 return = returnFC
86
87 {-# INLINE thenC #-}
88 {-# INLINE thenFC #-}
89 {-# INLINE returnFC #-}
90
91 initC :: DynFlags -> Module -> FCode a -> IO a
92 initC dflags mod (FCode code)
93 = do { uniqs <- mkSplitUniqSupply 'c'
94 ; case code (initCgInfoDown dflags mod) (initCgState uniqs) of
95 (res, _) -> return res
96 }
97
98 returnFC :: a -> FCode a
99 returnFC val = FCode (\_info_down state -> (val, state))
100
101 thenC :: FCode () -> FCode a -> FCode a
102 thenC (FCode m) (FCode k) =
103 FCode (\info_down state -> let (_,new_state) = m info_down state in
104 k info_down new_state)
105
106 nopC :: FCode ()
107 nopC = return ()
108
109 whenC :: Bool -> FCode () -> FCode ()
110 whenC True code = code
111 whenC False _code = nopC
112
113 listCs :: [FCode ()] -> FCode ()
114 listCs [] = return ()
115 listCs (fc:fcs) = do
116 fc
117 listCs fcs
118
119 mapCs :: (a -> FCode ()) -> [a] -> FCode ()
120 mapCs = mapM_
121
122 thenFC :: FCode a -> (a -> FCode c) -> FCode c
123 thenFC (FCode m) k = FCode (
124 \info_down state ->
125 let
126 (m_result, new_state) = m info_down state
127 (FCode kcode) = k m_result
128 in
129 kcode info_down new_state
130 )
131
132 listFCs :: [FCode a] -> FCode [a]
133 listFCs = Prelude.sequence
134
135 mapFCs :: (a -> FCode b) -> [a] -> FCode [b]
136 mapFCs = mapM
137
138 fixC :: (a -> FCode a) -> FCode a
139 fixC fcode = FCode (
140 \info_down state ->
141 let
142 FCode fc = fcode v
143 result@(v,_) = fc info_down state
144 -- ^--------^
145 in
146 result
147 )
148
149 fixC_ :: (a -> FCode a) -> FCode ()
150 fixC_ fcode = fixC fcode >> return ()
151
152 --------------------------------------------------------
153 -- The code generator environment
154 --------------------------------------------------------
155
156 -- This monadery has some information that it only passes
157 -- *downwards*, as well as some ``state'' which is modified
158 -- as we go along.
159
160 data CgInfoDownwards -- information only passed *downwards* by the monad
161 = MkCgInfoDown {
162 cgd_dflags :: DynFlags,
163 cgd_mod :: Module, -- Module being compiled
164 cgd_statics :: CgBindings, -- [Id -> info] : static environment
165 cgd_srt_lbl :: CLabel, -- Label of the current top-level SRT
166 cgd_updfr_off :: UpdFrameOffset, -- Size of current update frame
167 cgd_ticky :: CLabel, -- Current destination for ticky counts
168 cgd_sequel :: Sequel -- What to do at end of basic block
169 }
170
171 type CgBindings = IdEnv CgIdInfo
172
173 data CgIdInfo
174 = CgIdInfo
175 { cg_id :: Id -- Id that this is the info for
176 -- Can differ from the Id at occurrence sites by
177 -- virtue of being externalised, for splittable C
178 , cg_lf :: LambdaFormInfo
179 , cg_loc :: CgLoc -- CmmExpr for the *tagged* value
180 , cg_tag :: {-# UNPACK #-} !DynTag -- Cache for (lfDynTag cg_lf)
181 }
182
183 data CgLoc
184 = CmmLoc CmmExpr -- A stable CmmExpr; that is, one not mentioning
185 -- Hp, so that it remains valid across calls
186
187 | LneLoc BlockId [LocalReg] -- A join point
188 -- A join point (= let-no-escape) should only
189 -- be tail-called, and in a saturated way.
190 -- To tail-call it, assign to these locals,
191 -- and branch to the block id
192
193 instance PlatformOutputable CgIdInfo where
194 pprPlatform platform (CgIdInfo { cg_id = id, cg_loc = loc })
195 = ppr id <+> ptext (sLit "-->") <+> pprPlatform platform loc
196
197 instance PlatformOutputable CgLoc where
198 pprPlatform platform (CmmLoc e) = ptext (sLit "cmm") <+> pprPlatform platform e
199 pprPlatform _ (LneLoc b rs) = ptext (sLit "lne") <+> ppr b <+> ppr rs
200
201
202 -- Sequel tells what to do with the result of this expression
203 data Sequel
204 = Return Bool -- Return result(s) to continuation found on the stack
205 -- True <=> the continuation is update code (???)
206
207 | AssignTo
208 [LocalReg] -- Put result(s) in these regs and fall through
209 -- NB: no void arguments here
210 Bool -- Should we adjust the heap pointer back to recover
211 -- space that's unused on this path?
212 -- We need to do this only if the expression may
213 -- allocate (e.g. it's a foreign call or allocating primOp)
214 instance Show Sequel where
215 show (Return _) = "Sequel: Return"
216 show (AssignTo _ _) = "Sequel: Assign"
217
218 initCgInfoDown :: DynFlags -> Module -> CgInfoDownwards
219 initCgInfoDown dflags mod
220 = MkCgInfoDown { cgd_dflags = dflags,
221 cgd_mod = mod,
222 cgd_statics = emptyVarEnv,
223 cgd_srt_lbl = error "initC: srt_lbl",
224 cgd_updfr_off = initUpdFrameOff,
225 cgd_ticky = mkTopTickyCtrLabel,
226 cgd_sequel = initSequel }
227
228 initSequel :: Sequel
229 initSequel = Return False
230
231 initUpdFrameOff :: UpdFrameOffset
232 initUpdFrameOff = widthInBytes wordWidth -- space for the RA
233
234
235 --------------------------------------------------------
236 -- The code generator state
237 --------------------------------------------------------
238
239 data CgState
240 = MkCgState {
241 cgs_stmts :: CmmAGraph, -- Current procedure
242
243 cgs_tops :: OrdList CmmDecl,
244 -- Other procedures and data blocks in this compilation unit
245 -- Both are ordered only so that we can
246 -- reduce forward references, when it's easy to do so
247
248 cgs_binds :: CgBindings, -- [Id -> info] : *local* bindings environment
249 -- Bindings for top-level things are given in
250 -- the info-down part
251
252 cgs_hp_usg :: HeapUsage,
253
254 cgs_uniqs :: UniqSupply }
255
256 data HeapUsage =
257 HeapUsage {
258 virtHp :: VirtualHpOffset, -- Virtual offset of highest-allocated word
259 -- Incremented whenever we allocate
260 realHp :: VirtualHpOffset -- realHp: Virtual offset of real heap ptr
261 -- Used in instruction addressing modes
262 }
263
264 type VirtualHpOffset = WordOff
265
266 initCgState :: UniqSupply -> CgState
267 initCgState uniqs
268 = MkCgState { cgs_stmts = mkNop, cgs_tops = nilOL,
269 cgs_binds = emptyVarEnv,
270 cgs_hp_usg = initHpUsage,
271 cgs_uniqs = uniqs }
272
273 stateIncUsage :: CgState -> CgState -> CgState
274 -- stateIncUsage@ e1 e2 incorporates in e1
275 -- the heap high water mark found in e2.
276 stateIncUsage s1 s2@(MkCgState { cgs_hp_usg = hp_usg })
277 = s1 { cgs_hp_usg = cgs_hp_usg s1 `maxHpHw` virtHp hp_usg }
278 `addCodeBlocksFrom` s2
279
280 addCodeBlocksFrom :: CgState -> CgState -> CgState
281 -- Add code blocks from the latter to the former
282 -- (The cgs_stmts will often be empty, but not always; see codeOnly)
283 s1 `addCodeBlocksFrom` s2
284 = s1 { cgs_stmts = cgs_stmts s1 <*> cgs_stmts s2,
285 cgs_tops = cgs_tops s1 `appOL` cgs_tops s2 }
286
287
288 -- The heap high water mark is the larger of virtHp and hwHp. The latter is
289 -- only records the high water marks of forked-off branches, so to find the
290 -- heap high water mark you have to take the max of virtHp and hwHp. Remember,
291 -- virtHp never retreats!
292 --
293 -- Note Jan 04: ok, so why do we only look at the virtual Hp??
294
295 heapHWM :: HeapUsage -> VirtualHpOffset
296 heapHWM = virtHp
297
298 initHpUsage :: HeapUsage
299 initHpUsage = HeapUsage { virtHp = 0, realHp = 0 }
300
301 maxHpHw :: HeapUsage -> VirtualHpOffset -> HeapUsage
302 hp_usg `maxHpHw` hw = hp_usg { virtHp = virtHp hp_usg `max` hw }
303
304
305 --------------------------------------------------------
306 -- Operators for getting and setting the state and "info_down".
307 --------------------------------------------------------
308
309 getState :: FCode CgState
310 getState = FCode $ \_info_down state -> (state,state)
311
312 setState :: CgState -> FCode ()
313 setState state = FCode $ \_info_down _ -> ((),state)
314
315 getHpUsage :: FCode HeapUsage
316 getHpUsage = do
317 state <- getState
318 return $ cgs_hp_usg state
319
320 setHpUsage :: HeapUsage -> FCode ()
321 setHpUsage new_hp_usg = do
322 state <- getState
323 setState $ state {cgs_hp_usg = new_hp_usg}
324
325 setVirtHp :: VirtualHpOffset -> FCode ()
326 setVirtHp new_virtHp
327 = do { hp_usage <- getHpUsage
328 ; setHpUsage (hp_usage {virtHp = new_virtHp}) }
329
330 getVirtHp :: FCode VirtualHpOffset
331 getVirtHp
332 = do { hp_usage <- getHpUsage
333 ; return (virtHp hp_usage) }
334
335 setRealHp :: VirtualHpOffset -> FCode ()
336 setRealHp new_realHp
337 = do { hp_usage <- getHpUsage
338 ; setHpUsage (hp_usage {realHp = new_realHp}) }
339
340 getBinds :: FCode CgBindings
341 getBinds = do
342 state <- getState
343 return $ cgs_binds state
344
345 setBinds :: CgBindings -> FCode ()
346 setBinds new_binds = do
347 state <- getState
348 setState $ state {cgs_binds = new_binds}
349
350 getStaticBinds :: FCode CgBindings
351 getStaticBinds = do
352 info <- getInfoDown
353 return (cgd_statics info)
354
355 withState :: FCode a -> CgState -> FCode (a,CgState)
356 withState (FCode fcode) newstate = FCode $ \info_down state ->
357 let (retval, state2) = fcode info_down newstate in ((retval,state2), state)
358
359 newUniqSupply :: FCode UniqSupply
360 newUniqSupply = do
361 state <- getState
362 let (us1, us2) = splitUniqSupply (cgs_uniqs state)
363 setState $ state { cgs_uniqs = us1 }
364 return us2
365
366 newUnique :: FCode Unique
367 newUnique = do
368 us <- newUniqSupply
369 return (uniqFromSupply us)
370
371 ------------------
372 getInfoDown :: FCode CgInfoDownwards
373 getInfoDown = FCode $ \info_down state -> (info_down,state)
374
375 getDynFlags :: FCode DynFlags
376 getDynFlags = liftM cgd_dflags getInfoDown
377
378 getThisPackage :: FCode PackageId
379 getThisPackage = liftM thisPackage getDynFlags
380
381 withInfoDown :: FCode a -> CgInfoDownwards -> FCode a
382 withInfoDown (FCode fcode) info_down = FCode $ \_ state -> fcode info_down state
383
384 doFCode :: FCode a -> CgInfoDownwards -> CgState -> (a,CgState)
385 doFCode (FCode fcode) info_down state = fcode info_down state
386
387
388 -- ----------------------------------------------------------------------------
389 -- Get the current module name
390
391 getModuleName :: FCode Module
392 getModuleName = do { info <- getInfoDown; return (cgd_mod info) }
393
394 -- ----------------------------------------------------------------------------
395 -- Get/set the end-of-block info
396
397 withSequel :: Sequel -> FCode () -> FCode ()
398 withSequel sequel code
399 = do { info <- getInfoDown
400 ; withInfoDown code (info {cgd_sequel = sequel }) }
401
402 getSequel :: FCode Sequel
403 getSequel = do { info <- getInfoDown
404 ; return (cgd_sequel info) }
405
406 -- ----------------------------------------------------------------------------
407 -- Get/set the current SRT label
408
409 -- There is just one SRT for each top level binding; all the nested
410 -- bindings use sub-sections of this SRT. The label is passed down to
411 -- the nested bindings via the monad.
412
413 getSRTLabel :: FCode CLabel -- Used only by cgPanic
414 getSRTLabel = do info <- getInfoDown
415 return (cgd_srt_lbl info)
416
417 setSRTLabel :: CLabel -> FCode a -> FCode a
418 setSRTLabel srt_lbl code
419 = do info <- getInfoDown
420 withInfoDown code (info { cgd_srt_lbl = srt_lbl})
421
422 -- ----------------------------------------------------------------------------
423 -- Get/set the size of the update frame
424
425 -- We keep track of the size of the update frame so that we
426 -- can set the stack pointer to the proper address on return
427 -- (or tail call) from the closure.
428 -- There should be at most one update frame for each closure.
429 -- Note: I'm including the size of the original return address
430 -- in the size of the update frame -- hence the default case on `get'.
431
432 withUpdFrameOff :: UpdFrameOffset -> FCode () -> FCode ()
433 withUpdFrameOff size code
434 = do { info <- getInfoDown
435 ; withInfoDown code (info {cgd_updfr_off = size }) }
436
437 getUpdFrameOff :: FCode UpdFrameOffset
438 getUpdFrameOff
439 = do { info <- getInfoDown
440 ; return $ cgd_updfr_off info }
441
442 -- ----------------------------------------------------------------------------
443 -- Get/set the current ticky counter label
444
445 getTickyCtrLabel :: FCode CLabel
446 getTickyCtrLabel = do
447 info <- getInfoDown
448 return (cgd_ticky info)
449
450 setTickyCtrLabel :: CLabel -> FCode () -> FCode ()
451 setTickyCtrLabel ticky code = do
452 info <- getInfoDown
453 withInfoDown code (info {cgd_ticky = ticky})
454
455
456 --------------------------------------------------------
457 -- Forking
458 --------------------------------------------------------
459
460 forkClosureBody :: FCode () -> FCode ()
461 -- forkClosureBody takes a code, $c$, and compiles it in a
462 -- fresh environment, except that:
463 -- - compilation info and statics are passed in unchanged.
464 -- - local bindings are passed in unchanged
465 -- (it's up to the enclosed code to re-bind the
466 -- free variables to a field of the closure)
467 --
468 -- The current state is passed on completely unaltered, except that
469 -- C-- from the fork is incorporated.
470
471 forkClosureBody body_code
472 = do { info <- getInfoDown
473 ; us <- newUniqSupply
474 ; state <- getState
475 ; let body_info_down = info { cgd_sequel = initSequel
476 , cgd_updfr_off = initUpdFrameOff }
477 fork_state_in = (initCgState us) { cgs_binds = cgs_binds state }
478 ((),fork_state_out)
479 = doFCode body_code body_info_down fork_state_in
480 ; setState $ state `addCodeBlocksFrom` fork_state_out }
481
482 forkStatics :: FCode a -> FCode a
483 -- @forkStatics@ $fc$ compiles $fc$ in an environment whose *statics* come
484 -- from the current *local bindings*, but which is otherwise freshly initialised.
485 -- The Abstract~C returned is attached to the current state, but the
486 -- bindings and usage information is otherwise unchanged.
487 forkStatics body_code
488 = do { info <- getInfoDown
489 ; us <- newUniqSupply
490 ; state <- getState
491 ; let rhs_info_down = info { cgd_statics = cgs_binds state
492 , cgd_sequel = initSequel
493 , cgd_updfr_off = initUpdFrameOff }
494 (result, fork_state_out) = doFCode body_code rhs_info_down
495 (initCgState us)
496 ; setState (state `addCodeBlocksFrom` fork_state_out)
497 ; return result }
498
499 forkProc :: FCode a -> FCode a
500 -- 'forkProc' takes a code and compiles it in the *current* environment,
501 -- returning the graph thus constructed.
502 --
503 -- The current environment is passed on completely unchanged to
504 -- the successor. In particular, any heap usage from the enclosed
505 -- code is discarded; it should deal with its own heap consumption
506 forkProc body_code
507 = do { info_down <- getInfoDown
508 ; us <- newUniqSupply
509 ; state <- getState
510 ; let info_down' = info_down -- { cgd_sequel = initSequel }
511 fork_state_in = (initCgState us) { cgs_binds = cgs_binds state }
512 (result, fork_state_out) = doFCode body_code info_down' fork_state_in
513 ; setState $ state `addCodeBlocksFrom` fork_state_out
514 ; return result }
515
516 codeOnly :: FCode () -> FCode ()
517 -- Emit any code from the inner thing into the outer thing
518 -- Do not affect anything else in the outer state
519 -- Used in almost-circular code to prevent false loop dependencies
520 codeOnly body_code
521 = do { info_down <- getInfoDown
522 ; us <- newUniqSupply
523 ; state <- getState
524 ; let fork_state_in = (initCgState us) { cgs_binds = cgs_binds state,
525 cgs_hp_usg = cgs_hp_usg state }
526 ((), fork_state_out) = doFCode body_code info_down fork_state_in
527 ; setState $ state `addCodeBlocksFrom` fork_state_out }
528
529 forkAlts :: [FCode a] -> FCode [a]
530 -- (forkAlts' bs d) takes fcodes 'bs' for the branches of a 'case', and
531 -- an fcode for the default case 'd', and compiles each in the current
532 -- environment. The current environment is passed on unmodified, except
533 -- that the virtual Hp is moved on to the worst virtual Hp for the branches
534
535 forkAlts branch_fcodes
536 = do { info_down <- getInfoDown
537 ; us <- newUniqSupply
538 ; state <- getState
539 ; let compile us branch
540 = (us2, doFCode branch info_down branch_state)
541 where
542 (us1,us2) = splitUniqSupply us
543 branch_state = (initCgState us1) {
544 cgs_binds = cgs_binds state,
545 cgs_hp_usg = cgs_hp_usg state }
546
547 (_us, results) = mapAccumL compile us branch_fcodes
548 (branch_results, branch_out_states) = unzip results
549 ; setState $ foldl stateIncUsage state branch_out_states
550 -- NB foldl. state is the *left* argument to stateIncUsage
551 ; return branch_results }
552
553 -- collect the code emitted by an FCode computation
554 getCodeR :: FCode a -> FCode (a, CmmAGraph)
555 getCodeR fcode
556 = do { state1 <- getState
557 ; (a, state2) <- withState fcode (state1 { cgs_stmts = mkNop })
558 ; setState $ state2 { cgs_stmts = cgs_stmts state1 }
559 ; return (a, cgs_stmts state2) }
560
561 getCode :: FCode a -> FCode CmmAGraph
562 getCode fcode = do { (_,stmts) <- getCodeR fcode; return stmts }
563
564 -- 'getHeapUsage' applies a function to the amount of heap that it uses.
565 -- It initialises the heap usage to zeros, and passes on an unchanged
566 -- heap usage.
567 --
568 -- It is usually a prelude to performing a GC check, so everything must
569 -- be in a tidy and consistent state.
570 --
571 -- Note the slightly subtle fixed point behaviour needed here
572
573 getHeapUsage :: (VirtualHpOffset -> FCode a) -> FCode a
574 getHeapUsage fcode
575 = do { info_down <- getInfoDown
576 ; state <- getState
577 ; let fstate_in = state { cgs_hp_usg = initHpUsage }
578 (r, fstate_out) = doFCode (fcode hp_hw) info_down fstate_in
579 hp_hw = heapHWM (cgs_hp_usg fstate_out) -- Loop here!
580
581 ; setState $ fstate_out { cgs_hp_usg = cgs_hp_usg state }
582 ; return r }
583
584 -- ----------------------------------------------------------------------------
585 -- Combinators for emitting code
586
587 emit :: CmmAGraph -> FCode ()
588 emit ag
589 = do { state <- getState
590 ; setState $ state { cgs_stmts = cgs_stmts state <*> ag } }
591
592 emitDecl :: CmmDecl -> FCode ()
593 emitDecl decl
594 = do { state <- getState
595 ; setState $ state { cgs_tops = cgs_tops state `snocOL` decl } }
596
597 emitProcWithConvention :: Convention -> CmmInfoTable -> CLabel -> [CmmFormal] ->
598 CmmAGraph -> FCode ()
599 emitProcWithConvention conv info lbl args blocks
600 = do { us <- newUniqSupply
601 ; let (offset, entry) = mkCallEntry conv args
602 blks = initUs_ us $ lgraphOfAGraph $ entry <*> blocks
603 ; let sinfo = StackInfo {arg_space = offset, updfr_space = Just initUpdFrameOff}
604 proc_block = CmmProc (TopInfo {info_tbl=info, stack_info=sinfo}) lbl blks
605 ; state <- getState
606 ; setState $ state { cgs_tops = cgs_tops state `snocOL` proc_block } }
607
608 emitProc :: CmmInfoTable -> CLabel -> [CmmFormal] -> CmmAGraph -> FCode ()
609 emitProc = emitProcWithConvention NativeNodeCall
610
611 emitSimpleProc :: CLabel -> CmmAGraph -> FCode ()
612 emitSimpleProc lbl code =
613 emitProc CmmNonInfoTable lbl [] code
614
615 getCmm :: FCode () -> FCode CmmGroup
616 -- Get all the CmmTops (there should be no stmts)
617 -- Return a single Cmm which may be split from other Cmms by
618 -- object splitting (at a later stage)
619 getCmm code
620 = do { state1 <- getState
621 ; ((), state2) <- withState code (state1 { cgs_tops = nilOL })
622 ; setState $ state2 { cgs_tops = cgs_tops state1 }
623 ; return (fromOL (cgs_tops state2)) }
624
625 -- ----------------------------------------------------------------------------
626 -- CgStmts
627
628 -- These functions deal in terms of CgStmts, which is an abstract type
629 -- representing the code in the current proc.
630
631 -- turn CgStmts into [CmmBasicBlock], for making a new proc.
632 cgStmtsToBlocks :: CmmAGraph -> FCode CmmGraph
633 cgStmtsToBlocks stmts
634 = do { us <- newUniqSupply
635 ; return (initUs_ us (lgraphOfAGraph stmts)) }
636