在Java方法中使用dup进行计算
我目前有一种方法可以实现以下功能:给定值、偏移量、步幅,它将偏移量添加到值中,使其保持在一组大小步幅内。在Java方法中使用dup进行计算,java,jvm,javac,Java,Jvm,Javac,我目前有一种方法可以实现以下功能:给定值、偏移量、步幅,它将偏移量添加到值中,使其保持在一组大小步幅内。 示例: 20,5,30=>25 29,5,30=>4 42,5,30=>47 我现在的代码是: int cycle(int value, int offset, int stride) { final int rem = value % stride; return ((rem + offset) % stride - rem + value); } 其汇编如下: int
示例:
20,5,30=>25
29,5,30=>4
42,5,30=>47
我现在的代码是:
int cycle(int value, int offset, int stride) {
final int rem = value % stride;
return ((rem + offset) % stride - rem + value);
}
其汇编如下:
int cycle(int, int, int);
Code:
0: iload_1
1: iload_3
2: irem
3: istore 4
5: iload 4
7: iload_2
8: iadd
9: iload_3
10: irem
11: iload 4
13: isub
14: iload_1
15: iadd
16: ireturn
是否有任何代码更改和/或编译器选项的组合可以使它产生类似的结果?(示例是手写的):
大多数优化JVM,尤其是最常用的HotSpot JVM,在应用任何其他优化之前都会将代码转换为。对于这种表示法,无论原始代码是在操作数堆栈上使用临时局部变量还是
dup
,都是完全不相关的,因此中间表示法将是相同的
因此,
javac
没有提供任何选项来控制这样一个构造的字节码表示,但这并不重要。你希望生成后一个字节码,因为它性能更好吗?好吧,没有这样的javac选项。但你为什么需要这个?基本上,是的。我意识到还有一种翻译成本地机器代码的方法,这可能会进一步优化事情。我考虑的另一种方法是内联rem。不过,在对其进行基准测试后,它似乎最终并不重要,因为测试循环有10亿次调用,两种方法都会产生大约0.25ns的每次调用的计时。第二种方法是用源代码中的值%步长替换rem。然而,我得到的计时是不准确的,尽管修正它仍然会产生一致的结果。结果是JVM检测到它是用所有常量输入调用的,并且完全优化了方法。这就是为什么1)听并接受霍尔格的答案,因为他绝对正确2)查看jmh
如果你想对java方法进行微基准测试,结果是当它是JIT时,变量根本不会写入堆栈。因为它保存在寄存器中,所以只需要在需要的地方重用它。(如果这就是SSA表单,我很抱歉,我只理解了那篇文章)@Tahg SSA表单是一种中间表示,它甚至没有堆栈的概念。它基本上是一种将变量(它们的实际值)的实际使用与其源连接起来的图形。这有效地消除了变量和操作数堆栈之间以及不同变量之间的所有中间传输。这就是我的答案,“无论原始代码是在操作数堆栈上使用临时局部变量还是dup,都是完全不相关的,中间表示形式将是相同的”。从SSA表示中,它最终被分配到CPU寄存器
int cycle(int, int, int);
Code:
0: iload_1
1: iload_3
2: irem
3: dup
4: iload_2
5: iadd
6: iload_3
7: irem
8: isub
9: iload_1
10: iadd
11: ireturn