<div dir="ltr"><div>This turned out to be rather lengthy and ambivalent, but my current TLDR; of this is that GHC.Magic Ids could all be PseudoOps, because we don't use their definitions anyway.<br></div><div><br></div><div>---<br></div><div><br></div><div>Regarding 2., the answer has been right before my eyes in the form of Note [ghcPrimIds (aka pseudoops)] and Note [magicIds]. The most important difference I guess is that we can give meaningful, yet forgetful definitions for functions in GHC.Magic, whereas we can't for proper pseudoops.</div><div><br></div><div>Note [ghcPrimIds (aka pseudoops)] also answers 3.: IIUC if PseudoOps aren't free abstractions already (proxy#), we try to inline them immediately in Core. For example `noinline`, which is never inlined, could never be a PseudoOp. As a side note: `noinline` seems to lack proper handling in the demand analyser. For example, `noinline id x` should be detected as strict in `x` by unleashing `id`s strictness signature. Not sure if we currently do that.</div><div><br></div><div>The "What are PseudoOps" part of 1. is thus mostly resolved: PseudoOps are functions with special semantics that can be lowered or erased in Core or STG, so we will never have to think about generating code for them. We still need to treat them specially, because we have no way to encode their semantics at the source level. Examples (these are all current PseudoOps):</div><div><ul><li>`seq` works on functions, but Haskell's `case` doesn't</li><li>`proxy#` is a symbolic inhabitant of `Proxy#`, which will be erased in code generation. I guess with -XUnliftedNewtypes we can finally define `Proxy#` in source Haskell as `newtype Proxy# a = Proxy# (# #)`</li><li>`unsafeCoerce#` can only be erased when going to STG, where we don't type check as part of linting.</li><li>`coerce` gets translated to casts as part of desugaring.</li><li>`nullAddr#` get inlined immediately to corresponding literal in Core. This is so that source syntax doesn't have to introduce a new literal.</li></ul>Similarly, the definitions of GHC.Magic all seem to vanish after CorePrep. In fact, I begin to think that GHC.Magic is just a subset of PseudoOps that have semantics expressible in source Haskell (thus have a meaningful definition). Which somewhat contradicts my observation above that `noinline` couldn't be a PseudoOp: Clearly it could, because it is lowered to id by the time we go to STG. This lowering (even in higher-order situations, which is why we actually don't need the definition) seems to be the whole point about having the compiler be aware of these special identifiers.</div><div><br></div><div>So, for a concrete question: What are the reasons that we don't make i.e. `lazy` a PseudoOp?<br></div><div><br></div></div><br><div class="gmail_quote"><div dir="ltr" class="gmail_attr">Am So., 11. Aug. 2019 um 12:42 Uhr schrieb Sebastian Graf <<a href="mailto:sgraf1337@gmail.com">sgraf1337@gmail.com</a>>:<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir="ltr"><div>Hey fellow devs,</div><div><br></div><div>While implementing new PseudoOps, a couple of questions popped up:</div><div><ol><li>What are PseudoOps? When do we want to declare one? There doesn't seem to be any documentation around them. I only figured out that I probably want a PseudoOp by comparing to PrimOps I thought would be lowered at a similar stage (i.e. somewhere in Core or STG).<br></li><li> Why aren't GHC.Magic.{lazy,noinline,oneShot} PseudoOps?</li><li>Since we have to set all the IdInfo for `seq` and `noinline` manually, why is this incomplete? I.e., I'd expect a useful strictness signature and arity for both of these.</li></ol><div>Thanks!</div><div>Sebastian<br></div></div></div>
</blockquote></div>