使用 C 内在函数从一个 ZMM 寄存器中提取四个 XMM 寄存器,反之亦然

问题描述 投票:0回答:2

有一个一般性问题在 SSE 和 AVX512 寄存器之间移动数据 但这个问题是关于 C 内在函数的。

有一个intrinsic可以把两个xmm寄存器插入一个ymm:__m256 _mm256_set_m128(__m128 hi, __m128 lo)对应vinsertf128指令,但是没有类似的intrinsic可以把两个ymm寄存器插入一个zmm寄存器,例如假设的 __m512 _mm512_set_m256 (__m256 hi, __m256 lo)。使用汇编指令,当我设置 ymm 寄存器(即通过 vinsertf128)时,该操作还明确清除相应 zmm 寄存器的高 256 位,但是 C 将 ymm 类型转换为 zmm 的类似内在是什么? vinsertf32x8 指令的所有内在函数 已经需要一个 512 位 zmm 寄存器输入,而 _mm256_set_m128 只返回一个 256 位 ymm 寄存器。

从一个 zmm 寄存器中提取四个 xmm 寄存器的 C 内在函数是什么,反之亦然?我无法使用定义的寄存器创建汇编函数,我需要指令与任何可用的寄存器内联。

assembly x86-64 intel intrinsics avx512
2个回答
0
投票

提取,使用

/* floating point domain */
__m128 _mm512_extractf32x4_ps (__m512 a, int imm8);
__m256 _mm512_extractf32x8_ps (__m512 a, int imm8);

/* integer domain */
__m128i _mm512_extracti64x2_epi64 (__m512i a, int imm8);
__m256i _mm512_extracti64x4_epi64 (__m512i a, int imm8);

要组装,要么遍历内存(例如,存储到 4

__m128
的数组中,然后从中加载),要么使用一系列插入指令。请注意,插入是跨通道操作,因此非常慢。通过内存可能会更快,你应该测量它。

/* floating point domain */
__m512 _mm512_insertf32x4 (__m512 a, __m128 b, int imm8);
__m512 _mm512_insertf32x8 (__m512 a, __m256 b, int imm8);

/* integer domain */
__m256i _mm256_inserti64x2 (__m256i a, __m128i b, int imm8);
__m512i _mm512_inserti64x4 (__m512i a, __m256i b, int imm8);

0
投票

我们可以使用以下内在函数进行转换,它们不会产生任何指令:

_mm256_castps128_ps256    __m128  →  __m256
_mm256_castps256_ps128    __m256  →  __m128

_mm512_castps256_ps512    __m256  →  __m512
_mm512_castps512_ps256    __m512  →  __m256 

不同类型有相似的内在函数:

_mm256_castsi256_si128   __m256i  →  __m128i
_mm256_castsi128_si256   __m128i  →  __m256i

此外,如果我们需要在相同大小的各种类型之间进行转换,我们可以使用以下类型转换内在函数:

_mm256_castps_si256    __m256   →  __m256i
_mm256_castsi256_ps    __m256i  →  __m256

所有演员说明都列在https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#ig_expand=6371&cats=Cast

因此,将4个xmm寄存器组合成1个zmm寄存器的代码如下:

__m512 m512_combine_m128x4(__m128 x4, __m128 x3, __m128 x2, __m128 x1) 
{
    const __m256 h = _mm256_set_m128(x4, x3);
    const __m256 l = _mm256_set_m128(x2, x1);
    return _mm512_insertf32x8(_mm512_castps256_ps512(l), h, 1);
}

翻译成两条vinsertf128指令和一条vinsertf32x8指令

因此,一旦我们使用 cast intrinsics,这就太容易了。 split 的代码是相似的,使用上面提到的转换。

© www.soinside.com 2019 - 2024. All rights reserved.