Skip to content
forked from scala/scala3

Modified version of dotty suporting language specific and library-specific optimizations

License

Notifications You must be signed in to change notification settings

dotty-linker/dotty

This branch is 319 commits ahead of, 35892 commits behind scala/scala3:main.

Folders and files

NameName
Last commit message
Last commit date
Sep 17, 2014
Feb 16, 2016
Feb 16, 2016
Jan 23, 2014
Nov 23, 2015
Feb 16, 2016
Feb 16, 2016
Feb 16, 2016
Nov 10, 2016
Nov 10, 2016
May 9, 2016
Feb 10, 2013
Oct 31, 2015
Feb 23, 2014
Feb 6, 2014
Feb 6, 2014
May 13, 2016
Apr 9, 2015

Repository files navigation

dotty linker

Join the chat at Join the chat at https://gitter.im/lampepfl/dotty and call for @Darkdimius if you have questions.

This is a modified version of Dotty compiler, that includes optimization phases. Currently included phases are:

  • auto-specialization, enabled by passing -lto:spec or -lto:all flag;
  • rewrite rules, enabled by passing -rewrites.

Rewrite rules

This a mechanism that allows to define custom optimizations alongside with a library. See this illustaration:

import dotty.linker._

@rewrites
object rules{
  // Library authors can define rewrite rules alongside with a library.
  // Rules are applied by a phase that runs after pickler. Thus they do not interact with type checking.
  // Rules can be defined in other compilation units, as they are discovered through TASTY.
  // The following examples are already working in my prototype:

  def isEmpty(x: Seq[Int]) =
    Rewrite(from = x.length == 0,               // linker will look for pattern in `from`, where method arguments are variables to be bound to trees
            to   = x.isEmpty)                   // if the pattern matches, it will rewrite it to `to`, replacing arguments with bound trees

  def twoDropRights(x: List[Int], a: Int, b: Int) =
    Rewrite(from = x.dropRight(a).dropRight(b), // multiple variables can be bound at once
            to   = x.dropRight(a + b))
  
  def bigIntShift(bi: BigInt, a: Int)(implicit evi: Literal[a.type]) =
  Rewrite(from = bi / a,
     to = 
      if (Integer.bitCount(a) == 1) // one of those 2 branches will be eliminated either by Linker or by JIT as dead code
        bi >> java.lang.Integer.numberOfTrailingZeros(a) 
      else bi / a
     )

  def twoFilters(x: List[Int], a: Int => Boolean, b: Int => Boolean)(implicit apure: IsPure[a.type]) =
                                                // implicits can be used to specify additional constraints. 
                                                // my prototype currently supports IsPure and IsLiteral
                                                // IsPure is a tweaked check from tpd.
    Rewrite(from = x.filter(a).filter(b), 
            to   = x.filter(x => a(x) && b(x)))

  def customFancyWarning(x: ParSeq[Int], x: (Int, Int) => Int) =
    Warn(pattern = x.reduceLeft(x)),            // custom warnings are also supported
             msg = “reduceLeft on parallel collection makes no sense”)

  def customFancyError(a: BigInt) =
    Error(pattern = a / 0,                      // custom errors are also supported
              msg =This code is going to fail in runtime“)

  // the following examples are not _yet_ implemented in the prototype.

  def twoFiltersGeneric[T](x: List[T], a: T => Boolean, b: T => Boolean)(implicit apure: IsPure[a.type]) =
                                                // in case method takes type arguments, T becomes a similar type-variable to-be-bound.  
    Rewrite(from = x.filter(a).filter(b), 
            to   = x.filter(x => a(x) && b(x)))

  def metaExample[T](x: List[T])(implicit apure: IsPure[a.type]) =
                                                // in case method takes type arguments, T becomes a similar type-variable to-be-bound.  
    RewriteMeta(from = x.toString, 
            to = meta { /* entry point to interpreted scala-meta macros */})
}

object Test{
  def myPrettyPrint(a: Any): Unit = ()
  def main(args: Array[String]): Unit = {
     List(1,2,3).length == 0                    // will be rewritten to List(1,2,3).isEmpty
     List(1,2,3).drop(1).drop(1)                // will be rewritten to List(1, 2, 3).drop(2)
     List(1,2,3).dropRight(1).dropRight(1)      // will be rewritten to List(1, 2, 3).dropRight(1 + 1)
     List(1,2,3).filter(_ > 2).filter(_ > 1)    // will be rewritten to List(1, 2, 3).filter(x =>  _ > 2 && _ > 1)
     myPrettyPrint(args.length)                 // will be rewritten to println(“args.length” + “ = “ + args.length)
  }
}

Auto specialization

Build a callgraph, sees which specializations are needed and generates only the required ones. Enabled by -lto:spec or -lto:all.

For details, see

Talks:

About

Modified version of dotty suporting language specific and library-specific optimizations

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages

  • Scala 97.3%
  • Java 2.6%
  • Shell 0.1%