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

IRFunctionRegistry changes #3202

Merged
merged 3 commits into from
Mar 21, 2018

Conversation

catoverdrive
Copy link
Contributor

cc @cseed @danking

I changed the ApplyFunction IR to store the function name instead of the IRFunction implementation. (The implementation gets looked up during Infer if it doesn't already exist, but we're always pre-populating it in IRFunctionRegistry.lookupConversion).

As part of this, I separated the way that IRFunctionRegistry stores IR => IR from the IRFunction lookup, since the lookup in Infer wants to grab the IRFunction and not necessarily the entire Apply IR that we currently store. Maybe the IR => IR aspect (handled by IRFunction.lookupConversion) could go away once we no longer need the AST to IR conversion and start constructing the IR directly in python.

Copy link
Contributor

@tpoterba tpoterba left a comment

Choose a reason for hiding this comment

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

one tiny style comment

}

def lookupFunction(name: String, args: Seq[Type]): Option[IRFunction] = {
val validF = codeRegistry(name).flatMap { case (ts, f) =>
Copy link
Contributor

Choose a reason for hiding this comment

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

can you use any fail all fail here?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

None of the things (except the return) are Options? I don't see how it would work here

Copy link
Contributor

Choose a reason for hiding this comment

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

ahh, got it. nevermind.

@tpoterba tpoterba merged commit 127a3de into hail-is:master Mar 21, 2018
jbloom22 pushed a commit to jbloom22/hail that referenced this pull request Mar 22, 2018
* separate IR conversions from IRFunction conversions in IRFunctionRegistry

* change ApplyFunction(impl, args) => Apply(fn, args, impl)

* cleanup
val registry: mutable.Map[String, Seq[(Seq[Type], Seq[IR] => IR)]] = mutable.Map().withDefaultValue(Seq.empty)
val irRegistry: mutable.Map[String, Seq[(Seq[Type], Seq[IR] => IR)]] = mutable.Map().withDefaultValue(Seq.empty)

val codeRegistry: mutable.Map[String, Seq[(Seq[Type], IRFunction)]] = mutable.Map().withDefaultValue(Seq.empty)
Copy link
Contributor

Choose a reason for hiding this comment

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

@catoverdrive Sorry I'm late to the game here. We should use mutable.MultiMap when we have Map[K, Set[V]]. Unless there's a compelling case for Seq here?

Copy link
Contributor

Choose a reason for hiding this comment

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

That also makes addIRFunction and addIR just calls to irRegistry.addBinding and codeRegistry.addBinding

Copy link
Contributor Author

Choose a reason for hiding this comment

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

womp, I didn't know this was a thing. I'll change.

}

def lookupFunction(name: String, args: Seq[Type]): Option[Seq[IR] => IR] = {
def lookupConversion(name: String, args: Seq[Type]): Option[Seq[IR] => IR] = {
Copy link
Contributor

@danking danking Mar 26, 2018

Choose a reason for hiding this comment

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

lookupConversion and lookupFunction are suspiciously similar. I'm not sure I see the compelling reason to keep them separate.

Would the code look simpler if we had one MultiMap[String, IRFun] where IRFun was something like:

trait IRFun {
  def args: Seq[Type]
  def ret: Type
  def emit(
    emitter: IR => (Code[Unit], Code[Boolean], Code[_]),
    mb: MethodBuilder,
    args: IR*
  ): (Code[Unit], Code[Boolean], Code[_])
}

class IRMacro(
  val args: Seq[Type],
  val ret: Type,
  val impl: Array[IR] => IR
) extends IRFun {
  def emit(
    emitter: IR => (Code[Unit], Code[Boolean], Code[_]),
    mb: MethodBuilder,
    args: IR*
  ): (Code[Unit], Code[Boolean], Code[_]) = emitter(impl(args.toArray))
}

class JVMFun(
  val args: Seq[Type],
  retType: Type,
  impl: (MethodBuilder, Array[Code[_]]) => Code[_]
) extends IRFun {
  def emit(
    emitter: IR => (Code[Unit], Code[Boolean], Code[_]),
    mb: MethodBuilder,
    args: IR*
  ): (Code[Unit], Code[Boolean], Code[_]) = {
    val (setup, ms, vs) = args.map(emitter).unzip
    (Code(setup:_*), ms.fold(_ || _), impl(mb, vs))
  }
}

Copy link
Contributor

Choose a reason for hiding this comment

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

Or maybe let JVMFun also control missingness?

class MissingAwareJVMFun(
  val args: Seq[Type],
  retType: Type,
  impl: (MethodBuilder, Array[Code[_]]) => (Code[Unit], Code[Boolean], Code[_])
) extends IRFun {
  def emit(
    emitter: IR => (Code[Unit], Code[Boolean], Code[_]),
    mb: MethodBuilder,
    args: IR*
  ): (Code[Unit], Code[Boolean], Code[_]) = {
    val (setups, ms, vs) = args.map(emitter).unzip
    val (setup, m, v) = impl(mb, vs)
    (Code(setups ++ setup:_*), (ms :+ m).fold(_ || _), v)
  }
}

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I don't really want to entangle them because of two resasons:

  • Things that can be translated directly (Seq[IR] => IR) are maybe things that we don't want to keep in the function registry once we can directly pass AST nodes from Python. I kind of want all of them to go away.
  • Even if we do want to keep them in the function registry, I want to be able to look up the non-IR conversions post optimization, when we go to compile the code. Once we're no longer translating from AST, we don't need to store the implementation as part of the IR node and can look it up after we're done optimizing the overall IR. I feel like the things that are implemented in terms of existing IR nodes should just go directly into the IR tree and optimized away with the rest of it. (this is kind of what currently happens; Infer on Apply nodes does a lookup on the IRFunction registry to be able to properly infer the return type)

konradjk pushed a commit to konradjk/hail that referenced this pull request Jun 12, 2018
* separate IR conversions from IRFunction conversions in IRFunctionRegistry

* change ApplyFunction(impl, args) => Apply(fn, args, impl)

* cleanup
jackgoldsmith4 pushed a commit to jackgoldsmith4/hail that referenced this pull request Jun 25, 2018
* separate IR conversions from IRFunction conversions in IRFunctionRegistry

* change ApplyFunction(impl, args) => Apply(fn, args, impl)

* cleanup
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