summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSimon Peyton Jones <simonpj@microsoft.com>2011-12-12 11:16:49 +0000
committerSimon Peyton Jones <simonpj@microsoft.com>2011-12-12 11:16:49 +0000
commit56a05294f3a94a6826c8eaaef6c9946d42c71eaf (patch)
treee109e655eae9fd8308b06615f108df493ec14729
parent88cd0d1fd68ec88dfe843fa14f3895a21e1ca07f (diff)
downloadhaskell-56a05294f3a94a6826c8eaaef6c9946d42c71eaf.tar.gz
Add comments about the meaning of can_fail and has_side_effects
Taken from Trac #5658
-rw-r--r--compiler/prelude/PrimOp.lhs136
-rw-r--r--compiler/prelude/primops.txt.pp5
2 files changed, 89 insertions, 52 deletions
diff --git a/compiler/prelude/PrimOp.lhs b/compiler/prelude/PrimOp.lhs
index ec5c09611e..d57d1f926e 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 a695344225..5047b3cb63 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.