首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >完全内联AnyVal隐式类构造器而不使用-Yopt-内联启发式:所有

完全内联AnyVal隐式类构造器而不使用-Yopt-内联启发式:所有
EN

Stack Overflow用户
提问于 2022-01-10 17:03:52
回答 1查看 86关注 0票数 0

我正在试验Java 17 Vector孵化器,我决定看看能否为它创建一个零成本的语法糖。下面是我所写内容的一个小片段:

代码语言:javascript
复制
import jdk.incubator.vector._

object VectorOps {
  implicit final class FloatVectorOps @inline() (val _this: FloatVector) extends AnyVal {
    @inline def +(that: FloatVector): FloatVector = _this.add(that)
    @inline def apply(i: Int): Float = _this.lane(i)
  }
}

class Test {
  def test(x: Float, y: Float): Float = {
    import VectorOps._
    val SSE = FloatVector.SPECIES_128
    val xv = FloatVector.broadcast(SSE, x)
    val yv = FloatVector.broadcast(SSE, y)
    (xv + yv)(0) // sugar for xv.add(yv).lane(0)
  }
}

我使用Scala 2.13.5和Java 17。

Scala编译器使用-optimize -opt:inline -opt-warnings:at-inline-failed -Yopt-inline-heuristics:at-inline-annotated -opt:nullness-tracking -opt:box-unbox -opt:copy-propagation -opt:unreachable-code -language:implicitConversions -opt:closure-invocations运行。

JVM是用--add-modules jdk.incubator.vector运行的。

但是,Scala编译器将test方法的最后一行编译为

代码语言:javascript
复制
    GETSTATIC VectorOps$FloatVectorOps$.MODULE$ : LVectorOps$FloatVectorOps$;
    POP
    GETSTATIC VectorOps$.MODULE$ : LVectorOps$;
    GETSTATIC VectorOps$FloatVectorOps$.MODULE$ : LVectorOps$FloatVectorOps$;
    POP
    GETSTATIC VectorOps$.MODULE$ : LVectorOps$;
    ALOAD 4
    INVOKEVIRTUAL VectorOps$.FloatVectorOps (Ljdk/incubator/vector/FloatVector;)Ljdk/incubator/vector/FloatVector;
    ALOAD 5
    INVOKEVIRTUAL jdk/incubator/vector/FloatVector.add (Ljdk/incubator/vector/Vector;)Ljdk/incubator/vector/FloatVector;
    INVOKEVIRTUAL VectorOps$.FloatVectorOps (Ljdk/incubator/vector/FloatVector;)Ljdk/incubator/vector/FloatVector;
    ICONST_0
    INVOKEVIRTUAL jdk/incubator/vector/FloatVector.lane (I)F
    FRETURN

这些对隐式类构造函数的调用完全抛出Hotspot,它无法打开向量变量,从而降低性能。注意,就字节码而言,隐式类构造函数是一个标识函数,这实际上意味着它是一个非操作函数。使用MODULE$的所有东西也是不必要的。但是Hotspot没有看到它。

(请注意,对+apply的方法调用已成功内联。)

添加-Yopt-inline-heuristics:everything移除构造函数调用和MODULE$,并修复性能,但这就像使用大锤破解一个螺母一样。就像一把大锤,感觉不安全。

当然,用Java风格编写整个代码也可以改善性能,但这并不是重点。

所以我的问题是:

  1. 可以在不使用-Yopt-inline-heuristics:everything的情况下消除调用,并且无需重写原始-Yopt-inline-heuristics:everything语法中的所有内容吗?

  1. Scala 3有一些新的内联特性。这能在Scala 3中完成吗?没有积极的优化选项吗?
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2022-09-28 19:49:35

我想出了一个解决方案:宏。

代码语言:javascript
复制
object VectorOps {
  implicit final class FloatVectorOps @inline() (val _this: FloatVector) extends AnyVal {
    @inline def +(that: FloatVector): FloatVector = macro MacroVectorOps.add
    @inline def apply(i: Int): Float = macro MacroVectorOps.lane
  }
}

object MacroVectorOps {
  import scala.reflect.macros.blackbox
  def add(c: blackbox.Context)(that: c.Tree): c.Tree = {
    import c.universe._
    // deconstruct the implicit conversion:
    val q"$conv($in)" = c.prefix.tree
    q"$in.add($that)"
  }  
  def lane(c: blackbox.Context)(i: c.Tree): c.Tree = {
    import c.universe._
    val q"$conv($in)" = c.prefix.tree
    q"$in.lane($i)"
  }
}

使用它的代码编译成高效的字节码,就像我使用原始Java编写它一样,字节码中根本没有FloatVectorOps类或VectorOps对象的痕迹。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/70656216

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档