Note [exprOkForSpeculation and evaluated variables]
Consider these examples:
* case x of y { DEFAULT -> ....y.... }
Should 'y' (alone) be considered ok-for-speculation?
* case x of y { DEFAULT -> ....let z = dataToTagLarge# y... }
Should (dataToTagLarge# y) be considered ok-for-spec? Recall that
dataToTagLarge# :: forall a. a -> Int#
must always evaluate its argument. (See also Note [DataToTag overview].)
You could argue 'yes', because in the case alternative we know that
'y' is evaluated. But the binder-swap transformation, which is
extremely useful for float-out, changes these expressions to
case x of y { DEFAULT -> ....x.... }
case x of y { DEFAULT -> ....let z = dataToTagLarge# x... }
And now the expression does not obey the let-can-float invariant! Yikes!
Moreover we really might float (dataToTagLarge# x) outside the case,
and then it really, really doesn't obey the let-can-float invariant.
The solution is simple: exprOkForSpeculation does not try to take
advantage of the evaluated-ness of (lifted) variables. And it returns
False (always) for primops that perform evaluation. We achieve the latter
by marking the relevant primops as "ThrowsException" or
"ReadWriteEffect"; see also Note [Classifying primop effects] in
GHC.Builtin.PrimOps.
Note that exprIsHNF /can/ and does take advantage of evaluated-ness;
it doesn't have the trickiness of the let-can-float invariant to worry about.
************************************************************************
* *
exprIsHNF, exprIsConLike
* *
************************************************************************ References 2
- Classifying primop effects GHC.Builtin.PrimOps
- DataToTag overview GHC.Tc.Instance.Class
Referenced by 6
- GHC.Core.Utils call site ×3
- GHC.Core.Opt.CprAnal call site
- Floating single-alternative cases GHC.Core.Opt.SetLevels
- No unboxed tuple for single, unlifted transit var GHC.Core.Opt.WorkWrap.Utils