PageRenderTime 54ms CodeModel.GetById 23ms RepoModel.GetById 0ms app.codeStats 0ms

/compiler/cmm/CmmCommonBlockElim.hs

https://bitbucket.org/carter/ghc
Haskell | 208 lines | 137 code | 36 blank | 35 comment | 29 complexity | a4dc7125b5d68bd9487af338c8a91ec4 MD5 | raw file
  1. {-# LANGUAGE GADTs #-}
  2. -- ToDo: remove -fno-warn-warnings-deprecations
  3. {-# OPTIONS_GHC -fno-warn-warnings-deprecations #-}
  4. -- ToDo: remove -fno-warn-incomplete-patterns
  5. {-# OPTIONS_GHC -fno-warn-incomplete-patterns #-}
  6. module CmmCommonBlockElim
  7. ( elimCommonBlocks
  8. )
  9. where
  10. import BlockId
  11. import Cmm
  12. import CmmUtils
  13. import CmmContFlowOpt
  14. import Prelude hiding (iterate, succ, unzip, zip)
  15. import Hoopl hiding (ChangeFlag)
  16. import Data.Bits
  17. import qualified Data.List as List
  18. import Data.Word
  19. import Outputable
  20. import UniqFM
  21. my_trace :: String -> SDoc -> a -> a
  22. my_trace = if False then pprTrace else \_ _ a -> a
  23. -- -----------------------------------------------------------------------------
  24. -- Eliminate common blocks
  25. -- If two blocks are identical except for the label on the first node,
  26. -- then we can eliminate one of the blocks. To ensure that the semantics
  27. -- of the program are preserved, we have to rewrite each predecessor of the
  28. -- eliminated block to proceed with the block we keep.
  29. -- The algorithm iterates over the blocks in the graph,
  30. -- checking whether it has seen another block that is equal modulo labels.
  31. -- If so, then it adds an entry in a map indicating that the new block
  32. -- is made redundant by the old block.
  33. -- Otherwise, it is added to the useful blocks.
  34. -- TODO: Use optimization fuel
  35. elimCommonBlocks :: CmmGraph -> CmmGraph
  36. elimCommonBlocks g = replaceLabels env g
  37. where
  38. env = iterate hashed_blocks mapEmpty
  39. hashed_blocks = map (\b -> (hash_block b, b)) $ postorderDfs g
  40. -- Iterate over the blocks until convergence
  41. iterate :: [(HashCode,CmmBlock)] -> BlockEnv BlockId -> BlockEnv BlockId
  42. iterate blocks subst =
  43. case foldl common_block (False, emptyUFM, subst) blocks of
  44. (changed, _, subst)
  45. | changed -> iterate blocks subst
  46. | otherwise -> subst
  47. type State = (ChangeFlag, UniqFM [CmmBlock], BlockEnv BlockId)
  48. type ChangeFlag = Bool
  49. type HashCode = Int
  50. -- Try to find a block that is equal (or ``common'') to b.
  51. common_block :: State -> (HashCode, CmmBlock) -> State
  52. common_block (old_change, bmap, subst) (hash, b) =
  53. case lookupUFM bmap hash of
  54. Just bs -> case (List.find (eqBlockBodyWith (eqBid subst) b) bs,
  55. mapLookup bid subst) of
  56. (Just b', Nothing) -> addSubst b'
  57. (Just b', Just b'') | entryLabel b' /= b'' -> addSubst b'
  58. | otherwise -> (old_change, bmap, subst)
  59. _ -> (old_change, addToUFM bmap hash (b : bs), subst)
  60. Nothing -> (old_change, addToUFM bmap hash [b], subst)
  61. where bid = entryLabel b
  62. addSubst b' = my_trace "found new common block" (ppr bid <> char '=' <> ppr (entryLabel b')) $
  63. (True, bmap, mapInsert bid (entryLabel b') subst)
  64. -- -----------------------------------------------------------------------------
  65. -- Hashing and equality on blocks
  66. -- Below here is mostly boilerplate: hashing blocks ignoring labels,
  67. -- and comparing blocks modulo a label mapping.
  68. -- To speed up comparisons, we hash each basic block modulo labels.
  69. -- The hashing is a bit arbitrary (the numbers are completely arbitrary),
  70. -- but it should be fast and good enough.
  71. hash_block :: CmmBlock -> HashCode
  72. hash_block block =
  73. fromIntegral (foldBlockNodesB3 (hash_fst, hash_mid, hash_lst) block (0 :: Word32) .&. (0x7fffffff :: Word32))
  74. -- UniqFM doesn't like negative Ints
  75. where hash_fst _ h = h
  76. hash_mid m h = hash_node m + h `shiftL` 1
  77. hash_lst m h = hash_node m + h `shiftL` 1
  78. hash_node :: CmmNode O x -> Word32
  79. hash_node (CmmComment _) = 0 -- don't care
  80. hash_node (CmmAssign r e) = hash_reg r + hash_e e
  81. hash_node (CmmStore e e') = hash_e e + hash_e e'
  82. hash_node (CmmUnsafeForeignCall t _ as) = hash_tgt t + hash_list hash_e as
  83. hash_node (CmmBranch _) = 23 -- NB. ignore the label
  84. hash_node (CmmCondBranch p _ _) = hash_e p
  85. hash_node (CmmCall e _ _ _ _ _) = hash_e e
  86. hash_node (CmmForeignCall t _ _ _ _ _) = hash_tgt t
  87. hash_node (CmmSwitch e _) = hash_e e
  88. hash_reg :: CmmReg -> Word32
  89. hash_reg (CmmLocal _) = 117
  90. hash_reg (CmmGlobal _) = 19
  91. hash_e :: CmmExpr -> Word32
  92. hash_e (CmmLit l) = hash_lit l
  93. hash_e (CmmLoad e _) = 67 + hash_e e
  94. hash_e (CmmReg r) = hash_reg r
  95. hash_e (CmmMachOp _ es) = hash_list hash_e es -- pessimal - no operator check
  96. hash_e (CmmRegOff r i) = hash_reg r + cvt i
  97. hash_e (CmmStackSlot _ _) = 13
  98. hash_lit :: CmmLit -> Word32
  99. hash_lit (CmmInt i _) = fromInteger i
  100. hash_lit (CmmFloat r _) = truncate r
  101. hash_lit (CmmLabel _) = 119 -- ugh
  102. hash_lit (CmmLabelOff _ i) = cvt $ 199 + i
  103. hash_lit (CmmLabelDiffOff _ _ i) = cvt $ 299 + i
  104. hash_lit (CmmBlock _) = 191 -- ugh
  105. hash_lit (CmmHighStackMark) = cvt 313
  106. hash_tgt (ForeignTarget e _) = hash_e e
  107. hash_tgt (PrimTarget _) = 31 -- lots of these
  108. hash_list f = foldl (\z x -> f x + z) (0::Word32)
  109. cvt = fromInteger . toInteger
  110. -- Utilities: equality and substitution on the graph.
  111. -- Given a map ``subst'' from BlockID -> BlockID, we define equality.
  112. eqBid :: BlockEnv BlockId -> BlockId -> BlockId -> Bool
  113. eqBid subst bid bid' = lookupBid subst bid == lookupBid subst bid'
  114. lookupBid :: BlockEnv BlockId -> BlockId -> BlockId
  115. lookupBid subst bid = case mapLookup bid subst of
  116. Just bid -> lookupBid subst bid
  117. Nothing -> bid
  118. -- Middle nodes and expressions can contain BlockIds, in particular in
  119. -- CmmStackSlot and CmmBlock, so we have to use a special equality for
  120. -- these.
  121. --
  122. eqMiddleWith :: (BlockId -> BlockId -> Bool)
  123. -> CmmNode O O -> CmmNode O O -> Bool
  124. eqMiddleWith _ (CmmComment _) (CmmComment _) = True
  125. eqMiddleWith eqBid (CmmAssign r1 e1) (CmmAssign r2 e2)
  126. = r1 == r2 && eqExprWith eqBid e1 e2
  127. eqMiddleWith eqBid (CmmStore l1 r1) (CmmStore l2 r2)
  128. = eqExprWith eqBid l1 l2 && eqExprWith eqBid r1 r2
  129. eqMiddleWith eqBid (CmmUnsafeForeignCall t1 r1 a1)
  130. (CmmUnsafeForeignCall t2 r2 a2)
  131. = t1 == t2 && r1 == r2 && and (zipWith (eqExprWith eqBid) a1 a2)
  132. eqMiddleWith _ _ _ = False
  133. eqExprWith :: (BlockId -> BlockId -> Bool)
  134. -> CmmExpr -> CmmExpr -> Bool
  135. eqExprWith eqBid = eq
  136. where
  137. CmmLit l1 `eq` CmmLit l2 = eqLit l1 l2
  138. CmmLoad e1 _ `eq` CmmLoad e2 _ = e1 `eq` e2
  139. CmmReg r1 `eq` CmmReg r2 = r1==r2
  140. CmmRegOff r1 i1 `eq` CmmRegOff r2 i2 = r1==r2 && i1==i2
  141. CmmMachOp op1 es1 `eq` CmmMachOp op2 es2 = op1==op2 && es1 `eqs` es2
  142. CmmStackSlot a1 i1 `eq` CmmStackSlot a2 i2 = eqArea a1 a2 && i1==i2
  143. _e1 `eq` _e2 = False
  144. xs `eqs` ys = and (zipWith eq xs ys)
  145. eqLit (CmmBlock id1) (CmmBlock id2) = eqBid id1 id2
  146. eqLit l1 l2 = l1 == l2
  147. eqArea Old Old = True
  148. eqArea (Young id1) (Young id2) = eqBid id1 id2
  149. eqArea _ _ = False
  150. -- Equality on the body of a block, modulo a function mapping block
  151. -- IDs to block IDs.
  152. eqBlockBodyWith :: (BlockId -> BlockId -> Bool) -> CmmBlock -> CmmBlock -> Bool
  153. eqBlockBodyWith eqBid block block'
  154. = and (zipWith (eqMiddleWith eqBid) (blockToList m) (blockToList m')) &&
  155. eqLastWith eqBid l l'
  156. where (_,m,l) = blockSplit block
  157. (_,m',l') = blockSplit block'
  158. eqLastWith :: (BlockId -> BlockId -> Bool) -> CmmNode O C -> CmmNode O C -> Bool
  159. eqLastWith eqBid (CmmBranch bid1) (CmmBranch bid2) = eqBid bid1 bid2
  160. eqLastWith eqBid (CmmCondBranch c1 t1 f1) (CmmCondBranch c2 t2 f2) =
  161. c1 == c2 && eqBid t1 t2 && eqBid f1 f2
  162. eqLastWith eqBid (CmmCall t1 c1 g1 a1 r1 u1) (CmmCall t2 c2 g2 a2 r2 u2) =
  163. t1 == t2 && eqMaybeWith eqBid c1 c2 && a1 == a2 && r1 == r2 && u1 == u2 && g1 == g2
  164. eqLastWith eqBid (CmmSwitch e1 bs1) (CmmSwitch e2 bs2) =
  165. e1 == e2 && eqListWith (eqMaybeWith eqBid) bs1 bs2
  166. eqLastWith _ _ _ = False
  167. eqListWith :: (a -> b -> Bool) -> [a] -> [b] -> Bool
  168. eqListWith eltEq es es' = all (uncurry eltEq) (List.zip es es')
  169. eqMaybeWith :: (a -> b -> Bool) -> Maybe a -> Maybe b -> Bool
  170. eqMaybeWith eltEq (Just e) (Just e') = eltEq e e'
  171. eqMaybeWith _ Nothing Nothing = True
  172. eqMaybeWith _ _ _ = False