Skip to content
  • Eric Seidel's avatar
    Do Worker/Wrapper for NOINLINE things · b572aadb
    Eric Seidel authored and Ben Gamari's avatar Ben Gamari committed
    Disabling worker/wrapper for NOINLINE things can cause unnecessary
    reboxing of values. Consider
    
        {-# NOINLINE f #-}
        f :: Int -> a
        f x = error (show x)
    
        g :: Bool -> Bool -> Int -> Int
        g True  True  p = f p
        g False True  p = p + 1
        g b     False p = g b True p
    
    the strictness analysis will discover f and g are strict, but because f
    has no wrapper, the worker for g will rebox p. So we get
    
        $wg x y p# =
          let p = I# p# in  -- Yikes! Reboxing!
          case x of
            False ->
              case y of
                False -> $wg False True p#
                True -> +# p# 1#
            True ->
              case y of
                False -> $wg True True p#
                True -> case f p of { }
    
        g x y p = case p of (I# p#) -> $wg x y p#
    
    Now, in this case the reboxing will float into the True branch, an so
    the allocation will only happen on the error path. But it won't float
    inwards if there are multiple branches that call (f p), so the reboxing
    will happen on every call of g. Disaster.
    
    Solution: do worker/wrapper even on NOINLINE things; but move the
    NOINLINE pragma to the worker.
    
    Test Plan: make test TEST="13143"
    
    Reviewers: simonpj, bgamari, dfeuer, austin
    
    Reviewed By: simonpj, bgamari
    
    Subscribers: dfeuer, thomie
    
    Differential Revision: https://phabricator.haskell.org/D3046
    b572aadb