[commit: ghc] master: Add comments explaining ProbOneShot (abfbdd1)

git at git.haskell.org git at git.haskell.org
Tue Nov 4 10:38:57 UTC 2014


Repository : ssh://git@git.haskell.org/ghc

On branch  : master
Link       : http://ghc.haskell.org/trac/ghc/changeset/abfbdd1c639c0c60bcc20bde81d61a9ad3e786fa/ghc

>---------------------------------------------------------------

commit abfbdd1c639c0c60bcc20bde81d61a9ad3e786fa
Author: Simon Peyton Jones <simonpj at microsoft.com>
Date:   Fri Oct 31 11:13:37 2014 +0000

    Add comments explaining ProbOneShot


>---------------------------------------------------------------

abfbdd1c639c0c60bcc20bde81d61a9ad3e786fa
 compiler/basicTypes/BasicTypes.lhs |   8 ++-
 compiler/basicTypes/Demand.lhs     | 110 ++++++++++++++++++++++++-------------
 compiler/simplCore/OccurAnal.lhs   |   0
 compiler/simplCore/SetLevels.lhs   |   1 +
 4 files changed, 77 insertions(+), 42 deletions(-)

diff --git a/compiler/basicTypes/BasicTypes.lhs b/compiler/basicTypes/BasicTypes.lhs
index 2f86db7..4fbfb60 100644
--- a/compiler/basicTypes/BasicTypes.lhs
+++ b/compiler/basicTypes/BasicTypes.lhs
@@ -155,9 +155,11 @@ type Alignment = Int -- align to next N-byte boundary (N must be a power of 2).
 -- This information may be useful in optimisation, as computations may
 -- safely be floated inside such a lambda without risk of duplicating
 -- work.
-data OneShotInfo = NoOneShotInfo -- ^ No information
-                 | ProbOneShot   -- ^ The lambda is probably applied at most once
-                 | OneShotLam    -- ^ The lambda is applied at most once.
+data OneShotInfo
+  = NoOneShotInfo -- ^ No information
+  | ProbOneShot   -- ^ The lambda is probably applied at most once
+                  -- See Note [Computing one-shot info, and ProbOneShot] in OccurAnl
+  | OneShotLam    -- ^ The lambda is applied at most once.
 
 -- | It is always safe to assume that an 'Id' has no lambda-bound variable information
 noOneShotInfo :: OneShotInfo
diff --git a/compiler/basicTypes/Demand.lhs b/compiler/basicTypes/Demand.lhs
index 2aa25ce..f553fc2 100644
--- a/compiler/basicTypes/Demand.lhs
+++ b/compiler/basicTypes/Demand.lhs
@@ -1493,6 +1493,11 @@ newtype StrictSig = StrictSig DmdType
 instance Outputable StrictSig where
    ppr (StrictSig ty) = ppr ty
 
+-- Used for printing top-level strictness pragmas in interface files
+pprIfaceStrictSig :: StrictSig -> SDoc
+pprIfaceStrictSig (StrictSig (DmdType _ dmds res))
+  = hcat (map ppr dmds) <> ppr res
+
 mkStrictSig :: DmdType -> StrictSig
 mkStrictSig dmd_ty = StrictSig dmd_ty
 
@@ -1520,29 +1525,8 @@ botSig = StrictSig botDmdType
 cprProdSig :: Arity -> StrictSig
 cprProdSig arity = StrictSig (cprProdDmdType arity)
 
-argsOneShots :: StrictSig -> Arity -> [[OneShotInfo]]
-argsOneShots (StrictSig (DmdType _ arg_ds _)) n_val_args
-  = go arg_ds
-  where
-    good_one_shot
-      | arg_ds `lengthExceeds` n_val_args = ProbOneShot
-      | otherwise                         = OneShotLam
-
-    go []               = []
-    go (arg_d : arg_ds) = argOneShots good_one_shot arg_d `cons` go arg_ds
-
-    cons [] [] = []
-    cons a  as = a:as
-
-argOneShots :: OneShotInfo -> JointDmd -> [OneShotInfo]
-argOneShots one_shot_info (JD { absd = usg })
-  = case usg of
-      Use _ arg_usg -> go arg_usg
-      _             -> []
-  where
-    go (UCall One  u) = one_shot_info : go u
-    go (UCall Many u) = NoOneShotInfo : go u
-    go _              = []
+seqStrictSig :: StrictSig -> ()
+seqStrictSig (StrictSig ty) = seqDmdType ty
 
 dmdTransformSig :: StrictSig -> CleanDemand -> DmdType
 -- (dmdTransformSig fun_sig dmd) considers a call to a function whose
@@ -1617,31 +1601,79 @@ you might do strictness analysis, but there is no inlining for the class op.
 This is weird, so I'm not worried about whether this optimises brilliantly; but
 it should not fall over.
 
-Note [Non-full application] 
-~~~~~~~~~~~~~~~~~~~~~~~~~~~ 
-If a function having bottom as its demand result is applied to a less
-number of arguments than its syntactic arity, we cannot say for sure
-that it is going to diverge. This is the reason why we use the
-function appIsBottom, which, given a strictness signature and a number
-of arguments, says conservatively if the function is going to diverge
-or not.
+\begin{code}
+argsOneShots :: StrictSig -> Arity -> [[OneShotInfo]]
+-- See Note [Computing one-shot info, and ProbOneShot]
+argsOneShots (StrictSig (DmdType _ arg_ds _)) n_val_args
+  = go arg_ds
+  where
+    unsaturated_call = arg_ds `lengthExceeds` n_val_args
+    good_one_shot
+      | unsaturated_call = ProbOneShot
+      | otherwise        = OneShotLam
+
+    go []               = []
+    go (arg_d : arg_ds) = argOneShots good_one_shot arg_d `cons` go arg_ds
+
+    -- Avoid list tail like [ [], [], [] ]
+    cons [] [] = []
+    cons a  as = a:as
+
+argOneShots :: OneShotInfo -> JointDmd -> [OneShotInfo]
+argOneShots one_shot_info (JD { absd = usg })
+  = case usg of
+      Use _ arg_usg -> go arg_usg
+      _             -> []
+  where
+    go (UCall One  u) = one_shot_info : go u
+    go (UCall Many u) = NoOneShotInfo : go u
+    go _              = []
+\end{code}
+
+Note [Computing one-shot info, and ProbOneShot]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+Consider a call
+    f (\pqr. e1) (\xyz. e2) e3
+where f has usage signature
+    C1(C(C1(U))) C1(U) U
+Then argsOneShots returns a [[OneShotInfo]] of
+    [[OneShot,NoOneShotInfo,OneShot],  [OneShot]]
+The occurrence analyser propagates this one-shot infor to the
+binders \pqr and \xyz; see Note [Use one-shot information] in OccurAnal.
+
+But suppose f was not saturated, so the call looks like
+    f (\pqr. e1) (\xyz. e2)
+The in principle this partial application might be shared, and
+the (\prq.e1) abstraction might be called more than once.  So
+we can't mark them OneShot. But instead we return
+    [[ProbOneShot,NoOneShotInfo,ProbOneShot],  [ProbOneShot]]
+The occurrence analyser propagates this to the \pqr and \xyz
+binders.
+
+How is it used?  Well, it's quite likely that the partial application
+of f is not shared, so the float-out pass (in SetLevels.lvlLamBndrs)
+does not float MFEs out of a ProbOneShot lambda.  That currently is
+the only way that ProbOneShot is used.
+
 
 \begin{code}
 -- appIsBottom returns true if an application to n args would diverge
+-- See Note [Unsaturated applications]
 appIsBottom :: StrictSig -> Int -> Bool
 appIsBottom (StrictSig (DmdType _ ds res)) n
             | isBotRes res                      = not $ lengthExceeds ds n 
 appIsBottom _                                 _ = False
-
-seqStrictSig :: StrictSig -> ()
-seqStrictSig (StrictSig ty) = seqDmdType ty
-
--- Used for printing top-level strictness pragmas in interface files
-pprIfaceStrictSig :: StrictSig -> SDoc
-pprIfaceStrictSig (StrictSig (DmdType _ dmds res))
-  = hcat (map ppr dmds) <> ppr res
 \end{code}
 
+Note [Unsaturated applications]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+If a function having bottom as its demand result is applied to a less
+number of arguments than its syntactic arity, we cannot say for sure
+that it is going to diverge. This is the reason why we use the
+function appIsBottom, which, given a strictness signature and a number
+of arguments, says conservatively if the function is going to diverge
+or not.
+
 Zap absence or one-shot information, under control of flags
 
 \begin{code}
diff --git a/compiler/simplCore/SetLevels.lhs b/compiler/simplCore/SetLevels.lhs
index e5cd42e..b8726d9 100644
--- a/compiler/simplCore/SetLevels.lhs
+++ b/compiler/simplCore/SetLevels.lhs
@@ -827,6 +827,7 @@ lvlLamBndrs env lvl bndrs
     is_major bndr = isId bndr && not (isProbablyOneShotLambda bndr)
        -- The "probably" part says "don't float things out of a
        -- probable one-shot lambda"
+       -- See Note [Computing one-shot info] in Demand.lhs
 
 
 lvlBndrs :: LevelEnv -> Level -> [CoreBndr] -> (LevelEnv, [LevelledBndr])



More information about the ghc-commits mailing list