summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBen Gamari <bgamari.foss@gmail.com>2017-09-21 18:02:36 -0400
committerBen Gamari <ben@smart-cactus.org>2017-09-21 18:02:37 -0400
commit9aa73892e10e90a1799b9277da593e816a827364 (patch)
treec64d7a5ce4c625192fcfb2f01080d76910ab7406
parentddb38b51b8211247c2e31ddfcb96fe86479b9a9b (diff)
downloadhaskell-9aa73892e10e90a1799b9277da593e816a827364.tar.gz
cmm/CBE: Use foldLocalRegsDefd
Simonpj suggested this as a follow-on to #14226 to avoid code duplication. This also gives us the ability to CBE cases involving foreign calls for free. Test Plan: Validate Reviewers: austin, simonmar, simonpj Reviewed By: simonpj Subscribers: michalt, simonpj, rwbarton, thomie GHC Trac Issues: #14226 Differential Revision: https://phabricator.haskell.org/D3999
-rw-r--r--compiler/cmm/CmmCommonBlockElim.hs168
-rw-r--r--compiler/cmm/CmmPipeline.hs2
2 files changed, 95 insertions, 75 deletions
diff --git a/compiler/cmm/CmmCommonBlockElim.hs b/compiler/cmm/CmmCommonBlockElim.hs
index aca39bc9d0..c83497e036 100644
--- a/compiler/cmm/CmmCommonBlockElim.hs
+++ b/compiler/cmm/CmmCommonBlockElim.hs
@@ -24,6 +24,7 @@ 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
@@ -59,11 +60,11 @@ import Control.Arrow (first, second)
-- rightfully complained: #10397
-- TODO: Use optimization fuel
-elimCommonBlocks :: CmmGraph -> CmmGraph
-elimCommonBlocks g = replaceLabels env $ copyTicks env g
+elimCommonBlocks :: DynFlags -> CmmGraph -> CmmGraph
+elimCommonBlocks dflags g = replaceLabels env $ copyTicks env g
where
- env = iterate mapEmpty blocks_with_key
- groups = groupByInt hash_block (postorderDfs g)
+ env = iterate dflags mapEmpty blocks_with_key
+ groups = groupByInt (hash_block dflags) (postorderDfs g)
blocks_with_key = [ [ (successors b, [b]) | b <- bs] | bs <- groups]
-- Invariant: The blocks in the list are pairwise distinct
@@ -73,42 +74,47 @@ type Key = [Label]
type Subst = LabelMap BlockId
-- The outer list groups by hash. We retain this grouping throughout.
-iterate :: Subst -> [[(Key, DistinctBlocks)]] -> Subst
-iterate subst blocks
+iterate :: DynFlags -> Subst -> [[(Key, DistinctBlocks)]] -> Subst
+iterate dflags subst blocks
| mapNull new_substs = subst
- | otherwise = iterate subst' updated_blocks
+ | otherwise = iterate dflags 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 subst dbs
+ (new_subst2, db) = mergeBlockList dflags subst dbs
subst' = subst `mapUnion` new_substs
updated_blocks = map (map (first (map (lookupBid subst')))) merged_blocks
-mergeBlocks :: Subst -> DistinctBlocks -> DistinctBlocks -> (Subst, DistinctBlocks)
-mergeBlocks subst existing new = go new
+mergeBlocks :: DynFlags -> Subst
+ -> DistinctBlocks -> DistinctBlocks
+ -> (Subst, DistinctBlocks)
+mergeBlocks dflags subst existing new = go new
where
go [] = (mapEmpty, existing)
- 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
+ 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
where
go !new_subst1 b [] = (new_subst1, b)
go !new_subst1 b1 (b2:bs) = go new_subst b bs
where
- (new_subst2, b) = mergeBlocks subst b1 b2
+ (new_subst2, b) = mergeBlocks dflags subst b1 b2
new_subst = new_subst1 `mapUnion` new_subst2
@@ -175,8 +181,8 @@ data HashEnv = HashEnv { localRegHashEnv :: !(LocalRegEnv DeBruijn)
, nextIndex :: !DeBruijn
}
-hash_block :: CmmBlock -> HashCode
-hash_block block =
+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)
@@ -196,20 +202,24 @@ hash_block block =
hash_node :: HashEnv -> CmmNode O x -> (HashEnv, Word32)
hash_node env n =
- case n of
- n | dont_care n -> pure_ 0 -- don't care
- CmmAssign (CmmLocal r) e -> (bind_local_reg r env, hash_e env e)
- CmmAssign r e -> pure_ $ hash_reg env r + hash_e env e
- CmmStore e e' -> pure_ $ hash_e env e + hash_e env e'
- CmmUnsafeForeignCall t _ as
- -> pure_ $ hash_tgt env t + hash_list (hash_e env) as
- CmmBranch _ -> pure_ 23 -- NB. ignore the label
- CmmCondBranch p _ _ _ -> pure_ $ hash_e env p
- CmmCall e _ _ _ _ _ -> pure_ $ hash_e env e
- CmmForeignCall t _ _ _ _ _ _ -> pure_ $ hash_tgt env t
- CmmSwitch e _ -> pure_ $ hash_e env e
- _ -> error "hash_node: unknown Cmm node!"
- where pure_ x = (env, x)
+ (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)
@@ -281,38 +291,45 @@ type LocalRegMapping = LocalRegEnv LocalReg
-- CmmStackSlot and CmmBlock, so we have to use a special equality for
-- these.
--
-eqMiddleWith :: (BlockId -> BlockId -> Bool)
+eqMiddleWith :: DynFlags
+ -> (BlockId -> BlockId -> Bool)
-> LocalRegMapping
-> CmmNode O O -> CmmNode O O
-> (LocalRegMapping, Bool)
-eqMiddleWith eqBid env a b =
+eqMiddleWith dflags eqBid env a b =
case (a, b) of
- (CmmAssign (CmmLocal r1) e1, CmmAssign (CmmLocal r2) e2) ->
+ -- registers aren't compared since they are binding occurrences
+ (CmmAssign (CmmLocal _) e1, CmmAssign (CmmLocal _) e2) ->
let eq = eqExprWith eqBid env e1 e2
- env' = addToUFM env r1 r2
in (env', eq)
(CmmAssign r1 e1, CmmAssign r2 e2) ->
let eq = r1 == r2
&& eqExprWith eqBid env e1 e2
- in (env, eq)
+ in (env', eq)
(CmmStore l1 r1, CmmStore l2 r2) ->
let eq = eqExprWith eqBid env l1 l2
&& eqExprWith eqBid env r1 r2
- in (env, eq)
+ in (env', eq)
- (CmmUnsafeForeignCall t1 r1 a1, CmmUnsafeForeignCall t2 r2 a2) ->
+ -- result registers aren't compared since they are binding occurrences
+ (CmmUnsafeForeignCall t1 _ a1, CmmUnsafeForeignCall t2 _ a2) ->
let eq = t1 == t2
- && r1 == r2
&& and (zipWith (eqExprWith eqBid env) a1 a2)
- in (env, eq)
+ 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
eqExprWith :: (BlockId -> BlockId -> Bool)
-> LocalRegMapping
- -> CmmExpr -> CmmExpr -> Bool
+ -> CmmExpr -> CmmExpr
+ -> Bool
eqExprWith eqBid env = eq
where
CmmLit l1 `eq` CmmLit l2 = eqLit l1 l2
@@ -340,47 +357,50 @@ eqExprWith eqBid env = eq
-- Equality on the body of a block, modulo a function mapping block
-- IDs to block IDs.
-eqBlockBodyWith :: (BlockId -> BlockId -> Bool) -> CmmBlock -> CmmBlock -> Bool
-eqBlockBodyWith eqBid block block'
+eqBlockBodyWith :: DynFlags
+ -> (BlockId -> BlockId -> Bool)
+ -> CmmBlock -> CmmBlock -> Bool
+eqBlockBodyWith dflags eqBid block block'
{-
| equal = pprTrace "equal" (vcat [ppr block, ppr block']) True
| otherwise = pprTrace "not equal" (vcat [ppr block, ppr block']) False
-}
- = equal_go emptyUFM nodes nodes'
+ = equal
where (_,m,l) = blockSplit block
nodes = filter (not . dont_care) (blockToList m)
(_,m',l') = blockSplit block'
nodes' = filter (not . dont_care) (blockToList m')
- -- Compare middle nodes, accumulating a local register mapping as we go.
- -- We also must ensure that the lists are of equal length. Finally,
- -- compare the last nodes.
- equal_go :: LocalRegMapping -> [CmmNode O O] -> [CmmNode O O] -> Bool
- equal_go acc (a:as) (b:bs)
- | let (acc', eq) = eqMiddleWith eqBid acc a b
- , eq
- = equal_go acc' as bs
- equal_go acc [] [] = eqLastWith eqBid acc l l'
- equal_go _ _ _ = False
+ (env_mid, eqs_mid) =
+ List.mapAccumL (\acc (a,b) -> eqMiddleWith dflags eqBid acc a b)
+ emptyUFM
+ (List.zip nodes nodes')
+ equal = and eqs_mid && eqLastWith eqBid env_mid l l'
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) ->
- eqExprWith eqBid env 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
- _ -> False
+ 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
+ && and (zipWith (eqExprWith eqBid env) a1 a2)
+ && s1 == s2
+ && ret_args1 == ret_args2
+ && ret_off1 == ret_off2
+ && intrbl1 == intrbl2
+ _ -> 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 4d109a4086..b90b92a92f 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 g
+ condPass Opt_CmmElimCommonBlocks (elimCommonBlocks dflags) g
Opt_D_dump_cmm_cbe "Post common block elimination"
-- Any work storing block Labels must be performed _after_