Note [Which Ids should be strictified]
For some arguments we would like to convince GHC to pass them call by value. One way to achieve this is described in see Note [Call-by-value for worker args]. We separate the concerns of "should we pass this argument using cbv" and "should we do so by making the rhs strict in this argument". This note deals with the second part. There are multiple reasons why we might not want to insert a seq in the rhs to strictify a functions argument: 1) The argument doesn't exist at runtime. For zero width types (like Types) there is no benefit as we don't operate on them at runtime at all. This includes things like void#, coercions and state tokens. 2) The argument is a unlifted type. If the argument is a unlifted type the calling convention already is explicitly cbv. This means inserting a seq on this argument wouldn't do anything as the seq would be a no-op *and* it wouldn't affect the calling convention. 3) The argument is absent. If the argument is absent in the body there is no advantage to it being passed as cbv to the function. The function won't ever look at it so we don't safe any work. This mostly happens for join point. For example we might have: data T = MkT ![Int] [Char] f t = case t of MkT xs{strict} ys-> snd (xs,ys) and abstract the case alternative to: f t = join j1 = \xs ys -> snd (xs,ys) in case t of MkT xs{strict} ys-> j1 xs xy While we "use" xs inside `j1` it's not used inside the function `snd` we pass it to. In short a absent demand means neither our RHS, nor any function we pass the argument to will inspect it. So there is no work to be saved by forcing `xs` early. NB: There is an edge case where if we rebox we *can* end up seqing an absent value. Note [Absent fillers] has an example of this. However this is so rare it's not worth caring about here. 4) The argument is already strict. Consider this code: data T = MkT ![Int] f t = case t of MkT xs{strict} -> reverse xs The `xs{strict}` indicates that `xs` is used strictly by the `reverse xs`. If we do a w/w split, and add the extra eval on `xs`, we'll get $wf xs = case xs of xs1 -> let t = MkT xs1 in case t of MkT xs2 -> reverse xs2 That's not wrong; but the w/w body will simplify to $wf xs = case xs of xs1 -> reverse xs1 and now we'll drop the `case xs` because `xs1` is used strictly in its scope. Adding that eval was a waste of time. So don't add it for strictly-demanded Ids. 5) Functions Functions are tricky (see Note [TagInfo of functions] in EnforceEpt). But the gist of it even if we make a higher order function argument strict we can't avoid the tag check when it's used later in the body. So there is no benefit.
References 3
- Absent fillers GHC.Core.Opt.WorkWrap.Utils
- Call-by-value for worker args GHC.Core.Utils
- TagInfo of functions GHC.Stg.EnforceEpt
Referenced by 7
- GHC.Core.Utils call site ×6
- Call-by-value for worker args GHC.Core.Utils