+mkTopSigTy :: CoreExpr -> DmdType -> StrictSig
+ -- Take a DmdType and turn it into a StrictSig
+ -- NB: not used for never-inline things; hence False
+mkTopSigTy rhs dmd_ty = snd (mk_sig_ty False False rhs dmd_ty)
+
+mkSigTy :: TopLevelFlag -> RecFlag -> Id -> CoreExpr -> DmdType -> (DmdEnv, StrictSig)
+mkSigTy top_lvl rec_flag id rhs dmd_ty
+ = mk_sig_ty never_inline thunk_cpr_ok rhs dmd_ty
+ where
+ never_inline = isNeverActive (idInlinePragma id)
+ maybe_id_dmd = idNewDemandInfo_maybe id
+ -- Is Nothing the first time round
+
+ thunk_cpr_ok
+ | isTopLevel top_lvl = False -- Top level things don't get
+ -- their demandInfo set at all
+ | isRec rec_flag = False -- Ditto recursive things
+ | Just dmd <- maybe_id_dmd = isStrictDmd dmd
+ | otherwise = True -- Optimistic, first time round
+ -- See notes below
+\end{code}
+
+The thunk_cpr_ok stuff [CPR-AND-STRICTNESS]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+If the rhs is a thunk, we usually forget the CPR info, because
+it is presumably shared (else it would have been inlined, and
+so we'd lose sharing if w/w'd it into a function.
+
+However, if the strictness analyser has figured out (in a previous
+iteration) that it's strict, then we DON'T need to forget the CPR info.
+Instead we can retain the CPR info and do the thunk-splitting transform
+(see WorkWrap.splitThunk).
+
+This made a big difference to PrelBase.modInt, which had something like
+ modInt = \ x -> let r = ... -> I# v in
+ ...body strict in r...
+r's RHS isn't a value yet; but modInt returns r in various branches, so
+if r doesn't have the CPR property then neither does modInt
+Another case I found in practice (in Complex.magnitude), looks like this:
+ let k = if ... then I# a else I# b
+ in ... body strict in k ....
+(For this example, it doesn't matter whether k is returned as part of
+the overall result; but it does matter that k's RHS has the CPR property.)
+Left to itself, the simplifier will make a join point thus:
+ let $j k = ...body strict in k...
+ if ... then $j (I# a) else $j (I# b)
+With thunk-splitting, we get instead
+ let $j x = let k = I#x in ...body strict in k...
+ in if ... then $j a else $j b
+This is much better; there's a good chance the I# won't get allocated.
+
+The difficulty with this is that we need the strictness type to
+look at the body... but we now need the body to calculate the demand
+on the variable, so we can decide whether its strictness type should
+have a CPR in it or not. Simple solution:
+ a) use strictness info from the previous iteration
+ b) make sure we do at least 2 iterations, by doing a second
+ round for top-level non-recs. Top level recs will get at
+ least 2 iterations except for totally-bottom functions
+ which aren't very interesting anyway.
+
+NB: strictly_demanded is never true of a top-level Id, or of a recursive Id.
+
+The Nothing case in thunk_cpr_ok [CPR-AND-STRICTNESS]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+Demand info now has a 'Nothing' state, just like strictness info.
+The analysis works from 'dangerous' towards a 'safe' state; so we
+start with botSig for 'Nothing' strictness infos, and we start with
+"yes, it's demanded" for 'Nothing' in the demand info. The
+fixpoint iteration will sort it all out.
+
+We can't start with 'not-demanded' because then consider
+ f x = let
+ t = ... I# x
+ in
+ if ... then t else I# y else f x'
+
+In the first iteration we'd have no demand info for x, so assume
+not-demanded; then we'd get TopRes for f's CPR info. Next iteration
+we'd see that t was demanded, and so give it the CPR property, but by
+now f has TopRes, so it will stay TopRes. Instead, with the Nothing
+setting the first time round, we say 'yes t is demanded' the first
+time.
+
+However, this does mean that for non-recursive bindings we must
+iterate twice to be sure of not getting over-optimistic CPR info,
+in the case where t turns out to be not-demanded. This is handled
+by dmdAnalTopBind.
+
+
+\begin{code}
+mk_sig_ty never_inline thunk_cpr_ok rhs (DmdType fv dmds res)
+ | never_inline && not (isBotRes res)
+ -- HACK ALERT
+ -- Don't strictness-analyse NOINLINE things. Why not? Because
+ -- the NOINLINE says "don't expose any of the inner workings at the call
+ -- site" and the strictness is certainly an inner working.
+ --
+ -- More concretely, the demand analyser discovers the following strictness
+ -- for unsafePerformIO: C(U(AV))
+ -- But then consider
+ -- unsafePerformIO (\s -> let r = f x in
+ -- case writeIORef v r s of (# s1, _ #) ->
+ -- (# s1, r #)
+ -- The strictness analyser will find that the binding for r is strict,
+ -- (becuase of uPIO's strictness sig), and so it'll evaluate it before
+ -- doing the writeIORef. This actually makes tests/lib/should_run/memo002
+ -- get a deadlock!
+ --
+ -- Solution: don't expose the strictness of unsafePerformIO.
+ --
+ -- But we do want to expose the strictness of error functions,
+ -- which are also often marked NOINLINE
+ -- {-# NOINLINE foo #-}
+ -- foo x = error ("wubble buggle" ++ x)
+ -- So (hack, hack) we only drop the strictness for non-bottom things
+ -- This is all very unsatisfactory.
+ = (deferEnv fv, topSig)
+
+ | otherwise
+ = (lazy_fv, mkStrictSig dmd_ty)