Skip to content

`NOINLINE` honored up until `Prep`, then `Prep` inlines it

Given the following program:

module NoInline (quux2) where

{-# NOINLINE quux1 #-}
quux1 :: [v]
quux1 = mempty

quux2 :: [String]
quux2 = quux1

Compiling this with -fno-ignore-interface-pragmas, I see that quux1 is not inlined into quux2 up until Tidy:

$ ./_build/ghc-stage1 -fforce-recomp -dno-typeable-binds input/NoInline.hs -ddump-prep -ddump-simpl -dverbose-core2core -fno-ignore-interface-pragmas
...
==================== Simplifier ====================
  Max iterations = 4
  SimplMode {Phase = FinalPhase [final],
             inline,
             no rules,
             eta-expand,
             cast-swizzle,
             case-of-case}
Result size of Simplifier
  = {terms: 4, types: 6, coercions: 0, joins: 0/0}

-- RHS size: {terms: 1, types: 0, coercions: 0, joins: 0/0}
quux1 [InlPrag=NOINLINE] :: forall v. [v]
[LclId,
 Unf=Unf{Src=<vanilla>, TopLvl=True,
         Value=True, ConLike=True, WorkFree=True, Expandable=True,
         Guidance=ALWAYS_IF(arity=0,unsat_ok=True,boring_ok=True)}]
quux1 = GHC.Types.[]

-- RHS size: {terms: 1, types: 1, coercions: 0, joins: 0/0}
quux2 :: [String]
[LclIdX,
 Unf=Unf{Src=<vanilla>, TopLvl=True,
         Value=True, ConLike=True, WorkFree=True, Expandable=True,
         Guidance=ALWAYS_IF(arity=0,unsat_ok=True,boring_ok=True)}]
quux2 = quux1 @String
==================== Tidy Core ====================
Result size of Tidy Core
  = {terms: 4, types: 6, coercions: 0, joins: 0/0}

-- RHS size: {terms: 1, types: 0, coercions: 0, joins: 0/0}
quux1_rh1 :: forall v. [v]
[GblId, Unf=OtherCon []]
quux1_rh1 = GHC.Types.[]

-- RHS size: {terms: 1, types: 1, coercions: 0, joins: 0/0}
quux2 :: [String]
[GblId, Unf=OtherCon []]
quux2 = quux1_rh1 @String

But then Prep inlines quux1 into quux2:

==================== CorePrep ====================
Result size of CorePrep
  = {terms: 2, types: 3, coercions: 0, joins: 0/0}

-- RHS size: {terms: 1, types: 1, coercions: 0, joins: 0/0}
NoInline.quux2 :: [GHC.Base.String]
[GblId, Unf=OtherCon []]
NoInline.quux2 = GHC.Types.[] @GHC.Base.String

Note that the Tidy output doesn't contain the NOINLINE pragma on quux1 anymore, but also it doesn't have an unfolding...

Is this all intentional? As a library user who cares about the Prep output and can observe the difference between inlining or not inlining quux1, is there a way to avoid this behaviour?

To upload designs, you'll need to enable LFS and have an admin enable hashed storage. More information