1 {-# LANGUAGE ScopedTypeVariables #-}
3 ( -- These data types and names are carefully thought out
4 BlockId(..), freshBlockId -- ToDo: BlockId should be abstract,
6 , BlockEnv, emptyBlockEnv, lookupBlockEnv, extendBlockEnv, insertBlock, mkBlockEnv
7 , BlockSet, emptyBlockSet, elemBlockSet, extendBlockSet, mkBlockSet
8 , Graph(..), LGraph(..), FGraph(..)
9 , Block(..), ZBlock(..), ZHead(..), ZTail(..), ZLast(..)
10 , HavingSuccessors, succs, fold_succs
11 , LastNode, mkBranchNode, isBranchNode, branchNodeTarget
13 -- Observers and transformers
14 -- (open to renaming suggestions here)
15 , blockId, zip, unzip, last, goto_end, zipht, tailOfLast
17 , splice_tail, splice_head, splice_head_only', splice_head'
18 , of_block_list, to_block_list
20 , postorder_dfs, postorder_dfs_from, postorder_dfs_from_except
28 -- the following functions might one day be useful and can be found
29 -- either below or in ZipCfgExtras:
30 , entry, exit, focus, focusp, unfocus
31 , ht_to_block, ht_to_last,
32 , splice_focus_entry, splice_focus_exit
33 , fold_fwd_block, foldM_fwd_block
39 #include "HsVersions.h"
41 import Outputable hiding (empty)
49 import Prelude hiding (zip, unzip, last)
51 -------------------------------------------------------------------------
52 -- GENERIC ZIPPER-BASED CONTROL-FLOW GRAPH --
53 -------------------------------------------------------------------------
56 This module defines datatypes used to represent control-flow graphs,
57 along with some functions for analyzing and splicing graphs.
58 Functions for building graphs are found in a separate module 'MkZipCfg'.
60 Every graph has a distinguished entry point. A graph has at least one
61 exit; most exits are instructions (or statements) like 'jump' or
62 'return', which transfer control to other procedures, but a graph may
63 have up to one 'fall through' exit. (A graph that represents an
64 entire Haskell or C-- procedure does not have a 'fall through' exit.)
66 A graph is a collection of basic blocks. A basic block begins with a
67 label (unique id; see Note [Unique BlockId]) which is followed by a
68 sequence of zero or more 'middle' nodes; the basic block ends with a
69 'last' node. Each 'middle' node is a single-entry, single-exit,
70 uninterruptible computation. A 'last' node is a single-entry,
71 multiple-exit computation. A last node may have zero or more successors,
72 which are identified by their unique ids.
74 A special case of last node is the ``default exit,'' which represents
75 'falling off the end' of the graph. Such a node is always represented by
76 the data constructor 'LastExit'. A graph may contain at most one
77 'LastExit' node, and a graph representing a full procedure should not
78 contain any 'LastExit' nodes. 'LastExit' nodes are used only to splice
79 graphs together, either during graph construction (see module 'MkZipCfg')
80 or during optimization (see module 'ZipDataflow').
82 A graph is parameterized over the types of middle and last nodes. Each of
83 these types will typically be instantiated with a subset of C-- statements
84 (see module 'ZipCfgCmmRep') or a subset of machine instructions (yet to be
85 implemented as of August 2007).
88 Note [Kinds of Graphs]
89 ~~~~~~~~~~~~~~~~~~~~~~
90 This module exposes three representations of graphs. In order of
91 increasing complexity, they are:
93 Graph m l The basic graph with its distinguished entry point
95 LGraph m l A graph with a *labelled* entry point
97 FGraph m l A labelled graph with the *focus* on a particular edge
99 There are three types because each type offers a slightly different
100 invariant or cost model.
102 * The distinguished entry of a Graph has no label. Because labels must
103 be unique, acquiring one requires a monadic operation ('freshBlockId').
104 The primary advantage of the Graph representation is that we can build
105 a small Graph purely functionally, without entering a monad. For
106 example, during optimization we can easily rewrite a single middle
107 node into a Graph containing a sequence of two middle nodes followed by
110 * In an LGraph, every basic block is labelled. The primary advantage of
111 this representation is its simplicity: each basic block can be treated
112 like any other. This representation is used for mapping, folding, and
113 translation, as well as layout.
115 Like any graph, an LGraph still has a distinguished entry point,
116 which you can discover using 'lg_entry'.
118 * An FGraph is an LGraph with the *focus* on one particular edge. The
119 primary advantage of this representation is that it provides
120 constant-time access to the nodes connected by that edge, and it also
121 allows constant-time, functional *replacement* of those nodes---in the
122 style of Huet's 'zipper'.
124 None of these representations is ideally suited to the incremental
125 construction of large graphs. A separate module, 'MkZipCfg', provides a
126 fourth representation that is asymptotically optimal for such construction.
130 --------------- Representation --------------------
132 -- | A basic block is a 'first' node, followed by zero or more 'middle'
133 -- nodes, followed by a 'last' node.
135 -- eventually this module should probably replace the original Cmm, but for
136 -- now we leave it to dynamic invariants what can be found where
139 = LastExit -- fall through; used for the block that has no last node
140 -- LastExit is a device used only for graphs under
141 -- construction, or framgments of graph under optimisation,
142 -- so we don't want to pollute the 'l' type parameter with it
145 data ZHead m = ZFirst BlockId | ZHead (ZHead m) m
146 -- ZHead is a (reversed) sequence of middle nodes labeled by a BlockId
147 data ZTail m l = ZLast (ZLast l) | ZTail m (ZTail m l)
148 -- ZTail is a sequence of middle nodes followed by a last node
150 -- | Blocks and flow graphs; see Note [Kinds of graphs]
151 data Block m l = Block BlockId (ZTail m l)
153 data Graph m l = Graph { g_entry :: (ZTail m l), g_blocks :: (BlockEnv (Block m l)) }
155 data LGraph m l = LGraph { lg_entry :: BlockId
156 , lg_blocks :: BlockEnv (Block m l) }
157 -- Invariant: lg_entry is in domain( lg_blocks )
159 -- | And now the zipper. The focus is between the head and tail.
160 -- We cannot ever focus on an inter-block edge.
161 data ZBlock m l = ZBlock (ZHead m) (ZTail m l)
162 data FGraph m l = FGraph { fg_entry :: BlockId
163 , fg_focus :: ZBlock m l
164 , fg_others :: BlockEnv (Block m l) }
165 -- Invariant: the block represented by 'fg_focus' is *not*
166 -- in the map 'fg_others'
168 ---- Utility functions ---
170 -- | The string argument to 'freshBlockId' was originally helpful in debugging the Quick C--
171 -- compiler, so I have kept it here even though at present it is thrown away at
172 -- this spot---there's no reason a BlockId couldn't one day carry a string.
173 freshBlockId :: String -> UniqSM BlockId
175 blockId :: Block m l -> BlockId
176 zip :: ZBlock m l -> Block m l
177 unzip :: Block m l -> ZBlock m l
179 last :: ZBlock m l -> ZLast l
180 goto_end :: ZBlock m l -> (ZHead m, ZLast l)
182 tailOfLast :: l -> ZTail m l
184 -- | Take a head and tail and go to beginning or end. The asymmetry
185 -- in the types and names is a bit unfortunate, but 'Block m l' is
186 -- effectively '(BlockId, ZTail m l)' and is accepted in many more places.
188 ht_to_block, zipht :: ZHead m -> ZTail m l -> Block m l
189 ht_to_last :: ZHead m -> ZTail m l -> (ZHead m, ZLast l)
191 -- | We can splice a single-entry, single-exit LGraph onto a head or a tail.
192 -- For a head, we have a head 'h' followed by a LGraph 'g'.
193 -- The entry node of 'g' gets joined to 'h', forming the entry into
194 -- the new LGraph. The exit of 'g' becomes the new head.
195 -- For both arguments and results, the order of values is the order of
196 -- control flow: before splicing, the head flows into the LGraph; after
197 -- splicing, the LGraph flows into the head.
198 -- Splicing a tail is the dual operation.
199 -- (In order to maintain the order-means-control-flow convention, the
200 -- orders are reversed.)
202 -- For example, assume
204 -- grph = (M, [M: <stuff>,
206 -- N: y:=x; LastExit])
207 -- tail = [return (y,x)]
209 -- Then splice_head head grph
210 -- = ((L, [L: x:=0; goto M,
215 -- Then splice_tail grph tail
217 -- , (???, [<blocks>,
218 -- N: y:=x; return (y,x)])
220 splice_head :: ZHead m -> LGraph m l -> (LGraph m l, ZHead m)
221 splice_head' :: ZHead m -> Graph m l -> (BlockEnv (Block m l), ZHead m)
222 splice_tail :: Graph m l -> ZTail m l -> Graph m l
224 -- | We can also splice a single-entry, no-exit Graph into a head.
225 splice_head_only :: ZHead m -> LGraph m l -> LGraph m l
226 splice_head_only' :: ZHead m -> Graph m l -> LGraph m l
229 -- | A safe operation
231 -- | Conversion to and from the environment form is convenient. For
232 -- layout or dataflow, however, one will want to use 'postorder_dfs'
233 -- in order to get the blocks in an order that relates to the control
234 -- flow in the procedure.
235 of_block_list :: BlockId -> [Block m l] -> LGraph m l -- N log N
236 to_block_list :: LGraph m l -> [Block m l] -- N log N
238 -- | Traversal: 'postorder_dfs' returns a list of blocks reachable
239 -- from the entry node. This list has the following property:
241 -- Say a "back reference" exists if one of a block's
242 -- control-flow successors precedes it in the output list
244 -- Then there are as few back references as possible
246 -- The output is suitable for use in
247 -- a forward dataflow problem. For a backward problem, simply reverse
248 -- the list. ('postorder_dfs' is sufficiently tricky to implement that
249 -- one doesn't want to try and maintain both forward and backward
252 postorder_dfs :: LastNode l => LGraph m l -> [Block m l]
254 -- | For layout, we fold over pairs of 'Block m l' and 'Maybe BlockId'
255 -- in layout order. The 'Maybe BlockId', if present, identifies the
256 -- block that will be the layout successor of the current block. This
257 -- may be useful to help an emitter omit the final 'goto' of a block
258 -- that flows directly to its layout successor.
260 -- For example: fold_layout f z [ L1:B1, L2:B2, L3:B3 ]
261 -- = z <$> f (L1:B1) (Just L2)
262 -- <$> f (L2:B2) (Just L3)
263 -- <$> f (L3:B3) Nothing
264 -- where a <$> f = f a
266 LastNode l => (Block m l -> Maybe BlockId -> a -> a) -> a -> LGraph m l-> a
268 -- | We can also fold over blocks in an unspecified order. The
269 -- 'ZipCfgExtras' module provides a monadic version, which we
270 -- haven't needed (else it would be here).
271 fold_blocks :: (Block m l -> a -> a) -> a -> LGraph m l -> a
273 map_nodes :: (BlockId -> BlockId) -> (m -> m') -> (l -> l') -> LGraph m l -> LGraph m' l'
274 -- mapping includes the entry id!
276 -- | These translation functions are speculative. I hope eventually
277 -- they will be used in the native-code back ends ---NR
278 translate :: (m -> UniqSM (LGraph m' l')) ->
279 (l -> UniqSM (LGraph m' l')) ->
280 (LGraph m l -> UniqSM (LGraph m' l'))
283 -- | It's possible that another form of translation would be more suitable:
284 translateA :: (m -> Agraph m' l') -> (l -> AGraph m' l') -> LGraph m l -> LGraph m' l'
287 ------------------- Last nodes
289 -- | We can't make a graph out of just any old 'last node' type. A last node
290 -- has to be able to find its successors, and we need to be able to create and
291 -- identify unconditional branches. We put these capabilities in a type class.
292 -- Moreover, the property of having successors is also shared by 'Block's and
293 -- 'ZTails', so it is useful to have that property in a type class of its own.
295 class HavingSuccessors b where
296 succs :: b -> [BlockId]
297 fold_succs :: (BlockId -> a -> a) -> b -> a -> a
299 fold_succs add l z = foldr add z $ succs l
301 class HavingSuccessors l => LastNode l where
302 mkBranchNode :: BlockId -> l
303 isBranchNode :: l -> Bool
304 branchNodeTarget :: l -> BlockId -- panics if not branch node
305 -- ^ N.B. This interface seems to make for more congenial clients than a
306 -- single function of type 'l -> Maybe BlockId'
308 instance HavingSuccessors l => HavingSuccessors (ZLast l) where
310 succs (LastOther l) = succs l
311 fold_succs _ LastExit z = z
312 fold_succs f (LastOther l) z = fold_succs f l z
314 instance LastNode l => LastNode (ZLast l) where
315 mkBranchNode id = LastOther $ mkBranchNode id
316 isBranchNode LastExit = False
317 isBranchNode (LastOther l) = isBranchNode l
318 branchNodeTarget LastExit = panic "branchNodeTarget LastExit"
319 branchNodeTarget (LastOther l) = branchNodeTarget l
321 instance LastNode l => HavingSuccessors (ZBlock m l) where
322 succs b = succs (last b)
324 instance LastNode l => HavingSuccessors (Block m l) where
325 succs b = succs (unzip b)
327 instance LastNode l => HavingSuccessors (ZTail m l) where
328 succs b = succs (lastTail b)
332 -- ================ IMPLEMENTATION ================--
334 ----- block manipulations
336 blockId (Block id _) = id
338 freshBlockId _ = do { u <- getUniqueUs; return $ BlockId u }
340 -- | Convert block between forms.
341 -- These functions are tail-recursive, so we can go as deep as we like
342 -- without fear of stack overflow.
344 ht_to_block head tail = case head of
345 ZFirst id -> Block id tail
346 ZHead h m -> ht_to_block h (ZTail m tail)
348 ht_to_last head (ZLast l) = (head, l)
349 ht_to_last head (ZTail m t) = ht_to_last (ZHead head m) t
351 zipht h t = ht_to_block h t
352 zip (ZBlock h t) = ht_to_block h t
353 goto_end (ZBlock h t) = ht_to_last h t
355 unzip (Block id t) = ZBlock (ZFirst id) t
357 head_id :: ZHead m -> BlockId
358 head_id (ZFirst id) = id
359 head_id (ZHead h _) = head_id h
361 last (ZBlock _ t) = lastTail t
363 lastTail :: ZTail m l -> ZLast l
364 lastTail (ZLast l) = l
365 lastTail (ZTail _ t) = lastTail t
367 tailOfLast l = ZLast (LastOther l) -- ^ tedious to write in every client
370 ------------------ simple graph manipulations
372 focus :: BlockId -> LGraph m l -> FGraph m l -- focus on edge out of node with id
373 focus id (LGraph entry blocks) =
374 case lookupBlockEnv blocks id of
375 Just b -> FGraph entry (unzip b) (delFromUFM blocks id)
376 Nothing -> panic "asked for nonexistent block in flow graph"
378 entry :: LGraph m l -> FGraph m l -- focus on edge out of entry node
379 entry g@(LGraph eid _) = focus eid g
381 -- | pull out a block satisfying the predicate, if any
382 splitp_blocks :: (Block m l -> Bool) -> BlockEnv (Block m l) ->
383 Maybe (Block m l, BlockEnv (Block m l))
384 splitp_blocks p blocks = lift $ foldUFM scan (Nothing, emptyBlockEnv) blocks
385 where scan b (yes, no) =
387 Nothing | p b -> (Just b, no)
388 | otherwise -> (yes, insertBlock b no)
389 Just _ -> (yes, insertBlock b no)
390 lift (Nothing, _) = Nothing
391 lift (Just b, bs) = Just (b, bs)
393 -- | 'insertBlock' should not be used to *replace* an existing block
394 -- but only to insert a new one
395 insertBlock :: Block m l -> BlockEnv (Block m l) -> BlockEnv (Block m l)
397 ASSERT (isNothing $ lookupBlockEnv bs id)
398 extendBlockEnv bs id b
401 -- | Used in assertions; tells if a graph has exactly one exit
402 single_exit :: LGraph l m -> Bool
403 single_exit g = foldUFM check 0 (lg_blocks g) == 1
404 where check block count = case last (unzip block) of
405 LastExit -> count + (1 :: Int)
408 -- | Used in assertions; tells if a graph has exactly one exit
409 single_exitg :: Graph l m -> Bool
410 single_exitg (Graph tail blocks) = foldUFM add (exit_count (lastTail tail)) blocks == 1
411 where add block count = count + exit_count (last (unzip block))
412 exit_count LastExit = 1 :: Int
415 ------------------ graph traversals
417 -- | This is the most important traversal over this data structure. It drops
418 -- unreachable code and puts blocks in an order that is good for solving forward
419 -- dataflow problems quickly. The reverse order is good for solving backward
420 -- dataflow problems quickly. The forward order is also reasonably good for
421 -- emitting instructions, except that it will not usually exploit Forrest
422 -- Baskett's trick of eliminating the unconditional branch from a loop. For
423 -- that you would need a more serious analysis, probably based on dominators, to
424 -- identify loop headers.
426 -- The ubiquity of 'postorder_dfs' is one reason for the ubiquity of the 'LGraph'
427 -- representation, when for most purposes the plain 'Graph' representation is
428 -- more mathematically elegant (but results in more complicated code).
430 -- Here's an easy way to go wrong! Consider
434 -- Then ordinary dfs would give [A,B,D,C] which has a back ref from C to D.
435 -- Better to geot [A,B,C,D]
438 postorder_dfs' :: LastNode l => LGraph m l -> [Block m l]
439 postorder_dfs' g@(LGraph _ blocks) =
440 let FGraph _ eblock _ = entry g
441 in vnode (zip eblock) (\acc _visited -> acc) [] emptyBlockSet
444 -- Block m l -> ([Block m l] -> BlockSet -> a) -> [Block m l] -> BlockSet -> a
445 vnode block@(Block id _) cont acc visited =
446 if elemBlockSet id visited then
449 vchildren block (get_children block) cont acc (extendBlockSet visited id)
450 vchildren block bs cont acc visited =
451 let next children acc visited =
452 case children of [] -> cont (block : acc) visited
453 (b:bs) -> vnode b (next bs) acc visited
454 in next bs acc visited
455 get_children block = foldl add_id [] (succs block)
456 add_id rst id = case lookupBlockEnv blocks id of
460 postorder_dfs g@(LGraph _ blockenv) =
461 let FGraph id eblock _ = entry g
463 postorder_dfs_from_except blockenv eblock (unitUniqSet id)
464 dfs2 = postorder_dfs' g
465 in ASSERT (map blockId dfs1 == map blockId dfs2) dfs2
468 :: (HavingSuccessors b, LastNode l) => BlockEnv (Block m l) -> b -> [Block m l]
469 postorder_dfs_from blocks b = postorder_dfs_from_except blocks b emptyBlockSet
471 postorder_dfs_from_except :: forall b m l . (HavingSuccessors b, LastNode l) => BlockEnv (Block m l) -> b -> BlockSet -> [Block m l]
472 postorder_dfs_from_except blocks b visited =
473 vchildren (get_children b) (\acc _visited -> acc) [] visited
476 -- Block m l -> ([Block m l] -> BlockSet -> a) -> [Block m l] -> BlockSet -> a
477 vnode block@(Block id _) cont acc visited =
478 if elemBlockSet id visited then
481 let cont' acc visited = cont (block:acc) visited in
482 vchildren (get_children block) cont' acc (extendBlockSet visited id)
483 vchildren bs cont acc visited =
484 let next children acc visited =
485 case children of [] -> cont acc visited
486 (b:bs) -> vnode b (next bs) acc visited
487 in next bs acc visited
488 get_children block = foldl add_id [] (succs block)
489 add_id rst id = case lookupBlockEnv blocks id of
494 -- | Slightly more complicated than the usual fold because we want to tell block
495 -- 'b1' what its inline successor is going to be, so that if 'b1' ends with
496 -- 'goto b2', the goto can be omitted.
498 fold_layout f z g@(LGraph eid _) = fold (postorder_dfs g) z
499 where fold blocks z =
500 case blocks of [] -> z
502 b1 : b2 : bs -> fold (b2 : bs) (f b1 (nextlabel b2) z)
503 nextlabel (Block id _) =
504 if id == eid then panic "entry as successor"
507 -- | The rest of the traversals are straightforward
509 map_nodes idm middle last (LGraph eid blocks) = LGraph (idm eid) (mapUFM block blocks)
510 where block (Block id t) = Block (idm id) (tail t)
511 tail (ZTail m t) = ZTail (middle m) (tail t)
512 tail (ZLast LastExit) = ZLast LastExit
513 tail (ZLast (LastOther l)) = ZLast (LastOther (last l))
515 fold_blocks f z (LGraph _ blocks) = foldUFM f z blocks
517 of_block_list e blocks = LGraph e $ foldr insertBlock emptyBlockEnv blocks
518 to_block_list (LGraph _ blocks) = eltsUFM blocks
523 -- We want to be able to scrutinize a single-entry, single-exit 'LGraph' for
524 -- splicing purposes. There are two useful cases: the 'LGraph' is a single block
525 -- or it isn't. We use continuation-passing style.
527 prepare_for_splicing ::
528 LGraph m l -> (ZTail m l -> a) -> (ZTail m l -> ZHead m -> BlockEnv (Block m l) -> a)
530 prepare_for_splicing g single multi =
531 let FGraph _ gentry gblocks = entry g
532 ZBlock _ etail = gentry
533 in if isNullUFM gblocks then
535 LastExit -> single etail
536 _ -> panic "bad single block"
538 case splitp_blocks is_exit gblocks of
539 Nothing -> panic "Can't find an exit block"
540 Just (gexit, gblocks) ->
541 let (gh, gl) = goto_end $ unzip gexit in
542 case gl of LastExit -> multi etail gh gblocks
543 _ -> panic "exit is not exit?!"
545 prepare_for_splicing' ::
546 Graph m l -> (ZTail m l -> a) -> (ZTail m l -> ZHead m -> BlockEnv (Block m l) -> a)
548 prepare_for_splicing' (Graph etail gblocks) single multi =
549 if isNullUFM gblocks then
550 case lastTail etail of
551 LastExit -> single etail
552 _ -> panic "bad single block"
554 case splitp_blocks is_exit gblocks of
555 Nothing -> panic "Can't find an exit block"
556 Just (gexit, gblocks) ->
557 let (gh, gl) = goto_end $ unzip gexit in
558 case gl of LastExit -> multi etail gh gblocks
559 _ -> panic "exit is not exit?!"
561 is_exit :: Block m l -> Bool
562 is_exit b = case last (unzip b) of { LastExit -> True; _ -> False }
565 ASSERT (single_exit g) prepare_for_splicing g splice_one_block splice_many_blocks
566 where eid = head_id head
567 splice_one_block tail' =
568 case ht_to_last head tail' of
569 (head, LastExit) -> (LGraph eid emptyBlockEnv, head)
570 _ -> panic "spliced LGraph without exit"
571 splice_many_blocks entry exit others =
572 (LGraph eid (insertBlock (zipht head entry) others), exit)
574 splice_head' head g =
575 ASSERT (single_exitg g) prepare_for_splicing' g splice_one_block splice_many_blocks
576 where splice_one_block tail' =
577 case ht_to_last head tail' of
578 (head, LastExit) -> (emptyBlockEnv, head)
579 _ -> panic "spliced LGraph without exit"
580 splice_many_blocks entry exit others =
581 (insertBlock (zipht head entry) others, exit)
583 -- splice_tail :: Graph m l -> ZTail m l -> Graph m l
585 ASSERT (single_exitg g) prepare_for_splicing' g splice_one_block splice_many_blocks
586 where splice_one_block tail' = Graph (tail' `append_tails` tail) emptyBlockEnv
587 append_tails (ZLast LastExit) tail = tail
588 append_tails (ZLast _) _ = panic "spliced single block without LastExit"
589 append_tails (ZTail m t) tail = ZTail m (append_tails t tail)
590 splice_many_blocks entry exit others =
591 Graph entry (insertBlock (zipht exit tail) others)
595 AS SERT (single_exit g) prepare_for_splicing g splice_one_block splice_many_blocks
596 where splice_one_block tail' = -- return tail' .. tail
597 case ht_to_last (ZFirst (lg_entry g)) tail' of
599 case ht_to_block head' tail of
600 Block id t | id == lg_entry g -> (t, LGraph id emptyBlockEnv)
601 _ -> panic "entry in; garbage out"
602 _ -> panic "spliced single block without Exit"
603 splice_many_blocks entry exit others =
604 (entry, LGraph (lg_entry g) (insertBlock (zipht exit tail) others))
607 splice_head_only head g =
608 let FGraph eid gentry gblocks = entry g
610 ZBlock (ZFirst _) tail -> LGraph eid (insertBlock (zipht head tail) gblocks)
611 _ -> panic "entry not at start of block?!"
613 splice_head_only' head (Graph tail gblocks) =
614 let eblock = zipht head tail in
615 LGraph (blockId eblock) (insertBlock eblock gblocks)
620 translate txm txl (LGraph eid blocks) =
621 do blocks' <- foldUFM txblock (return emptyBlockEnv) blocks
622 return $ LGraph eid blocks'
625 -- Block m l -> UniqSM (BlockEnv (Block m' l')) -> UniqSM (BlockEnv (Block m' l'))
626 txblock (Block id t) expanded =
627 do blocks' <- expanded
628 txtail (ZFirst id) t blocks'
629 -- txtail :: ZHead m' -> ZTail m l -> BlockEnv (Block m' l') ->
630 -- UniqSM (BlockEnv (Block m' l'))
631 txtail h (ZTail m t) blocks' =
633 let (g, h') = splice_head h m'
634 txtail h' t (plusUFM (lg_blocks g) blocks')
635 txtail h (ZLast (LastOther l)) blocks' =
637 return $ plusUFM (lg_blocks (splice_head_only h l')) blocks'
638 txtail h (ZLast LastExit) blocks' =
639 return $ insertBlock (zipht h (ZLast LastExit)) blocks'
641 ----------------------------------------------------------------
642 --- Block Ids, their environments, and their sets
644 {- Note [Unique BlockId]
645 ~~~~~~~~~~~~~~~~~~~~~~~~
646 Although a 'BlockId' is a local label, for reasons of implementation,
647 'BlockId's must be unique within an entire compilation unit. The reason
648 is that each local label is mapped to an assembly-language label, and in
649 most assembly languages allow, a label is visible throughout the enitre
650 compilation unit in which it appears.
653 newtype BlockId = BlockId Unique
656 instance Uniquable BlockId where
657 getUnique (BlockId u) = u
659 instance Show BlockId where
660 show (BlockId u) = show u
662 instance Outputable BlockId where
663 ppr = ppr . getUnique
666 type BlockEnv a = UniqFM {- BlockId -} a
667 emptyBlockEnv :: BlockEnv a
668 emptyBlockEnv = emptyUFM
669 lookupBlockEnv :: BlockEnv a -> BlockId -> Maybe a
670 lookupBlockEnv = lookupUFM
671 extendBlockEnv :: BlockEnv a -> BlockId -> a -> BlockEnv a
672 extendBlockEnv = addToUFM
673 mkBlockEnv :: [(BlockId,a)] -> BlockEnv a
674 mkBlockEnv = listToUFM
676 type BlockSet = UniqSet BlockId
677 emptyBlockSet :: BlockSet
678 emptyBlockSet = emptyUniqSet
679 elemBlockSet :: BlockId -> BlockSet -> Bool
680 elemBlockSet = elementOfUniqSet
681 extendBlockSet :: BlockSet -> BlockId -> BlockSet
682 extendBlockSet = addOneToUniqSet
683 mkBlockSet :: [BlockId] -> BlockSet
684 mkBlockSet = mkUniqSet
686 ----------------------------------------------------------------
688 ----------------------------------------------------------------
690 -- putting this code in PprCmmZ leads to circular imports :-(
692 instance (Outputable m, Outputable l) => Outputable (ZTail m l) where
695 pprTail :: (Outputable m, Outputable l) => ZTail m l -> SDoc
696 pprTail (ZTail m t) = ppr m $$ ppr t
697 pprTail (ZLast LastExit) = text "<exit>"
698 pprTail (ZLast (LastOther l)) = ppr l
700 pprLgraph :: (Outputable m, Outputable l, LastNode l) => LGraph m l -> SDoc
701 pprLgraph g = text "{" $$ nest 2 (vcat $ map pprBlock blocks) $$ text "}"
702 where pprBlock (Block id tail) = ppr id <> colon $$ ppr tail
703 blocks = postorder_dfs g
705 pprGraph :: (Outputable m, Outputable l, LastNode l) => Graph m l -> SDoc
706 pprGraph (Graph tail blockenv) =
707 text "{" $$ nest 2 (ppr tail $$ (vcat $ map pprBlock blocks)) $$ text "}"
708 where pprBlock (Block id tail) = ppr id <> colon $$ ppr tail
709 blocks = postorder_dfs_from blockenv tail
711 _unused :: FS.FastString