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 |