PageRenderTime 49ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 0ms

/ghc-7.0.4/compiler/cmm/CmmCommonBlockElimZ.hs

http://picorec.googlecode.com/
Haskell | 164 lines | 126 code | 17 blank | 21 comment | 22 complexity | e5ea38ff709b6387325409c6fcd4624f MD5 | raw file
Possible License(s): BSD-3-Clause, BSD-2-Clause
  1. module CmmCommonBlockElimZ
  2. ( elimCommonBlocks
  3. )
  4. where
  5. import BlockId
  6. import CmmExpr
  7. import Prelude hiding (iterate, zip, unzip)
  8. import ZipCfg
  9. import ZipCfgCmmRep
  10. import Data.Bits
  11. import qualified Data.List as List
  12. import Data.Word
  13. import FastString
  14. import Control.Monad
  15. import Outputable
  16. import UniqFM
  17. import Unique
  18. my_trace :: String -> SDoc -> a -> a
  19. my_trace = if False then pprTrace else \_ _ a -> a
  20. -- Eliminate common blocks:
  21. -- If two blocks are identical except for the label on the first node,
  22. -- then we can eliminate one of the blocks. To ensure that the semantics
  23. -- of the program are preserved, we have to rewrite each predecessor of the
  24. -- eliminated block to proceed with the block we keep.
  25. -- The algorithm iterates over the blocks in the graph,
  26. -- checking whether it has seen another block that is equal modulo labels.
  27. -- If so, then it adds an entry in a map indicating that the new block
  28. -- is made redundant by the old block.
  29. -- Otherwise, it is added to the useful blocks.
  30. -- TODO: Use optimization fuel
  31. elimCommonBlocks :: CmmGraph -> CmmGraph
  32. elimCommonBlocks g =
  33. upd_graph g . snd $ iterate common_block reset hashed_blocks
  34. (emptyUFM, emptyBlockEnv)
  35. where hashed_blocks = map (\b -> (hash_block b, b)) (reverse (postorder_dfs g))
  36. reset (_, subst) = (emptyUFM, subst)
  37. -- Iterate over the blocks until convergence
  38. iterate :: (t -> a -> (Bool, t)) -> (t -> t) -> [a] -> t -> t
  39. iterate upd reset blocks state =
  40. case foldl upd' (False, state) blocks of
  41. (True, state') -> iterate upd reset blocks (reset state')
  42. (False, state') -> state'
  43. where upd' (b, s) a = let (b', s') = upd s a in (b || b', s') -- lift to track changes
  44. -- Try to find a block that is equal (or ``common'') to b.
  45. type BidMap = BlockEnv BlockId
  46. type State = (UniqFM [CmmBlock], BidMap)
  47. common_block :: (Outputable h, Uniquable h) => State -> (h, CmmBlock) -> (Bool, State)
  48. common_block (bmap, subst) (hash, b) =
  49. case lookupUFM bmap hash of
  50. Just bs -> case (List.find (eqBlockBodyWith (eqBid subst) b) bs,
  51. lookupBlockEnv subst bid) of
  52. (Just b', Nothing) -> addSubst b'
  53. (Just b', Just b'') | blockId b' /= b'' -> addSubst b'
  54. _ -> (False, (addToUFM bmap hash (b : bs), subst))
  55. Nothing -> (False, (addToUFM bmap hash [b], subst))
  56. where bid = blockId b
  57. addSubst b' = my_trace "found new common block" (ppr (blockId b')) $
  58. (True, (bmap, extendBlockEnv subst bid (blockId b')))
  59. -- Given the map ``subst'' from BlockId -> BlockId, we rewrite the graph.
  60. upd_graph :: CmmGraph -> BidMap -> CmmGraph
  61. upd_graph g subst = map_nodes id middle last g
  62. where middle = mapExpDeepMiddle exp
  63. last l = last' (mapExpDeepLast exp l)
  64. last' (LastBranch bid) = LastBranch $ sub bid
  65. last' (LastCondBranch p t f) = cond p (sub t) (sub f)
  66. last' (LastCall t (Just bid) args res u) = LastCall t (Just $ sub bid) args res u
  67. last' l@(LastCall _ Nothing _ _ _) = l
  68. last' (LastSwitch e bs) = LastSwitch e $ map (liftM sub) bs
  69. cond p t f = if t == f then LastBranch t else LastCondBranch p t f
  70. exp (CmmStackSlot (CallArea (Young id)) off) =
  71. CmmStackSlot (CallArea (Young (sub id))) off
  72. exp (CmmLit (CmmBlock id)) = CmmLit (CmmBlock (sub id))
  73. exp e = e
  74. sub = lookupBid subst
  75. -- To speed up comparisons, we hash each basic block modulo labels.
  76. -- The hashing is a bit arbitrary (the numbers are completely arbitrary),
  77. -- but it should be fast and good enough.
  78. hash_block :: CmmBlock -> Int
  79. hash_block (Block _ t) =
  80. fromIntegral (hash_tail t (0 :: Word32) .&. (0x7fffffff :: Word32))
  81. -- UniqFM doesn't like negative Ints
  82. where hash_mid (MidComment (FastString u _ _ _ _)) = cvt u
  83. hash_mid (MidAssign r e) = hash_reg r + hash_e e
  84. hash_mid (MidStore e e') = hash_e e + hash_e e'
  85. hash_mid (MidForeignCall _ t _ as) = hash_tgt t + hash_lst hash_e as
  86. hash_reg :: CmmReg -> Word32
  87. hash_reg (CmmLocal l) = hash_local l
  88. hash_reg (CmmGlobal _) = 19
  89. hash_local (LocalReg _ _) = 117
  90. hash_e :: CmmExpr -> Word32
  91. hash_e (CmmLit l) = hash_lit l
  92. hash_e (CmmLoad e _) = 67 + hash_e e
  93. hash_e (CmmReg r) = hash_reg r
  94. hash_e (CmmMachOp _ es) = hash_lst hash_e es -- pessimal - no operator check
  95. hash_e (CmmRegOff r i) = hash_reg r + cvt i
  96. hash_e (CmmStackSlot _ _) = 13
  97. hash_lit :: CmmLit -> Word32
  98. hash_lit (CmmInt i _) = fromInteger i
  99. hash_lit (CmmFloat r _) = truncate r
  100. hash_lit (CmmLabel _) = 119 -- ugh
  101. hash_lit (CmmLabelOff _ i) = cvt $ 199 + i
  102. hash_lit (CmmLabelDiffOff _ _ i) = cvt $ 299 + i
  103. hash_lit (CmmBlock _) = 191 -- ugh
  104. hash_lit (CmmHighStackMark) = cvt 313
  105. hash_tgt (ForeignTarget e _) = hash_e e
  106. hash_tgt (PrimTarget _) = 31 -- lots of these
  107. hash_lst f = foldl (\z x -> f x + z) (0::Word32)
  108. hash_last (LastBranch _) = 23 -- would be great to hash these properly
  109. hash_last (LastCondBranch p _ _) = hash_e p
  110. hash_last (LastCall e _ _ _ _) = hash_e e
  111. hash_last (LastSwitch e _) = hash_e e
  112. hash_tail (ZLast LastExit) v = 29 + v `shiftL` 1
  113. hash_tail (ZLast (LastOther l)) v = hash_last l + (v `shiftL` 1)
  114. hash_tail (ZTail m t) v = hash_tail t (hash_mid m + (v `shiftL` 1))
  115. cvt = fromInteger . toInteger
  116. -- Utilities: equality and substitution on the graph.
  117. -- Given a map ``subst'' from BlockID -> BlockID, we define equality.
  118. eqBid :: BidMap -> BlockId -> BlockId -> Bool
  119. eqBid subst bid bid' = lookupBid subst bid == lookupBid subst bid'
  120. lookupBid :: BidMap -> BlockId -> BlockId
  121. lookupBid subst bid = case lookupBlockEnv subst bid of
  122. Just bid -> lookupBid subst bid
  123. Nothing -> bid
  124. -- Equality on the body of a block, modulo a function mapping block IDs to block IDs.
  125. eqBlockBodyWith :: (BlockId -> BlockId -> Bool) -> CmmBlock -> CmmBlock -> Bool
  126. eqBlockBodyWith eqBid (Block _ t) (Block _ t') = eqTailWith eqBid t t'
  127. type CmmTail = ZTail Middle Last
  128. eqTailWith :: (BlockId -> BlockId -> Bool) -> CmmTail -> CmmTail -> Bool
  129. eqTailWith eqBid (ZTail m t) (ZTail m' t') = m == m' && eqTailWith eqBid t t'
  130. eqTailWith _ (ZLast LastExit) (ZLast LastExit) = True
  131. eqTailWith eqBid (ZLast (LastOther l)) (ZLast (LastOther l')) = eqLastWith eqBid l l'
  132. eqTailWith _ _ _ = False
  133. eqLastWith :: (BlockId -> BlockId -> Bool) -> Last -> Last -> Bool
  134. eqLastWith eqBid (LastBranch bid1) (LastBranch bid2) = eqBid bid1 bid2
  135. eqLastWith eqBid (LastCondBranch c1 t1 f1) (LastCondBranch c2 t2 f2) =
  136. c1 == c2 && eqBid t1 t2 && eqBid f1 f2
  137. eqLastWith eqBid (LastCall t1 c1 a1 r1 u1) (LastCall t2 c2 a2 r2 u2) =
  138. t1 == t2 && eqMaybeWith eqBid c1 c2 && a1 == a2 && r1 == r2 && u1 == u2
  139. eqLastWith eqBid (LastSwitch e1 bs1) (LastSwitch e2 bs2) =
  140. e1 == e2 && eqLstWith (eqMaybeWith eqBid) bs1 bs2
  141. eqLastWith _ _ _ = False
  142. eqLstWith :: (a -> b -> Bool) -> [a] -> [b] -> Bool
  143. eqLstWith eltEq es es' = all (uncurry eltEq) (List.zip es es')
  144. eqMaybeWith :: (a -> b -> Bool) -> Maybe a -> Maybe b -> Bool
  145. eqMaybeWith eltEq (Just e) (Just e') = eltEq e e'
  146. eqMaybeWith _ Nothing Nothing = True
  147. eqMaybeWith _ _ _ = False