Skip to content

DmdAnal: Interleaved demand representation for expressive strictness information

Currently, we store strictness and usage demands independently of another in a JointDmd, which is basically a pair. It turns out that makes it impossible to express useful strictness demands. Here's an example:

h :: Int -> Int
h m =
  let g :: Int -> (Int,Int)
      g 1 = (m, 0)
      g n = (2 * n, 2 `div` n)
      {-# NOINLINE g #-}
  in case m of
    1 -> 0
    2 -> snd (g m)
    _ -> uncurry (+) (g m)

What is the demand on g? Currently, we say <L,1*C1(U(1*U(U),1*U(U)))>. Note that we have pretty precise usage demand, but the strictness demand is completely uninformative since g is not called strictly.

But we can still have useful strictness information under the assumption that g is called (see why that's useful below)! Here, we can see that whenever g is called, then we evaluate the second component of the returned pair strictly. If we interleaved both demands, we could write [0,1]*C[0,1](([0,1]([0,n]),[1,1]([0,n]))) (notation is up for debate): Each [l,u] denotes an evaluation cardinality, consisting of a lower (strictness) bound l (ranging over {0,1}) and an upper (usage) bound u (ranging over {0,1,n}, n meaning many times).

Note how we expressed that g was called at most once (possibly never, lower bound 0), and that in all such evaluation contexts we evaluate the first pair component exactly once ([1,1]).

Why is this useful

The information on g is useful for Nested CPR (!1866 (closed)), as this allows us to safely also unbox the second pair component in the returned pair, even though evaluation of 2 / n might not terminate on some inputs.

Similarly, we can have nested strictness on products to omit some thunks, e.g.

let x = (expensive 3, blah)
in if b then fst x else 0

If we give x strictness demand L(S,L), then we can transform to

let x = case expensive 3 of y -> (y, blah)
in if b then fst x else 0

But that requires us to resolve #18885 (closed) first.

Edited by Simon Peyton Jones
To upload designs, you'll need to enable LFS and have an admin enable hashed storage. More information