[GHC] #14865: GHC Defeats Manual Worker Wrapper with Unboxed Sum
GHC
ghc-devs at haskell.org
Tue Feb 27 18:09:46 UTC 2018
#14865: GHC Defeats Manual Worker Wrapper with Unboxed Sum
-------------------------------------+-------------------------------------
Reporter: andrewthad | Owner: (none)
Type: bug | Status: new
Priority: normal | Milestone:
Component: Compiler | Version: 8.5
Keywords: UnboxedSums | Operating System: Unknown/Multiple
Architecture: | Type of failure: None/Unknown
Unknown/Multiple |
Test Case: | Blocked By:
Blocking: | Related Tickets:
Differential Rev(s): | Wiki Page:
-------------------------------------+-------------------------------------
Here's the code in question:
{{{
{-# LANGUAGE BangPatterns #-}
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE MagicHash #-}
{-# LANGUAGE TypeInType #-}
{-# LANGUAGE UnboxedSums #-}
{-# LANGUAGE UnboxedTuples #-}
{-# OPTIONS_GHC -O2 #-}
module Byte.Array.Window
( findByte
, boxMaybeInt
) where
import Data.Primitive (ByteArray)
import Data.Word (Word8)
import GHC.Types (RuntimeRep,TYPE)
import GHC.Int (Int(I#))
import GHC.Exts (Int#)
import qualified Data.Primitive as PM
type Maybe# (a :: TYPE (r :: RuntimeRep)) = (# (# #) | a #)
boxMaybeInt :: Maybe# Int# -> Maybe Int
boxMaybeInt = \case
(# | a #) -> Just (I# a)
(# (# #) | #) -> Nothing
unboxInt :: Int -> Int#
unboxInt (I# i) = i
-- | Finds the first occurrence of the given byte.
-- TODO: optimize this to search through a whole
-- Word64 at a time if the bytearray is pinned.
findByte :: Int -> Int -> Word8 -> ByteArray -> Maybe Int
findByte !off !len !w !arr = boxMaybeInt (go off) where
go :: Int -> Maybe# Int#
go !ix = if ix < len
then if PM.indexByteArray arr ix == w
then (# | unboxInt ix #)
else go (ix + 1)
else (# (# #) | #)
}}}
When compiled with GHC 8.5 with `-ddump-simpl -dsuppress-all`, here is the
relevant part of the resulting Core:
{{{
-- RHS size: {terms: 33, types: 13, coercions: 0, joins: 1/1}
$wfindByte
$wfindByte
= \ ww_s38C ww1_s38G ww2_s38K ww3_s38O ->
joinrec {
$wgo_s38v
$wgo_s38v ww4_s38t
= case <# ww4_s38t ww1_s38G of {
__DEFAULT -> Nothing;
1# ->
case indexWord8Array# ww3_s38O ww4_s38t of wild_a36w {
__DEFAULT ->
case eqWord# wild_a36w ww2_s38K of {
__DEFAULT -> jump $wgo_s38v (+# ww4_s38t 1#);
1# -> Just (I# ww4_s38t)
}
}
}; } in
jump $wgo_s38v ww_s38C
-- RHS size: {terms: 21, types: 12, coercions: 0, joins: 0/0}
findByte
findByte
= \ w_s38w w1_s38x w2_s38y w3_s38z ->
case w_s38w of { I# ww1_s38C ->
case w1_s38x of { I# ww3_s38G ->
case w2_s38y of { W8# ww5_s38K ->
case w3_s38z of { ByteArray ww7_s38O ->
$wfindByte ww1_s38C ww3_s38G ww5_s38K ww7_s38O
}
}
}
}
}}}
I expected that the tail recursive `go` helpful function from my original
code would still be a function that returns an unboxed sum when optimized
and turned into Core. However, it isn't. The call to `boxMaybeInt` gets
pushed into `go`. This means that when `findByte` is called and the result
cased on, an allocation is going to happen. I think it would be preferable
for `boxMaybeInt` to not get pushed into the worker, since `boxMaybeInt
(go off)` could be inlined and the allocation of `Maybe` could be
prevented (assuming that it was cased on right afterward).
--
Ticket URL: <http://ghc.haskell.org/trac/ghc/ticket/14865>
GHC <http://www.haskell.org/ghc/>
The Glasgow Haskell Compiler
More information about the ghc-tickets
mailing list