【发布时间】:2018-05-16 16:36:27
【问题描述】:
我有一个如下所示的 Java 循环:
public void testMethod() {
int[] nums = new int[10];
for (int i = 0; i < nums.length; i++) {
nums[i] = 0x42;
}
}
我得到的程序集是这样的:
0x00000001296ac845: cmp %r10d,%ebp
0x00000001296ac848: jae 0x00000001296ac8b4
0x00000001296ac84a: movl $0x42,0x10(%rbx,%rbp,4)
0x00000001296ac852: inc %ebp
0x00000001296ac854: cmp %r11d,%ebp
0x00000001296ac857: jl 0x00000001296ac845
0x00000001296ac859: mov %r10d,%r8d
0x00000001296ac85c: add $0xfffffffd,%r8d
0x00000001296ac860: mov $0x80000000,%r9d
0x00000001296ac866: cmp %r8d,%r10d
0x00000001296ac869: cmovl %r9d,%r8d
0x00000001296ac86d: cmp %r8d,%ebp
0x00000001296ac870: jge 0x00000001296ac88e
0x00000001296ac872: vmovq -0xda(%rip),%xmm0
0x00000001296ac87a: vpunpcklqdq %xmm0,%xmm0,%xmm0
0x00000001296ac87e: xchg %ax,%ax
0x00000001296ac880: vmovdqu %xmm0,0x10(%rbx,%rbp,4)
0x00000001296ac886: add $0x4,%ebp
0x00000001296ac889: cmp %r8d,%ebp
0x00000001296ac88c: jl 0x00000001296ac880
如果我的理解是正确的,那么第一个程序块就是执行nums[i] = 0x42; 的程序块。在第三块,有vmovdqu
vmovdqu 指令将值从整数向量移动到未对齐的内存位置。
但是,我仍然不完全理解 vmovdqu 在我的循环上下文中所做的事情。
第三段汇编代码到底在做什么?
完整的代码在这里:https://pastebin.com/cT5cJcMS
【问题讨论】:
-
@Sneftel 啊,为了简洁起见,我省略了它。我将添加实际的汇编代码。 :)
-
这看起来确实是自动矢量化的结果,但你真的应该发布整个代码,缺少几个重要部分。
-
@MatteoItalia 用完整代码的链接更新了帖子:)
-
另外,它真的只从这段代码之前的
0xda字节加载数据吗?通常将代码和数据保存在同一页面中没有任何优势,因为现代 x86 使用单独的 iTLB 和 dTLB。使用 AVX2,我会将0x42放入寄存器并使用vmovd %eax, %xmm0/vpbroadcastd %xmm0, %xmm0(或vpshufd),而不是从内存中加载常量。并且在内存中复制0x42两次是没有意义的,除非他们的 JIT 优化器只是在洗牌时很糟糕。我想我们确实必须考虑这样一个事实,即 JIT 必须快速编译并且不需要花费时间来制作更优化的代码。 -
最糟糕的是,如果
new成功,nums.length应该是编译时常量,那么您可以用 2vmovdqu xmm+ 1vmovq xmm填充数组(完全展开环形)。我想知道使用10作为循环绑定是否有帮助?或者由于没有返回nums,所以整个函数应该只是一个ret,或者内联后什么都没有。
标签: assembly x86 avx java-bytecode-asm jvm-hotspot