[Git][ghc/ghc][wip/T17910] Try not doing floatConsts

Simon Peyton Jones (@simonpj) gitlab at gitlab.haskell.org
Thu Aug 31 15:25:25 UTC 2023



Simon Peyton Jones pushed to branch wip/T17910 at Glasgow Haskell Compiler / GHC


Commits:
9bedd485 by Simon Peyton Jones at 2023-08-31T16:23:58+01:00
Try not doing floatConsts

This avoid flattening, and generating lots of top level
bindings. Instead do it in late-lambda-lift.

I moved late-lambda-lift to run with -O because it is cheap
and valuable.  That's a somewhat orthogonal change, probably
should test separately.

- - - - -


8 changed files:

- compiler/GHC/Core/Opt/Pipeline.hs
- compiler/GHC/Core/Opt/SetLevels.hs
- compiler/GHC/Driver/DynFlags.hs
- compiler/GHC/Stg/Lift.hs
- compiler/GHC/Stg/Lift/Analysis.hs
- compiler/GHC/Stg/Lift/Monad.hs
- compiler/GHC/Stg/Syntax.hs
- testsuite/tests/perf/compiler/LargeRecord.hs


Changes:

=====================================
compiler/GHC/Core/Opt/Pipeline.hs
=====================================
@@ -215,8 +215,8 @@ getCoreToDo dflags hpt_rule_base extra_vars
 
         if full_laziness then
            CoreDoFloatOutwards FloatOutSwitches {
-                                 floatOutLambdas   = Just 0,
-                                 floatOutConstants = False,
+                                 floatOutLambdas     = Just 0,
+                                 floatOutConstants   = False,
                                  floatOutOverSatApps = False,
                                  floatToTopLevelOnly = False }
                 -- Was: gentleFloatOutSwitches
@@ -279,7 +279,7 @@ getCoreToDo dflags hpt_rule_base extra_vars
         runWhen full_laziness $
            CoreDoFloatOutwards FloatOutSwitches {
                                  floatOutLambdas     = floatLamArgs dflags,
-                                 floatOutConstants   = True,
+                                 floatOutConstants   = False,
                                  floatOutOverSatApps = True,
                                  floatToTopLevelOnly = False },
                 -- nofib/spectral/hartel/wang doubles in speed if you


=====================================
compiler/GHC/Core/Opt/SetLevels.hs
=====================================
@@ -739,10 +739,10 @@ lvlMFE env strict_ctxt ann_expr
     -- See Note [Floating to the top]
     saves_alloc =  isTopLvl dest_lvl
                 && (floatConsts env || is_function || is_bot_lam)
-                                  -- Always float constant lambdas
-                                  -- T5237 is a good example
+                            -- Always float constant lambdas
+                            -- T5237 is a good example
                 && (   not strict_ctxt                     -- (a)
-                    || exprIsHNF expr                      -- (b)
+                    || exprIsExpandable expr               -- (b)
                     || (is_bot_lam && escapes_value_lam))  -- (c)
 
 hasFreeJoin :: LevelEnv -> DVarSet -> Bool


=====================================
compiler/GHC/Driver/DynFlags.hs
=====================================
@@ -1249,7 +1249,7 @@ optLevelFlags -- see Note [Documenting optimisation flags]
     , ([1,2],   Opt_CmmStaticPred)
     , ([1,2],   Opt_CSE)
     , ([1,2],   Opt_StgCSE)
-    , ([2],     Opt_StgLiftLams)
+    , ([1,2],   Opt_StgLiftLams)
     , ([1,2],   Opt_CmmControlFlow)
 
     , ([1,2],   Opt_EnableRewriteRules)


=====================================
compiler/GHC/Stg/Lift.hs
=====================================
@@ -31,7 +31,6 @@ import GHC.Utils.Outputable
 import GHC.Utils.Panic
 import GHC.Types.Var.Set
 import Control.Monad ( when )
-import Data.Maybe ( isNothing )
 
 -- Note [Late lambda lifting in STG]
 -- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -199,9 +198,12 @@ liftRhs
   -> LlStgRhs
   -> LiftM OutStgRhs
 liftRhs mb_former_fvs rhs@(StgRhsCon ccs con mn ts args typ)
-  = assertPpr (isNothing mb_former_fvs)
+  = assertPpr (case mb_former_fvs of
+                 Nothing -> True
+                 Just fvs -> isEmptyDVarSet fvs)
               (text "Should never lift a constructor"
                $$ pprStgRhs panicStgPprOpts rhs) $
+       -- We should never float a constructor, unless it's a constant
     StgRhsCon ccs con mn ts <$> traverse liftArgs args <*> pure typ
 liftRhs Nothing (StgRhsClosure _ ccs upd infos body typ) =
   -- This RHS wasn't lifted.
@@ -215,17 +217,16 @@ liftRhs (Just former_fvs) (StgRhsClosure _ ccs upd infos body typ) =
 
 liftArgs :: InStgArg -> LiftM OutStgArg
 liftArgs a@(StgLitArg _) = pure a
-liftArgs (StgVarArg occ) = do
-  assertPprM (not <$> isLifted occ) (text "StgArgs should never be lifted" $$ ppr occ)
-  StgVarArg <$> substOcc occ
+liftArgs (StgVarArg x)   = do { (x', fvs') <- substOcc x
+                              ; assertPpr (null fvs') (ppr x <+> ppr x' $$ ppr fvs') $
+                                pure (StgVarArg x') }
 
 liftExpr :: LlStgExpr -> LiftM OutStgExpr
 liftExpr (StgLit lit) = pure (StgLit lit)
 liftExpr (StgTick t e) = StgTick t <$> liftExpr e
 liftExpr (StgApp f args) = do
-  f' <- substOcc f
+  (f',fvs') <- substOcc f
   args' <- traverse liftArgs args
-  fvs' <- formerFreeVars f
   let top_lvl_args = map StgVarArg fvs' ++ args'
   pure (StgApp f' top_lvl_args)
 liftExpr (StgConApp con mn args tys) = StgConApp con mn <$> traverse liftArgs args <*> pure tys


=====================================
compiler/GHC/Stg/Lift/Analysis.hs
=====================================
@@ -43,72 +43,87 @@ import GHC.Types.Var.Set
 
 import Data.Maybe ( mapMaybe )
 
--- Note [When to lift]
--- ~~~~~~~~~~~~~~~~~~~
--- $when
--- The analysis proceeds in two steps:
---
---   1. It tags the syntax tree with analysis information in the form of
---      'BinderInfo' at each binder and 'Skeleton's at each let-binding
---      by 'tagSkeletonTopBind' and friends.
---   2. The resulting syntax tree is treated by the "GHC.Stg.Lift"
---      module, calling out to 'goodToLift' to decide if a binding is worthwhile
---      to lift.
---      'goodToLift' consults argument occurrence information in 'BinderInfo'
---      and estimates 'closureGrowth', for which it needs the 'Skeleton'.
---
--- So the annotations from 'tagSkeletonTopBind' ultimately fuel 'goodToLift',
--- which employs a number of heuristics to identify and exclude lambda lifting
--- opportunities deemed non-beneficial:
---
---  [Top-level bindings] can't be lifted.
---  [Thunks] and data constructors shouldn't be lifted in order not to destroy
---    sharing.
---  [Argument occurrences] #arg_occs# of binders prohibit them to be lifted.
---    Doing the lift would re-introduce the very allocation at call sites that
---    we tried to get rid off in the first place. We capture analysis
---    information in 'BinderInfo'. Note that we also consider a nullary
---    application as argument occurrence, because it would turn into an n-ary
---    partial application created by a generic apply function. This occurs in
---    CPS-heavy code like the CS benchmark.
---  [Join points] should not be lifted, simply because there's no reduction in
---    allocation to be had.
---  [Abstracting over join points] destroys join points, because they end up as
---    arguments to the lifted function.
---  [Abstracting over known local functions] turns a known call into an unknown
---    call (e.g. some @stg_ap_*@), which is generally slower. Can be turned off
---    with @-fstg-lift-lams-known at .
---  [Calling convention] Don't lift when the resulting function would have a
---    higher arity than available argument registers for the calling convention.
---    Can be influenced with @-fstg-lift-(non)rec-args(-any)@.
---  [Closure growth] introduced when former free variables have to be available
---    at call sites may actually lead to an increase in overall allocations
---  resulting from a lift. Estimating closure growth is described in
---  "GHC.Stg.Lift.Analysis#clogro" and is what most of this module is ultimately
---  concerned with.
---
--- There's a <https://gitlab.haskell.org/ghc/ghc/wikis/late-lam-lift wiki page> with
--- some more background and history.
-
--- Note [Estimating closure growth]
--- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
--- $clogro
--- We estimate closure growth by abstracting the syntax tree into a 'Skeleton',
--- capturing only syntactic details relevant to 'closureGrowth', such as
---
---   * 'ClosureSk', representing closure allocation.
---   * 'RhsSk', representing a RHS of a binding and how many times it's called
---     by an appropriate 'Card'.
---   * 'AltSk', 'BothSk' and 'NilSk' for choice, sequence and empty element.
---
--- This abstraction is mostly so that the main analysis function 'closureGrowth'
--- can stay simple and focused. Also, skeletons tend to be much smaller than
--- the syntax tree they abstract, so it makes sense to construct them once and
--- and operate on them instead of the actual syntax tree.
---
--- A more detailed treatment of computing closure growth, including examples,
--- can be found in the paper referenced from the
--- <https://gitlab.haskell.org/ghc/ghc/wikis/late-lam-lift wiki page>.
+{- Note [When to lift]
+~~~~~~~~~~~~~~~~~~~~~~
+$when
+The analysis proceeds in two steps:
+
+  1. It tags the syntax tree with analysis information in the form of
+     'BinderInfo' at each binder and 'Skeleton's at each let-binding
+     by 'tagSkeletonTopBind' and friends.
+  2. The resulting syntax tree is treated by the "GHC.Stg.Lift"
+     module, calling out to 'goodToLift' to decide if a binding is worthwhile
+     to lift.
+     'goodToLift' consults argument occurrence information in 'BinderInfo'
+     and estimates 'closureGrowth', for which it needs the 'Skeleton'.
+
+So the annotations from 'tagSkeletonTopBind' ultimately fuel 'goodToLift',
+which employs a number of heuristics to identify and exclude lambda lifting
+opportunities deemed non-beneficial:
+
+* [WL1: Top-level bindings] can't be lifted.
+
+* [WL2: Thunks] and data constructors shouldn't be lifted in order not to destroy
+  sharing.
+
+* [WL3: Argument occurrences] #arg_occs# of binders prohibit them to be lifted.
+  Doing the lift would re-introduce the very allocation at call sites that
+  we tried to get rid of in the first place. Example
+       g y = let f x = ...x..y...
+             in map f xs
+  No point in lambda-lifting f:
+      f' y x = ...x..y...
+      g y = let f = f' y in map f xs
+  because we still have a closure allocation for f!
+
+  We capture analysis information in 'BinderInfo'. Note that we also consider a
+  nullary application as argument occurrence, because it would turn into an
+  n-ary partial application created by a generic apply function. This occurs in
+  CPS-heavy code like the CS benchmark.
+
+* [WL4: Join points] should not be lifted, simply because there's no reduction in
+  allocation to be had.
+
+* [WL5: Abstracting over join points] destroys join points, because they end up as
+  arguments to the lifted function.
+
+* [WL6: Abstracting over known local functions] turns a known call into an unknown
+  call (e.g. some @stg_ap_*@), which is generally slower. Can be turned off
+  with @-fstg-lift-lams-known at .
+
+* [WL7: Calling convention] Don't lift when the resulting function would have a
+  higher arity than available argument registers for the calling convention.
+  Can be influenced with @-fstg-lift-(non)rec-args(-any)@.
+
+* [WL8: Closure growth] introduced when former free variables have to be available
+  at call sites may actually lead to an increase in overall allocations
+  resulting from a lift. Estimating closure growth is described in
+  "GHC.Stg.Lift.Analysis#clogro" and is what most of this module is ultimately
+  concerned with.
+
+There's a <https://gitlab.haskell.org/ghc/ghc/wikis/late-lam-lift wiki page> with
+some more background and history.
+
+Note [Estimating closure growth]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+$clogro
+We estimate closure growth by abstracting the syntax tree into a 'Skeleton',
+capturing only syntactic details relevant to 'closureGrowth', such as
+
+  * 'ClosureSk', representing closure allocation.
+  * 'RhsSk', representing a RHS of a binding and how many times it's called
+    by an appropriate 'Card'.
+  * 'AltSk', 'BothSk' and 'NilSk' for choice, sequence and empty element.
+
+This abstraction is mostly so that the main analysis function 'closureGrowth'
+can stay simple and focused. Also, skeletons tend to be much smaller than
+the syntax tree they abstract, so it makes sense to construct them once and
+and operate on them instead of the actual syntax tree.
+
+A more detailed treatment of computing closure growth, including examples,
+can be found in the paper referenced from the
+<https://gitlab.haskell.org/ghc/ghc/wikis/late-lam-lift wiki page>.
+-}
 
 llTrace :: String -> SDoc -> a -> a
 llTrace _ _ c = c
@@ -282,30 +297,38 @@ goodToLift
   -> Maybe DIdSet       -- ^ @Just abs_ids@ <=> This binding is beneficial to
                         -- lift and @abs_ids@ are the variables it would
                         -- abstract over
-goodToLift cfg top_lvl rec_flag expander pairs scope = decide
-  [ ("top-level", isTopLevel top_lvl) -- keep in sync with Note [When to lift]
-  , ("memoized", any_memoized)
-  , ("argument occurrences", arg_occs)
-  , ("join point", is_join_point)
-  , ("abstracts join points", abstracts_join_ids)
-  , ("abstracts known local function", abstracts_known_local_fun)
-  , ("args spill on stack", args_spill_on_stack)
-  , ("increases allocation", inc_allocs)
-  ] where
+goodToLift cfg top_lvl rec_flag expander pairs scope
+  | not (fancy_or deciders)
+  = llTrace "stgLiftLams:lifting" (ppr bndrs) $
+    Just expanded_abs_ids
+  | otherwise
+  = Nothing
+
+  where
+      deciders :: [(String,Bool)]   -- True <=> do not lift
+      -- Keep in sync with Note [When to lift]
+      deciders
+        = [ ("top-level", isTopLevel top_lvl)             -- [WL1: Top-level bindings]
+          , ("memoized", any_memoized)                    -- [WL2: Thunks]
+          , ("argument occurrences", arg_occs)            -- [WL3: Argument occurrences]
+          , ("join point", is_join_point)                 -- [WL4: Join points]
+          , ("abstracts join points", abstracts_join_ids) -- [WL5: Abstracting over join points]
+          , ("abstracts known local function", abstracts_known_local_fun)
+                                                          -- [WL6: Abstracting over known local functions]
+          , ("args spill on stack", args_spill_on_stack)  -- [WL7: Calling convention]
+          , ("increases allocation", inc_allocs)          -- [WL8: Closure growth]
+          ]
+
       profile  = c_targetProfile cfg
       platform = profilePlatform profile
-      decide deciders
-        | not (fancy_or deciders)
-        = llTrace "stgLiftLams:lifting"
-                  (ppr bndrs <+> ppr abs_ids $$
-                   ppr allocs $$
-                   ppr scope) $
-          Just abs_ids
-        | otherwise
-        = Nothing
       ppr_deciders = vcat . map (text . fst) . filter snd
       fancy_or deciders
-        = llTrace "stgLiftLams:goodToLift" (ppr bndrs $$ ppr_deciders deciders) $
+        = llTrace "stgLiftLams:goodToLift?"
+            (vcat [ text "bndrs:"           <+> ppr bndrs
+                  , text "fvs:"             <+> ppr fvs
+                  , text "abs_ids:"         <+> ppr abs_ids
+                  , text "expanded_abs_ids" <+> ppr expanded_abs_ids
+                  , text "bad deciders:"    <+> ppr_deciders deciders ]) $
           any snd deciders
 
       bndrs = map (binderInfoBndr . fst) pairs
@@ -316,33 +339,41 @@ goodToLift cfg top_lvl rec_flag expander pairs scope = decide
       -- the lifted binding would abstract over. We have to merge the free
       -- variables of all RHS to get the set of variables that will have to be
       -- passed through parameters.
-      fvs = unionDVarSets (map freeVarsOfRhs rhss)
-      -- To lift the binding to top-level, we want to delete the lifted binders
+      --
+      -- delVarSetList: to lift the binding to top-level, we want to delete the lifted binders
       -- themselves from the free var set. Local let bindings track recursive
       -- occurrences in their free variable set. We neither want to apply our
       -- cost model to them (see 'tagSkeletonRhs'), nor pass them as parameters
-      -- when lifted, as these are known calls. We call the resulting set the
-      -- identifiers we abstract over, thus @abs_ids at . These are all 'OutId's.
+      -- when lifted, as these are known calls.
+      --
+      -- expander: map to OutIds, expanding Ids that are themselves lifted
+      --
+      -- The resulting set is `expanded_abs_ids`; we will abstract over them.
       -- We will save the set in 'LiftM.e_expansions' for each of the variables
       -- if we perform the lift.
-      abs_ids = expander (delDVarSetList fvs bndrs)
+      fvs                 = unionDVarSets (map freeVarsOfRhs rhss)  -- InIds
+      abs_ids             = delDVarSetList fvs bndrs                -- InIds
+      expanded_abs_ids    = expander abs_ids                        -- OutIds
+      no_expanded_abs_ids = isEmptyDVarSet expanded_abs_ids  -- A constant expression
 
       -- We don't lift updatable thunks or constructors
-      any_memoized = any is_memoized_rhs rhss
-      is_memoized_rhs StgRhsCon{} = True
-      is_memoized_rhs (StgRhsClosure _ _ upd _ _ _) = isUpdatable upd
+      -- unless there are no Ids to abstract over, so it's a constant
+      any_memoized | no_expanded_abs_ids             = False -- OK to lift
+                   | otherwise                       = any is_memoized_rhs rhss
+      is_memoized_rhs (StgRhsCon{})                  = True  -- Never lift
+      is_memoized_rhs (StgRhsClosure _ _ upd _ _ _)  = isUpdatable upd
 
       -- Don't lift binders occurring as arguments. This would result in complex
       -- argument expressions which would have to be given a name, reintroducing
       -- the very allocation at each call site that we wanted to get rid off in
-      -- the first place.
-      arg_occs = or (mapMaybe (binderInfoOccursAsArg . fst) pairs)
+      -- the first place.  Only matters if abstraction will take place
+      arg_occs = not no_expanded_abs_ids && or (mapMaybe (binderInfoOccursAsArg . fst) pairs)
 
       -- These don't allocate anyway.
       is_join_point = any isJoinId bndrs
 
       -- Abstracting over join points/let-no-escapes spoils them.
-      abstracts_join_ids = any isJoinId (dVarSetElems abs_ids)
+      abstracts_join_ids = anyDVarSet isJoinId abs_ids
 
       -- Abstracting over known local functions that aren't floated themselves
       -- turns a known, fast call into an unknown, slow call:
@@ -361,14 +392,17 @@ goodToLift cfg top_lvl rec_flag expander pairs scope = decide
       -- idArity f > 0 ==> known
       known_fun id = idArity id > 0
       abstracts_known_local_fun
-        = not (c_liftLamsKnown cfg) && any known_fun (dVarSetElems abs_ids)
+        = not (c_liftLamsKnown cfg) && anyDVarSet known_fun expanded_abs_ids
+          -- NB: expanded_abs_ids: if `f` is floated, the abs_ids for
+          --     `g` will mention `f`; but the /expanded/ abs_ids will
+          --     mention f's free vars, not f itself.
 
       -- Number of arguments of a RHS in the current binding group if we decide
       -- to lift it
       n_args
         = length
         . StgToCmm.Closure.nonVoidIds -- void parameters don't appear in Cmm
-        . (dVarSetElems abs_ids ++)
+        . (dVarSetElems expanded_abs_ids ++)
         . rhsLambdaBndrs
       max_n_args
         | isRec rec_flag = c_liftLamsRecArgs cfg
@@ -395,7 +429,8 @@ goodToLift cfg top_lvl rec_flag expander pairs scope = decide
         . expander
         . flip dVarSetMinusVarSet bndrs_set
         $ freeVarsOfRhs rhs
-      clo_growth = closureGrowth expander (idClosureFootprint platform) bndrs_set abs_ids scope
+      clo_growth = closureGrowth expander (idClosureFootprint platform)
+                                 bndrs_set expanded_abs_ids scope
 
 rhsLambdaBndrs :: LlStgRhs -> [Id]
 rhsLambdaBndrs StgRhsCon{} = []
@@ -436,8 +471,8 @@ closureGrowth
   -> IdSet
   -- ^ Binding group for which lifting is to be decided
   -> DIdSet
-  -- ^ Free vars of the whole binding group prior to lifting it. These must be
-  --   available at call sites if we decide to lift the binding group.
+  -- ^ Free vars (OutIds) of the whole binding group prior to lifting it. These
+  --   must be available at call sites if we decide to lift the binding group.
   -> Skeleton
   -- ^ Abstraction of the scope of the function
   -> IntWithInf


=====================================
compiler/GHC/Stg/Lift/Monad.hs
=====================================
@@ -19,7 +19,7 @@ module GHC.Stg.Lift.Monad (
     -- ** Substitution and binders
     withSubstBndr, withSubstBndrs, withLiftedBndr, withLiftedBndrs,
     -- ** Occurrences
-    substOcc, isLifted, formerFreeVars, liftedIdsExpander
+    substOcc, isLifted, liftedIdsExpander
   ) where
 
 import GHC.Prelude
@@ -65,6 +65,7 @@ data Env
   = Env
   { e_config     :: StgLiftConfig
   -- ^ Read-only.
+
   , e_subst      :: !Subst
   -- ^ We need to track the renamings of local 'InId's to their lifted 'OutId',
   -- because shadowing might make a closure's free variables unavailable at its
@@ -74,6 +75,7 @@ data Env
   -- @
   -- Here, @f@ can't be lifted to top-level, because its free variable @x@ isn't
   -- available at its call site.
+
   , e_expansions :: !(IdEnv DIdSet)
   -- ^ Lifted 'Id's don't occur as free variables in any closure anymore, because
   -- they are bound at the top-level. Every occurrence must supply the formerly
@@ -295,23 +297,27 @@ withLiftedBndrs abs_ids = runContT . traverse (ContT . withLiftedBndr abs_ids)
 
 -- | Substitutes a binder /occurrence/, which was brought in scope earlier by
 -- 'withSubstBndr' \/ 'withLiftedBndr'.
-substOcc :: Id -> LiftM Id
-substOcc id = LiftM (RWS.asks (lookupIdSubst id . e_subst))
+-- Also returns an empty list for a binding that was not lifted and the list of all
+-- local variables the binding abstracts over (so, exactly the additional
+-- arguments at adjusted call sites) otherwise.
+--
+-- We are going to replace f with (f' fvs)
+substOcc :: InId -> LiftM (OutId, [OutId])
+substOcc f = LiftM (RWS.asks subst_occ)
+  where
+    subst_occ :: Env -> (OutId, [OutId])
+    subst_occ (Env { e_subst = subst, e_expansions = expansions })
+      = (lookupIdSubst f subst, get_expansions expansions)
+
+    get_expansions :: IdEnv DIdSet -> [OutId]
+    get_expansions expansions = case lookupVarEnv expansions f of
+                       Nothing  -> []
+                       Just fvs -> dVarSetElems fvs
 
 -- | Whether the given binding was decided to be lambda lifted.
 isLifted :: InId -> LiftM Bool
 isLifted bndr = LiftM (RWS.asks (elemVarEnv bndr . e_expansions))
 
--- | Returns an empty list for a binding that was not lifted and the list of all
--- local variables the binding abstracts over (so, exactly the additional
--- arguments at adjusted call sites) otherwise.
-formerFreeVars :: InId -> LiftM [OutId]
-formerFreeVars f = LiftM $ do
-  expansions <- RWS.asks e_expansions
-  pure $ case lookupVarEnv expansions f of
-    Nothing -> []
-    Just fvs -> dVarSetElems fvs
-
 -- | Creates an /expander function/ for the current set of lifted binders.
 -- This expander function will replace any 'InId' by their corresponding 'OutId'
 -- and, in addition, will expand any lifted binders by the former free variables


=====================================
compiler/GHC/Stg/Syntax.hs
=====================================
@@ -492,7 +492,7 @@ stgRhsArity (StgRhsClosure _ _ _ bndrs _ _)
 stgRhsArity (StgRhsCon {}) = 0
 
 freeVarsOfRhs :: (XRhsClosure pass ~ DIdSet) => GenStgRhs pass -> DIdSet
-freeVarsOfRhs (StgRhsCon _ _ _ _ args _) = mkDVarSet [ id | StgVarArg id <- args ]
+freeVarsOfRhs (StgRhsCon _ _ _ _ args _) = mkDVarSet [ id | StgVarArg id <- args, isLocalId id ]
 freeVarsOfRhs (StgRhsClosure fvs _ _ _ _ _) = fvs
 
 {-


=====================================
testsuite/tests/perf/compiler/LargeRecord.hs
=====================================
@@ -60,6 +60,7 @@ type BigFieldList =
   '[ "f1" := Int
    , "f2" := Int
    , "f3" := Int
+{-
    , "f4" := Int
    , "f5" := Int
    , "f6" := Int
@@ -72,6 +73,7 @@ type BigFieldList =
    , "f13" := Int
    , "f14" := Int
    , "f15" := Int
+-}
    ]
 
 bigRec :: Record BigFieldList
@@ -79,6 +81,7 @@ bigRec =
     #f1   := 1
   & #f2   := 2
   & #f3   := 3
+{-
   & #f4   := 4
   & #f5   := 5
   & #f6   := 6
@@ -91,6 +94,7 @@ bigRec =
   & #f13  := 13
   & #f14  := 14
   & #f15  := 15
+-}
   & rnil
 
 main :: IO ()



View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/commit/9bedd485ba8e7b051570902fa95eb13e3d82bdfa

-- 
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/commit/9bedd485ba8e7b051570902fa95eb13e3d82bdfa
You're receiving this email because of your account on gitlab.haskell.org.


-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.haskell.org/pipermail/ghc-commits/attachments/20230831/c87029c2/attachment-0001.html>


More information about the ghc-commits mailing list