Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/performance/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Performance 无符号32位整数的水平最小值和SSE位置_Performance_Algorithm_Optimization_Sse_Simd - Fatal编程技术网

Performance 无符号32位整数的水平最小值和SSE位置

Performance 无符号32位整数的水平最小值和SSE位置,performance,algorithm,optimization,sse,simd,Performance,Algorithm,Optimization,Sse,Simd,我正在寻找一种方法来查找无符号32位整数的最小值及其在SSE中的位置(类似于_mm_minpos_epu16)。我知道我可以通过一系列的_mm_min_epu32和洗牌/换位来找到最小值,但这并不能让我得到这个位置 __m128i mask1 = _mm_setr_epi8(0x0,0x1,0x4,0x5, 0x8,0x9,0xc,0xd, 0x0,0x1,0x4,0x5, 0x8,0x9,0xc,0xd); __m128i mask2 = _mm_setr_epi8(0x2,0x3,0x6,

我正在寻找一种方法来查找无符号32位整数的最小值及其在SSE中的位置(类似于_mm_minpos_epu16)。我知道我可以通过一系列的_mm_min_epu32和洗牌/换位来找到最小值,但这并不能让我得到这个位置

__m128i mask1 = _mm_setr_epi8(0x0,0x1,0x4,0x5, 0x8,0x9,0xc,0xd, 0x0,0x1,0x4,0x5,  0x8,0x9,0xc,0xd);
__m128i mask2 = _mm_setr_epi8(0x2,0x3,0x6,0x7, 0xa,0xb,0xe,0xf, 0x2,0x3,0x6,0x7,  0xa,0xb,0xe,0xf);
__m128i mask3 = _mm_set1_epi32(0x01000100);

有人有什么很酷的方法吗?

可能有一种更聪明的方法,但现在有一种蛮力方法:

#包括
#包括//SSE4.1
内部主(空)
{
__m128i v=_mm_setr_epi32(42,1,43,2);
printf(“v=%vlu\n”,v);
__m128i-vmin=v;
vmin=_-mm_-min_-epu32(vmin,_-mm_-aligner_-epi8(vmin,vmin,4));
vmin=_-mm_-min_-epu32(vmin,_-mm_-aligner_-epi8(vmin,vmin,8));
//在vmin的所有元素中获取最小值
printf(“vmin=%vlu\n”,vmin);
__m128i vmask=_mm_cmpeq_epi32(v,vmin);//将掩码中的最小元素设置为-1,
//所有其他设置为0[1]
printf(“vmask=%vld\n”,vmask);
int16_t mask=_mm_movemask_epi8(vmask);//将mask获取为标量[2]
printf(“掩码=%#x\n”,掩码);
int pos=\uuu内置ctz(掩码)>>2;//将标量掩码转换为索引[3]
printf(“pos=%d\n”,pos);
返回0;
}
如果可以使用设置在最小元素位置的遮罩,则可以在[1]处停止,否则继续到[3]获取(最低有效)最小元素的索引


还要注意的是,
\uuuu builtin\uctz
是一个特定于gcc的内在特性(尽管在其他与gcc兼容的编译器中也可以找到它)。如果您使用的是MSVC,则需要使用等效的Microsoft内部版本(
\u BitScanForward
)。

通常,如果将水平运算符用于SIMD,则表明SIMD没有得到最佳使用。然而,在循环结束时,水平操作是可以的,在这种情况下,我只需要这样做

int result[4] __attribute__((aligned(16)));
_mm_store_si128((__m128i *) result, v);
for(int i=0; i<4; i++) if(result[i]<min) { min = result[i]; index = i; }
vpos中的第二个16位字包含位置的两倍

__m128i mask1 = _mm_setr_epi8(0x0,0x1,0x4,0x5, 0x8,0x9,0xc,0xd, 0x0,0x1,0x4,0x5,  0x8,0x9,0xc,0xd);
__m128i mask2 = _mm_setr_epi8(0x2,0x3,0x6,0x7, 0xa,0xb,0xe,0xf, 0x2,0x3,0x6,0x7,  0xa,0xb,0xe,0xf);
__m128i mask3 = _mm_set1_epi32(0x01000100);
这里是另一个使用
\u mm\u minpos\u epu16
的变体。它首先找到最小的上16位,然后屏蔽不在最小16位的值(通过将它们全部设置为高),然后找到下16位的最小值以及位置

__m128i mask1 = _mm_setr_epi8(0x0,0x1,0x4,0x5, 0x8,0x9,0xc,0xd, 0x0,0x1,0x4,0x5,  0x8,0x9,0xc,0xd);
__m128i mask2 = _mm_setr_epi8(0x2,0x3,0x6,0x7, 0xa,0xb,0xe,0xf, 0x2,0x3,0x6,0x7,  0xa,0xb,0xe,0xf);
__m128i mask3 = _mm_set1_epi32(0x01000100);
掩码是常量,因此可以在编译时或循环外部计算它们

__m128i lo = _mm_shuffle_epi8(v,mask1);            //lower 16-bits
__m128i hi = _mm_shuffle_epi8(v,mask2);            //upper 16-bits
__m128i t1 = _mm_minpos_epu16(hi);                 //upper 16-bits min
__m128i t2 = _mm_shuffle_epi8(t1, mask3);          //broadcast upper min
__m128i t3 = _mm_cmpeq_epi32(t2,hi);               //select equal
__m128i t4 = _mm_xor_si128(t3, _mm_set1_epi32(-1));//invert
__m128i t5 = _mm_or_si128(lo,t4);                   
__m128i t6 = _mm_minpos_epu16(t5);                 //lower 16-bits hi and position

最小值的上16位在
t1
的前16位,最小值的下16位在
t6
的前16位。位置位于
t6的第二个16位

您希望该位置作为索引值(如
\u mm\u minpos\u epu16
所做的)还是掩码可以(最小元素设置为-1,所有其他元素设置为0)?请问您为什么要这样做?我无法想象你为什么要在循环中每次迭代都这样做。为什么这很关键?我想如果我知道为什么英特尔首先创建了
\u mm\u minpos\u epu16
,那会有所帮助。你抢先给了我一个答案:-)我可能有不同的方法使用
minpos
,但我不确定。最有效的解决方案可能是将结果存储到一个数组中,并在四个元素上循环。嘿-你必须在早上早些时候使用StackOverflow!;-)我认为最好的解决方案取决于结果的首选格式——如果向量最小值和掩码足够,那么使用上述方法只需要5条指令,但如果需要实际索引,那么我怀疑可能有更好的方法。你能想到一个关键的情况吗?为什么
\u mm\u minpos\u epu16
甚至存在?我认为它可能用于MPEG之类的东西,可能用于运动补偿,但视频不是我真正的领域。是的,我需要实际的索引值。很好的主意是反转掩码,然后使用
\u mm\u minpos\u epu16
来获得2倍的索引@保罗,谢谢。是啊,可惜SSE没有
=
表示未签名。XOP和AVX512都有。很抱歉提到这一点,但这段伟大的代码中有一个打印错误!它不应该是uum128i t3=mm\ucmpeq\uepi32(t2,hi);但是(t2,hi)t3=(mm)cmpeq(16);;除此之外,它就像一个魅力,谢谢!顺便说一句,它对于AVX的使用非常有用-它正好包含8个32位,所以在相应的洗牌之后,我们得到8个上半部和下半部用于处理。