summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlexis Williams <alexis@typedr.at>2019-12-25 11:48:33 -0800
committerAlexis Williams <alexis@typedr.at>2019-12-25 11:48:33 -0800
commitba18dfd316bf869540e3bf03d1b52aedb0165f97 (patch)
tree859ab3d244a723eac81e7af25e454abac270db86
parentecbce0507c5e247dcdbd41dc716e26ab6fb4b6ea (diff)
downloadhaskell-ba18dfd316bf869540e3bf03d1b52aedb0165f97.tar.gz
Attempt to speed up compiler with DList
-rw-r--r--compiler/GHC/StgToCmm/Layout.hs56
-rw-r--r--compiler/basicTypes/Avail.hs16
-rw-r--r--compiler/cmm/CmmNode.hs17
-rw-r--r--compiler/coreSyn/CoreLint.hs2
-rw-r--r--compiler/coreSyn/CoreSyn.hs11
-rw-r--r--compiler/coreSyn/CoreUtils.hs61
-rw-r--r--compiler/deSugar/DsBinds.hs13
-rw-r--r--compiler/deSugar/DsUsage.hs29
-rw-r--r--compiler/ghci/ByteCodeAsm.hs2
-rw-r--r--compiler/ghci/ByteCodeGen.hs9
-rw-r--r--compiler/utils/DList.hs21
11 files changed, 143 insertions, 94 deletions
diff --git a/compiler/GHC/StgToCmm/Layout.hs b/compiler/GHC/StgToCmm/Layout.hs
index f4834376ed..9e4f604a0e 100644
--- a/compiler/GHC/StgToCmm/Layout.hs
+++ b/compiler/GHC/StgToCmm/Layout.hs
@@ -1,5 +1,6 @@
{-# LANGUAGE BangPatterns #-}
{-# LANGUAGE CPP #-}
+{-# LANGUAGE ViewPatterns #-}
-----------------------------------------------------------------------------
--
@@ -52,6 +53,7 @@ import StgSyn
import Id
import TyCon ( PrimRep(..), primRepSizeB )
import BasicTypes ( RepArity )
+import qualified DList as DL
import DynFlags
import Module
@@ -362,19 +364,21 @@ just more arguments that we are passing on the stack (cml_args).
-- pushing on the stack for "extra" arguments to a function which requires
-- fewer arguments than we currently have.
slowArgs :: DynFlags -> [(ArgRep, Maybe CmmExpr)] -> [(ArgRep, Maybe CmmExpr)]
-slowArgs _ [] = []
-slowArgs dflags args -- careful: reps contains voids (V), but args does not
- | gopt Opt_SccProfilingOn dflags
- = save_cccs ++ this_pat ++ slowArgs dflags rest_args
- | otherwise = this_pat ++ slowArgs dflags rest_args
+slowArgs dflags args = DL.toList (go dflags args)
where
- (arg_pat, n) = slowCallPattern (map fst args)
- (call_args, rest_args) = splitAt n args
+ go _ [] = DL.empty
+ go dflags args -- careful: reps contains voids (V), but args does not
+ | gopt Opt_SccProfilingOn dflags
+ = save_cccs DL.++ this_pat DL.++ go dflags rest_args
+ | otherwise = this_pat DL.++ go dflags rest_args
+ where
+ (arg_pat, n) = slowCallPattern (map fst args)
+ (DL.fromList -> call_args, rest_args) = splitAt n args
- stg_ap_pat = mkCmmRetInfoLabel rtsUnitId arg_pat
- this_pat = (N, Just (mkLblExpr stg_ap_pat)) : call_args
- save_cccs = [(N, Just (mkLblExpr save_cccs_lbl)), (N, Just cccsExpr)]
- save_cccs_lbl = mkCmmRetInfoLabel rtsUnitId (fsLit "stg_restore_cccs")
+ stg_ap_pat = mkCmmRetInfoLabel rtsUnitId arg_pat
+ this_pat = DL.cons (N, Just (mkLblExpr stg_ap_pat)) call_args
+ save_cccs = DL.fromList [(N, Just (mkLblExpr save_cccs_lbl)), (N, Just cccsExpr)]
+ save_cccs_lbl = mkCmmRetInfoLabel rtsUnitId (fsLit "stg_restore_cccs")
-------------------------------------------------------------------------
---- Laying out objects on the heap and stack
@@ -427,9 +431,12 @@ mkVirtHeapOffsetsWithPadding dflags header things =
ASSERT(not (any (isVoidRep . fst . fromNonVoid) things))
( tot_wds
, bytesToWordsRoundUp dflags bytes_of_ptrs
- , concat (ptrs_w_offsets ++ non_ptrs_w_offsets) ++ final_pad
+ , DL.toList paddings_out
)
where
+ paddings_out = DL.concat ptrs_w_offsets DL.++ DL.concat non_ptrs_w_offsets
+ DL.++ final_pad
+
hdr_words = case header of
NoHeader -> 0
StdHeader -> fixedHdrSizeW dflags
@@ -447,9 +454,9 @@ mkVirtHeapOffsetsWithPadding dflags header things =
final_pad_size = tot_wds * word_size - tot_bytes
final_pad
- | final_pad_size > 0 = [(Padding final_pad_size
- (hdr_bytes + tot_bytes))]
- | otherwise = []
+ | final_pad_size > 0 = DL.singleton $
+ Padding final_pad_size (hdr_bytes + tot_bytes)
+ | otherwise = DL.empty
word_size = wORD_SIZE dflags
@@ -474,10 +481,11 @@ mkVirtHeapOffsetsWithPadding dflags header things =
field_off = FieldOff (NonVoid thing) final_offset
with_padding field_off
- | padding == 0 = [field_off]
- | otherwise = [ Padding padding (hdr_bytes + bytes_so_far)
- , field_off
- ]
+ | padding == 0 = DL.singleton field_off
+ | otherwise = DL.fromList
+ [ Padding padding (hdr_bytes + bytes_so_far)
+ , field_off
+ ]
mkVirtHeapOffsets
@@ -538,10 +546,12 @@ mkArgDescr dflags args
Nothing -> ArgGen arg_bits
argBits :: DynFlags -> [ArgRep] -> [Bool] -- True for non-ptr, False for ptr
-argBits _ [] = []
-argBits dflags (P : args) = False : argBits dflags args
-argBits dflags (arg : args) = take (argRepSizeW dflags arg) (repeat True)
- ++ argBits dflags args
+argBits dflags args = DL.toList (go dflags args)
+ where
+ go _ [] = DL.empty
+ go dflags (P : args) = DL.cons False (go dflags args)
+ go dflags (arg : args) = DL.replicate (argRepSizeW dflags arg) True
+ DL.++ go dflags args
----------------------
stdPattern :: [ArgRep] -> Maybe Int
diff --git a/compiler/basicTypes/Avail.hs b/compiler/basicTypes/Avail.hs
index 291c95abe8..5695c7e782 100644
--- a/compiler/basicTypes/Avail.hs
+++ b/compiler/basicTypes/Avail.hs
@@ -36,6 +36,8 @@ import NameSet
import FieldLabel
import Binary
+import qualified DList as DL
+import DList ( DList )
import ListSetOps
import Outputable
import Util
@@ -178,7 +180,7 @@ availFlds (AvailTC _ _ fs) = fs
availFlds _ = []
availsNamesWithOccs :: [AvailInfo] -> [(Name, OccName)]
-availsNamesWithOccs = concatMap availNamesWithOccs
+availsNamesWithOccs = DL.toList . DL.concatMap availNamesWithOccs'
-- | 'Name's made available by the availability information, paired with
-- the 'OccName' used to refer to each one.
@@ -189,10 +191,14 @@ availsNamesWithOccs = concatMap availNamesWithOccs
--
-- See Note [Representing fields in AvailInfo].
availNamesWithOccs :: AvailInfo -> [(Name, OccName)]
-availNamesWithOccs (Avail n) = [(n, nameOccName n)]
-availNamesWithOccs (AvailTC _ ns fs)
- = [ (n, nameOccName n) | n <- ns ] ++
- [ (flSelector fl, mkVarOccFS (flLabel fl)) | fl <- fs ]
+availNamesWithOccs = DL.toList . availNamesWithOccs'
+
+availNamesWithOccs' :: AvailInfo -> DList (Name, OccName)
+availNamesWithOccs' (Avail n) = DL.singleton (n, nameOccName n)
+availNamesWithOccs' (AvailTC _ ns fs) = ns' DL.++ fs'
+ where
+ ns' = DL.fromList [ (n, nameOccName n) | n <- ns ]
+ fs' = DL.fromList [ (flSelector fl, mkVarOccFS (flLabel fl)) | fl <- fs ]
-- -----------------------------------------------------------------------------
-- Utility
diff --git a/compiler/cmm/CmmNode.hs b/compiler/cmm/CmmNode.hs
index 1b387020f5..2517bdeb01 100644
--- a/compiler/cmm/CmmNode.hs
+++ b/compiler/cmm/CmmNode.hs
@@ -36,6 +36,7 @@ import Outputable
import SMRep
import CoreSyn (Tickish)
import qualified Unique as U
+import qualified DList as DL
import Hoopl.Block
import Hoopl.Graph
@@ -655,18 +656,22 @@ data CmmTickScope
-- | Output all scope paths.
scopeToPaths :: CmmTickScope -> [[U.Unique]]
-scopeToPaths GlobalScope = [[]]
-scopeToPaths (SubScope u s) = map (u:) (scopeToPaths s)
-scopeToPaths (CombinedScope s1 s2) = scopeToPaths s1 ++ scopeToPaths s2
+scopeToPaths s = DL.toList (go s)
+ where
+ go GlobalScope = DL.singleton []
+ go (SubScope u s) = fmap (u:) (go s)
+ go (CombinedScope s1 s2) = go s1 DL.++ go s2
-- | Returns the head uniques of the scopes. This is based on the
-- assumption that the @Unique@ of @SubScope@ identifies the
-- underlying super-scope. Used for efficient equality and comparison,
-- see below.
scopeUniques :: CmmTickScope -> [U.Unique]
-scopeUniques GlobalScope = []
-scopeUniques (SubScope u _) = [u]
-scopeUniques (CombinedScope s1 s2) = scopeUniques s1 ++ scopeUniques s2
+scopeUniques s = DL.toList (go s)
+ where
+ go GlobalScope = DL.empty
+ go (SubScope u _) = DL.singleton u
+ go (CombinedScope s1 s2) = go s1 DL.++ go s2
-- Equality and order is based on the head uniques defined above. We
-- take care to short-cut the (extremely) common cases.
diff --git a/compiler/coreSyn/CoreLint.hs b/compiler/coreSyn/CoreLint.hs
index 6f551c009f..7ddeeeeb9c 100644
--- a/compiler/coreSyn/CoreLint.hs
+++ b/compiler/coreSyn/CoreLint.hs
@@ -2765,7 +2765,7 @@ lintAnnots pname pass guts = do
when (not (null diffs)) $ CoreMonad.putMsg $ vcat
[ lint_banner "warning" pname
, text "Core changes with annotations:"
- , withPprStyle (defaultDumpStyle dflags) $ nest 2 $ vcat diffs
+ , withPprStyle (defaultDumpStyle dflags) . nest 2 . vcat . toList $ diffs
]
-- Return actual new guts
return nguts
diff --git a/compiler/coreSyn/CoreSyn.hs b/compiler/coreSyn/CoreSyn.hs
index 919e2300be..71b2c587c2 100644
--- a/compiler/coreSyn/CoreSyn.hs
+++ b/compiler/coreSyn/CoreSyn.hs
@@ -111,6 +111,7 @@ import Literal
import DataCon
import Module
import BasicTypes
+import qualified DList as DL
import DynFlags
import Outputable
import Util
@@ -2108,7 +2109,7 @@ bindersOf (Rec pairs) = [binder | (binder, _) <- pairs]
-- | 'bindersOf' applied to a list of binding groups
bindersOfBinds :: [Bind b] -> [b]
-bindersOfBinds binds = foldr ((++) . bindersOf) [] binds
+bindersOfBinds = DL.toList . DL.concat . fmap (DL.fromList . bindersOf)
rhssOfBind :: Bind b -> [Expr b]
rhssOfBind (NonRec _ rhs) = [rhs]
@@ -2120,9 +2121,11 @@ rhssOfAlts alts = [e | (_,_,e) <- alts]
-- | Collapse all the bindings in the supplied groups into a single
-- list of lhs\/rhs pairs suitable for binding in a 'Rec' binding group
flattenBinds :: [Bind b] -> [(b, Expr b)]
-flattenBinds (NonRec b r : binds) = (b,r) : flattenBinds binds
-flattenBinds (Rec prs1 : binds) = prs1 ++ flattenBinds binds
-flattenBinds [] = []
+flattenBinds = DL.toList . go
+ where
+ go (NonRec b r : binds) = DL.cons (b,r) (go binds)
+ go (Rec prs1 : binds) = (DL.fromList prs1) DL.++ go binds
+ go [] = DL.empty
-- | We often want to strip off leading lambdas before getting down to
-- business. Variants are 'collectTyBinders', 'collectValBinders',
diff --git a/compiler/coreSyn/CoreUtils.hs b/compiler/coreSyn/CoreUtils.hs
index 50fdcd9c7b..e5365436e1 100644
--- a/compiler/coreSyn/CoreUtils.hs
+++ b/compiler/coreSyn/CoreUtils.hs
@@ -84,6 +84,8 @@ import TyCon
import Unique
import Outputable
import TysPrim
+import qualified DList as DL
+import DList ( DList )
import DynFlags
import FastString
import Maybes
@@ -2144,12 +2146,12 @@ eqTickish _ l r = l == r
-- | Finds differences between core expressions, modulo alpha and
-- renaming. Setting @top@ means that the @IdInfo@ of bindings will be
-- checked for differences as well.
-diffExpr :: Bool -> RnEnv2 -> CoreExpr -> CoreExpr -> [SDoc]
-diffExpr _ env (Var v1) (Var v2) | rnOccL env v1 == rnOccR env v2 = []
-diffExpr _ _ (Lit lit1) (Lit lit2) | lit1 == lit2 = []
-diffExpr _ env (Type t1) (Type t2) | eqTypeX env t1 t2 = []
+diffExpr :: Bool -> RnEnv2 -> CoreExpr -> CoreExpr -> DList SDoc
+diffExpr _ env (Var v1) (Var v2) | rnOccL env v1 == rnOccR env v2 = DL.empty
+diffExpr _ _ (Lit lit1) (Lit lit2) | lit1 == lit2 = DL.empty
+diffExpr _ env (Type t1) (Type t2) | eqTypeX env t1 t2 = DL.empty
diffExpr _ env (Coercion co1) (Coercion co2)
- | eqCoercionX env co1 co2 = []
+ | eqCoercionX env co1 co2 = DL.empty
diffExpr top env (Cast e1 co1) (Cast e2 co2)
| eqCoercionX env co1 co2 = diffExpr top env e1 e2
diffExpr top env (Tick n1 e1) e2
@@ -2162,25 +2164,25 @@ diffExpr top env (Tick n1 e1) (Tick n2 e2)
-- generated names, which are allowed to differ.
diffExpr _ _ (App (App (Var absent) _) _)
(App (App (Var absent2) _) _)
- | isBottomingId absent && isBottomingId absent2 = []
+ | isBottomingId absent && isBottomingId absent2 = DL.empty
diffExpr top env (App f1 a1) (App f2 a2)
- = diffExpr top env f1 f2 ++ diffExpr top env a1 a2
+ = diffExpr top env f1 f2 DL.++ diffExpr top env a1 a2
diffExpr top env (Lam b1 e1) (Lam b2 e2)
| eqTypeX env (varType b1) (varType b2) -- False for Id/TyVar combination
= diffExpr top (rnBndr2 env b1 b2) e1 e2
diffExpr top env (Let bs1 e1) (Let bs2 e2)
= let (ds, env') = diffBinds top env (flattenBinds [bs1]) (flattenBinds [bs2])
- in ds ++ diffExpr top env' e1 e2
+ in ds DL.++ diffExpr top env' e1 e2
diffExpr top env (Case e1 b1 t1 a1) (Case e2 b2 t2 a2)
| equalLength a1 a2 && not (null a1) || eqTypeX env t1 t2
-- See Note [Empty case alternatives] in TrieMap
- = diffExpr top env e1 e2 ++ concat (zipWith diffAlt a1 a2)
+ = diffExpr top env e1 e2 DL.++ DL.concat (zipWith diffAlt a1 a2)
where env' = rnBndr2 env b1 b2
diffAlt (c1, bs1, e1) (c2, bs2, e2)
- | c1 /= c2 = [text "alt-cons " <> ppr c1 <> text " /= " <> ppr c2]
+ | c1 /= c2 = DL.singleton (text "alt-cons " <> ppr c1 <> text " /= " <> ppr c2)
| otherwise = diffExpr top (rnBndrs2 env' bs1 bs2) e1 e2
diffExpr _ _ e1 e2
- = [fsep [ppr e1, text "/=", ppr e2]]
+ = DL.singleton (fsep [ppr e1, text "/=", ppr e2])
-- | Finds differences between core bindings, see @diffExpr@.
--
@@ -2193,10 +2195,10 @@ diffExpr _ _ e1 e2
-- which we then speculatively match by ordering them. It's by no means
-- perfect, but gets the job done well enough.
diffBinds :: Bool -> RnEnv2 -> [(Var, CoreExpr)] -> [(Var, CoreExpr)]
- -> ([SDoc], RnEnv2)
+ -> (DList SDoc, RnEnv2)
diffBinds top env binds1 = go (length binds1) env binds1
where go _ env [] []
- = ([], env)
+ = (DL.empty, env)
go fuel env binds1 binds2
-- No binds left to compare? Bail out early.
| null binds1 || null binds2
@@ -2225,23 +2227,24 @@ diffBinds top env binds1 = go (length binds1) env binds1
-- now we just return the comparison results when we pair up
-- the binds in a pseudo-random order.
warn env binds1 binds2 =
- concatMap (uncurry (diffBind env)) (zip binds1' binds2') ++
- unmatched "unmatched left-hand:" (drop l binds1') ++
+ DL.concatMap (uncurry (diffBind env)) (zip binds1' binds2') DL.++
+ unmatched "unmatched left-hand:" (drop l binds1') DL.++
unmatched "unmatched right-hand:" (drop l binds2')
where binds1' = sortBy (comparing fst) binds1
binds2' = sortBy (comparing fst) binds2
l = min (length binds1') (length binds2')
- unmatched _ [] = []
- unmatched txt bs = [text txt $$ ppr (Rec bs)]
+ unmatched _ [] = DL.empty
+ unmatched txt bs = DL.singleton (text txt $$ ppr (Rec bs))
diffBind env (bndr1,expr1) (bndr2,expr2)
- | ds@(_:_) <- diffExpr top env expr1 expr2
+ | ds <- diffExpr top env expr1 expr2
+ , not (null ds)
= locBind "in binding" bndr1 bndr2 ds
| otherwise
= diffIdInfo env bndr1 bndr2
-- | Find differences in @IdInfo@. We will especially check whether
-- the unfoldings match, if present (see @diffUnfold@).
-diffIdInfo :: RnEnv2 -> Var -> Var -> [SDoc]
+diffIdInfo :: RnEnv2 -> Var -> Var -> DList SDoc
diffIdInfo env bndr1 bndr2
| arityInfo info1 == arityInfo info2
&& cafInfo info1 == cafInfo info2
@@ -2254,21 +2257,21 @@ diffIdInfo env bndr1 bndr2
= locBind "in unfolding of" bndr1 bndr2 $
diffUnfold env (unfoldingInfo info1) (unfoldingInfo info2)
| otherwise
- = locBind "in Id info of" bndr1 bndr2
- [fsep [pprBndr LetBind bndr1, text "/=", pprBndr LetBind bndr2]]
+ = locBind "in Id info of" bndr1 bndr2 . DL.singleton $
+ fsep [pprBndr LetBind bndr1, text "/=", pprBndr LetBind bndr2]
where info1 = idInfo bndr1; info2 = idInfo bndr2
-- | Find differences in unfoldings. Note that we will not check for
-- differences of @IdInfo@ in unfoldings, as this is generally
-- redundant, and can lead to an exponential blow-up in complexity.
-diffUnfold :: RnEnv2 -> Unfolding -> Unfolding -> [SDoc]
-diffUnfold _ NoUnfolding NoUnfolding = []
-diffUnfold _ BootUnfolding BootUnfolding = []
-diffUnfold _ (OtherCon cs1) (OtherCon cs2) | cs1 == cs2 = []
+diffUnfold :: RnEnv2 -> Unfolding -> Unfolding -> DList SDoc
+diffUnfold _ NoUnfolding NoUnfolding = DL.empty
+diffUnfold _ BootUnfolding BootUnfolding = DL.empty
+diffUnfold _ (OtherCon cs1) (OtherCon cs2) | cs1 == cs2 = DL.empty
diffUnfold env (DFunUnfolding bs1 c1 a1)
(DFunUnfolding bs2 c2 a2)
| c1 == c2 && equalLength bs1 bs2
- = concatMap (uncurry (diffExpr False env')) (zip a1 a2)
+ = DL.concatMap (uncurry (diffExpr False env')) (zip a1 a2)
where env' = rnBndrs2 env bs1 bs2
diffUnfold env (CoreUnfolding t1 _ _ v1 cl1 wf1 x1 g1)
(CoreUnfolding t2 _ _ v2 cl2 wf2 x2 g2)
@@ -2276,11 +2279,11 @@ diffUnfold env (CoreUnfolding t1 _ _ v1 cl1 wf1 x1 g1)
&& wf1 == wf2 && x1 == x2 && g1 == g2
= diffExpr False env t1 t2
diffUnfold _ uf1 uf2
- = [fsep [ppr uf1, text "/=", ppr uf2]]
+ = DL.singleton $ fsep [ppr uf1, text "/=", ppr uf2]
-- | Add location information to diff messages
-locBind :: String -> Var -> Var -> [SDoc] -> [SDoc]
-locBind loc b1 b2 diffs = map addLoc diffs
+locBind :: String -> Var -> Var -> DList SDoc -> DList SDoc
+locBind loc b1 b2 diffs = fmap addLoc diffs
where addLoc d = d $$ nest 2 (parens (text loc <+> bindLoc))
bindLoc | b1 == b2 = ppr b1
| otherwise = ppr b1 <> char '/' <> ppr b2
diff --git a/compiler/deSugar/DsBinds.hs b/compiler/deSugar/DsBinds.hs
index dbfc6f52fd..e1a8ac016e 100644
--- a/compiler/deSugar/DsBinds.hs
+++ b/compiler/deSugar/DsBinds.hs
@@ -64,6 +64,7 @@ import Maybes
import OrdList
import Bag
import BasicTypes
+import qualified DList as DL
import DynFlags
import FastString
import Util
@@ -110,10 +111,14 @@ dsTopLHsBinds binds
-- | Desugar all other kind of bindings, Ids of strict binds are returned to
-- later be forced in the binding group body, see Note [Desugar Strict binds]
dsLHsBinds :: LHsBinds GhcTc -> DsM ([Id], [(Id,CoreExpr)])
-dsLHsBinds binds
- = do { ds_bs <- mapBagM dsLHsBind binds
- ; return (foldBag (\(a, a') (b, b') -> (a ++ b, a' ++ b'))
- id ([], []) ds_bs) }
+dsLHsBinds binds = do
+ let bindsToDL (str, bnds) = (DL.fromList str, DL.fromList bnds)
+ ds_bs <- mapBagM (fmap bindsToDL . dsLHsBind) binds
+ let
+ (strictDL, bindingDL) =
+ foldBag (\(a, a') (b, b') -> (a DL.++ b, a' DL.++ b'))
+ id (DL.empty, DL.empty) ds_bs
+ return (DL.toList strictDL, DL.toList bindingDL)
------------------------
dsLHsBind :: LHsBind GhcTc
diff --git a/compiler/deSugar/DsUsage.hs b/compiler/deSugar/DsUsage.hs
index ed9f4cd371..024dcba8cd 100644
--- a/compiler/deSugar/DsUsage.hs
+++ b/compiler/deSugar/DsUsage.hs
@@ -11,6 +11,7 @@ module DsUsage (
import GhcPrelude
+import qualified DList as DL
import DynFlags
import HscTypes
import TcRnTypes
@@ -111,18 +112,16 @@ mkUsageInfo hsc_env this_mod dir_imp_mods used_names dependent_files merged
= do
eps <- hscEPS hsc_env
hashes <- mapM getFileHash dependent_files
- plugin_usages <- mapM (mkPluginUsage hsc_env) pluginModules
- let mod_usages = mk_mod_usage_info (eps_PIT eps) hsc_env this_mod
- dir_imp_mods used_names
- usages = mod_usages ++ [ UsageFile { usg_file_path = f
- , usg_file_hash = hash }
- | (f, hash) <- zip dependent_files hashes ]
- ++ [ UsageMergedRequirement
- { usg_mod = mod,
- usg_mod_hash = hash
- }
- | (mod, hash) <- merged ]
- ++ concat plugin_usages
+ plugin_usages <- DL.concatMapA (mkPluginUsage hsc_env) pluginModules
+ let mod_usages = DL.fromList $ mk_mod_usage_info (eps_PIT eps) hsc_env
+ this_mod dir_imp_mods
+ used_names
+ usage_files = DL.fromList $
+ uncurry UsageFile <$> zip dependent_files hashes
+ usage_mergedreqs = DL.fromList $
+ uncurry UsageMergedRequirement <$> merged
+ usages = DL.toList $ mod_usages DL.++ usage_files DL.++ usage_mergedreqs
+ DL.++ plugin_usages
usages `seqList` return usages
-- seq the list of Usages returned: occasionally these
-- don't get evaluated for a while and we can end up hanging on to
@@ -163,7 +162,7 @@ One way to improve this is to either:
compare implementation hashes for recompilation. Creation of implementation
hashes is however potentially expensive.
-}
-mkPluginUsage :: HscEnv -> ModIface -> IO [Usage]
+mkPluginUsage :: HscEnv -> ModIface -> IO (DL.DList Usage)
mkPluginUsage hsc_env pluginModule
= case lookupPluginModuleWithSuggestions dflags pNm Nothing of
LookupFound _ pkg -> do
@@ -196,7 +195,7 @@ mkPluginUsage hsc_env pluginModule
++ unlines paths
)
(ppr pNm)
- _ -> mapM hashFile (nub files)
+ _ -> DL.fromList <$> mapM hashFile (nub files)
_ -> do
foundM <- findPluginModule hsc_env pNm
case foundM of
@@ -206,7 +205,7 @@ mkPluginUsage hsc_env pluginModule
Found ml _ -> do
pluginObject <- hashFile (ml_obj_file ml)
depObjects <- catMaybes <$> mapM lookupObjectFile deps
- return (nub (pluginObject : depObjects))
+ return . DL.fromList $ nub (pluginObject : depObjects)
_ -> pprPanic "mkPluginUsage: no object file found" (ppr pNm)
where
dflags = hsc_dflags hsc_env
diff --git a/compiler/ghci/ByteCodeAsm.hs b/compiler/ghci/ByteCodeAsm.hs
index 82de14346e..34b8a6d0b5 100644
--- a/compiler/ghci/ByteCodeAsm.hs
+++ b/compiler/ghci/ByteCodeAsm.hs
@@ -101,7 +101,7 @@ assembleBCOs hsc_env proto_bcos tycons top_strs modbreaks = do
return CompiledByteCode
{ bc_bcos = bcos'
, bc_itbls = itblenv
- , bc_ffis = concat (map protoBCOFFIs proto_bcos)
+ , bc_ffis = concatMap protoBCOFFIs proto_bcos
, bc_strs = top_strs ++ ptrs
, bc_breaks = modbreaks
}
diff --git a/compiler/ghci/ByteCodeGen.hs b/compiler/ghci/ByteCodeGen.hs
index 4a8e138daf..60087a148f 100644
--- a/compiler/ghci/ByteCodeGen.hs
+++ b/compiler/ghci/ByteCodeGen.hs
@@ -21,6 +21,7 @@ import GHCi
import GHCi.FFI
import GHCi.RemoteTypes
import BasicTypes
+import qualified DList as DL
import DynFlags
import Outputable
import GHC.Platform
@@ -1110,10 +1111,10 @@ doCase d s p (_,scrut) bndr alts is_unboxed_tuple
binds = Map.toList p
-- NB: unboxed tuple cases bind the scrut binder to the same offset
-- as one of the alt binders, so we have to remove any duplicates here:
- rel_slots = nub $ map fromIntegral $ concat (map spread binds)
- spread (id, offset) | isFollowableArg (bcIdArgRep id) = [ rel_offset ]
- | otherwise = []
- where rel_offset = trunc16W $ bytesToWords dflags (d - offset)
+ rel_slots = nub . DL.toList $ DL.concatMap spread binds
+ spread (id, offset) | isFollowableArg (bcIdArgRep id) = DL.singleton rel_offset
+ | otherwise = DL.empty
+ where rel_offset = fromIntegral . trunc16W $ bytesToWords dflags (d - offset)
alt_stuff <- mapM codeAlt alts
alt_final <- mkMultiBranch maybe_ncons alt_stuff
diff --git a/compiler/utils/DList.hs b/compiler/utils/DList.hs
index 1215bb7a4b..18e2274439 100644
--- a/compiler/utils/DList.hs
+++ b/compiler/utils/DList.hs
@@ -36,6 +36,7 @@ module DList
, cons
, snoc
, append
+ , (++)
, concat
, replicate
, list
@@ -44,9 +45,11 @@ module DList
, unfoldr
, foldr
, map
+ , concatMap
+ , concatMapA
) where
-import Prelude hiding (concat, foldr, map, head, tail, replicate)
+import Prelude hiding (concat, foldr, map, head, tail, replicate, (++), concatMap)
import qualified Data.List as List
import Control.Monad as M
import Data.Function (on)
@@ -94,7 +97,7 @@ newtype DList a = DL { unDL :: [a] -> [a] }
-- | Convert a list to a dlist
fromList :: [a] -> DList a
-fromList = DL . (++)
+fromList = DL . (List.++)
{-# INLINE fromList #-}
-- | Convert a dlist to a list
@@ -145,6 +148,12 @@ append :: DList a -> DList a -> DList a
append xs ys = DL (unDL xs . unDL ys)
{-# INLINE append #-}
+-- | /O(1)/. 'append' in operator form.
+(++) :: DList a -> DList a -> DList a
+(++) = append
+{-# INLINE (++) #-}
+infixr 5 ++
+
-- | /O(spine)/. Concatenate dlists
concat :: [DList a] -> DList a
concat = List.foldr append empty
@@ -189,6 +198,14 @@ map :: (a -> b) -> DList a -> DList b
map f = foldr (cons . f) empty
{-# INLINE map #-}
+-- | /O(n)/. concatMap for difference lists.
+concatMap :: (Foldable t) => (a -> DList b) -> t a -> DList b
+concatMap f xs = F.foldr (append . f) empty xs
+
+-- | /O(n)/. Applicative 'concatMap'.
+concatMapA :: (Foldable t, Applicative f) => (a -> f (DList b)) -> t a -> f (DList b)
+concatMapA f xs = F.foldr (\x acc -> append <$> f x <*> acc) (pure empty) xs
+
instance Eq a => Eq (DList a) where
(==) = (==) `on` toList