[GHC] #8589: Bad choice of loop breaker with INLINABLE/INLINE
GHC
ghc-devs at haskell.org
Mon Dec 2 12:27:59 UTC 2013
#8589: Bad choice of loop breaker with INLINABLE/INLINE
------------------------------+--------------------------------------------
Reporter: | Owner:
NickSmallbone | Status: new
Type: bug | Milestone:
Priority: normal | Version: 7.6.3
Component: Compiler | Operating System: Unknown/Multiple
Keywords: | Type of failure: Runtime performance bug
Architecture: | Test Case:
Unknown/Multiple | Blocking:
Difficulty: Unknown |
Blocked By: |
Related Tickets: |
------------------------------+--------------------------------------------
Take the following program, which defines a pair of lists recursively:
{{{
module Test(xs, ys) where
pair :: ([Bool], [Bool])
pair = (False:xs, True:ys)
where
(xs, ys) = pair
(xs, ys) = pair
}}}
GHC is clever enough to disentangle {{{xs}}} from {{{ys}}} and with
{{{-ddump-simpl -O}}} I get:
{{{
Rec {
xs [Occ=LoopBreaker] :: [Bool]
[GblId, Caf=NoCafRefs, Str=DmdType]
xs = : False xs
end Rec }
Rec {
ys [Occ=LoopBreaker] :: [Bool]
[GblId, Caf=NoCafRefs, Str=DmdType]
ys = : True ys
end Rec }
}}}
However, if I mark {{{pair}}} as {{{INLINABLE}}} or {{{INLINE}}} (it
doesn't matter which), I get much worse code where {{{xs}}} and {{{ys}}}
go through {{{pair}}}:
{{{
Rec {
pair [InlPrag=INLINABLE[ALWAYS], Occ=LoopBreaker]
:: ([Bool], [Bool])
[GblId,
Str=DmdType m,
Unf=Unf{Src=InlineStable, TopLvl=True, Arity=0, Value=True,
ConLike=True, WorkFree=False, Expandable=True,
Guidance=IF_ARGS [] 50 30
Tmpl= (: False
(case pair of _ { (xs1_Xf6 [Occ=Once], _) -> xs1_Xf6 }),
: True (case pair of _ { (_, ys1_Xf6 [Occ=Once]) ->
ys1_Xf6 }))}]
pair = (a1_rgo, a_rgn)
ys_ys :: [Bool]
[GblId,
Str=DmdType,
Unf=Unf{Src=<vanilla>, TopLvl=True, Arity=0, Value=False,
ConLike=False, WorkFree=True, Expandable=True,
Guidance=IF_ARGS [] 10 0}]
ys_ys = case pair of _ { (xs1_XeW, ys1_Xf7) -> ys1_Xf7 }
a_rgn :: [Bool]
[GblId, Str=DmdType]
a_rgn = : True ys_ys
xs_xs :: [Bool]
[GblId,
Str=DmdType,
Unf=Unf{Src=<vanilla>, TopLvl=True, Arity=0, Value=False,
ConLike=False, WorkFree=True, Expandable=True,
Guidance=IF_ARGS [] 10 0}]
xs_xs = case pair of _ { (xs1_XeW, ys1_XeS) -> xs1_XeW }
a1_rgo :: [Bool]
[GblId, Str=DmdType]
a1_rgo = : False xs_xs
end Rec }
ys :: [Bool]
[GblId,
Str=DmdType,
Unf=Unf{Src=<vanilla>, TopLvl=True, Arity=0, Value=False,
ConLike=False, WorkFree=True, Expandable=True,
Guidance=ALWAYS_IF(unsat_ok=True,boring_ok=True)}]
ys = ys_ys
xs :: [Bool]
[GblId,
Str=DmdType,
Unf=Unf{Src=<vanilla>, TopLvl=True, Arity=0, Value=False,
ConLike=False, WorkFree=True, Expandable=True,
Guidance=ALWAYS_IF(unsat_ok=True,boring_ok=True)}]
xs = xs_xs
}}}
It seems that GHC chooses {{{pair}}} as the loop breaker, which stops the
simplifier in its tracks.
It might seem a bit silly to mark {{{pair}}} as {{{INLINE}}}, since it's
not mutually recursive. The function I really had was polymorphic with a
typeclass constraint, and I wrote {{{INLINABLE}}} to get it specialised at
its call site. (Also, {{{pair}}} is mutually recursive in the Core, so you
would expect GHC to avoid using it as a loop breaker if I mark it
{{{INLINE}}}.)
--
Ticket URL: <http://ghc.haskell.org/trac/ghc/ticket/8589>
GHC <http://www.haskell.org/ghc/>
The Glasgow Haskell Compiler
More information about the ghc-tickets
mailing list