Snapshot of codegen refactoring to share with simonpj
[ghc.git] / compiler / cmm / CmmUtils.hs
1 {-# LANGUAGE GADTs #-}
2 -----------------------------------------------------------------------------
3 --
4 -- Cmm utilities.
5 --
6 -- (c) The University of Glasgow 2004-2006
7 --
8 -----------------------------------------------------------------------------
9
10 module CmmUtils(
11 -- CmmType
12 primRepCmmType, primRepForeignHint,
13 typeCmmType, typeForeignHint,
14
15 -- CmmLit
16 zeroCLit, mkIntCLit,
17 mkWordCLit, packHalfWordsCLit,
18 mkByteStringCLit,
19 mkDataLits, mkRODataLits,
20
21 -- CmmExpr
22 mkLblExpr,
23 cmmRegOff, cmmOffset, cmmLabelOff, cmmOffsetLit, cmmOffsetExpr,
24 cmmRegOffB, cmmOffsetB, cmmLabelOffB, cmmOffsetLitB, cmmOffsetExprB,
25 cmmRegOffW, cmmOffsetW, cmmLabelOffW, cmmOffsetLitW, cmmOffsetExprW,
26 cmmIndex, cmmIndexExpr, cmmLoadIndex, cmmLoadIndexW,
27 cmmNegate,
28 cmmULtWord, cmmUGeWord, cmmUGtWord, cmmSubWord,
29 cmmNeWord, cmmEqWord, cmmOrWord, cmmAndWord,
30 cmmUShrWord, cmmAddWord, cmmMulWord,
31
32 isTrivialCmmExpr, hasNoGlobalRegs,
33
34 -- Statics
35 blankWord,
36
37 -- Tagging
38 cmmTagMask, cmmPointerMask, cmmUntag, cmmGetTag, cmmIsTagged,
39 cmmConstrTag, cmmConstrTag1,
40
41 -- Liveness and bitmaps
42 mkLiveness,
43
44 -- * Operations that probably don't belong here
45 modifyGraph,
46
47 lastNode, replaceLastNode, insertBetween,
48 ofBlockMap, toBlockMap, insertBlock,
49 ofBlockList, toBlockList, bodyToBlockList,
50 foldGraphBlocks, mapGraphNodes, postorderDfs,
51
52 analFwd, analBwd, analRewFwd, analRewBwd,
53 dataflowPassFwd, dataflowPassBwd
54 ) where
55
56 #include "HsVersions.h"
57
58 import TyCon ( PrimRep(..) )
59 import Type ( Type, typePrimRep )
60
61 import SMRep
62 import Cmm
63 import BlockId
64 import CLabel
65 import Outputable
66 import OptimizationFuel as F
67 import Unique
68 import UniqSupply
69 import Constants( wORD_SIZE, tAG_MASK )
70
71 import Data.Word
72 import Data.Maybe
73 import Data.Bits
74 import Control.Monad
75 import Compiler.Hoopl hiding ( Unique )
76
77 ---------------------------------------------------
78 --
79 -- CmmTypes
80 --
81 ---------------------------------------------------
82
83 primRepCmmType :: PrimRep -> CmmType
84 primRepCmmType VoidRep = panic "primRepCmmType:VoidRep"
85 primRepCmmType PtrRep = gcWord
86 primRepCmmType IntRep = bWord
87 primRepCmmType WordRep = bWord
88 primRepCmmType Int64Rep = b64
89 primRepCmmType Word64Rep = b64
90 primRepCmmType AddrRep = bWord
91 primRepCmmType FloatRep = f32
92 primRepCmmType DoubleRep = f64
93
94 typeCmmType :: Type -> CmmType
95 typeCmmType ty = primRepCmmType (typePrimRep ty)
96
97 primRepForeignHint :: PrimRep -> ForeignHint
98 primRepForeignHint VoidRep = panic "primRepForeignHint:VoidRep"
99 primRepForeignHint PtrRep = AddrHint
100 primRepForeignHint IntRep = SignedHint
101 primRepForeignHint WordRep = NoHint
102 primRepForeignHint Int64Rep = SignedHint
103 primRepForeignHint Word64Rep = NoHint
104 primRepForeignHint AddrRep = AddrHint -- NB! AddrHint, but NonPtrArg
105 primRepForeignHint FloatRep = NoHint
106 primRepForeignHint DoubleRep = NoHint
107
108 typeForeignHint :: Type -> ForeignHint
109 typeForeignHint = primRepForeignHint . typePrimRep
110
111 ---------------------------------------------------
112 --
113 -- CmmLit
114 --
115 ---------------------------------------------------
116
117 mkIntCLit :: Int -> CmmLit
118 mkIntCLit i = CmmInt (toInteger i) wordWidth
119
120 zeroCLit :: CmmLit
121 zeroCLit = CmmInt 0 wordWidth
122
123 mkByteStringCLit :: Unique -> [Word8] -> (CmmLit, GenCmmTop CmmStatics info stmt)
124 -- We have to make a top-level decl for the string,
125 -- and return a literal pointing to it
126 mkByteStringCLit uniq bytes
127 = (CmmLabel lbl, CmmData ReadOnlyData $ Statics lbl [CmmString bytes])
128 where
129 lbl = mkStringLitLabel uniq
130 mkDataLits :: Section -> CLabel -> [CmmLit] -> GenCmmTop CmmStatics info stmt
131 -- Build a data-segment data block
132 mkDataLits section lbl lits
133 = CmmData section (Statics lbl $ map CmmStaticLit lits)
134
135 mkRODataLits :: CLabel -> [CmmLit] -> GenCmmTop CmmStatics info stmt
136 -- Build a read-only data block
137 mkRODataLits lbl lits
138 = mkDataLits section lbl lits
139 where
140 section | any needsRelocation lits = RelocatableReadOnlyData
141 | otherwise = ReadOnlyData
142 needsRelocation (CmmLabel _) = True
143 needsRelocation (CmmLabelOff _ _) = True
144 needsRelocation _ = False
145
146 mkWordCLit :: StgWord -> CmmLit
147 mkWordCLit wd = CmmInt (fromIntegral wd) wordWidth
148
149 packHalfWordsCLit :: (Integral a, Integral b) => a -> b -> CmmLit
150 -- Make a single word literal in which the lower_half_word is
151 -- at the lower address, and the upper_half_word is at the
152 -- higher address
153 -- ToDo: consider using half-word lits instead
154 -- but be careful: that's vulnerable when reversed
155 packHalfWordsCLit lower_half_word upper_half_word
156 #ifdef WORDS_BIGENDIAN
157 = mkWordCLit ((fromIntegral lower_half_word `shiftL` hALF_WORD_SIZE_IN_BITS)
158 .|. fromIntegral upper_half_word)
159 #else
160 = mkWordCLit ((fromIntegral lower_half_word)
161 .|. (fromIntegral upper_half_word `shiftL` hALF_WORD_SIZE_IN_BITS))
162 #endif
163
164 ---------------------------------------------------
165 --
166 -- CmmExpr
167 --
168 ---------------------------------------------------
169
170 mkLblExpr :: CLabel -> CmmExpr
171 mkLblExpr lbl = CmmLit (CmmLabel lbl)
172
173 cmmOffsetExpr :: CmmExpr -> CmmExpr -> CmmExpr
174 -- assumes base and offset have the same CmmType
175 cmmOffsetExpr e (CmmLit (CmmInt n _)) = cmmOffset e (fromInteger n)
176 cmmOffsetExpr e byte_off = CmmMachOp (MO_Add (cmmExprWidth e)) [e, byte_off]
177
178 -- NB. Do *not* inspect the value of the offset in these smart constructors!!!
179 -- because the offset is sometimes involved in a loop in the code generator
180 -- (we don't know the real Hp offset until we've generated code for the entire
181 -- basic block, for example). So we cannot eliminate zero offsets at this
182 -- stage; they're eliminated later instead (either during printing or
183 -- a later optimisation step on Cmm).
184 --
185 cmmOffset :: CmmExpr -> Int -> CmmExpr
186 cmmOffset e 0 = e
187 cmmOffset (CmmReg reg) byte_off = cmmRegOff reg byte_off
188 cmmOffset (CmmRegOff reg m) byte_off = cmmRegOff reg (m+byte_off)
189 cmmOffset (CmmLit lit) byte_off = CmmLit (cmmOffsetLit lit byte_off)
190 cmmOffset (CmmMachOp (MO_Add rep) [expr, CmmLit (CmmInt byte_off1 _rep)]) byte_off2
191 = CmmMachOp (MO_Add rep)
192 [expr, CmmLit (CmmInt (byte_off1 + toInteger byte_off2) rep)]
193 cmmOffset expr byte_off
194 = CmmMachOp (MO_Add width) [expr, CmmLit (CmmInt (toInteger byte_off) width)]
195 where
196 width = cmmExprWidth expr
197
198 -- Smart constructor for CmmRegOff. Same caveats as cmmOffset above.
199 cmmRegOff :: CmmReg -> Int -> CmmExpr
200 cmmRegOff reg byte_off = CmmRegOff reg byte_off
201
202 cmmOffsetLit :: CmmLit -> Int -> CmmLit
203 cmmOffsetLit (CmmLabel l) byte_off = cmmLabelOff l byte_off
204 cmmOffsetLit (CmmLabelOff l m) byte_off = cmmLabelOff l (m+byte_off)
205 cmmOffsetLit (CmmInt m rep) byte_off = CmmInt (m + fromIntegral byte_off) rep
206 cmmOffsetLit _ byte_off = pprPanic "cmmOffsetLit" (ppr byte_off)
207
208 cmmLabelOff :: CLabel -> Int -> CmmLit
209 -- Smart constructor for CmmLabelOff
210 cmmLabelOff lbl 0 = CmmLabel lbl
211 cmmLabelOff lbl byte_off = CmmLabelOff lbl byte_off
212
213 -- | Useful for creating an index into an array, with a staticaly known offset.
214 -- The type is the element type; used for making the multiplier
215 cmmIndex :: Width -- Width w
216 -> CmmExpr -- Address of vector of items of width w
217 -> Int -- Which element of the vector (0 based)
218 -> CmmExpr -- Address of i'th element
219 cmmIndex width base idx = cmmOffset base (idx * widthInBytes width)
220
221 -- | Useful for creating an index into an array, with an unknown offset.
222 cmmIndexExpr :: Width -- Width w
223 -> CmmExpr -- Address of vector of items of width w
224 -> CmmExpr -- Which element of the vector (0 based)
225 -> CmmExpr -- Address of i'th element
226 cmmIndexExpr width base (CmmLit (CmmInt n _)) = cmmIndex width base (fromInteger n)
227 cmmIndexExpr width base idx =
228 cmmOffsetExpr base byte_off
229 where
230 idx_w = cmmExprWidth idx
231 byte_off = CmmMachOp (MO_Shl idx_w) [idx, CmmLit (mkIntCLit (widthInLog width))]
232
233 cmmLoadIndex :: CmmType -> CmmExpr -> Int -> CmmExpr
234 cmmLoadIndex ty expr ix = CmmLoad (cmmIndex (typeWidth ty) expr ix) ty
235
236 -- The "B" variants take byte offsets
237 cmmRegOffB :: CmmReg -> ByteOff -> CmmExpr
238 cmmRegOffB = cmmRegOff
239
240 cmmOffsetB :: CmmExpr -> ByteOff -> CmmExpr
241 cmmOffsetB = cmmOffset
242
243 cmmOffsetExprB :: CmmExpr -> CmmExpr -> CmmExpr
244 cmmOffsetExprB = cmmOffsetExpr
245
246 cmmLabelOffB :: CLabel -> ByteOff -> CmmLit
247 cmmLabelOffB = cmmLabelOff
248
249 cmmOffsetLitB :: CmmLit -> ByteOff -> CmmLit
250 cmmOffsetLitB = cmmOffsetLit
251
252 -----------------------
253 -- The "W" variants take word offsets
254 cmmOffsetExprW :: CmmExpr -> CmmExpr -> CmmExpr
255 -- The second arg is a *word* offset; need to change it to bytes
256 cmmOffsetExprW e (CmmLit (CmmInt n _)) = cmmOffsetW e (fromInteger n)
257 cmmOffsetExprW e wd_off = cmmIndexExpr wordWidth e wd_off
258
259 cmmOffsetW :: CmmExpr -> WordOff -> CmmExpr
260 cmmOffsetW e n = cmmOffsetB e (wORD_SIZE * n)
261
262 cmmRegOffW :: CmmReg -> WordOff -> CmmExpr
263 cmmRegOffW reg wd_off = cmmRegOffB reg (wd_off * wORD_SIZE)
264
265 cmmOffsetLitW :: CmmLit -> WordOff -> CmmLit
266 cmmOffsetLitW lit wd_off = cmmOffsetLitB lit (wORD_SIZE * wd_off)
267
268 cmmLabelOffW :: CLabel -> WordOff -> CmmLit
269 cmmLabelOffW lbl wd_off = cmmLabelOffB lbl (wORD_SIZE * wd_off)
270
271 cmmLoadIndexW :: CmmExpr -> Int -> CmmType -> CmmExpr
272 cmmLoadIndexW base off ty = CmmLoad (cmmOffsetW base off) ty
273
274 -----------------------
275 cmmULtWord, cmmUGeWord, cmmUGtWord, cmmSubWord,
276 cmmNeWord, cmmEqWord, cmmOrWord, cmmAndWord,
277 cmmUShrWord, cmmAddWord, cmmMulWord
278 :: CmmExpr -> CmmExpr -> CmmExpr
279 cmmOrWord e1 e2 = CmmMachOp mo_wordOr [e1, e2]
280 cmmAndWord e1 e2 = CmmMachOp mo_wordAnd [e1, e2]
281 cmmNeWord e1 e2 = CmmMachOp mo_wordNe [e1, e2]
282 cmmEqWord e1 e2 = CmmMachOp mo_wordEq [e1, e2]
283 cmmULtWord e1 e2 = CmmMachOp mo_wordULt [e1, e2]
284 cmmUGeWord e1 e2 = CmmMachOp mo_wordUGe [e1, e2]
285 cmmUGtWord e1 e2 = CmmMachOp mo_wordUGt [e1, e2]
286 --cmmShlWord e1 e2 = CmmMachOp mo_wordShl [e1, e2]
287 cmmUShrWord e1 e2 = CmmMachOp mo_wordUShr [e1, e2]
288 cmmAddWord e1 e2 = CmmMachOp mo_wordAdd [e1, e2]
289 cmmSubWord e1 e2 = CmmMachOp mo_wordSub [e1, e2]
290 cmmMulWord e1 e2 = CmmMachOp mo_wordMul [e1, e2]
291
292 cmmNegate :: CmmExpr -> CmmExpr
293 cmmNegate (CmmLit (CmmInt n rep)) = CmmLit (CmmInt (-n) rep)
294 cmmNegate e = CmmMachOp (MO_S_Neg (cmmExprWidth e)) [e]
295
296 blankWord :: CmmStatic
297 blankWord = CmmUninitialised wORD_SIZE
298
299 ---------------------------------------------------
300 --
301 -- CmmExpr predicates
302 --
303 ---------------------------------------------------
304
305 isTrivialCmmExpr :: CmmExpr -> Bool
306 isTrivialCmmExpr (CmmLoad _ _) = False
307 isTrivialCmmExpr (CmmMachOp _ _) = False
308 isTrivialCmmExpr (CmmLit _) = True
309 isTrivialCmmExpr (CmmReg _) = True
310 isTrivialCmmExpr (CmmRegOff _ _) = True
311 isTrivialCmmExpr (CmmStackSlot _ _) = panic "isTrivialCmmExpr CmmStackSlot"
312
313 hasNoGlobalRegs :: CmmExpr -> Bool
314 hasNoGlobalRegs (CmmLoad e _) = hasNoGlobalRegs e
315 hasNoGlobalRegs (CmmMachOp _ es) = all hasNoGlobalRegs es
316 hasNoGlobalRegs (CmmLit _) = True
317 hasNoGlobalRegs (CmmReg (CmmLocal _)) = True
318 hasNoGlobalRegs (CmmRegOff (CmmLocal _) _) = True
319 hasNoGlobalRegs _ = False
320
321 ---------------------------------------------------
322 --
323 -- Tagging
324 --
325 ---------------------------------------------------
326
327 -- Tag bits mask
328 --cmmTagBits = CmmLit (mkIntCLit tAG_BITS)
329 cmmTagMask, cmmPointerMask :: CmmExpr
330 cmmTagMask = CmmLit (mkIntCLit tAG_MASK)
331 cmmPointerMask = CmmLit (mkIntCLit (complement tAG_MASK))
332
333 -- Used to untag a possibly tagged pointer
334 -- A static label need not be untagged
335 cmmUntag, cmmGetTag :: CmmExpr -> CmmExpr
336 cmmUntag e@(CmmLit (CmmLabel _)) = e
337 -- Default case
338 cmmUntag e = (e `cmmAndWord` cmmPointerMask)
339
340 cmmGetTag e = (e `cmmAndWord` cmmTagMask)
341
342 -- Test if a closure pointer is untagged
343 cmmIsTagged :: CmmExpr -> CmmExpr
344 cmmIsTagged e = (e `cmmAndWord` cmmTagMask)
345 `cmmNeWord` CmmLit zeroCLit
346
347 cmmConstrTag, cmmConstrTag1 :: CmmExpr -> CmmExpr
348 cmmConstrTag e = (e `cmmAndWord` cmmTagMask) `cmmSubWord` (CmmLit (mkIntCLit 1))
349 -- Get constructor tag, but one based.
350 cmmConstrTag1 e = e `cmmAndWord` cmmTagMask
351
352
353 --------------------------------------------
354 --
355 -- mkLiveness
356 --
357 ---------------------------------------------
358
359 mkLiveness :: [Maybe LocalReg] -> Liveness
360 mkLiveness [] = []
361 mkLiveness (reg:regs)
362 = take sizeW bits ++ mkLiveness regs
363 where
364 sizeW = case reg of
365 Nothing -> 1
366 Just r -> (widthInBytes (typeWidth (localRegType r)) + wORD_SIZE - 1)
367 `quot` wORD_SIZE
368 -- number of words, rounded up
369 bits = repeat $ is_non_ptr reg -- True <=> Non Ptr
370
371 is_non_ptr Nothing = True
372 is_non_ptr (Just reg) = not $ isGcPtrType (localRegType reg)
373
374
375 -- ============================================== -
376 -- ============================================== -
377 -- ============================================== -
378
379 ---------------------------------------------------
380 --
381 -- Manipulating CmmGraphs
382 --
383 ---------------------------------------------------
384
385 modifyGraph :: (Graph n C C -> Graph n' C C) -> GenCmmGraph n -> GenCmmGraph n'
386 modifyGraph f g = CmmGraph {g_entry=g_entry g, g_graph=f (g_graph g)}
387
388 toBlockMap :: CmmGraph -> LabelMap CmmBlock
389 toBlockMap (CmmGraph {g_graph=GMany NothingO body NothingO}) = body
390
391 ofBlockMap :: BlockId -> LabelMap CmmBlock -> CmmGraph
392 ofBlockMap entry bodyMap = CmmGraph {g_entry=entry, g_graph=GMany NothingO bodyMap NothingO}
393
394 insertBlock :: CmmBlock -> LabelMap CmmBlock -> LabelMap CmmBlock
395 insertBlock block map =
396 ASSERT (isNothing $ mapLookup id map)
397 mapInsert id block map
398 where id = entryLabel block
399
400 toBlockList :: CmmGraph -> [CmmBlock]
401 toBlockList g = mapElems $ toBlockMap g
402
403 ofBlockList :: BlockId -> [CmmBlock] -> CmmGraph
404 ofBlockList entry blocks = CmmGraph {g_entry=entry, g_graph=GMany NothingO body NothingO}
405 where body = foldr addBlock emptyBody blocks
406
407 bodyToBlockList :: Body CmmNode -> [CmmBlock]
408 bodyToBlockList body = mapElems body
409
410 mapGraphNodes :: ( CmmNode C O -> CmmNode C O
411 , CmmNode O O -> CmmNode O O
412 , CmmNode O C -> CmmNode O C)
413 -> CmmGraph -> CmmGraph
414 mapGraphNodes funs@(mf,_,_) g =
415 ofBlockMap (entryLabel $ mf $ CmmEntry $ g_entry g) $ mapMap (blockMapNodes3 funs) $ toBlockMap g
416
417 foldGraphBlocks :: (CmmBlock -> a -> a) -> a -> CmmGraph -> a
418 foldGraphBlocks k z g = mapFold k z $ toBlockMap g
419
420 postorderDfs :: CmmGraph -> [CmmBlock]
421 postorderDfs g = postorder_dfs_from (toBlockMap g) (g_entry g)
422
423 -------------------------------------------------
424 -- Manipulating CmmBlocks
425
426 lastNode :: CmmBlock -> CmmNode O C
427 lastNode block = foldBlockNodesF3 (nothing, nothing, const) block ()
428 where nothing :: a -> b -> ()
429 nothing _ _ = ()
430
431 replaceLastNode :: Block CmmNode e C -> CmmNode O C -> Block CmmNode e C
432 replaceLastNode block last = blockOfNodeList (first, middle, JustC last)
433 where (first, middle, _) = blockToNodeList block
434
435 ----------------------------------------------------------------------
436 ----- Splicing between blocks
437 -- Given a middle node, a block, and a successor BlockId,
438 -- we can insert the middle node between the block and the successor.
439 -- We return the updated block and a list of new blocks that must be added
440 -- to the graph.
441 -- The semantics is a bit tricky. We consider cases on the last node:
442 -- o For a branch, we can just insert before the branch,
443 -- but sometimes the optimizer does better if we actually insert
444 -- a fresh basic block, enabling some common blockification.
445 -- o For a conditional branch, switch statement, or call, we must insert
446 -- a new basic block.
447 -- o For a jump or return, this operation is impossible.
448
449 insertBetween :: MonadUnique m => CmmBlock -> [CmmNode O O] -> BlockId -> m (CmmBlock, [CmmBlock])
450 insertBetween b ms succId = insert $ lastNode b
451 where insert :: MonadUnique m => CmmNode O C -> m (CmmBlock, [CmmBlock])
452 insert (CmmBranch bid) =
453 if bid == succId then
454 do (bid', bs) <- newBlocks
455 return (replaceLastNode b (CmmBranch bid'), bs)
456 else panic "tried invalid block insertBetween"
457 insert (CmmCondBranch c t f) =
458 do (t', tbs) <- if t == succId then newBlocks else return $ (t, [])
459 (f', fbs) <- if f == succId then newBlocks else return $ (f, [])
460 return (replaceLastNode b (CmmCondBranch c t' f'), tbs ++ fbs)
461 insert (CmmSwitch e ks) =
462 do (ids, bs) <- mapAndUnzipM mbNewBlocks ks
463 return (replaceLastNode b (CmmSwitch e ids), join bs)
464 insert (CmmCall {}) =
465 panic "unimp: insertBetween after a call -- probably not a good idea"
466 insert (CmmForeignCall {}) =
467 panic "unimp: insertBetween after a foreign call -- probably not a good idea"
468
469 newBlocks :: MonadUnique m => m (BlockId, [CmmBlock])
470 newBlocks = do id <- liftM mkBlockId $ getUniqueM
471 return $ (id, [blockOfNodeList (JustC (CmmEntry id), ms, JustC (CmmBranch succId))])
472 mbNewBlocks :: MonadUnique m => Maybe BlockId -> m (Maybe BlockId, [CmmBlock])
473 mbNewBlocks (Just k) = if k == succId then liftM fstJust newBlocks
474 else return (Just k, [])
475 mbNewBlocks Nothing = return (Nothing, [])
476 fstJust (id, bs) = (Just id, bs)
477
478 -------------------------------------------------
479 -- Running dataflow analysis and/or rewrites
480
481 -- Constructing forward and backward analysis-only pass
482 analFwd :: Monad m => DataflowLattice f -> FwdTransfer n f -> FwdPass m n f
483 analBwd :: Monad m => DataflowLattice f -> BwdTransfer n f -> BwdPass m n f
484
485 analFwd lat xfer = analRewFwd lat xfer noFwdRewrite
486 analBwd lat xfer = analRewBwd lat xfer noBwdRewrite
487
488 -- Constructing forward and backward analysis + rewrite pass
489 analRewFwd :: Monad m => DataflowLattice f -> FwdTransfer n f -> FwdRewrite m n f -> FwdPass m n f
490 analRewBwd :: Monad m => DataflowLattice f -> BwdTransfer n f -> BwdRewrite m n f -> BwdPass m n f
491
492 analRewFwd lat xfer rew = FwdPass {fp_lattice = lat, fp_transfer = xfer, fp_rewrite = rew}
493 analRewBwd lat xfer rew = BwdPass {bp_lattice = lat, bp_transfer = xfer, bp_rewrite = rew}
494
495 -- Running forward and backward dataflow analysis + optional rewrite
496 dataflowPassFwd :: NonLocal n => GenCmmGraph n -> [(BlockId, f)] -> FwdPass FuelUniqSM n f -> FuelUniqSM (GenCmmGraph n, BlockEnv f)
497 dataflowPassFwd (CmmGraph {g_entry=entry, g_graph=graph}) facts fwd = do
498 (graph, facts, NothingO) <- analyzeAndRewriteFwd fwd (JustC [entry]) graph (mkFactBase (fp_lattice fwd) facts)
499 return (CmmGraph {g_entry=entry, g_graph=graph}, facts)
500
501 dataflowPassBwd :: NonLocal n => GenCmmGraph n -> [(BlockId, f)] -> BwdPass FuelUniqSM n f -> FuelUniqSM (GenCmmGraph n, BlockEnv f)
502 dataflowPassBwd (CmmGraph {g_entry=entry, g_graph=graph}) facts bwd = do
503 (graph, facts, NothingO) <- analyzeAndRewriteBwd bwd (JustC [entry]) graph (mkFactBase (bp_lattice bwd) facts)
504 return (CmmGraph {g_entry=entry, g_graph=graph}, facts)