First: Guaranteed Optimization and GHC do not mix well. Due to the high level, it is very difficult to predict the code that the GHC will generate in each case. The only way to make sure is to look at Core. If you are developing a performance-dependent application with GHC, you need to become familiar with Core I.
I don't know any optimization in GHC that does exactly what you describe. Here is an example program:
module Test where data Sum = A {-# UNPACK #-} !Int | B {-# UNPACK #-} !Int consumeSum :: Sum -> Int consumeSum x = case x of A y -> y + 1 B y -> y + 2 {-# NOINLINE consumeSumNoinline #-} consumeSumNoinline = consumeSum {-# INLINE produceSumInline #-} produceSumInline :: Int -> Sum produceSumInline x = if x == 0 then A x else B x {-# NOINLINE produceSumNoinline #-} produceSumNoinline :: Int -> Sum produceSumNoinline x = if x == 0 then A x else B x test :: Int -> Int --test x = consumeSum (produceSumInline x) test x = consumeSumNoinline (produceSumNoinline x)
Let's first see what happens if we do not include consumeSum and produceSum . Here is the core:
test :: Int -> Int test = \ (x :: Int) -> consumeSumNoinline (produceSumNoinline x)
(done using ghc-core test.hs -- -dsuppress-unfoldings -dsuppress-idinfo -dsuppress-module-prefixes -dsuppress-uniques )
Here we see that GHC (8.0 in this case) does not decompress the sum type passed as an argument to the function. Nothing changes if we embed either consumeSum or produceSum .
If we embed both, the following code is generated:
test :: Int -> Int test = \ (x :: Int) -> case x of _ { I
What happened is that through inline, the GHC ends:
\x -> case (if x == 0 then A x else B x) of A y -> y + 1 B y -> y + 2
Which in the case case ( if is only a special case ) turns into:
\x -> if x == 0 then case (A x) of ... else case (B x) of ...
Now this is the case with a well-known constructor, so GHC can reduce the compilation time by ending:
\x -> if x == 0 then x + 1 else x + 2
Thus, he completely eliminated the constructor.
In general, I believe that GHC does not have a concept like "unboxed sum" prior to version 8.2, which also applies to function arguments. The only way to get the “unpacked” amounts is to get a constructor that is completely excluded by nesting.