
#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