diff options
Diffstat (limited to 'compiler/GHC/Core/Opt/OccurAnal.hs')
-rw-r--r-- | compiler/GHC/Core/Opt/OccurAnal.hs | 112 |
1 files changed, 68 insertions, 44 deletions
diff --git a/compiler/GHC/Core/Opt/OccurAnal.hs b/compiler/GHC/Core/Opt/OccurAnal.hs index d014b4a30c..eb4c2ef6b6 100644 --- a/compiler/GHC/Core/Opt/OccurAnal.hs +++ b/compiler/GHC/Core/Opt/OccurAnal.hs @@ -1757,6 +1757,7 @@ occAnalUnfolding !env is_rec mb_join_arity unf env' = env `addInScope` bndrs (WithUsageDetails usage args') = occAnalList env' args final_usage = markAllManyNonTail (delDetailsList usage bndrs) + `addLamCoVarOccs` bndrs unf -> WithUsageDetails emptyDetails unf @@ -1777,8 +1778,8 @@ occAnalRules !env mb_join_arity bndr | otherwise = rule { ru_args = args', ru_rhs = rhs' } (WithUsageDetails lhs_uds args') = occAnalList env' args - lhs_uds' = markAllManyNonTail $ - lhs_uds `delDetailsList` bndrs + lhs_uds' = markAllManyNonTail (lhs_uds `delDetailsList` bndrs) + `addLamCoVarOccs` bndrs (WithUsageDetails rhs_uds rhs') = occAnal env' rhs -- Note [Rules are extra RHSs] @@ -1902,9 +1903,9 @@ occAnal :: OccEnv -> CoreExpr -> WithUsageDetails CoreExpr -- Gives info only about the "interesting" Ids -occAnal !_ expr@(Type _) = WithUsageDetails emptyDetails expr -occAnal _ expr@(Lit _) = WithUsageDetails emptyDetails expr -occAnal env expr@(Var _) = occAnalApp env (expr, [], []) +occAnal !_ expr@(Lit _) = WithUsageDetails emptyDetails expr + +occAnal env expr@(Var _) = occAnalApp env (expr, [], []) -- At one stage, I gathered the idRuleVars for the variable here too, -- which in a way is the right thing to do. -- But that went wrong right after specialisation, when @@ -1912,15 +1913,54 @@ occAnal env expr@(Var _) = occAnalApp env (expr, [], []) -- rules in them, so the *specialised* versions looked as if they -- weren't used at all. -occAnal _ (Coercion co) - = WithUsageDetails (addManyOccs emptyDetails (coVarsOfCo co)) (Coercion co) +occAnal _ expr@(Type ty) + = WithUsageDetails (addManyOccs emptyDetails (coVarsOfType ty)) expr +occAnal _ expr@(Coercion co) + = WithUsageDetails (addManyOccs emptyDetails (coVarsOfCo co)) expr -- See Note [Gather occurrences of coercion variables] -{- -Note [Gather occurrences of coercion variables] +{- Note [Gather occurrences of coercion variables] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -We need to gather info about what coercion variables appear, so that -we can sort them into the right place when doing dependency analysis. +We need to gather info about what coercion variables appear, for two reasons: + +1. So that we can sort them into the right place when doing dependency analysis. + +2. So that we know when they are surely dead. + +It is useful to know when they a coercion variable is surely dead, +when we want to discard a case-expression, in GHC.Core.Opt.Simplify.rebuildCase. +For example (#20143): + + case unsafeEqualityProof @blah of + UnsafeRefl cv -> ...no use of cv... + +Here we can discard the case, since unsafeEqualityProof always terminates. +But only if the coercion variable 'cv' is unused. + +Another example from #15696: we had something like + case eq_sel d of co -> ...(typeError @(...co...) "urk")... +Then 'd' was substituted by a dictionary, so the expression +simpified to + case (Coercion <blah>) of cv -> ...(typeError @(...cv...) "urk")... + +We can only drop the case altogether if 'cv' is unused, which is not +the case here. + +Conclusion: we need accurate dead-ness info for CoVars. +We gather CoVar occurrences from: + + * The (Type ty) and (Coercion co) cases of occAnal + + * The type 'ty' of a lambda-binder (\(x:ty). blah) + See addLamCoVarOccs + +But it is not necessary to gather CoVars from the types of other binders. + +* For let-binders, if the type mentions a CoVar, so will the RHS (since + it has the same type) + +* For case-alt binders, if the type mentions a CoVar, so will the scrutinee + (since it has the same type) -} occAnal env (Tick tickish body) @@ -2000,6 +2040,8 @@ occAnal env expr@(Lam _ _) usage1 = markAllNonTail usage one_shot_gp = all isOneShotBndr tagged_bndrs final_usage = markAllInsideLamIf (not one_shot_gp) usage1 + `addLamCoVarOccs` bndrs + -- See Note [Gather occurrences of coercion variables] in WithUsageDetails final_usage expr' occAnal env (Case scrut bndr ty alts) @@ -2828,6 +2870,12 @@ addManyOccs :: UsageDetails -> VarSet -> UsageDetails addManyOccs usage id_set = nonDetStrictFoldUniqSet addManyOcc usage id_set -- It's OK to use nonDetStrictFoldUniqSet here because addManyOcc commutes +addLamCoVarOccs :: UsageDetails -> [Var] -> UsageDetails +-- Add any CoVars free in the type of a lambda-binder +-- See Note [Gather occurrences of coercion variables] +addLamCoVarOccs uds bndrs + = uds `addManyOccs` coVarsOfTypes (map varType bndrs) + delDetails :: UsageDetails -> Id -> UsageDetails delDetails ud bndr = ud `alterUsageDetails` (`delVarEnv` bndr) @@ -2870,10 +2918,6 @@ markAllManyNonTailIf False uds = uds lookupDetails :: UsageDetails -> Id -> OccInfo lookupDetails ud id - | isCoVar id -- We do not currently gather occurrence info (from types) - = noOccInfo -- for CoVars, so we must conservatively mark them as used - -- See Note [DoO not mark CoVars as dead] - | otherwise = case lookupVarEnv (ud_env ud) id of Just occ -> doZapping ud id occ Nothing -> IAmDead @@ -2888,25 +2932,6 @@ udFreeVars bndrs ud = restrictFreeVars bndrs (ud_env ud) restrictFreeVars :: VarSet -> OccInfoEnv -> VarSet restrictFreeVars bndrs fvs = restrictUniqSetToUFM bndrs fvs -{- Note [Do not mark CoVars as dead] -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -It's obviously wrong to mark CoVars as dead if they are used. -Currently we don't traverse types to gather usage info for CoVars, -so we had better treat them as having noOccInfo. - -This showed up in #15696 we had something like - case eq_sel d of co -> ...(typeError @(...co...) "urk")... - -Then 'd' was substituted by a dictionary, so the expression -simpified to - case (Coercion <blah>) of co -> ...(typeError @(...co...) "urk")... - -But then the "drop the case altogether" equation of rebuildCase -thought that 'co' was dead, and discarded the entire case. Urk! - -I have no idea how we managed to avoid this pitfall for so long! --} - ------------------- -- Auxiliary functions for UsageDetails implementation @@ -2938,20 +2963,19 @@ doZappingByUnique (UD { ud_z_many = many occ2 | uniq `elemVarEnvByKey` no_tail = markNonTail occ1 | otherwise = occ1 -alterZappedSets :: UsageDetails -> (ZappedSet -> ZappedSet) -> UsageDetails -alterZappedSets ud f - = ud { ud_z_many = f (ud_z_many ud) +alterUsageDetails :: UsageDetails -> (OccInfoEnv -> OccInfoEnv) -> UsageDetails +alterUsageDetails !ud f + = UD { ud_env = f (ud_env ud) + , ud_z_many = f (ud_z_many ud) , ud_z_in_lam = f (ud_z_in_lam ud) , ud_z_no_tail = f (ud_z_no_tail ud) } -alterUsageDetails :: UsageDetails -> (OccInfoEnv -> OccInfoEnv) -> UsageDetails -alterUsageDetails ud f - = ud { ud_env = f (ud_env ud) } `alterZappedSets` f - flattenUsageDetails :: UsageDetails -> UsageDetails -flattenUsageDetails ud - = ud { ud_env = mapUFM_Directly (doZappingByUnique ud) (ud_env ud) } - `alterZappedSets` const emptyVarEnv +flattenUsageDetails ud@(UD { ud_env = env }) + = UD { ud_env = mapUFM_Directly (doZappingByUnique ud) env + , ud_z_many = emptyVarEnv + , ud_z_in_lam = emptyVarEnv + , ud_z_no_tail = emptyVarEnv } ------------------- -- See Note [Adjusting right-hand sides] |