Skip to content

SpecConstr broken for NOINLINE loops in 6.13

Example:

foo :: Int -> Int -> Int
{-# NOINLINE foo #-}
foo n k | n <= 0    = k
        | otherwise = foo (n-1) (k+1)

This is what GHC generates:

Rec {
X.foo_$sfoo [Occ=LoopBreaker]
  :: GHC.Prim.Int# -> GHC.Prim.Int# -> GHC.Types.Int
[GblId, Arity=2, Caf=NoCafRefs, Str=DmdType LL]
X.foo_$sfoo =
  \ (sc_sjW :: GHC.Prim.Int#) (sc1_sjX :: GHC.Prim.Int#) ->
    case GHC.Prim.<=# sc1_sjX 0 of _ {
      GHC.Bool.False ->
        X.foo
          (GHC.Types.I# (GHC.Prim.-# sc1_sjX 1))
          (GHC.Types.I# (GHC.Prim.+# sc_sjW 1));
      GHC.Bool.True -> GHC.Types.I# sc_sjW
    }

X.foo [InlPrag=NOINLINE (sat-args=2), Occ=LoopBreaker]
  :: GHC.Types.Int -> GHC.Types.Int -> GHC.Types.Int
[GblId, Arity=2, Caf=NoCafRefs, Str=DmdType U(L)U(L)m]
X.foo =
  \ (n_aaj :: GHC.Types.Int) (k_aak :: GHC.Types.Int) ->
    case n_aaj of _ { GHC.Types.I# x_ajn ->
    case GHC.Prim.<=# x_ajn 0 of _ {
      GHC.Bool.False ->
        case k_aak of _ { GHC.Types.I# x1_aiX ->
        X.foo
          (GHC.Types.I# (GHC.Prim.-# x_ajn 1))
          (GHC.Types.I# (GHC.Prim.+# x1_aiX 1))
        };
      GHC.Bool.True -> k_aak
    }
    }
end Rec }


------ Local rules for imported ids --------
"SC:X.foo0" [NEVER]
    forall {sc_sjW :: GHC.Prim.Int# sc1_sjX :: GHC.Prim.Int#}
      X.foo (GHC.Types.I# sc1_sjX) (GHC.Types.I# sc_sjW)
      = X.foo_$sfoo sc_sjW sc1_sjX

At the moment, we don't worker/wrapper NOINLINE things because doing so would generate a wrapper which wouldn't be inlined. But apparently, we do !SpecConstr NOINLINE functions, generating rules and specialisations which can never be used, like above.

The trivial solution is to have !SpecConstr ignore NOINLINE functions. Perhaps we could also think about transforming foo to this instead:

{-# NOINLINE foo #-}
foo = foo'

foo' n k | n <= 0    = k
         | otherwise = foo' (n-1) (k+1)

Now, we can apply worker/wrapper and !SpecConstr to foo' without any restrictions. One could argue that foo has been "inlined" into its own rhs but I can't imagine how that could ever be a problem.

Trac metadata
Trac field Value
Version 6.13
Type Bug
TypeOfFailure OtherFailure
Priority normal
Resolution Unresolved
Component Compiler
Test case
Differential revisions
BlockedBy
Related
Blocking
CC
Operating system
Architecture
To upload designs, you'll need to enable LFS and have an admin enable hashed storage. More information