When does GHC produce unlifted `let` bindings?

Hi folks, I was debugging a Core-to-Core transform for TEST=spec-inline https://github.com/ghc/ghc/blob/fe04f3783b662c52c4a0ff36b2d62a7a575998a5/tes... and was wondering (yet again) why GHC produces unlifted `let` bindings in Core like it seems supposed to be doing https://github.com/ghc/ghc/blob/fe04f3783b662c52c4a0ff36b2d62a7a575998a5/tes... . - Why doesn't this use `case` instead? - Is there a semantic difference? - Can `case` be used with unlifted types? - And if not, why can `let`? Unlifted `let` seems much close to `case` than to `let`. Some GHC passes seem to agree. https://github.com/ghc/ghc/search?l=Haskell&q=%22strict+let%22&type=&utf8=%E2%9C%93 Cheers, Sebastian

Sebastian Graf
Hi folks,
I was debugging a Core-to-Core transform for TEST=spec-inline https://github.com/ghc/ghc/blob/fe04f3783b662c52c4a0ff36b2d62a7a575998a5/tes... and was wondering (yet again) why GHC produces unlifted `let` bindings in Core like it seems supposed to be doing https://github.com/ghc/ghc/blob/fe04f3783b662c52c4a0ff36b2d62a7a575998a5/tes... .
- Why doesn't this use `case` instead? - Is there a semantic difference?
My understanding is that we use `case` in this case since there is no thunk evaluation necessary. Recall that operationally (under STG) `case` is what drives evaluation whereas `let` is simply allocation. In a sense, bringing an unlifted binding into scope is closer to the latter than the former, being a simple register assignment.
- Can `case` be used with unlifted types?
I'm honestly not sure what would happen in this case. It may work fine or something may explode. I suspect CoreToStg will lower a case with an unlifted scrutinee to a let, but perhaps not. If not then things likely will blow up since, according to Note [Types in StgConApp], unlifted values can't be let-bound in STG. Cheers, - Ben

See Note [CoreSyn let/app invariant] in CoreSyn.
Briefly, you can write
let x::Int# = e in …
if e is “ok-for-speculation”. See extensive comments in CoreUtils on what that means.
You could also use case, but let-bindings “float” more easily than cases, because they are not worried about preserving exception behaviour.
Simon
From: ghc-devs [mailto:ghc-devs-bounces@haskell.org] On Behalf Of Sebastian Graf
Sent: 29 October 2017 21:07
To: ghc-devs

Thanks both of you, that makes sense.
Re: let-bindings floating more easily, would a check for
`exprIsOkForSpeculation scrut` in theory suffice to float out cases?
On Mon, Oct 30, 2017 at 10:56 AM, Simon Peyton Jones
See Note [CoreSyn let/app invariant] in CoreSyn.
Briefly, you can write
let x::Int# = e in …
if e is “ok-for-speculation”. See extensive comments in CoreUtils on what that means.
You could also use case, but let-bindings “float” more easily than cases, because they are not worried about preserving exception behaviour.
Simon
*From:* ghc-devs [mailto:ghc-devs-bounces@haskell.org] *On Behalf Of *Sebastian Graf *Sent:* 29 October 2017 21:07 *To:* ghc-devs
*Subject:* When does GHC produce unlifted `let` bindings? Hi folks,
I was debugging a Core-to-Core transform for TEST=spec-inline https://na01.safelinks.protection.outlook.com/?url=https%3A%2F%2Fgithub.com%2Fghc%2Fghc%2Fblob%2Ffe04f3783b662c52c4a0ff36b2d62a7a575998a5%2Ftestsuite%2Ftests%2FsimplCore%2Fshould_compile%2Fspec-inline.hs&data=02%7C01%7Csimonpj%40microsoft.com%7C77699e26801a4d458b9a08d51f11085f%7C72f988bf86f141af91ab2d7cd011db47%7C1%7C0%7C636449080385955811&sdata=t%2BAXQszqKfFRYNjjLJtMHpLsS2RzwTaBFA42JuLBN4o%3D&reserved=0 and was wondering (yet again) why GHC produces unlifted `let` bindings in Core like it seems supposed to be doing https://na01.safelinks.protection.outlook.com/?url=https%3A%2F%2Fgithub.com%2Fghc%2Fghc%2Fblob%2Ffe04f3783b662c52c4a0ff36b2d62a7a575998a5%2Ftestsuite%2Ftests%2FsimplCore%2Fshould_compile%2Fspec-inline.stderr%23L68-L76&data=02%7C01%7Csimonpj%40microsoft.com%7C77699e26801a4d458b9a08d51f11085f%7C72f988bf86f141af91ab2d7cd011db47%7C1%7C0%7C636449080385955811&sdata=pVNrzDY%2ByfK%2FVl%2Fk8B5P0HuGC6PG5kD7mHiwa0Vck9o%3D&reserved=0 .
- Why doesn't this use `case` instead? - Is there a semantic difference? - Can `case` be used with unlifted types? - And if not, why can `let`?
Unlifted `let` seems much close to `case` than to `let`. Some GHC passes seem to agree. https://na01.safelinks.protection.outlook.com/?url=https%3A%2F%2Fgithub.com%2Fghc%2Fghc%2Fsearch%3Fl%3DHaskell%26q%3D%2522strict%2Blet%2522%26type%3D%26utf8%3D%25E2%259C%2593&data=02%7C01%7Csimonpj%40microsoft.com%7C77699e26801a4d458b9a08d51f11085f%7C72f988bf86f141af91ab2d7cd011db47%7C1%7C0%7C636449080385955811&sdata=ksdZGbGyw6%2FLEIMiJpCaHlDh4iipdkKcSCEDdTySExk%3D&reserved=0
Cheers,
Sebastian

Re: let-bindings floating more easily, would a check for `exprIsOkForSpeculation scrut` in theory suffice to float out cases?
Yes; but instead we simply turn such cases into lets.
Simon
From: Sebastian Graf [mailto:sgraf1337@gmail.com]
Sent: 02 November 2017 08:33
To: Simon Peyton Jones
participants (3)
-
Ben Gamari
-
Sebastian Graf
-
Simon Peyton Jones