Do not float-in let-bindings marked NOINLINE
Motivation
I first became aware of the issue from this comment: #9349 (comment 86355)
The main motivation behind this change is to give the user more control over performance in the face of the "state hack" without resorting to the heavier -fno-state-hack
. If you have a let-binding you know is expensive & shouldn't be duplicated via inlining, you could mark it as NOINLINE
to help ensure that. In general, I think this behavior would be more in line with what a user expects when they mark some binding as NOINLINE
.
I'm not familiar with the subtleties of the issue, but I was recently bitten by it: I had an IO action had JSON parsing inlined into it, causing performance issues. Adding a NOINLINE
pragma to the offending let-binding seemed to force ghc to do what I wanted, but then I saw the linked comment which made me think that fix as it stands is a bit brittle. (I've since just thrown the parse result into a compact region which fixes the issue anyways.)
There was also a recent Reddit thread where another user could've benefited from this.
Proposal
As described in this comment, when a let-binding is marked NOINLINE
, do not allow it to be floated into a lambda.