Xeon Phi 的 reduce 操作的内联组装
inline assembly of reduce operation for Xeon Phi
我正在寻找 Xeon Phi 的加减操作的内联汇编操作。我在 intel intrinsic 网站 (link) 上找到了 _mm512_reduce_add_epi32 intrinsic。但是在网站上,他们并没有提到实际的组装操作。
谁能帮我找到Xeon Phi 平台上归约操作的内联汇编?
谢谢
在阅读汇编方面我几乎一无所知,所以我就这样做了:
创建了一个 foo.c 文件,如下所示:
#include "immintrin.h"
int foo(__m512i a) {
return _mm512_reduce_add_epi32(a);
}
我使用 -mmic -S
符合英特尔编译器版本 16.0.1。它给了我以下汇编代码:
# -- Begin foo
.text
# mark_begin;
# Threads 4
.align 16,0x90
.globl foo
# --- foo(__m512i)
foo:
# parameter 1: %zmm0
..B1.1: # Preds ..B1.0 Latency 53
.cfi_startproc
..___tag_value_foo.1:
..L2:
#3.20
movl , %eax #4.12 c1
vpermf32x4 8, %zmm0, %zmm1 #4.12 c5
kmov %eax, %k1 #4.12 c5
vpaddd %zmm0, %zmm1, %zmm3 #4.12 c9
nop #4.12 c13
vpermf32x4 , %zmm3, %zmm2 #4.12 c17
vpaddd %zmm3, %zmm2, %zmm4 #4.12 c21
nop #4.12 c25
vpaddd %zmm4{badc}, %zmm4, %zmm5 #4.12 c29
nop #4.12 c33
vpaddd %zmm5{cdab}, %zmm5, %zmm6 #4.12 c37
nop #4.12 c41
vpackstorelps %zmm6, -8(%rsp){%k1} #4.12 c45
movl -8(%rsp), %eax #4.12 c49
ret #4.12 c53
.align 16,0x90
.cfi_endproc
# LOE
# mark_end;
.type foo,@function
.size foo,.-foo
.data
# -- End foo
.data
.section .note.GNU-stack, ""
// -- Begin DWARF2 SEGMENT .eh_frame
.section .eh_frame,"a",@progbits
.eh_frame_seg:
.align 8
# End
我想你应该能找到自己的出路...
使用 KNC 减少 16 个整数是一个有趣的案例,可以说明它与 AVX512 的不同之处。
_mm512_reduce_add_epi32
内在函数仅受 Intel 编译器支持(当前)。它是 SVML 中那些烦人的许多指令内在函数之一。但我想我理解为什么英特尔在这种情况下实现了这个内在函数,因为 KNC 和 AVX512 的结果非常不同。
对于 AVX512,我会做这样的事情
__m256i hi8 = _mm512_extracti64x4_epi64(a,1);
__m256i lo8 = _mm512_castsi512_si256(a);
__m256i vsum1 = _mm256_add_epi32(hi8,lo8);
然后我会像在 AVX2
中那样进行缩减
__m256i vsum2 = _mm256_hadd_epi32(vsum1,vsum1);
__m256i vsum3 = _mm256_hadd_epi32(vsum2,vsum2);
__m128i hi4 = _mm256_extracti128_si256(vsum3,1);
__m128i lo4 = _mm256_castsi256_si128(vsum3);
__m128i vsum4 = _mm_add_epi32(hi4, lo4);
int sum = _mm_cvtsi128_si32(vsum4);
看看英特尔如何使用 AVX512 实现 _mm512_reduce_add_epi32
会很有趣。
但 KNC 指令集不支持 AVX 或 SSE,因此一切都必须使用 KNC 的完整 512 位向量来完成。英特尔已经创建了 KNC 独有的指令来执行此操作。
查看 Giles answer 中的程序集,我们可以看到它的作用。首先,它使用 KNC 独有的指令将高 256 位置换为低 256 位,如下所示:
vpermf32x4 8, %zmm0, %zmm1
值 238
是以 4 为基数的 3232
。因此 zmm1
就四个 128 位通道而言是 (3,2,3,2)
。
接下来它进行向量求和
vpaddd %zmm0, %zmm1, %zmm3
这给出了四个 128 位通道 (3+3, 2+2, 3+1, 2+0)
然后它排列第二个 128 位通道给出 (3+1, 3+1, 3+1, 3+1)
像这样
vpermf32x4 , %zmm3, %zmm2
其中 85
是以 4 为基数的 1111
。然后将它们相加
vpaddd %zmm3, %zmm2, %zmm4
因此 zmm4
中的低 128 位通道包含四个 128 位通道的总和 (3+2+1+0)
。
此时需要在每个 128 位通道中排列 32 位值。它再次使用了 KNC 的独特功能,允许它同时排列和添加(或者至少符号是唯一的)。
vpaddd %zmm4{badc}, %zmm4, %zmm5
产生(a+b, a+b, c+d, c+d)
和
vpaddd %zmm5{cdab}, %zmm5, %zmm6
产生 (a+b+c+d , a+b+c+d , a+b+c+d, a+b+c+d)
。现在只是提取低 32 位的问题。
这是 AVX512 的替代解决方案,它类似于 KNC 的解决方案
#include <x86intrin.h>
int foo(__m512i a) {
__m512i vsum1 = _mm512_add_epi32(a,_mm512_shuffle_i64x2(a,a, 0xee));
__m512i vsum2 = _mm512_add_epi32(a,_mm512_shuffle_i64x2(vsum1,vsum1, 0x55));
__m512i vsum3 = _mm512_add_epi32(a,_mm512_shuffle_epi32(vsum2, _MM_PERM_BADC));
__m512i vsum4 = _mm512_add_epi32(a,_mm512_shuffle_epi32(vsum3, _MM_PERM_CADB));
return _mm_cvtsi128_si32(_mm512_castsi512_si128(vsum4));
}
与 gcc -O3 -mavx512f
这给出。
vshufi64x2 8, %zmm0, %zmm0, %zmm1
vpaddd %zmm1, %zmm0, %zmm1
vshufi64x2 , %zmm1, %zmm1, %zmm1
vpaddd %zmm1, %zmm0, %zmm1
vpshufd , %zmm1, %zmm1
vpaddd %zmm0, %zmm1, %zmm1
vpshufd 1, %zmm1, %zmm1
vpaddd %zmm0, %zmm1, %zmm0
vmovd %xmm0, %eax
ret
AVX512 使用 vshufi64x2
而不是 vpermf32x4
并且 KNC 将通道内的排列和添加与 {abcd} 符号(例如 vpaddd %zmm4{badc}, %zmm4, %zmm5
)结合起来。这基本上是使用 _mm256_hadd_epi32
.
实现的
我忘了我已经看过这个关于 AVX512 的问题。 Here is another solution.
这里值得一提的是 KNC 的内在函数(未经测试)。
int foo(__m512i a) {
__m512i vsum1 = _mm512_add_epi32(a,_mm512_permute4f128_epi32(a, 0xee));
__m512i vsum2 = _mm512_add_epi32(a,_mm512_permute4f128_epi32(vsum1, 0x55));
__m512i vsum3 = _mm512_add_epi32(a,_mm512_swizzle_epi32(vsum2, _MM_SWIZ_REG_BADC));
__m512i vsum4 = _mm512_add_epi32(a,_mm512_swizzle_epi32(vsum3, _MM_SWIZ_REG_CADB));
int32_t out[2];
_mm512_packstorelo_epi32(out, vsum4);
return out[0];
}
我看不出 KNC _mm512_permute4f128_epi32(a,imm8
) 和 AVX512 _mm512_shuffle_i32x4(a,a,imm8)
.
之间的功能差异
这种情况下的主要区别是 _mm512_shuffle_epi32
生成 vpshufd
而 _mm512_swizzle_epi32
不会。这似乎
是 KNC 优于 AVX512 的优势。
我正在寻找 Xeon Phi 的加减操作的内联汇编操作。我在 intel intrinsic 网站 (link) 上找到了 _mm512_reduce_add_epi32 intrinsic。但是在网站上,他们并没有提到实际的组装操作。
谁能帮我找到Xeon Phi 平台上归约操作的内联汇编?
谢谢
在阅读汇编方面我几乎一无所知,所以我就这样做了:
创建了一个 foo.c 文件,如下所示:
#include "immintrin.h"
int foo(__m512i a) {
return _mm512_reduce_add_epi32(a);
}
我使用 -mmic -S
符合英特尔编译器版本 16.0.1。它给了我以下汇编代码:
# -- Begin foo
.text
# mark_begin;
# Threads 4
.align 16,0x90
.globl foo
# --- foo(__m512i)
foo:
# parameter 1: %zmm0
..B1.1: # Preds ..B1.0 Latency 53
.cfi_startproc
..___tag_value_foo.1:
..L2:
#3.20
movl , %eax #4.12 c1
vpermf32x4 8, %zmm0, %zmm1 #4.12 c5
kmov %eax, %k1 #4.12 c5
vpaddd %zmm0, %zmm1, %zmm3 #4.12 c9
nop #4.12 c13
vpermf32x4 , %zmm3, %zmm2 #4.12 c17
vpaddd %zmm3, %zmm2, %zmm4 #4.12 c21
nop #4.12 c25
vpaddd %zmm4{badc}, %zmm4, %zmm5 #4.12 c29
nop #4.12 c33
vpaddd %zmm5{cdab}, %zmm5, %zmm6 #4.12 c37
nop #4.12 c41
vpackstorelps %zmm6, -8(%rsp){%k1} #4.12 c45
movl -8(%rsp), %eax #4.12 c49
ret #4.12 c53
.align 16,0x90
.cfi_endproc
# LOE
# mark_end;
.type foo,@function
.size foo,.-foo
.data
# -- End foo
.data
.section .note.GNU-stack, ""
// -- Begin DWARF2 SEGMENT .eh_frame
.section .eh_frame,"a",@progbits
.eh_frame_seg:
.align 8
# End
我想你应该能找到自己的出路...
使用 KNC 减少 16 个整数是一个有趣的案例,可以说明它与 AVX512 的不同之处。
_mm512_reduce_add_epi32
内在函数仅受 Intel 编译器支持(当前)。它是 SVML 中那些烦人的许多指令内在函数之一。但我想我理解为什么英特尔在这种情况下实现了这个内在函数,因为 KNC 和 AVX512 的结果非常不同。
对于 AVX512,我会做这样的事情
__m256i hi8 = _mm512_extracti64x4_epi64(a,1);
__m256i lo8 = _mm512_castsi512_si256(a);
__m256i vsum1 = _mm256_add_epi32(hi8,lo8);
然后我会像在 AVX2
中那样进行缩减__m256i vsum2 = _mm256_hadd_epi32(vsum1,vsum1);
__m256i vsum3 = _mm256_hadd_epi32(vsum2,vsum2);
__m128i hi4 = _mm256_extracti128_si256(vsum3,1);
__m128i lo4 = _mm256_castsi256_si128(vsum3);
__m128i vsum4 = _mm_add_epi32(hi4, lo4);
int sum = _mm_cvtsi128_si32(vsum4);
看看英特尔如何使用 AVX512 实现 _mm512_reduce_add_epi32
会很有趣。
但 KNC 指令集不支持 AVX 或 SSE,因此一切都必须使用 KNC 的完整 512 位向量来完成。英特尔已经创建了 KNC 独有的指令来执行此操作。
查看 Giles answer 中的程序集,我们可以看到它的作用。首先,它使用 KNC 独有的指令将高 256 位置换为低 256 位,如下所示:
vpermf32x4 8, %zmm0, %zmm1
值 238
是以 4 为基数的 3232
。因此 zmm1
就四个 128 位通道而言是 (3,2,3,2)
。
接下来它进行向量求和
vpaddd %zmm0, %zmm1, %zmm3
这给出了四个 128 位通道 (3+3, 2+2, 3+1, 2+0)
然后它排列第二个 128 位通道给出 (3+1, 3+1, 3+1, 3+1)
像这样
vpermf32x4 , %zmm3, %zmm2
其中 85
是以 4 为基数的 1111
。然后将它们相加
vpaddd %zmm3, %zmm2, %zmm4
因此 zmm4
中的低 128 位通道包含四个 128 位通道的总和 (3+2+1+0)
。
此时需要在每个 128 位通道中排列 32 位值。它再次使用了 KNC 的独特功能,允许它同时排列和添加(或者至少符号是唯一的)。
vpaddd %zmm4{badc}, %zmm4, %zmm5
产生(a+b, a+b, c+d, c+d)
和
vpaddd %zmm5{cdab}, %zmm5, %zmm6
产生 (a+b+c+d , a+b+c+d , a+b+c+d, a+b+c+d)
。现在只是提取低 32 位的问题。
这是 AVX512 的替代解决方案,它类似于 KNC 的解决方案
#include <x86intrin.h>
int foo(__m512i a) {
__m512i vsum1 = _mm512_add_epi32(a,_mm512_shuffle_i64x2(a,a, 0xee));
__m512i vsum2 = _mm512_add_epi32(a,_mm512_shuffle_i64x2(vsum1,vsum1, 0x55));
__m512i vsum3 = _mm512_add_epi32(a,_mm512_shuffle_epi32(vsum2, _MM_PERM_BADC));
__m512i vsum4 = _mm512_add_epi32(a,_mm512_shuffle_epi32(vsum3, _MM_PERM_CADB));
return _mm_cvtsi128_si32(_mm512_castsi512_si128(vsum4));
}
与 gcc -O3 -mavx512f
这给出。
vshufi64x2 8, %zmm0, %zmm0, %zmm1
vpaddd %zmm1, %zmm0, %zmm1
vshufi64x2 , %zmm1, %zmm1, %zmm1
vpaddd %zmm1, %zmm0, %zmm1
vpshufd , %zmm1, %zmm1
vpaddd %zmm0, %zmm1, %zmm1
vpshufd 1, %zmm1, %zmm1
vpaddd %zmm0, %zmm1, %zmm0
vmovd %xmm0, %eax
ret
AVX512 使用 vshufi64x2
而不是 vpermf32x4
并且 KNC 将通道内的排列和添加与 {abcd} 符号(例如 vpaddd %zmm4{badc}, %zmm4, %zmm5
)结合起来。这基本上是使用 _mm256_hadd_epi32
.
我忘了我已经看过这个关于 AVX512 的问题。 Here is another solution.
这里值得一提的是 KNC 的内在函数(未经测试)。
int foo(__m512i a) {
__m512i vsum1 = _mm512_add_epi32(a,_mm512_permute4f128_epi32(a, 0xee));
__m512i vsum2 = _mm512_add_epi32(a,_mm512_permute4f128_epi32(vsum1, 0x55));
__m512i vsum3 = _mm512_add_epi32(a,_mm512_swizzle_epi32(vsum2, _MM_SWIZ_REG_BADC));
__m512i vsum4 = _mm512_add_epi32(a,_mm512_swizzle_epi32(vsum3, _MM_SWIZ_REG_CADB));
int32_t out[2];
_mm512_packstorelo_epi32(out, vsum4);
return out[0];
}
我看不出 KNC _mm512_permute4f128_epi32(a,imm8
) 和 AVX512 _mm512_shuffle_i32x4(a,a,imm8)
.
这种情况下的主要区别是 _mm512_shuffle_epi32
生成 vpshufd
而 _mm512_swizzle_epi32
不会。这似乎
是 KNC 优于 AVX512 的优势。