summaryrefslogtreecommitdiff
path: root/compiler/GHC/Core/Utils.hs
diff options
context:
space:
mode:
authorSimon Peyton Jones <simonpj@microsoft.com>2021-07-22 11:41:08 +0100
committerSimon Peyton Jones <simonpj@microsoft.com>2021-07-26 17:15:01 +0100
commit51af8af0a729751f946c87badf0a515d40050076 (patch)
treef10a17ee0fa6c0cb24348d75cddb754107e39f09 /compiler/GHC/Core/Utils.hs
parent5f3991c7cab8ccc9ab8daeebbfce57afbd9acc33 (diff)
downloadhaskell-wip/T20143.tar.gz
Eliminate unnecessary unsafeEqualityProofwip/T20143
This patch addresses #20143, which wants to discard unused calls to unsafeEqualityProof. There are two parts: * In exprOkForSideEffects, we want to know that unsafeEqualityProof indeed terminates, without any exceptions etc * But we can only discard the case if we know that the coercion variable is not used, which means we have to gather accurate occurrence info for CoVars. Previously OccurAnal only did a half hearted job of doing so; this patch finishes the job. See Note [Gather occurrences of coercion variables] in OccurAnal. Because the occurrence analyser does more work, there is a small compile-time cost but it's pretty small. The compiler perf tests are usually 0.0% but occasionally up to 0.3% increase. I'm just going to accept this -- gathering accurate occurrence information really seems like the Right Thing to do. There is an increase in `compile_time/peak_megabytes_allocated`, for T11545, or around 14%; but I can't reproduce it on my machine (it's the same before and after), and the peak-usage stats are vulnerable to when exactly the GC takes place, so I'm just going to accept it. Metric Increase: T11545
Diffstat (limited to 'compiler/GHC/Core/Utils.hs')
-rw-r--r--compiler/GHC/Core/Utils.hs40
1 files changed, 34 insertions, 6 deletions
diff --git a/compiler/GHC/Core/Utils.hs b/compiler/GHC/Core/Utils.hs
index 12efdddcd4..58a00eba76 100644
--- a/compiler/GHC/Core/Utils.hs
+++ b/compiler/GHC/Core/Utils.hs
@@ -79,7 +79,7 @@ import GHC.Core.Coercion
import GHC.Core.TyCon
import GHC.Core.Multiplicity
-import GHC.Builtin.Names (makeStaticName, unsafeEqualityProofName)
+import GHC.Builtin.Names ( makeStaticName, unsafeEqualityProofIdKey )
import GHC.Builtin.PrimOps
import GHC.Types.Var
@@ -1661,14 +1661,28 @@ app_ok primop_ok fun args
-> primop_ok op -- Check the primop itself
&& and (zipWith primop_arg_ok arg_tys args) -- Check the arguments
- _other -> isUnliftedType (idType fun) -- c.f. the Var case of exprIsHNF
- || idArity fun > n_val_args -- Partial apps
+ _ -- Unlifted types
+ -- c.f. the Var case of exprIsHNF
+ | isUnliftedType (idType fun)
+ -> assertPpr (n_val_args == 0) (ppr fun $$ ppr args)
+ True -- Our only unlifted types are Int# etc, so will have
+ -- no value args. The assert is just to check this.
+ -- If we added unlifted function types this would change,
+ -- and we'd need to actually test n_val_args == 0.
+
+ -- Partial applications
+ | idArity fun > n_val_args -> True
+
+ -- Functions that terminate fast without raising exceptions etc
+ -- See Note [Discarding unnecessary unsafeEqualityProofs]
+ | fun `hasKey` unsafeEqualityProofIdKey -> True
+
+ | otherwise -> False
-- NB: even in the nullary case, do /not/ check
-- for evaluated-ness of the fun;
-- see Note [exprOkForSpeculation and evaluated variables]
- where
- n_val_args = valArgCount args
where
+ n_val_args = valArgCount args
(arg_tys, _) = splitPiTys (idType fun)
primop_arg_ok :: TyBinder -> CoreExpr -> Bool
@@ -1841,6 +1855,20 @@ False (always) for DataToTagOp and SeqOp.
Note that exprIsHNF /can/ and does take advantage of evaluated-ness;
it doesn't have the trickiness of the let/app invariant to worry about.
+Note [Discarding unnecessary unsafeEqualityProofs]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+In #20143 we found
+ case unsafeEqualityProof @t1 @t2 of UnsafeRefl cv[dead] -> blah
+where 'blah' didn't mention 'cv'. We'd like to discard this
+redundant use of unsafeEqualityProof, via GHC.Core.Opt.Simplify.rebuildCase.
+To do this we need to know
+ (a) that cv is unused (done by OccAnal), and
+ (b) that unsafeEqualityProof terminates rapidly without side effects.
+
+At the moment we check that explicitly here in exprOkForSideEffects,
+but one might imagine a more systematic check in future.
+
+
************************************************************************
* *
exprIsHNF, exprIsConLike
@@ -2656,6 +2684,6 @@ isUnsafeEqualityProof :: CoreExpr -> Bool
-- Note [Implementing unsafeCoerce] in base:Unsafe.Coerce
isUnsafeEqualityProof e
| Var v `App` Type _ `App` Type _ `App` Type _ <- e
- = idName v == unsafeEqualityProofName
+ = v `hasKey` unsafeEqualityProofIdKey
| otherwise
= False