Note [Boxity analysis]
Alas, we don't want to unbox *every* strict argument (as Note [Strictness and Unboxing] might suggest). Here's an example (from T19871): ``` data Huge = H Bool Bool ... Bool ann :: Huge -> (Bool, Huge) ann h@(Huge True _ ... _) = (False, h) ann h = (True, h) ``` Unboxing 'h' yields ``` $wann :: Bool -> Bool -> ... -> Bool -> (Bool, Huge) $wann True b2 ... bn = (False, Huge True b2 ... bn) $wann b1 b2 ... bn = (True, Huge b1 b2 ... bn) ``` The pair constructor really needs its fields boxed. But '$wann' doesn't get passed 'h' anymore, only its components! Ergo it has to reallocate the 'Huge' box, in a process called "reboxing". After w/w, call sites like `case ... of Just h -> ann h` pay for the allocation of the additional box. In earlier versions of GHC we simply accepted that reboxing would sometimes happen, but we found some cases where it made a big difference: #19407, for example. We therefore perform a simple syntactic boxity analysis that piggy-backs on demand analysis in order to determine whether the box of a strict argument is always discarded in the function body, in which case we can pass it unboxed without risking regressions such as in 'ann' above. But as soon as one use needs the box, we want Boxed to win over any Unboxed uses. The demand signature (cf. Note [Demand notation]) will say whether it uses its arguments boxed or unboxed. Indeed it does so for every sub-component of the argument demand. Here's an example: ``` f :: (Int, Int) -> Bool f (a, b) = even (a + b) -- demand signature: <1!P(1!L,1!L)> ``` The '!' indicates places where we want to unbox, the lack thereof indicates the box is used by the function. Boxity flags are part of the 'Poly' and 'Prod' 'SubDemand's, see Note [Why Boxity in SubDemand and not in Demand?]. The given demand signature says "Unbox the pair and then nestedly unbox its two fields". By contrast, the demand signature of 'ann' above would look like <1P(1L,L,...,L)>, lacking any '!'. A demand signature like <1P(1!L)> -- Boxed outside but Unboxed in the field -- doesn't make a lot of sense, as we can never unbox the field without unboxing the containing record. See Note [Finalising boxity for demand signatures] in "GHC.Core.Opt.DmdAnal" for how we avoid to spread this and other kinds of misinformed boxities. Due to various practical reasons, Boxity Analysis is not conservative at times. Here are reasons for too much optimism: * Note [Function body boxity and call sites] is an observation about when it is beneficial to unbox a parameter that is returned from a function. Note [Unboxed demand on function bodies returning small products] derives a heuristic from the former Note, pretending that all call sites of a function need returned small products Unboxed. * Note [Boxity for bottoming functions] in DmdAnal makes all bottoming functions unbox their arguments, incurring reboxing in code paths that will diverge anyway. In turn we get more unboxing in hot code paths. Boxity analysis fixes a number of issues: #19871, #19407, #4267, #16859, #18907, #13331
References 7
- Boxity for bottoming functions GHC.Core.Opt.DmdAnal
- Finalising boxity for demand signatures GHC.Core.Opt.DmdAnal
- Demand notation GHC.Types.Demand
- Function body boxity and call sites GHC.Types.Demand
- Strictness and Unboxing GHC.Types.Demand
- Unboxed demand on function bodies returning small products GHC.Types.Demand
- Why Boxity in SubDemand and not in Demand? GHC.Types.Demand
Referenced by 6
- GHC.Core.Opt.DmdAnal call site
- Worker/wrapper for Strictness and Absence GHC.Core.Opt.WorkWrap.Utils
- GHC.Core.Opt.WorkWrap.Utils call site
- Boxity in Poly GHC.Types.Demand
- Unboxed demand on function bodies returning small products GHC.Types.Demand
- GHC.Types.Demand call site