有没有办法_mm_slli_si128
在AVX2中重建指令以将__mm256i
寄存器移位x个字节?
的_mm256_slli_si256
似乎只是执行两个_mm_slli_si128
上的[127:0]和A [255:128].
左移应该__m256i
是这样的:
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, ..., 32] -> [2, 3, 4, 5, 6, 7, 8, 9, ..., 0]
Run Code Online (Sandbox Code Playgroud)
我在线程中看到可以创建一个_mm256_permutevar8x32_ps
32位的移位.但我需要一个更通用的解决方案来换班x字节.有人已经解决了这个问题吗?
gcc 5.3 with -O3 -mavx -mtune=haswell
for x86-64使得代码处理可能错位的代码变得非常笨重,例如:
// convenient simple example of compiler input
// I'm not actually interested in this for any real program
void floatmul(float *a) {
for (int i=0; i<1024 ; i++)
a[i] *= 2;
}
Run Code Online (Sandbox Code Playgroud)
clang使用未对齐的加载/存储指令,但是gcc执行标量intro/outro和对齐的向量循环:它剥离了第一个最多7个未对齐的迭代,将其完全展开为一个序列
vmovss xmm0, DWORD PTR [rdi]
vaddss xmm0, xmm0, xmm0 ; multiply by two
vmovss DWORD PTR [rdi], xmm0
cmp eax, 1
je .L13
vmovss xmm0, DWORD PTR [rdi+4]
vaddss xmm0, xmm0, xmm0
vmovss …
Run Code Online (Sandbox Code Playgroud) 我已经实现了内联函数(_mm256_concat_epi16
).它连接两个包含16位值的AVX2向量.它适用于前8个数字.如果我想将它用于向量的其余部分,我应该更改实现.但是在我的主程序中使用单个内联函数会更好.
问题是:有没有比我的更好的解决方案或任何建议使这个内联函数更通用,它适用于16个值而不是我的解决方案适用于8个值?我的解决方案连接2个向量,但只解决了16个可能状态的8个状态.
**编辑*我对这个问题的当前解决方案是使用未对齐的加载函数,它可以从内存中的任何部分读取.但是,当数据在寄存器中准备就绪时,重用它可能会更好.但是,它可能会导致端口5出现瓶颈,导致混乱,置换等.但吞吐量可能已足够(尚未测试).
#include <stdio.h>
#include <x86intrin.h>
inline _mm256_print_epi16(__m256i a, char* name){
short temp[16], i;
_mm256_storeu_si256((__m256i *) &temp[0], a);
for(i=0; i<16; i++)
printf("%s[%d]=%4d , ",name,i+1,temp[i]);
printf("\n");
}
inline __m256i _mm256_concat_epi16(__m256i a, __m256i b, const int indx){
return _mm256_alignr_epi8(_mm256_permute2x128_si256(a,b,0x21),a,indx*2);
}
int main()
{
__m256i a = _mm256_setr_epi16(101,102,103,104,105,106,107,108,109,1010,1011,1012,1013,1014,1015,1016);_mm256_print_epi16(a, "a");
__m256i b = _mm256_setr_epi16(201,202,203,204,205,206,207,208,209,2010,2011,2012,2013,2014,2015,2016);_mm256_print_epi16(b, "b");
_mm256_print_epi16(_mm256_concat_epi16(a,b,8), "c");//numbers: 0-8
return 0;
}
Run Code Online (Sandbox Code Playgroud)
出局是:
// icc -march=native -O3 -D _GNU_SOURCE -o "concat" "concat.c"
[fedora@localhost concatination]$ "./concat"
a[1]= 101 …
Run Code Online (Sandbox Code Playgroud) SHLD/SHRD指令是用于实现多精度移位的汇编指令.
请考虑以下问题:
uint64_t array[4] = {/*something*/};
left_shift(array, 172);
right_shift(array, 172);
Run Code Online (Sandbox Code Playgroud)
什么是实行最有效的方法left_shift
和right_shift
,经营4个64位无符号整数数组上的转变,就好像它是一个巨大的256位无符号整数两种功能?
最有效的方法是使用SHLD/SHRD指令,还是有更好的(如SIMD版本)现代架构指令?
我试图找到一种更有效的方法来“旋转”或将 avx _m256 向量中的 32 位浮点值向右或向左移动一个位置。
这样:
a7、a6、a5、a4、a3、a2、a1、a0
变成
0、a7、a6、a5、a4、a3、a2、a1
(我不介意在我更换单元格时数据是否丢失。)
我已经看过这个线程:Emulating shifts on 32 bytes with AVX 但我真的不明白发生了什么,它也没有解释 _MM_SHUFFLE(0, 0, 3, 0) 的作用一个输入参数。
我正在尝试优化此代码:
_mm256_store_ps(temp, array[POS(ii, jj)]);
_mm256_store_ps(left, array[POS(ii, jj-1)]);
tmp_array[POS(ii, jj)] = _mm256_set_ps(left[0], temp[7], temp[6], temp[5], temp[4], temp[3], temp[2], temp[1]);
Run Code Online (Sandbox Code Playgroud)
我知道一旦轮班到位,我可以使用插入来替换剩余的单元格。我觉得这会比解压到 float[8] 数组并重建更有效。
-- 我还希望能够左右移动,因为我需要在其他地方执行类似的操作。
任何帮助是极大的赞赏!谢谢!
根据这个答案,我创建了以下测试程序:
#include <iso646.h>
#include <immintrin.h>
#include <stdio.h>
#define SHIFT_LEFT( N ) \
\
inline __m256i shift_left_##N ( __m256i A ) { \
\
if ( N == 0 ) return A; \
else if ( N < 16 ) return _mm256_alignr_epi8 ( A, _mm256_permute2x128_si256 ( A, A, _MM_SHUFFLE ( 0, 0, 2, 0 ) ), ( uint8_t ) ( 16 - N ) ); \
else if ( N == 16 ) return _mm256_permute2x128_si256 ( A, A, _MM_SHUFFLE …
Run Code Online (Sandbox Code Playgroud) 我需要按照下面的模式加载并重新排列12个字节到16(或24到32):
ABC DEF GHI JKL
Run Code Online (Sandbox Code Playgroud)
变
ABBC DEEF GHHI JKKL
Run Code Online (Sandbox Code Playgroud)
您能否建议使用SSE(2)和/或AVX(2)指令实现此目的的有效方法?
这需要重复执行,因此允许预先存储的掩码或常量.