summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--compiler/cmm/CmmCommonBlockElim.hs320
-rw-r--r--compiler/cmm/CmmPipeline.hs2
-rw-r--r--compiler/cmm/Hoopl/Block.hs1
3 files changed, 86 insertions, 237 deletions
diff --git a/compiler/cmm/CmmCommonBlockElim.hs b/compiler/cmm/CmmCommonBlockElim.hs
index 26004fb9e7..2c889b382a 100644
--- a/compiler/cmm/CmmCommonBlockElim.hs
+++ b/compiler/cmm/CmmCommonBlockElim.hs
@@ -24,7 +24,6 @@ import qualified Data.List as List
import Data.Word
import qualified Data.Map as M
import Outputable
-import DynFlags (DynFlags)
import UniqFM
import UniqDFM
import qualified TrieMap as TM
@@ -60,11 +59,11 @@ import Control.Arrow (first, second)
-- rightfully complained: #10397
-- TODO: Use optimization fuel
-elimCommonBlocks :: DynFlags -> CmmGraph -> CmmGraph
-elimCommonBlocks dflags g = replaceLabels env $ copyTicks env g
+elimCommonBlocks :: CmmGraph -> CmmGraph
+elimCommonBlocks g = replaceLabels env $ copyTicks env g
where
- env = iterate dflags mapEmpty blocks_with_key
- groups = groupByInt (hash_block dflags) (postorderDfs g)
+ env = iterate mapEmpty blocks_with_key
+ groups = groupByInt hash_block (postorderDfs g)
blocks_with_key = [ [ (successors b, [b]) | b <- bs] | bs <- groups]
-- Invariant: The blocks in the list are pairwise distinct
@@ -74,47 +73,42 @@ type Key = [Label]
type Subst = LabelMap BlockId
-- The outer list groups by hash. We retain this grouping throughout.
-iterate :: DynFlags -> Subst -> [[(Key, DistinctBlocks)]] -> Subst
-iterate dflags subst blocks
+iterate :: Subst -> [[(Key, DistinctBlocks)]] -> Subst
+iterate subst blocks
| mapNull new_substs = subst
- | otherwise = iterate dflags subst' updated_blocks
+ | otherwise = iterate subst' updated_blocks
where
grouped_blocks :: [[(Key, [DistinctBlocks])]]
grouped_blocks = map groupByLabel blocks
merged_blocks :: [[(Key, DistinctBlocks)]]
- (new_substs, merged_blocks) =
- List.mapAccumL (List.mapAccumL go) mapEmpty grouped_blocks
+ (new_substs, merged_blocks) = List.mapAccumL (List.mapAccumL go) mapEmpty grouped_blocks
where
go !new_subst1 (k,dbs) = (new_subst1 `mapUnion` new_subst2, (k,db))
where
- (new_subst2, db) = mergeBlockList dflags subst dbs
+ (new_subst2, db) = mergeBlockList subst dbs
subst' = subst `mapUnion` new_substs
updated_blocks = map (map (first (map (lookupBid subst')))) merged_blocks
-mergeBlocks :: DynFlags -> Subst
- -> DistinctBlocks -> DistinctBlocks
- -> (Subst, DistinctBlocks)
-mergeBlocks dflags subst existing new = go new
+mergeBlocks :: Subst -> DistinctBlocks -> DistinctBlocks -> (Subst, DistinctBlocks)
+mergeBlocks subst existing new = go new
where
go [] = (mapEmpty, existing)
- go (b:bs) =
- case List.find (eqBlockBodyWith dflags (eqBid subst) b) existing of
- -- This block is a duplicate. Drop it, and add it to the substitution
- Just b' -> first (mapInsert (entryLabel b) (entryLabel b')) $ go bs
- -- This block is not a duplicate, keep it.
- Nothing -> second (b:) $ go bs
-
-mergeBlockList :: DynFlags -> Subst -> [DistinctBlocks]
- -> (Subst, DistinctBlocks)
-mergeBlockList _ _ [] = pprPanic "mergeBlockList" empty
-mergeBlockList dflags subst (b:bs) = go mapEmpty b bs
+ go (b:bs) = case List.find (eqBlockBodyWith (eqBid subst) b) existing of
+ -- This block is a duplicate. Drop it, and add it to the substitution
+ Just b' -> first (mapInsert (entryLabel b) (entryLabel b')) $ go bs
+ -- This block is not a duplicate, keep it.
+ Nothing -> second (b:) $ go bs
+
+mergeBlockList :: Subst -> [DistinctBlocks] -> (Subst, DistinctBlocks)
+mergeBlockList _ [] = pprPanic "mergeBlockList" empty
+mergeBlockList subst (b:bs) = go mapEmpty b bs
where
go !new_subst1 b [] = (new_subst1, b)
go !new_subst1 b1 (b2:bs) = go new_subst b bs
where
- (new_subst2, b) = mergeBlocks dflags subst b1 b2
+ (new_subst2, b) = mergeBlocks subst b1 b2
new_subst = new_subst1 `mapUnion` new_subst2
@@ -132,110 +126,39 @@ mergeBlockList dflags subst (b:bs) = go mapEmpty b bs
-- expensive. So include as much as possible in the hash. Ideally everything
-- that is compared with (==) in eqBlockBodyWith.
-{-
-Note [Equivalence up to local registers in CBE]
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-CBE treats two blocks which are equivalent up to alpha-renaming of locally-bound
-local registers as equivalent. This was not always the case (see #14226) but is
-quite important for effective CBE. For instance, consider the blocks,
-
- c2VZ: // global
- _c2Yd::I64 = _s2Se::I64 + 1;
- _s2Sx::I64 = _c2Yd::I64;
- _s2Se::I64 = _s2Sx::I64;
- goto c2TE;
-
- c2VY: // global
- _c2Yb::I64 = _s2Se::I64 + 1;
- _s2Sw::I64 = _c2Yb::I64;
- _s2Se::I64 = _s2Sw::I64;
- goto c2TE;
-
-These clearly implement precisely the same logic, differing only register
-naming. This happens quite often in the code produced by GHC.
-
-This alpha-equivalence relation must be accounted for in two places:
-
- 1. the block hash function (hash_block), which we use for approximate "binning"
- 2. the exact block comparison function, which computes pair-wise equivalence
-
-In (1) we maintain a de Bruijn numbering of each block's locally-bound local
-registers and compute the hash relative to this numbering.
-
-For (2) we maintain a substitution which maps the local registers of one block
-onto those of the other. We then compare local registers modulo this
-substitution.
-
--}
-
type HashCode = Int
-type LocalRegEnv a = UniqFM a
-type DeBruijn = Int
-
--- | Maintains a de Bruijn numbering of local registers bound within a block.
---
--- See Note [Equivalence up to local registers in CBE]
-data HashEnv = HashEnv { localRegHashEnv :: !(LocalRegEnv DeBruijn)
- , nextIndex :: !DeBruijn
- }
-
-hash_block :: DynFlags -> CmmBlock -> HashCode
-hash_block dflags block =
- --pprTrace "hash_block" (ppr (entryLabel block) $$ ppr hash)
- hash
- where hash_fst _ (env, h) = (env, h)
- hash_mid m (env, h) = let (env', h') = hash_node env m
- in (env', h' + h `shiftL` 1)
- hash_lst m (env, h) = let (env', h') = hash_node env m
- in (env', h' + h `shiftL` 1)
-
- hash =
- let (_, raw_hash) =
- foldBlockNodesF3 (hash_fst, hash_mid, hash_lst)
- block
- (emptyEnv, 0 :: Word32)
- emptyEnv = HashEnv mempty 0
- in fromIntegral (raw_hash .&. (0x7fffffff :: Word32))
- -- UniqFM doesn't like negative Ints
-
- hash_node :: HashEnv -> CmmNode O x -> (HashEnv, Word32)
- hash_node env n =
- (env', hash)
- where
- hash =
- case n of
- n | dont_care n -> 0 -- don't care
- -- don't include register as it is a binding occurrence
- CmmAssign (CmmLocal _) e -> hash_e env e
- CmmAssign r e -> hash_reg env r + hash_e env e
- CmmStore e e' -> hash_e env e + hash_e env e'
- CmmUnsafeForeignCall t _ as
- -> hash_tgt env t + hash_list (hash_e env) as
- CmmBranch _ -> 23 -- NB. ignore the label
- CmmCondBranch p _ _ _ -> hash_e env p
- CmmCall e _ _ _ _ _ -> hash_e env e
- CmmForeignCall t _ _ _ _ _ _ -> hash_tgt env t
- CmmSwitch e _ -> hash_e env e
- _ -> error "hash_node: unknown Cmm node!"
- env' = foldLocalRegsDefd dflags (flip bind_local_reg) env n
-
- hash_reg :: HashEnv -> CmmReg -> Word32
- hash_reg env (CmmLocal localReg)
- | Just idx <- lookupUFM (localRegHashEnv env) localReg
- = fromIntegral idx
- | otherwise
- = hash_unique localReg -- important for performance, see #10397
- hash_reg _ (CmmGlobal _) = 19
-
- hash_e :: HashEnv -> CmmExpr -> Word32
- hash_e _ (CmmLit l) = hash_lit l
- hash_e env (CmmLoad e _) = 67 + hash_e env e
- hash_e env (CmmReg r) = hash_reg env r
- hash_e env (CmmMachOp _ es) = hash_list (hash_e env) es -- pessimal - no operator check
- hash_e env (CmmRegOff r i) = hash_reg env r + cvt i
- hash_e _ (CmmStackSlot _ _) = 13
+hash_block :: CmmBlock -> HashCode
+hash_block block =
+ fromIntegral (foldBlockNodesB3 (hash_fst, hash_mid, hash_lst) block (0 :: Word32) .&. (0x7fffffff :: Word32))
+ -- UniqFM doesn't like negative Ints
+ where hash_fst _ h = h
+ hash_mid m h = hash_node m + h `shiftL` 1
+ hash_lst m h = hash_node m + h `shiftL` 1
+
+ hash_node :: CmmNode O x -> Word32
+ hash_node n | dont_care n = 0 -- don't care
+ hash_node (CmmAssign r e) = hash_reg r + hash_e e
+ hash_node (CmmStore e e') = hash_e e + hash_e e'
+ hash_node (CmmUnsafeForeignCall t _ as) = hash_tgt t + hash_list hash_e as
+ hash_node (CmmBranch _) = 23 -- NB. ignore the label
+ hash_node (CmmCondBranch p _ _ _) = hash_e p
+ hash_node (CmmCall e _ _ _ _ _) = hash_e e
+ hash_node (CmmForeignCall t _ _ _ _ _ _) = hash_tgt t
+ hash_node (CmmSwitch e _) = hash_e e
+ hash_node _ = error "hash_node: unknown Cmm node!"
+
+ hash_reg :: CmmReg -> Word32
+ hash_reg (CmmLocal localReg) = hash_unique localReg -- important for performance, see #10397
+ hash_reg (CmmGlobal _) = 19
+
+ hash_e :: CmmExpr -> Word32
+ hash_e (CmmLit l) = hash_lit l
+ hash_e (CmmLoad e _) = 67 + hash_e e
+ hash_e (CmmReg r) = hash_reg r
+ hash_e (CmmMachOp _ es) = hash_list hash_e es -- pessimal - no operator check
+ hash_e (CmmRegOff r i) = hash_reg r + cvt i
+ hash_e (CmmStackSlot _ _) = 13
hash_lit :: CmmLit -> Word32
hash_lit (CmmInt i _) = fromInteger i
@@ -247,21 +170,13 @@ hash_block dflags block =
hash_lit (CmmBlock _) = 191 -- ugh
hash_lit (CmmHighStackMark) = cvt 313
- hash_tgt :: HashEnv -> ForeignTarget -> Word32
- hash_tgt env (ForeignTarget e _) = hash_e env e
- hash_tgt _ (PrimTarget _) = 31 -- lots of these
+ hash_tgt (ForeignTarget e _) = hash_e e
+ hash_tgt (PrimTarget _) = 31 -- lots of these
- hash_list f = List.foldl' (\z x -> f x + z) (0::Word32)
+ hash_list f = foldl (\z x -> f x + z) (0::Word32)
cvt = fromInteger . toInteger
- bind_local_reg :: LocalReg -> HashEnv -> HashEnv
- bind_local_reg reg env =
- env { localRegHashEnv =
- addToUFM (localRegHashEnv env) reg (nextIndex env)
- , nextIndex = nextIndex env + 1
- }
-
hash_unique :: Uniquable a => a -> Word32
hash_unique = cvt . getKey . getUnique
@@ -282,76 +197,34 @@ lookupBid subst bid = case mapLookup bid subst of
Just bid -> lookupBid subst bid
Nothing -> bid
--- | Maps the local registers of one block to those of another
---
--- See Note [Equivalence up to local registers in CBE]
-type LocalRegMapping = LocalRegEnv LocalReg
-
-- Middle nodes and expressions can contain BlockIds, in particular in
-- CmmStackSlot and CmmBlock, so we have to use a special equality for
-- these.
--
-eqMiddleWith :: DynFlags
- -> (BlockId -> BlockId -> Bool)
- -> LocalRegMapping
- -> CmmNode O O -> CmmNode O O
- -> (LocalRegMapping, Bool)
-eqMiddleWith dflags eqBid env a b =
- case (a, b) of
- -- registers aren't compared since they are binding occurrences
- (CmmAssign (CmmLocal _) e1, CmmAssign (CmmLocal _) e2) ->
- let eq = eqExprWith eqBid env e1 e2
- in (env', eq)
-
- (CmmAssign r1 e1, CmmAssign r2 e2) ->
- let eq = r1 == r2
- && eqExprWith eqBid env e1 e2
- in (env', eq)
-
- (CmmStore l1 r1, CmmStore l2 r2) ->
- let eq = eqExprWith eqBid env l1 l2
- && eqExprWith eqBid env r1 r2
- in (env', eq)
-
- -- result registers aren't compared since they are binding occurrences
- (CmmUnsafeForeignCall t1 _ a1, CmmUnsafeForeignCall t2 _ a2) ->
- let eq = t1 == t2
- && eqLists (eqExprWith eqBid env) a1 a2
- in (env', eq)
-
- _ -> (env, False)
- where
- env' = List.foldl' (\acc (ra,rb) -> addToUFM acc ra rb) emptyUFM
- $ List.zip defd_a defd_b
- defd_a = foldLocalRegsDefd dflags (flip (:)) [] a
- defd_b = foldLocalRegsDefd dflags (flip (:)) [] b
-
-eqLists :: (a -> b -> Bool) -> [a] -> [b] -> Bool
-eqLists f (a:as) (b:bs) = f a b && eqLists f as bs
-eqLists _ [] [] = True
-eqLists _ _ _ = False
+eqMiddleWith :: (BlockId -> BlockId -> Bool)
+ -> CmmNode O O -> CmmNode O O -> Bool
+eqMiddleWith eqBid (CmmAssign r1 e1) (CmmAssign r2 e2)
+ = r1 == r2 && eqExprWith eqBid e1 e2
+eqMiddleWith eqBid (CmmStore l1 r1) (CmmStore l2 r2)
+ = eqExprWith eqBid l1 l2 && eqExprWith eqBid r1 r2
+eqMiddleWith eqBid (CmmUnsafeForeignCall t1 r1 a1)
+ (CmmUnsafeForeignCall t2 r2 a2)
+ = t1 == t2 && r1 == r2 && and (zipWith (eqExprWith eqBid) a1 a2)
+eqMiddleWith _ _ _ = False
eqExprWith :: (BlockId -> BlockId -> Bool)
- -> LocalRegMapping
- -> CmmExpr -> CmmExpr
- -> Bool
-eqExprWith eqBid env = eq
+ -> CmmExpr -> CmmExpr -> Bool
+eqExprWith eqBid = eq
where
CmmLit l1 `eq` CmmLit l2 = eqLit l1 l2
CmmLoad e1 _ `eq` CmmLoad e2 _ = e1 `eq` e2
- CmmReg r1 `eq` CmmReg r2 = r1 `eqReg` r2
- CmmRegOff r1 i1 `eq` CmmRegOff r2 i2 = r1 `eqReg` r2 && i1==i2
+ CmmReg r1 `eq` CmmReg r2 = r1==r2
+ CmmRegOff r1 i1 `eq` CmmRegOff r2 i2 = r1==r2 && i1==i2
CmmMachOp op1 es1 `eq` CmmMachOp op2 es2 = op1==op2 && es1 `eqs` es2
CmmStackSlot a1 i1 `eq` CmmStackSlot a2 i2 = eqArea a1 a2 && i1==i2
_e1 `eq` _e2 = False
- xs `eqs` ys = eqLists eq xs ys
-
- -- See Note [Equivalence up to local registers in CBE]
- CmmLocal a `eqReg` CmmLocal b
- | Just a' <- lookupUFM env a
- = a' == b
- a `eqReg` b = a == b
+ xs `eqs` ys = and (zipWith eq xs ys)
eqLit (CmmBlock id1) (CmmBlock id2) = eqBid id1 id2
eqLit l1 l2 = l1 == l2
@@ -362,10 +235,8 @@ eqExprWith eqBid env = eq
-- Equality on the body of a block, modulo a function mapping block
-- IDs to block IDs.
-eqBlockBodyWith :: DynFlags
- -> (BlockId -> BlockId -> Bool)
- -> CmmBlock -> CmmBlock -> Bool
-eqBlockBodyWith dflags eqBid block block'
+eqBlockBodyWith :: (BlockId -> BlockId -> Bool) -> CmmBlock -> CmmBlock -> Bool
+eqBlockBodyWith eqBid block block'
{-
| equal = pprTrace "equal" (vcat [ppr block, ppr block']) True
| otherwise = pprTrace "not equal" (vcat [ppr block, ppr block']) False
@@ -376,40 +247,19 @@ eqBlockBodyWith dflags eqBid block block'
(_,m',l') = blockSplit block'
nodes' = filter (not . dont_care) (blockToList m')
- eqMids :: LocalRegMapping -> [CmmNode O O] -> [CmmNode O O] -> Bool
- eqMids env (a:as) (b:bs)
- | eq = eqMids env' as bs
- where
- (env', eq) = eqMiddleWith dflags eqBid env a b
- eqMids env [] [] = eqLastWith eqBid env l l'
- eqMids _ _ _ = False
-
- equal = eqMids emptyUFM nodes nodes'
-
-
-eqLastWith :: (BlockId -> BlockId -> Bool) -> LocalRegMapping
- -> CmmNode O C -> CmmNode O C -> Bool
-eqLastWith eqBid env a b =
- case (a, b) of
- (CmmBranch bid1, CmmBranch bid2) -> eqBid bid1 bid2
- (CmmCondBranch c1 t1 f1 l1, CmmCondBranch c2 t2 f2 l2) ->
- eqExprWith eqBid env c1 c2 && l1 == l2 && eqBid t1 t2 && eqBid f1 f2
- (CmmCall t1 c1 g1 a1 r1 u1, CmmCall t2 c2 g2 a2 r2 u2) ->
- t1 == t2
- && eqMaybeWith eqBid c1 c2
- && a1 == a2 && r1 == r2 && u1 == u2 && g1 == g2
- (CmmSwitch e1 ids1, CmmSwitch e2 ids2) ->
- eqExprWith eqBid env e1 e2 && eqSwitchTargetWith eqBid ids1 ids2
- -- result registers aren't compared since they are binding occurrences
- (CmmForeignCall t1 _ a1 s1 ret_args1 ret_off1 intrbl1,
- CmmForeignCall t2 _ a2 s2 ret_args2 ret_off2 intrbl2) ->
- t1 == t2
- && eqLists (eqExprWith eqBid env) a1 a2
- && s1 == s2
- && ret_args1 == ret_args2
- && ret_off1 == ret_off2
- && intrbl1 == intrbl2
- _ -> False
+ equal = and (zipWith (eqMiddleWith eqBid) nodes nodes') &&
+ eqLastWith eqBid l l'
+
+
+eqLastWith :: (BlockId -> BlockId -> Bool) -> CmmNode O C -> CmmNode O C -> Bool
+eqLastWith eqBid (CmmBranch bid1) (CmmBranch bid2) = eqBid bid1 bid2
+eqLastWith eqBid (CmmCondBranch c1 t1 f1 l1) (CmmCondBranch c2 t2 f2 l2) =
+ c1 == c2 && l1 == l2 && eqBid t1 t2 && eqBid f1 f2
+eqLastWith eqBid (CmmCall t1 c1 g1 a1 r1 u1) (CmmCall t2 c2 g2 a2 r2 u2) =
+ t1 == t2 && eqMaybeWith eqBid c1 c2 && a1 == a2 && r1 == r2 && u1 == u2 && g1 == g2
+eqLastWith eqBid (CmmSwitch e1 ids1) (CmmSwitch e2 ids2) =
+ e1 == e2 && eqSwitchTargetWith eqBid ids1 ids2
+eqLastWith _ _ _ = False
eqMaybeWith :: (a -> b -> Bool) -> Maybe a -> Maybe b -> Bool
eqMaybeWith eltEq (Just e) (Just e') = eltEq e e'
diff --git a/compiler/cmm/CmmPipeline.hs b/compiler/cmm/CmmPipeline.hs
index b90b92a92f..4d109a4086 100644
--- a/compiler/cmm/CmmPipeline.hs
+++ b/compiler/cmm/CmmPipeline.hs
@@ -68,7 +68,7 @@ cpsTop hsc_env proc =
----------- Eliminate common blocks -------------------------------------
g <- {-# SCC "elimCommonBlocks" #-}
- condPass Opt_CmmElimCommonBlocks (elimCommonBlocks dflags) g
+ condPass Opt_CmmElimCommonBlocks elimCommonBlocks g
Opt_D_dump_cmm_cbe "Post common block elimination"
-- Any work storing block Labels must be performed _after_
diff --git a/compiler/cmm/Hoopl/Block.hs b/compiler/cmm/Hoopl/Block.hs
index 4561fef199..c4ff1794e8 100644
--- a/compiler/cmm/Hoopl/Block.hs
+++ b/compiler/cmm/Hoopl/Block.hs
@@ -24,7 +24,6 @@ module Hoopl.Block
, foldBlockNodesB
, foldBlockNodesB3
, foldBlockNodesF
- , foldBlockNodesF3
, isEmptyBlock
, lastNode
, mapBlock