问题描述
auto mask_sse = _mm_cmplt_ps(a,b);
auto mask_avx = _mm_cmp_ps(a,b,17);
在某些情况下,当将旧的 avx 代码与新的 avx512 代码混合时,我想将这些旧样式的掩码转换为新的 avx512 __mmask4
或 __mmask8
类型。
我试过了:
auto mask_avx512 = _mm_cmp_ps_mask(sse_mask,_mm_setzero_ps(),25/*nge unordered quiet*/);
它似乎适用于普通的旧比较输出,但我认为它不能正确捕获可以与 sse4.1 _mm_blendv_ps
一起使用的正 NAN。
还有一个很好的旧 _mm_movemask_ps
但看起来它把掩码一直放在通用寄存器中,我需要用 _cvtu32_mask8
将它链接起来才能将它拉回专用掩码寄存器之一。
是否有一种更简洁的方法可以将旧式掩码中的符号位直接拉到 k 个寄存器之一中?
示例代码:
这是一个示例程序,它按照我上面提到的第一种方式进行掩码转换
#include "x86intrin.h"
#include <cassert>
#include <cstdio>
int main()
{
auto a = _mm_set_ps(-1,1,2);
auto c = _mm_set_ps(3,4,5,6);
auto sse_mask = _mm_cmplt_ps(a,_mm_setzero_ps());
auto avx512_mask = _mm_cmp_ps_mask(sse_mask,25);
alignas(16) float v1[4];
alignas(16) float v2[4];
_mm_store_ps(v1,_mm_blendv_ps(a,c,sse_mask));
_mm_store_ps(v2,_mm_mask_blend_ps(avx512_mask,a,c));
assert(v1[0] == v2[0]);
assert(v1[1] == v2[1]);
assert(v1[2] == v2[2]);
assert(v1[3] == v2[3]);
return 0;
}
解决方法
首先使用 AVX-512 比较内在来获得 AVX-512 掩码(如 class Player_sprite_Health(pygame.sprite.Sprite):
def __init__(self):
self.image = pygame.image.load("images/HUD/hud_heartFull.png")
self.rect = self.rect = self.image.get_rect(topleft = (35,10))
def healthDeleted(self):
''' Upon collision with an enemy object
this function will be called
It's purpose is to remove health
'''
);除非编译器为您优化了这种低效率,否则这将比比较向量然后转换它的效率要高得多。 (考虑使用像 Agner Fog's VCL 这样的包装库来尝试抽象出差异。VCL 许可证最近从 GPL 更改为 Apache。)
但是如果您真的需要这个(例如,作为您完成优化之前的权宜之计),您不需要 FP 比较。 C 中的 _mm_cmp_ps_mask
产生 _mm_cmp_ps
结果,但它不是真正浮点数的向量1。它是全一位/全零位。您只需要这些位,因此您正在寻找与 __m128
等效的 AVX-512,但要查找 vmovmskps
寄存器而不是 GP 整数。即 VPMOVD2M k,x/y/zmm
用于 32 位源元素。
k
https://uops.info/ 现在已关闭,否则我会将 VPMOVD2M 与 VCMPPS 的延迟和执行端口检查为掩码(对于 UNORD 谓词)与 VFPCLASSPS。
脚注 1:您可以将 AVX-512 __m128 cmpvec = _mm_cmplt_ps(v,_mm_setzero_ps() );
__mmask8 cmpmask = _mm_movepi32_mask( _mm_castps_si128(cmpvec) ); // <----
// equivalent to comparing into a mask in the first place:
__mmask8 cmpmask = _mm_cmplt_ps_mask(v,_mm_setzero_ps(),_CMP_LT_OQ);
// equivalent to (if I got this right)
__mmask8 cmpmask = _mm_fpclass_ps_mask(v,0x40 | 0x10); // negative | negative_inf
用于掩码,或者甚至与 UNORD 之类的 vfpclassps
谓词进行比较,以检测或不检测 NAN。但我认为这些比较慢。
我需要用 vcmpps
将其链接起来,以将其拉回专用掩码寄存器之一。
编译器目前做事的方式,_cvtu32_mask8
只是 __mmask8
的 typedef,而 unsigned char
是 __mmask16
。无论是好是坏,它们都可以在没有内在函数的情况下自由转换。但是在 asm 中,需要 unsigned short
指令才能将数据从 GP reg 获取到 k 掩码 reg,并且该指令只能在当前 CPU 的端口 5 上运行。