Constructor wrappers vs workers in generated Core

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
6 messages Options
Reply | Threaded
Open this post in threaded view
|

Constructor wrappers vs workers in generated Core

Christopher Done-2
Hi all,

I'm compiling Haskell modules with this simple function. I'd like to
interpret the Core for practical use and also educational use.

compile ::
     GHC.GhcMonad m
  => GHC.ModSummary
  -> m GHC.ModGuts
compile modSummary = do
  parsedModule <- GHC.parseModule modSummary
  typecheckedModule <- GHC.typecheckModule parsedModule
  desugared <- GHC.desugarModule typecheckedModule
  pure (GHC.dm_core_module desugared)

And then I'm taking the mg_binds from ModGuts. I want to work with the
simplest, least-transformed Core as possible. One thing that's a
problem for me is that e.g. the constructor

GHC.Integer.Type.S#

in this expression

\ (ds_dnHN :: Integer) ->
  case ds_dnHN of _ [Occ=Dead] {
    S# i# ->
      case isTrue# (># i# 1#) of _ [Occ=Dead] {
        False -> (\ _ [Occ=Dead, OS=OneShot] -> $WS# 2#) void#;
        True ->
          case nextPrimeWord# (int2Word# i#) of wild_Xp { __DEFAULT ->
          wordToInteger wild_Xp
          }
      };
    Jp# bn -> $WJp# (nextPrimeBigNat bn);
    Jn# _ [Occ=Dead] -> $WS# 2#
  }

is referred to by its wrapper, "$WS#". In general, I'd prefer if it
Core always constructed the worker S# directly. It would reduce the
number of cases I have to handle.

Additionally, what if a worker gets transformed by GHC from e.g.
"Wibble !(Int,Int)" to "Wibble !Int !Int", are then case alt patterns
going to scrutinize this transformed two-arg version?  (As documented
here https://ghc.haskell.org/trac/ghc/wiki/Commentary/Compiler/DataTypes#Thelifecycleofadatatype)

So my question is: is it possible to disable this wrapper
transformation of data constructors?

If not it seems like I'll have no option but to handle this extra
wrapper stuff, due to the case analyses. That wouldn't be the end of
the world, it'd just delay me by another week or so.

For strict fields in constructors I was planning on simply forcing the
fields in my interpreter when a constructor becomes saturated (and
thereby enabling some nice inspection capabilities), rather than
generating extra wrapper code that would force the arguments.

Cheers
_______________________________________________
ghc-devs mailing list
[hidden email]
http://mail.haskell.org/cgi-bin/mailman/listinfo/ghc-devs
Reply | Threaded
Open this post in threaded view
|

Re: Constructor wrappers vs workers in generated Core

Matthew Pickering
There is no way to turn off wrappers and I don't think it would be
possible to implement easily if at all.

However, they will all probably be inlined after the optimiser runs
but it seems that you don't want to run the optimiser at all on the
generated core?

Perhaps it would be possible to set the inliner parameters so that
only wrappers ended up being inlined and nothing else and then call
the relevant function from the simplifier on your bindings to get rid
of them again.

Cheers,

Matt

On Sat, Feb 2, 2019 at 2:43 PM Christopher Done <[hidden email]> wrote:

>
> Hi all,
>
> I'm compiling Haskell modules with this simple function. I'd like to
> interpret the Core for practical use and also educational use.
>
> compile ::
>      GHC.GhcMonad m
>   => GHC.ModSummary
>   -> m GHC.ModGuts
> compile modSummary = do
>   parsedModule <- GHC.parseModule modSummary
>   typecheckedModule <- GHC.typecheckModule parsedModule
>   desugared <- GHC.desugarModule typecheckedModule
>   pure (GHC.dm_core_module desugared)
>
> And then I'm taking the mg_binds from ModGuts. I want to work with the
> simplest, least-transformed Core as possible. One thing that's a
> problem for me is that e.g. the constructor
>
> GHC.Integer.Type.S#
>
> in this expression
>
> \ (ds_dnHN :: Integer) ->
>   case ds_dnHN of _ [Occ=Dead] {
>     S# i# ->
>       case isTrue# (># i# 1#) of _ [Occ=Dead] {
>         False -> (\ _ [Occ=Dead, OS=OneShot] -> $WS# 2#) void#;
>         True ->
>           case nextPrimeWord# (int2Word# i#) of wild_Xp { __DEFAULT ->
>           wordToInteger wild_Xp
>           }
>       };
>     Jp# bn -> $WJp# (nextPrimeBigNat bn);
>     Jn# _ [Occ=Dead] -> $WS# 2#
>   }
>
> is referred to by its wrapper, "$WS#". In general, I'd prefer if it
> Core always constructed the worker S# directly. It would reduce the
> number of cases I have to handle.
>
> Additionally, what if a worker gets transformed by GHC from e.g.
> "Wibble !(Int,Int)" to "Wibble !Int !Int", are then case alt patterns
> going to scrutinize this transformed two-arg version?  (As documented
> here https://ghc.haskell.org/trac/ghc/wiki/Commentary/Compiler/DataTypes#Thelifecycleofadatatype)
>
> So my question is: is it possible to disable this wrapper
> transformation of data constructors?
>
> If not it seems like I'll have no option but to handle this extra
> wrapper stuff, due to the case analyses. That wouldn't be the end of
> the world, it'd just delay me by another week or so.
>
> For strict fields in constructors I was planning on simply forcing the
> fields in my interpreter when a constructor becomes saturated (and
> thereby enabling some nice inspection capabilities), rather than
> generating extra wrapper code that would force the arguments.
>
> Cheers
> _______________________________________________
> ghc-devs mailing list
> [hidden email]
> http://mail.haskell.org/cgi-bin/mailman/listinfo/ghc-devs
_______________________________________________
ghc-devs mailing list
[hidden email]
http://mail.haskell.org/cgi-bin/mailman/listinfo/ghc-devs
Reply | Threaded
Open this post in threaded view
|

Re: Constructor wrappers vs workers in generated Core

Christopher Done-2
On Sat, 2 Feb 2019 at 14:50, Matthew Pickering
<[hidden email]> wrote:
> There is no way to turn off wrappers and I don't think it would be
> possible to implement easily if at all.

Fair enough.

> However, they will all probably be inlined after the optimiser runs
> but it seems that you don't want to run the optimiser at all on the
> generated core?

Yeah, I'm trying to avoid as much instability in the output shape as
possible, and for educational purposes, optimizations make fairly
readable code unreadable.

Wait. Can I rely on case alt patterns having the same arity as the
original user-defined data type before optimization passes are run?

If the answer to that is yes, then I could just replace all wrapper
calls with worker calls, which is an easy enough transformation. As a
precaution, I could add a check on all case alt patterns that the
arity matches the worker arity and barf if not.

Thanks for your help!

Chris
_______________________________________________
ghc-devs mailing list
[hidden email]
http://mail.haskell.org/cgi-bin/mailman/listinfo/ghc-devs
Reply | Threaded
Open this post in threaded view
|

RE: Constructor wrappers vs workers in generated Core

GHC - devs mailing list
In reply to this post by Christopher Done-2
|  is referred to by its wrapper, "$WS#". In general, I'd prefer if it Core
|  always constructed the worker S# directly. It would reduce the number of
|  cases I have to handle.

What do you mean by "constructed the worker directly"?  How does that differ from "call the wrapper, and then (in a simplifier pass) inline the wrapper?

In general, the wrapper of a data constructor can do quite a bit of work: evaluating arguments, unboxing them, casting newtypes, reducing type families.

Simon

|  -----Original Message-----
|  From: ghc-devs <[hidden email]> On Behalf Of Christopher
|  Done
|  Sent: 02 February 2019 14:44
|  To: [hidden email]
|  Subject: Constructor wrappers vs workers in generated Core
|  
|  Hi all,
|  
|  I'm compiling Haskell modules with this simple function. I'd like to
|  interpret the Core for practical use and also educational use.
|  
|  compile ::
|       GHC.GhcMonad m
|    => GHC.ModSummary
|    -> m GHC.ModGuts
|  compile modSummary = do
|    parsedModule <- GHC.parseModule modSummary
|    typecheckedModule <- GHC.typecheckModule parsedModule
|    desugared <- GHC.desugarModule typecheckedModule
|    pure (GHC.dm_core_module desugared)
|  
|  And then I'm taking the mg_binds from ModGuts. I want to work with the
|  simplest, least-transformed Core as possible. One thing that's a problem
|  for me is that e.g. the constructor
|  
|  GHC.Integer.Type.S#
|  
|  in this expression
|  
|  \ (ds_dnHN :: Integer) ->
|    case ds_dnHN of _ [Occ=Dead] {
|      S# i# ->
|        case isTrue# (># i# 1#) of _ [Occ=Dead] {
|          False -> (\ _ [Occ=Dead, OS=OneShot] -> $WS# 2#) void#;
|          True ->
|            case nextPrimeWord# (int2Word# i#) of wild_Xp { __DEFAULT ->
|            wordToInteger wild_Xp
|            }
|        };
|      Jp# bn -> $WJp# (nextPrimeBigNat bn);
|      Jn# _ [Occ=Dead] -> $WS# 2#
|    }
|  
|  is referred to by its wrapper, "$WS#". In general, I'd prefer if it Core
|  always constructed the worker S# directly. It would reduce the number of
|  cases I have to handle.
|  
|  Additionally, what if a worker gets transformed by GHC from e.g.
|  "Wibble !(Int,Int)" to "Wibble !Int !Int", are then case alt patterns
|  going to scrutinize this transformed two-arg version?  (As documented
|  here
|  https://nam06.safelinks.protection.outlook.com/?url=https%3A%2F%2Fghc.has
|  kell.org%2Ftrac%2Fghc%2Fwiki%2FCommentary%2FCompiler%2FDataTypes%23Thelif
|  ecycleofadatatype&amp;data=02%7C01%7Csimonpj%40microsoft.com%7Cf242a0e3c4
|  43448a439508d6891cd1d2%7C72f988bf86f141af91ab2d7cd011db47%7C1%7C0%7C63684
|  7154205957282&amp;sdata=amZzhNxmR8Ods4%2BpsLQE4NzGHP%2FYeEaJevar%2Bl9cKFE
|  %3D&amp;reserved=0)
|  
|  So my question is: is it possible to disable this wrapper transformation
|  of data constructors?
|  
|  If not it seems like I'll have no option but to handle this extra wrapper
|  stuff, due to the case analyses. That wouldn't be the end of the world,
|  it'd just delay me by another week or so.
|  
|  For strict fields in constructors I was planning on simply forcing the
|  fields in my interpreter when a constructor becomes saturated (and
|  thereby enabling some nice inspection capabilities), rather than
|  generating extra wrapper code that would force the arguments.
|  
|  Cheers
|  _______________________________________________
|  ghc-devs mailing list
|  [hidden email]
|  https://nam06.safelinks.protection.outlook.com/?url=http%3A%2F%2Fmail.has
|  kell.org%2Fcgi-bin%2Fmailman%2Flistinfo%2Fghc-
|  devs&amp;data=02%7C01%7Csimonpj%40microsoft.com%7Cf242a0e3c443448a439508d
|  6891cd1d2%7C72f988bf86f141af91ab2d7cd011db47%7C1%7C0%7C636847154205957282
|  &amp;sdata=KSCjmeulEQoL6CvOpLiiwNEX9a3DNnUVnPwbqdEXmOA%3D&amp;reserved=0
_______________________________________________
ghc-devs mailing list
[hidden email]
http://mail.haskell.org/cgi-bin/mailman/listinfo/ghc-devs
Reply | Threaded
Open this post in threaded view
|

Re: Constructor wrappers vs workers in generated Core

Matthew Pickering
In reply to this post by Christopher Done-2
If you want your core to look at much like the source program as
possible then you could print `$WFoo` as just `Foo`?

The existence of wrappers is a crucial part of desugaring so perhaps
it's useful for users to see them in the output of your program if
it's intended to be educational?

Matt


On Sat, Feb 2, 2019 at 3:06 PM Christopher Done <[hidden email]> wrote:

>
> On Sat, 2 Feb 2019 at 14:50, Matthew Pickering
> <[hidden email]> wrote:
> > There is no way to turn off wrappers and I don't think it would be
> > possible to implement easily if at all.
>
> Fair enough.
>
> > However, they will all probably be inlined after the optimiser runs
> > but it seems that you don't want to run the optimiser at all on the
> > generated core?
>
> Yeah, I'm trying to avoid as much instability in the output shape as
> possible, and for educational purposes, optimizations make fairly
> readable code unreadable.
>
> Wait. Can I rely on case alt patterns having the same arity as the
> original user-defined data type before optimization passes are run?
>
> If the answer to that is yes, then I could just replace all wrapper
> calls with worker calls, which is an easy enough transformation. As a
> precaution, I could add a check on all case alt patterns that the
> arity matches the worker arity and barf if not.
>
> Thanks for your help!
>
> Chris
_______________________________________________
ghc-devs mailing list
[hidden email]
http://mail.haskell.org/cgi-bin/mailman/listinfo/ghc-devs
Reply | Threaded
Open this post in threaded view
|

Re: Constructor wrappers vs workers in generated Core

Christopher Done-2
Sorry, here's my explanation.

In summary, I was trying to go for the cleanest, tidiest, simplest AST
possible for interpretation. My long-term goal is to have a slow but
working interpreter of GHC Haskell written in Haskell that is capable
of hot-swapping without segfaulting, by gracefully handling changing
types and functions (just report a type error like the Lisps do), and
the short-term goal is to export that interpretable AST as a web
service so that a simple JS interpreter and/or substitution stepper
could be written for the purposes of education, like
https://chrisdone.com/toys/duet-delta/.

I think this mailing list thread turns out to be an x/y problem. I need STG.

I ended up doing lots of cleaning steps to generate a more well-formed
Core. I learned that the Core that comes from the desugarer is
incomplete and realized today that I was duplicating work done by the
transformation that converts Core to STG. I'd initially avoided STG,
thinking that Core would suffice, but it seems that STG is the AST
that I was converging on anyway. It seems that STG will have all class
methods generated, wrappers generated (and inlined as appropriate),
primops and ffi calls are saturated, etc. no Types or coercions, etc.
It even has info about whether closures can be updated and how.

I wish I'd chosen STG instead of Core from the beginning, but it
doesn't set me back by much so I'll consider this a learning exercise.
If anything, it makes me appreciate almost everything going on in STG
for why it's there and is useful.

I'm aware of two projects that interpret their own form of STG:

http://hackage.haskell.org/package/stgi
http://hackage.haskell.org/package/ministg

But I intend on consuming directly the STG AST from GHC.

The bulk of the work I did that will stay useful is managing a global
mapping of Ids, in terms of global, local ids, and conids in separate
namespaces. IOW I replace all Ids in the AST with a globally unique
Int, like Unique, but it preserves across separate runs, rather than
being per GHC run. So I can plug that work into the STG AST instead. I
have a Docker file that compiles a patched GHC and outputs my AST for
ghc-prim, integer-gmp and base, that leads to all these files:

https://gist.github.com/chrisdone/5ed9adf9dba5fd82d582e9f2bbc30c9f

which have Ids that reference eachother cross-module/package without
any need for more fiddling/munging. The AST looks like this

https://github.com/chrisdone/prana/blob/eaa5b2111631c13eb6b41c9a47400a4ba6a09ffa/test/Main.hs#L164..L198

then I have a mapping from Int64->Name for debugging. I think having
an STG representation that tools like ministg/stgi can consume that
includes everything (ghc-prim, integer-gmp and base) is handy, aside
from my own use-cases (giving the AST to a web app and "real"
interpreting).

Cheers!

On Mon, 4 Feb 2019 at 17:56, Matthew Pickering
<[hidden email]> wrote:

>
> If you want your core to look at much like the source program as
> possible then you could print `$WFoo` as just `Foo`?
>
> The existence of wrappers is a crucial part of desugaring so perhaps
> it's useful for users to see them in the output of your program if
> it's intended to be educational?
>
> Matt
>
>
> On Sat, Feb 2, 2019 at 3:06 PM Christopher Done <[hidden email]> wrote:
> >
> > On Sat, 2 Feb 2019 at 14:50, Matthew Pickering
> > <[hidden email]> wrote:
> > > There is no way to turn off wrappers and I don't think it would be
> > > possible to implement easily if at all.
> >
> > Fair enough.
> >
> > > However, they will all probably be inlined after the optimiser runs
> > > but it seems that you don't want to run the optimiser at all on the
> > > generated core?
> >
> > Yeah, I'm trying to avoid as much instability in the output shape as
> > possible, and for educational purposes, optimizations make fairly
> > readable code unreadable.
> >
> > Wait. Can I rely on case alt patterns having the same arity as the
> > original user-defined data type before optimization passes are run?
> >
> > If the answer to that is yes, then I could just replace all wrapper
> > calls with worker calls, which is an easy enough transformation. As a
> > precaution, I could add a check on all case alt patterns that the
> > arity matches the worker arity and barf if not.
> >
> > Thanks for your help!
> >
> > Chris
_______________________________________________
ghc-devs mailing list
[hidden email]
http://mail.haskell.org/cgi-bin/mailman/listinfo/ghc-devs