WIP: Clear up PrimOp effect semantics
Previously we classified PrimOps with two boolean flags,
has_side_effects. Although there is quite a slew of documentation
surrounding them, see
Note [PrimOp can_fail and has_side_effects]
Note [Transformations affected by can_fail and has_side_effects],
I found it quite hard to understand and also was confused of
conservative misclassifications for some read-only primops like
readMutVar# (which is marked as
has_side_effect, although it
actually shouldn't per semantics of
has_side_effect, see #3207 (closed)), but
not for others (
indexIntArr#, which is just
This patch defines a total order of 5 different
NoEffect: A pure primop
ThrowsImprecise: Possibly throws an imprecise exception (and may perform read effects)
WriteEffect: May write to a mutable ref cell, array or the world (or read from them or throw an imprecise exception)
ThrowsPrecise: May throw a precise exception, or do any of the aforementioned effects.
Each effect is strictly "stronger" than its predecessor in this list wrt. to program transformation that are sound to apply to it. For example, we may speculatively execute read effects (as long as their data dependencies such as the state token are satisfied), but we may not speculate division (for fear of imprecise division-by-zero errors).
PrimOpEffect inhibits which transformation, including examples,
is spelled out in the rewritten
Note [Transformations affected by PrimOpEffect].