From befef2343cb1aded4172df800f72453eb5695b79 Mon Sep 17 00:00:00 2001
From: Simon Peyton Jones <simonpj@microsoft.com>
Date: Mon, 12 Dec 2011 11:16:49 +0000
Subject: [PATCH] Add comments about the meaning of can_fail and
 has_side_effects

Taken from Trac #5658
---
 compiler/prelude/PrimOp.lhs     | 136 ++++++++++++++++++++------------
 compiler/prelude/primops.txt.pp |   5 +-
 2 files changed, 89 insertions(+), 52 deletions(-)

diff --git a/compiler/prelude/PrimOp.lhs b/compiler/prelude/PrimOp.lhs
index ec5c09611ebd..d57d1f926ed6 100644
--- a/compiler/prelude/PrimOp.lhs
+++ b/compiler/prelude/PrimOp.lhs
@@ -285,7 +285,7 @@ code generator will fall over if they aren't satisfied.
 
 %************************************************************************
 %*                                                                      *
-\subsubsection[PrimOp-ool]{Which PrimOps are out-of-line}
+            Which PrimOps are out-of-line
 %*                                                                      *
 %************************************************************************
 
@@ -299,15 +299,39 @@ primOpOutOfLine :: PrimOp -> Bool
 \end{code}
 
 
-primOpOkForSpeculation
-~~~~~~~~~~~~~~~~~~~~~~
+%************************************************************************
+%*                                                                      *
+            Failure and side effects
+%*                                                                      *
+%************************************************************************
+
+Note [PrimOp can_fail and has_side_effects]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ * A primop that is neither can_fail nor has_side_effects can be
+   executed speculatively, any number of times
+
+ * A primop that is marked can_fail cannot be executed speculatively,
+   (becuase the might provoke the failure), but it can be repeated.
+   Why would you want to do that? Perhaps it might enable some
+   eta-expansion, if you can prove that the lambda is definitely
+   applied at least once. I guess we don't currently do that.
+
+ * A primop that is marked has_side_effects can be neither speculated
+   nor repeated; it must be executed exactly the right number of
+   times.
+
+So has_side_effects implies can_fail.  We don't currently exploit
+the case of primops that can_fail but do not have_side_effects.
+
+Note [primOpOkForSpeculation]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 Sometimes we may choose to execute a PrimOp even though it isn't
 certain that its result will be required; ie execute them
 ``speculatively''.  The same thing as ``cheap eagerness.'' Usually
 this is OK, because PrimOps are usually cheap, but it isn't OK for
-(a)~expensive PrimOps and (b)~PrimOps which can fail.
-
-PrimOps that have side effects also should not be executed speculatively.
+  * PrimOps that are expensive 
+  * PrimOps which can fail
+  * PrimOps that have side effects
 
 Ok-for-speculation also means that it's ok *not* to execute the
 primop. For example
@@ -318,10 +342,53 @@ that has side effects mustn't be dicarded in this way, of course!
 
 See also @primOpIsCheap@ (below).
 
+Note [primOpHasSideEffects]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~
+Some primops have side-effects and so, for example, must not be
+duplicated.
+
+This predicate means a little more than just "modifies the state of
+the world".  What it really means is "it cosumes the state on its
+input".  To see what this means, consider
+
+ let
+     t = case readMutVar# v s0 of (# s1, x #) -> (S# s1, x)
+     y = case t of (s,x) -> x
+ in
+     ... y ... y ...
+
+Now, this is part of an ST or IO thread, so we are guaranteed by
+construction that the program uses the state in a single-threaded way.
+Whenever the state resulting from the readMutVar# is demanded, the
+readMutVar# will be performed, and it will be ordered correctly with
+respect to other operations in the monad.
+
+But there's another way this could go wrong: GHC can inline t into y,
+and inline y.  Then although the original readMutVar# will still be
+correctly ordered with respect to the other operations, there will be
+one or more extra readMutVar#s performed later, possibly out-of-order.
+This really happened; see #3207.
+
+The property we need to capture about readMutVar# is that it consumes
+the State# value on its input.  We must retain the linearity of the
+State#.
+
+Our fix for this is to declare any primop that must be used linearly
+as having side-effects.  When primOpHasSideEffects is True,
+primOpOkForSpeculation will be False, and hence primOpIsCheap will
+also be False, and applications of the primop will never be
+duplicated.
 
 \begin{code}
+primOpHasSideEffects :: PrimOp -> Bool
+#include "primop-has-side-effects.hs-incl"
+
+primOpCanFail :: PrimOp -> Bool
+#include "primop-can-fail.hs-incl"
+
 primOpOkForSpeculation :: PrimOp -> Bool
-        -- See comments with CoreUtils.exprOkForSpeculation
+  -- See Note [primOpOkForSpeculation]
+  -- See comments with CoreUtils.exprOkForSpeculation
 primOpOkForSpeculation op
   = not (primOpHasSideEffects op || primOpOutOfLine op || primOpCanFail op)
 \end{code}
@@ -356,6 +423,13 @@ primOpIsCheap op = primOpOkForSpeculation op
 -- even if primOpIsCheap sometimes says 'True'.
 \end{code}
 
+
+%************************************************************************
+%*                                                                      *
+               PrimOp code size
+%*                                                                      *
+%************************************************************************
+
 primOpCodeSize
 ~~~~~~~~~~~~~~
 Gives an indication of the code size of a primop, for the purposes of
@@ -374,50 +448,12 @@ primOpCodeSizeForeignCall :: Int
 primOpCodeSizeForeignCall = 4
 \end{code}
 
-\begin{code}
-primOpCanFail :: PrimOp -> Bool
-#include "primop-can-fail.hs-incl"
-\end{code}
-
-And some primops have side-effects and so, for example, must not be
-duplicated.
-
-This predicate means a little more than just "modifies the state of
-the world".  What it really means is "it cosumes the state on its
-input".  To see what this means, consider
-
- let
-     t = case readMutVar# v s0 of (# s1, x #) -> (S# s1, x)
-     y = case t of (s,x) -> x
- in
-     ... y ... y ...
-
-Now, this is part of an ST or IO thread, so we are guaranteed by
-construction that the program uses the state in a single-threaded way.
-Whenever the state resulting from the readMutVar# is demanded, the
-readMutVar# will be performed, and it will be ordered correctly with
-respect to other operations in the monad.
-
-But there's another way this could go wrong: GHC can inline t into y,
-and inline y.  Then although the original readMutVar# will still be
-correctly ordered with respect to the other operations, there will be
-one or more extra readMutVar#s performed later, possibly out-of-order.
-This really happened; see #3207.
 
-The property we need to capture about readMutVar# is that it consumes
-the State# value on its input.  We must retain the linearity of the
-State#.
-
-Our fix for this is to declare any primop that must be used linearly
-as having side-effects.  When primOpHasSideEffects is True,
-primOpOkForSpeculation will be False, and hence primOpIsCheap will
-also be False, and applications of the primop will never be
-duplicated.
-
-\begin{code}
-primOpHasSideEffects :: PrimOp -> Bool
-#include "primop-has-side-effects.hs-incl"
-\end{code}
+%************************************************************************
+%*                                                                      *
+               PrimOp types
+%*                                                                      *
+%************************************************************************
 
 \begin{code}
 primOpType :: PrimOp -> Type  -- you may want to use primOpSig instead
diff --git a/compiler/prelude/primops.txt.pp b/compiler/prelude/primops.txt.pp
index a695344225a2..5047b3cb631e 100644
--- a/compiler/prelude/primops.txt.pp
+++ b/compiler/prelude/primops.txt.pp
@@ -41,12 +41,13 @@
 
 defaults
    has_side_effects = False
-   out_of_line      = False
+   out_of_line      = False   -- See Note Note [PrimOp can_fail and has_side_effects] in PrimOp
+   can_fail         = False   -- See Note Note [PrimOp can_fail and has_side_effects] in PrimOp
    commutable       = False
    code_size        = { primOpCodeSizeDefault }
-   can_fail         = False
    strictness       = { \ arity -> mkStrictSig (mkTopDmdType (replicate arity lazyDmd) TopRes) }
 
+
 -- Currently, documentation is produced using latex, so contents of
 -- description fields should be legal latex. Descriptions can contain
 -- matched pairs of embedded curly brackets.
-- 
GitLab