INLINABLE pragma prevents worker-wrapper to happen.
When working on containers I found out that a method returning a pair marked as INLINABLE does not go through a worker/wrapper transformation to get a worker that would return unboxed pair.
For example:
module Test where
smallerAndRest :: Ord a => a -> [a] -> (Maybe a, [a])
smallerAndRest x [] = (Nothing, [])
smallerAndRest x (y:ys) | y < x = (Just y, ys)
| otherwise = smallerAndRest x ys
{-# INLINABLE smallerAndRest #-}
With the INLINABLE pragma, -ddump-prep prints
==================== CorePrep ====================
Result size = 42
lvl_rkg :: forall a_ajz. (Data.Maybe.Maybe a_ajz, [a_ajz])
[GblId, Caf=NoCafRefs, Str=DmdType m, Unf=OtherCon []]
lvl_rkg =
\ (@ a_ajz) -> (Data.Maybe.Nothing @ a_ajz, GHC.Types.[] @ a_ajz)
Rec {
Test.smallerAndRest [InlPrag=INLINABLE[ALWAYS], Occ=LoopBreaker]
:: forall a_a9I.
GHC.Classes.Ord a_a9I =>
a_a9I -> [a_a9I] -> (Data.Maybe.Maybe a_a9I, [a_a9I])
[GblId, Arity=3, Caf=NoCafRefs, Str=DmdType LLSm, Unf=OtherCon []]
Test.smallerAndRest =
\ (@ a_ajz)
($dOrd_sko :: GHC.Classes.Ord a_ajz)
(x_skq :: a_ajz)
(ds_skk :: [a_ajz]) ->
case ds_skk of _ {
[] -> lvl_rkg @ a_ajz;
: y_skp ys_sks ->
case GHC.Classes.< @ a_ajz $dOrd_sko y_skp x_skq of _ {
GHC.Types.False ->
Test.smallerAndRest @ a_ajz $dOrd_sko x_skq ys_sks;
GHC.Types.True ->
let {
sat_skw :: Data.Maybe.Maybe a_ajz
[LclId]
sat_skw = Data.Maybe.Just @ a_ajz y_skp } in
(sat_skw, ys_sks)
}
}
end Rec }
but without the INLINABLE pragma, we get
==================== CorePrep ====================
Result size = 57
Rec {
Test.$wsmallerAndRest [Occ=LoopBreaker]
:: forall a_a9I.
GHC.Classes.Ord a_a9I =>
a_a9I -> [a_a9I] -> (# Data.Maybe.Maybe a_a9I, [a_a9I] #)
[GblId, Arity=3, Caf=NoCafRefs, Str=DmdType LLS, Unf=OtherCon []]
Test.$wsmallerAndRest =
\ (@ a_a9I)
(w_skC :: GHC.Classes.Ord a_a9I)
(w1_skE :: a_a9I)
(w2_sky :: [a_a9I]) ->
case w2_sky of _ {
[] -> (# Data.Maybe.Nothing @ a_a9I, GHC.Types.[] @ a_a9I #);
: y_skD ys_skG ->
case GHC.Classes.< @ a_a9I w_skC y_skD w1_skE of _ {
GHC.Types.False ->
Test.$wsmallerAndRest @ a_a9I w_skC w1_skE ys_skG;
GHC.Types.True ->
let {
sat_skV :: Data.Maybe.Maybe a_a9I
[LclId]
sat_skV = Data.Maybe.Just @ a_a9I y_skD } in
(# sat_skV, ys_skG #)
}
}
end Rec }
Test.smallerAndRest [InlPrag=INLINE[0]]
:: forall a_a9I.
GHC.Classes.Ord a_a9I =>
a_a9I -> [a_a9I] -> (Data.Maybe.Maybe a_a9I, [a_a9I])
[GblId, Arity=3, Caf=NoCafRefs, Str=DmdType LLSm, Unf=OtherCon []]
Test.smallerAndRest =
\ (@ a_a9I)
(w_skL :: GHC.Classes.Ord a_a9I)
(w1_skM :: a_a9I)
(w2_skN :: [a_a9I]) ->
case Test.$wsmallerAndRest @ a_a9I w_skL w1_skM w2_skN
of _ { (# ww1_skR, ww2_skS #) ->
(ww1_skR, ww2_skS)
}
Here the worker-wrapper creates a variant, which returns unboxed pair.
I assume that there is no simple solution to this, because the worker/wrapper changes the INLINABLE on smallerAndRest to INLINE. The INLINABLE could be added to $wsmallerAndRest, but then #5928 causes the specialization to fail.
Maybe at least both smallerAndRest and $wsmallerAndRest could be marked INLINABLE? Then it is not sure that smallerAndRest gets INLINED and $wsmallerAndRest exposed, but it is not worse than current situation.
Trac metadata
| Trac field | Value |
|---|---|
| Version | 7.4.1 |
| Type | Bug |
| TypeOfFailure | OtherFailure |
| Priority | normal |
| Resolution | Unresolved |
| Component | Compiler |
| Test case | |
| Differential revisions | |
| BlockedBy | |
| Related | |
| Blocking | |
| CC | fox@ucw.cz |
| Operating system | |
| Architecture |