Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/152.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
C++ 如何将X字节或位从_m128i复制到标准内存中_C++_Sse_Simd_Intrinsics_Sse2 - Fatal编程技术网

C++ 如何将X字节或位从_m128i复制到标准内存中

C++ 如何将X字节或位从_m128i复制到标准内存中,c++,sse,simd,intrinsics,sse2,C++,Sse,Simd,Intrinsics,Sse2,我有一个循环,通过\u mm\u add\u epi16()将两个数组中的int16添加到一起。有一个小数组和一个大数组,结果被写回大数组。 如果小阵列到达其末端,内部可能会从中获得小于8倍的int16s(128位)-如果我不想要其所有128位,如何将\u mm\u add\u epi16()的结果存储回标准内存int16\t*?将数组填充为二的幂不是一个选项。例如: int16_t* smallArray; int16_t* largeArray; __m128i inSmallArray =

我有一个循环,通过
\u mm\u add\u epi16()
将两个数组中的int16添加到一起。有一个小数组和一个大数组,结果被写回大数组。 如果小阵列到达其末端,内部可能会从中获得小于8倍的int16s(128位)-如果我不想要其所有128位,如何将
\u mm\u add\u epi16()
的结果存储回标准内存int16\t*?将数组填充为二的幂不是一个选项。例如:

int16_t* smallArray;
int16_t* largeArray;
__m128i inSmallArray = _mm_load_si128((__m128i*)smallArray);
__m128i* pInLargeArray = (__m128i*)largeArray;
__m128i inLargeArray = _mm_load_si128(pInLargeArray);
inLargeArray = _mm_add_epi16(inLargeArray, inSmallArray);
_mm_store_si128(pInLargeArray, inLargeArray);

我的猜测是,我需要以某种方式将
\u mm_store_si128()
替换为一个“屏蔽”存储。

有一个
\u mm_maskmoveu_si128
内在,它转换为
maskmovdqu
(在SSE中)或
vmaskmovdqu
(在AVX中)

AVX-512添加了掩码存储,您可以使用带有适当掩码的
vmovdqu8
/
vmovdqu16
来存储8位或16位元素

void store_n(__m128i mm, unsigned int n, void* storage)
{
    assert(n < 16u);
    _mm_mask_storeu_epi8(storage, static_cast< __mmask16 >((1u << n) - 1u), mm);
}
void存储区(m128i mm,无符号整数n,void*存储区)
{
断言(n<16u);
_毫米掩模存储epi8(存储、静态投射);
如果(n>=8u)
{
_mm\u storel\u epi64(重新解释铸件<\u m128i*>(p),mm);
mm=_mm_unpachi_epi64(mm,mm);//将高8字节移到低8字节
n-=8u;
p+=8;
}
如果(n>=4u)
{
标准:uint32_t数据=_mm_cvtsi128_si32(mm);
std::memcpy(p,&data,sizeof(data));//通常生成movd
mm=_mm_srli_si128(mm,4);
n-=4u;
p+=4;
}
如果(n>=2u)
{
std::uint16_t data=_mm_extract_epi16(mm,0);//或_mm_cvtsi128_si32
标准::memcpy(p,&data,sizeof(data));
mm=_mm_srli_si128(mm,2);
n-=2u;
p+=2;
}
如果(n>0u)
{
标准:uint32_t数据=_mm_cvtsi128_si32(mm);
*p=静态铸件(数据);
}
}

有一个
\u mm\u maskmoveu\u si128
固有,它转换为
maskmovdqu
(在SSE中)或
vmaskmovdqu
(在AVX中)

AVX-512添加了掩码存储,您可以使用带有适当掩码的
vmovdqu8
/
vmovdqu16
来存储8位或16位元素

void store_n(__m128i mm, unsigned int n, void* storage)
{
    assert(n < 16u);
    _mm_mask_storeu_epi8(storage, static_cast< __mmask16 >((1u << n) - 1u), mm);
}
void存储区(m128i mm,无符号整数n,void*存储区)
{
断言(n<16u);
_毫米掩模存储epi8(存储、静态投射);
如果(n>=8u)
{
_mm\u storel\u epi64(重新解释铸件<\u m128i*>(p),mm);
mm=_mm_unpachi_epi64(mm,mm);//将高8字节移到低8字节
n-=8u;
p+=8;
}
如果(n>=4u)
{
标准:uint32_t数据=_mm_cvtsi128_si32(mm);
std::memcpy(p,&data,sizeof(data));//通常生成movd
mm=_mm_srli_si128(mm,4);
n-=4u;
p+=4;
}
如果(n>=2u)
{
std::uint16_t data=_mm_extract_epi16(mm,0);//或_mm_cvtsi128_si32
标准::memcpy(p,&data,sizeof(data));
mm=_mm_srli_si128(mm,2);
n-=2u;
p+=2;
}
如果(n>0u)
{
标准:uint32_t数据=_mm_cvtsi128_si32(mm);
*p=静态铸件(数据);
}
}

您可以直接寻址它的元素。这是因为
\uuum128i
是一个并集。宽度是任何代码路径上的编译时常量,还是易于分支?有类似
movq
movd
的指令可以存储8或4个字节。或者,如果smallArray的长度至少为16,您可以执行未对齐的最终向量或者,如果您安排循环将结果保留在变量中,以便在下一次迭代中存储(或者在为可能重叠的未对齐最终向量加载数据后,在离开循环时)@PeterCordes宽度是在运行时确定的,我需要16位的粒度。我可以保证smallArray至少有16个字节-你能详细说明未对齐的最终向量的含义吗?谢谢!我的意思是你可以直接处理它的元素。这是因为
\um128i
是一个并集。宽度是编译时常量吗ant在任何代码路径上,或易于分支?有一些指令,如
movq
movd
,可以存储8或4个字节。或者,如果smallArray的长度至少为16,则可以执行未对齐的最终向量,前提是安排循环将结果保留在变量中,以便在下一次迭代中存储(或在为可能重叠的未对齐最终向量加载数据后离开循环时)@PeterCordes宽度是在运行时确定的,我需要16位的粒度。我可以保证smallArray至少有16个字节-你能详细说明未对齐的最终向量的含义吗?谢谢!我的意思是我认为
vmaskmovdqu
具有相同的NT语义;我认为只有AVX
vmaskmovps
和相关的指令具有4字节或8字节粒度的指令进行普通掩码存储(直到AVX512BW
vmaskmovdqu8
)@PeterCordes Intel SDM仅记录了一个非暂时性提示,用于
maskmovdqu
,而不用于
vmaskmovdqu
。您是否有一个参考,其中它也适用于
vmaskmovdqu
?@PeterCordes我在AMD APM中找到了
maskmovdqu
/
vmaskmovdqu
的描述,并且其中的描述确实表明指令有一个非暂时性的提示。我已经更新了我的答案。谢谢。PS:我找不到
vmaskmovdqu8
的描述,所以我不能对它说什么。那是一个大脑屁,AVX512有正常存储的掩蔽,这就是为什么所有向量
mov
指令都有一个元素大小作为助记符的一部分。我的意思是
vmovdqu8[rdi]{k1},xmm0
Re:Intel的文档:VEX编码是否包含NT提示是不明确的,但如果我们使用“MASKMOVDQU”,我认为它们的措辞与现实相符表示对同一条指令的任何一种编码。我认为,当VEX和旧版SSE工作相同时,英特尔文档只讨论指令的基名称是正常的
void store_n(__m128i mm, unsigned int n, void* storage)
{
    assert(n < 16u);
    _mm_mask_storeu_epi8(storage, static_cast< __mmask16 >((1u << n) - 1u), mm);
}
void store_n(__m128i mm, unsigned int n, void* storage)
{
    assert(n < 16u);

    unsigned char* p = static_cast< unsigned char* >(storage);
    if (n >= 8u)
    {
        _mm_storel_epi64(reinterpret_cast< __m128i* >(p), mm);
        mm = _mm_unpackhi_epi64(mm, mm); // move high 8 bytes to the low 8 bytes
        n -= 8u;
        p += 8;
    }

    if (n >= 4u)
    {
        std::uint32_t data = _mm_cvtsi128_si32(mm);
        std::memcpy(p, &data, sizeof(data)); // typically generates movd
        mm = _mm_srli_si128(mm, 4);
        n -= 4u;
        p += 4;
    }

    if (n >= 2u)
    {
        std::uint16_t data = _mm_extract_epi16(mm, 0); // or _mm_cvtsi128_si32
        std::memcpy(p, &data, sizeof(data));
        mm = _mm_srli_si128(mm, 2);
        n -= 2u;
        p += 2;
    }

    if (n > 0u)
    {
        std::uint32_t data = _mm_cvtsi128_si32(mm);
        *p = static_cast< std::uint8_t >(data);
    }
}