Skip to content

PatMat:(add support guards in switches) implement common subexpression elimination #1313

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

Closed
DarkDimius opened this issue Jun 7, 2016 · 0 comments · Fixed by #4982
Closed

Comments

@DarkDimius
Copy link
Contributor

DarkDimius commented Jun 7, 2016

In Scalac pattern matcher is able to support guards inside switches by generating arbitrary GOTOs.

Unlike this, in Dotty I propose to implement more general optimization outside of pattern-matcher, that would also give us support for guards.

I propose to add a phase, that would follow the structure of matches, match common prefixes of pattern match, and restructure that pattern.

See following examples for illustration:

x match {
  case List(1, 2, 3) => // 1
  case List(3, 4, 5) => // 2
  case 6 if pred     => // 3 
  case 6 =>             // 4
  case _ =>             // 5
}

should be rewritten as(a simplified version):

x match {
  case t: List[Int] => 
    t match {
      case List(1, 2, 3) => // 1
      case List(3, 4, 5) => // 2
      case _ => fallback
    }
  case x @ 6 => 
      x match {
        case _ if pred =>     // 3 
        case _ =>             // 4
        case _ => fallback
     }
  case _ => 
    fallback
   }
}
<label> def fallback = // 5
@nicolasstucki nicolasstucki self-assigned this Jun 10, 2016
@nicolasstucki nicolasstucki removed their assignment Mar 21, 2018
sjrd added a commit to sjrd/dotty that referenced this issue Aug 26, 2018
A Labeled block is an expression tree of the form

  label[T]: {
    expr
  }

where `expr` must conform to the type `T`. In addition, within
`expr` (but nowhere else), return from the label is allowed:

  return[label] e

where `e` must conform to the type `T` as well.

If execution of `expr` completes normally (rather than throwing an
exception or returning, etc.), then the result of evaluating the
`Labeled` block is the result of `expr`. If a `return[label] e` is
reached, the execution of `expr` is interrupted, and the result of
evaluating the `Labeled` block is the result of evaluating the
argument `e`.

Implementation-wise, a `Labeled` block is represented as a `Tree`
with the shape:

  Labeled(Bind(labelName), expr)

where the `Bind` nodes holds the definition of the label symbol.
That symbol is a term symbol with the flag `Label` (but not
`Method`, unlike symbols for label-defs) and whose `info` is the
result type `T` of the labeled block.

We use those new `Labeled` blocks in `PatternMatcher`, instead of
label-defs. This is the first step towards completely removing
label-defs from the compiler.

This commit structurally fixes a few issues:

* It fixes scala#1313 through the `mergeTests` optimization.
* It fixes scala#4563 because Labeled blocks are erasure-friendly.
* It does a big step towards fixing the upstream test t10387: the
  compiler can get to the back-end on that test, but it produces
  too much bytecode for a single JVM method. We do add a sister
  test t10387b which works because optimizations can kick in.
sjrd added a commit to sjrd/dotty that referenced this issue Aug 26, 2018
A Labeled block is an expression tree of the form

  label[T]: {
    expr
  }

where `expr` must conform to the type `T`. In addition, within
`expr` (but nowhere else), return from the label is allowed:

  return[label] e

where `e` must conform to the type `T` as well.

If execution of `expr` completes normally (rather than throwing an
exception or returning, etc.), then the result of evaluating the
`Labeled` block is the result of `expr`. If a `return[label] e` is
reached, the execution of `expr` is interrupted, and the result of
evaluating the `Labeled` block is the result of evaluating the
argument `e`.

Implementation-wise, a `Labeled` block is represented as a `Tree`
with the shape:

  Labeled(Bind(labelName), expr)

where the `Bind` nodes holds the definition of the label symbol.
That symbol is a term symbol with the flag `Label` (but not
`Method`, unlike symbols for label-defs) and whose `info` is the
result type `T` of the labeled block.

We use those new `Labeled` blocks in `PatternMatcher`, instead of
label-defs. This is the first step towards completely removing
label-defs from the compiler.

This commit structurally fixes a few issues:

* It fixes scala#1313 through the `mergeTests` optimization.
* It fixes scala#4563 because Labeled blocks are erasure-friendly.
* It does a big step towards fixing the upstream test t10387: the
  compiler can get to the back-end on that test, but it produces
  too much bytecode for a single JVM method. We do add a sister
  test t10387b which works because optimizations can kick in.
sjrd added a commit to sjrd/dotty that referenced this issue Aug 27, 2018
A Labeled block is an expression tree of the form

  label[T]: {
    expr
  }

where `expr` must conform to the type `T`. In addition, within
`expr` (but nowhere else), return from the label is allowed:

  return[label] e

where `e` must conform to the type `T` as well.

If execution of `expr` completes normally (rather than throwing an
exception or returning, etc.), then the result of evaluating the
`Labeled` block is the result of `expr`. If a `return[label] e` is
reached, the execution of `expr` is interrupted, and the result of
evaluating the `Labeled` block is the result of evaluating the
argument `e`.

Implementation-wise, a `Labeled` block is represented as a `Tree`
with the shape:

  Labeled(Bind(labelName), expr)

where the `Bind` nodes holds the definition of the label symbol.
That symbol is a term symbol with the flag `Label` (but not
`Method`, unlike symbols for label-defs) and whose `info` is the
result type `T` of the labeled block.

We use those new `Labeled` blocks in `PatternMatcher`, instead of
label-defs. This is the first step towards completely removing
label-defs from the compiler.

This commit structurally fixes a few issues:

* It fixes scala#1313 through the `mergeTests` optimization.
* It fixes scala#4563 because Labeled blocks are erasure-friendly.
* It does a big step towards fixing the upstream test t10387: the
  compiler can get to the back-end on that test, but it produces
  too much bytecode for a single JVM method. We do add a sister
  test t10387b which works because optimizations can kick in.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants