Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

User guided specialisation stage #252

Draft
wants to merge 5 commits into
base: hkmc2
Choose a base branch
from

Conversation

Oli-Ar
Copy link

@Oli-Ar Oli-Ar commented Dec 17, 2024

Draft PR for implementing a user-guided specialisation pass in the mlscript compiler, very much still WIP

@@ -0,0 +1,87 @@


:spt
Copy link
Contributor

@LPTK LPTK Dec 18, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be helpful to also show the JS code, which is much easier to read.

@Oli-Ar Oli-Ar force-pushed the hkmc2-specialisation-wip branch from 84db949 to 2a42dd2 Compare January 24, 2025 06:30
CAG2Mark and others added 5 commits February 14, 2025 05:42
Ported specialisation keyword from previous commits to new HEAD, as it
was easier than rebasing, as other components had significantly changed.
As part of moving specialiser code to the new head rewrote logic to pass
the specialisation flags through the compiler - now has a much smaller
footprint.
@Oli-Ar Oli-Ar force-pushed the hkmc2-specialisation-wip branch from 2a42dd2 to b91aa15 Compare February 26, 2025 01:25
case Primitive(name: Str)
case Function(lhs: SimpleType, rhs: SimpleType)
case Record(fields: Ls[(Str, SimpleType)])
case ClassType(sym: ClassSymbol, supers: Ls[SimpleType], members: Map[Str, SimpleType])
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is more like ClassInfo (which is not a SimpleType). The types of actual class instances should be a different constructor (which points back to the ClassInfo).

@LPTK
Copy link
Contributor

LPTK commented Feb 26, 2025

TODO: Write specification/architecture of algorithm first.

You need to attach the flows of normal parameters to the flows of specialized ones.

Example:

fun foo(spec x: ?a, p1: ?p1, p2: ?p2) = ...

fun bar(x: ?b, arg: ?arg) =
  foo(x, arg, 123)
// At this point, we know we'll need to specialize this call to `foo` for each new concrete LB coming into ?b
// Each of these specializations will need to create the flows `?arg <: ?p1` and `123 <: ?p2`.

Another way of thinking about this: specialized functions are polymorphic, but the polymorphic instances are indexed not by the individual call sites but by the list of concrete shapes flowing into their specialized parameters.

fun foo(spec x, spec y, p1, p2) = ... constraint ?p1 <: ?p2 -> ?result
foo: (x, y) => forall p1, p2, result where { p1 <: p2 -> result }. T

In this approach, we remember whatever flows into (p1, p2) by attaching it (indexing it) to what flows into (x, y). Only when the (x, y) flow becomes concrete do we look up the specialization table: then, if there is not yet an entry, we instantiate the polymorphic type scheme; afterwards, we connect the stashes (p1, p2) flows with the corresponding instantiated signature.

Note: Similarly, ClassInfos themselves should be indexed on their spec params.

@LPTK
Copy link
Contributor

LPTK commented Feb 26, 2025

Another interesting thing: the calls to specialized functions happening in non-specialized contexts may have to be turned into pattern matches.

Reusing the previous example:

fun foo(spec x, p1, p2) = ...

fun bar(x, arg) =
  foo(x, arg, 123)

bar(Int, 0)
bar(Str, true)

This should basically specialize into:

fun foo_Int(x, p1, p2) = ...
fun foo_Str(x, p1, p2) = ...

fun bar(x, arg) =
  if x is
    Int then foo_Int(x, arg, 123)
    Str then foo_Str(x, arg, 123)

bar(Int, 0)
bar(Str, true)

In fact, at least conceptually, we should probably always generate pattern matching by default and possibly optimize it later. So even a direct call like

foo(42, true, 0)

should be turned into

let $arg = 42
if $arg is
  Int then foo_Int($arg, true, 0)

which will be optimized the the expected

let $arg = 42
foo_Int($arg, true, 0)

So this looks pretty similar to the earlier defunctionalization/demethodization project!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants