-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Description
Idea
The goal of this project is to remove redundant vals that only alias other values.
For example:
val x = f()
val y = x
println(y)Here, the val y merely aliases x. Its single usage can be replaced by x, and its definition can be removed:
val x = f()
println(x)This can be understood as a form of copy propagation.
Motivation
The main motivation for this optimization is to simplify the code generated by the inliner, which often contains many useless aliases (known as “proxies”).
As a concrete example, consider the following code (adapted from @asunluer’s off-heap memory project). It contains logic to serialize Int, Point, and Line values into an array of Ints. inline functions are used to compute all relative offsets at compile time.
// pe.scala
case class Point(x: Int, y: Int)
case class Line(p1: Point, p2: Point)
inline def size[T]: Int =
inline compiletime.erasedValue[T] match
case i: Int => 1
case p: Point => 2
case vec: Line => size[Point] + size[Point]
case _ => compiletime.error("Unsupported type")
inline def encode(mem: Array[Int], baseOffset: Int, inline relativeOffset: Int, v: Any): Unit =
inline v match
case v: Int =>
mem(baseOffset + relativeOffset) = v
case p: Point =>
encode(mem, baseOffset, relativeOffset, p.x)
encode(mem, baseOffset, relativeOffset + size[Int], p.y)
case vec: Line =>
encode(mem, baseOffset, relativeOffset, vec.p1)
encode(mem, baseOffset, relativeOffset + size[Point], vec.p2)
case _ =>
compiletime.error("Unsupported type")
inline def encode(mem: Array[Int], baseOffset: Int, v: Any): Unit =
encode(mem, baseOffset, 0, v)
@main def Main =
val l: Array[Int] = Array(0, 0, 0, 0)
val offset: Int = ???
encode(l, offset, Line(Point(10, 20), Point(30, 40)))
println(l.toList) // should print List(10, 20, 30, 40)Currently, the compiler generates the following code:
$ scala --server=false -Xprint:genBCode pe.scala
[[syntax trees at end of genBCode]]
...
@main def Main(): Unit =
{
val l: Int[] = [0,0,0,0 : Int]
val offset: Int = ???()
{
val v$proxy1: Line =
Line.apply(Point.apply(10, 20), Point.apply(30, 40))
{
val $scrutinee1: Line = v$proxy1
val vec: Line = $scrutinee1
{
val $scrutinee2: Point = vec.p1()
val p: Point = $scrutinee2
{
val $scrutinee3: Int = p.x()
val v: Int = $scrutinee3
l.[]update(offset + 0, v)
}
{
val $scrutinee5: Int = p.y()
val v: Int = $scrutinee5
l.[]update(offset + 1, v)
}
}
{
val $scrutinee7: Point = vec.p2()
val p: Point = $scrutinee7
{
val $scrutinee8: Int = p.x()
val v: Int = $scrutinee8
l.[]update(offset + 2, v)
}
{
val $scrutinee10: Int = p.y()
val v: Int = $scrutinee10
l.[]update(offset + 3, v)
}
}
}
}
println(wrapIntArray(l).toList())
}
...This code is difficult to read, and its verbosity makes debugging inlining harder than it should be.
If we inline all redundant aliases (and unwrap trivial blocks), we obtain a much simpler and more readable result:
@main def Main(): Unit =
val offset: Int = ???()
val vec: inline_pe2.Line = inline_pe2.Line.apply(inline_pe2.Point.apply(10, 20), inline_pe2.Point.apply(30, 40))
val p: inline_pe2.Point = vec.p1()
l.[]update(offset + 0, p.x())
l.[]update(offset + 1, p.y())
val p2: inline_pe2.Point = vec.p2()
l.[]update(offset + 2, p2.x())
l.[]update(offset + 3, p2.y())
println(wrapIntArray(l).toList())As side benefits, this would also reduce the size of the generated bytecode and might speed up subsequent compilation phases.
Note that this optimization could also apply to user code, not only to code produced by the inliner.
Runtime performance would most probably not be affected by this optimization, as the JVM JIT (the Java Virtual Machine's Just-in-Time compiler) already performs similar optimization.
Implementation
This optimization should be implemented as a standalone compiler phase, executed after inlining.
Logistics
This would be a Master’s semester project (worth 8 or 12 credits) at EPFL, running from February to June 2026.
We are looking for a motivated Master’s student interested in compilers, proficient in Scala, and who has taken Software Construction and Computer Language Processing.
Still, feel free to apply if you are motivated but do not meet all requirements.
To apply, reach out to me.