intrinsics 相关问题

在编译语言中使用内在函数来使用语言范围之外的特定CPU指令。

为什么_mm256_unpacklo“跳”一个双词,在文档中在哪里说?

#include 我发现_mm256_unpacklo_epi32指令有点有趣,并且无法真正将其与文档相关联。 指令执行以下操作: #include <immintrin.h> #include <iostream> int main() { __m256i a = _mm256_set_epi32(8, 7, 6, 5, 4, 3, 2, 1); __m256i b = _mm256_set_epi32(16, 15, 14, 13, 12, 11, 10, 9); __m256i c = _mm256_unpacklo_epi32(a, b); int* values = (int*)&c; for (size_t i = 0; i < 8 - 1; i++) { std::cout << values[i] << ", "; } std::cout << values[7] << std::endl; } 输出为: 1, 9, 2, 10, 5, 13, 6, 14 对我来说,它似乎是两个源值中的第二低单词“跳”。 这样做的原因是什么?是否有一条指令将源向量的较低128位向量交织在一起?这种行为对我似乎并不有用。 我也不能与文档进行调和:https://www.intel.com/content/www/us/en/en/docs/cpp-compiler/developer-guide-guide-guide-guide-guide-guide-2021-10/mmm256-unpacklo--unpacklo-- EPI8-16-32-64.HTML。在哪里说第二个最低的双字被忽略了? 您链接的文档是如此短,如果您还不知道“高级数据元素被忽略了什么”,则没有用。 不是输入的前128位。 SSE SHUFFLES的AVX2版本是两个车道中的两个128位散装。没有数据在128位边界上移动。 即它们是“车道上”的散装,例如avx1__m256i。 vpermilps读取每个128位输入的低64位。 https://www.intel.com/content/www/us/en/en/docs/intrinsics-guide/index.html#techs=mmx,sse_all,sse_all,每128位的64位资料来源: vpunpackldq AVX2具有一些车道交叉的散装,例如DEFINE INTERLEAVE_DWORDS(src1[127:0], src2[127:0]) { dst[31:0] := src1[31:0] dst[63:32] := src2[31:0] dst[95:64] := src1[63:32] dst[127:96] := src2[63:32] RETURN dst[127:0] } dst[127:0] := INTERLEAVE_DWORDS(a[127:0], b[127:0]) dst[255:128] := INTERLEAVE_DWORDS(a[255:128], b[255:128]) dst[MAX:256] := 0 (一个矢量内的dwords)和vpermd(2输入128位粒度,即时控制),但没有一个粒度小于128-的2输入的人少量。 为此,您需要AVX-512vperm2i128(带有shuffle-Control载体)。 指令具有相同的限制,因此,如果您要打开零包装 有时,您实际上并不需要在向量中以特定顺序的数据,例如如果您要稍后再洗牌。 然后,通过零奇数/偶数为零,或者对于2个将奇数元素混合/偶数元素混合的向量可以以可用的方式混合数据。 或者只是打开lo / hi-确实以不同的顺序将所有元素都变成向量。 如果您确实需要从中期望的结果,则可能需要128位的lo/hi和vpermt2d::pack这是一个结果,这是一个结果,所以很烂。 当然,如果需要2个包括您所有输入的结果的向量,则使用256位拆包和vinserti128将拆卸输出的高2车道结合在一起,因此4个总散装(unvackhi/lo,vinserti128,vperm2i128) )获取 __m256i a, b; __m128i lo = _mm_unpacklo_epi32(_mm256_castsi256_si128(a), _mm256_castsi256_si128(b)); __m128i hi = _mm_unpackhi_epi32(_mm256_castsi256_si128(a), _mm256_castsi256_si128(b)); __m256i c = _mm256_set_m128i(hi, lo); // or _mm256_inserti128_si256(_mm256_castsi128_si256(lo), hi, 1); 和_mm256_permute2x128_si256(hi, lo, constant)。 因此,它的“仅”是AVX-512c而不是3x的两倍。 d是严格的ub口化,并且在GCC和/或Clang中可能会错误地编译。 不要那样做。 PRINTA __M128I变量

回答 1 投票 0

哪些系列内在系统将完成此PAETH预测代码?

&a, const std ::array 我具有在数组上运行的PAETH预测函数:<...

回答 2 投票 0

__assume() 似乎会导致 NVCC 中出现内部错误:“调用的参数数量错误...”

我有以下代码,它会在较大的代码库上下文中导致错误: 结构四元组 { 双_sum; 双_corr; // 快速乘以 -1、0 或 +1(不需要扩展

回答 2 投票 0

TypeScript 中的美元符号语法是什么?

我试图探索 TypeScript 内在的 Capitalize 实用程序类型,并找到了它如何实现的描述 - 它看起来像这样 输入 Capitalize = S 扩展 `${in...

回答 2 投票 0

如何使用 ISPC intel 编译器访问指向可变数据 (T**) 的指针

我正在学习如何使用ISPC,我了解如何在公共数据上有效地使用uniform和variable,但我很难找出如何使用uniform和variable与指针(以及指向点的指针......

回答 1 投票 0

无法使用GNU MIPS 向量内建函数(SIMD)

我正在开发适用于 MIPS CPU 的嵌入式 Linux 系统(内核 5.10.24)。现在我想测试 https://gcc.gnu.org/onlinedocs/gcc/MIPS-SIMD-Architecture-... 中列出的 MIPS SIMD 的 GNU 内置函数。

回答 1 投票 0

memcpy 击败 SIMD 内在函数

当 NEON 向量指令在 ARM 设备上可用时,我一直在寻找复制各种数据量的快速方法。 我做了一些基准测试,并得到了一些有趣的结果。 我很...

回答 2 投票 0

如何在 C (AVX2) 中向量化 int8 数组与 int16 常量的乘法,并扩展到 int32 结果数组

如何使用 AVX2 向量化这个 C 函数? static void propogate_neuron(const Short a, const int8_t *b, int *c) { 对于 (int i = 0; i < 32; ++i){ c[i] += a * b[i]; } } (Relat...

回答 2 投票 0

使用 AVX(车道交叉)模拟 32 字节的字节移位

我正在将使用 SSE2 内在函数编写的矢量化代码迁移到 AVX2 内在函数。 令我失望的是,我发现字节移位指令 _mm256_slli_si256 和 _mm256_srli_si256 运行

回答 3 投票 0

vfmlalq_low_f16 和 vfmlalq_high_f16 未将其第一个操作数设置为结果

我正在尝试使用 vfmlalq_low_f16 和 vfmlalq_high_f16 内在函数(对应于 FMLAL 和 FMLAL2 指令),但我观察到的行为似乎没有意义。 需要一个 float32x4 a...

回答 1 投票 0

vfmlalq_low_f16 和 vfmlalq_high_f16 行为

我正在尝试使用 vfmlalq_low_f16 和 vfmlalq_high_f16 内在函数(对应于 FMLAL 和 FMLAL2 指令),但我观察到的行为似乎没有意义。 需要一个 float32x4 a...

回答 1 投票 0

这是 gcc 错误吗?当在 __m256i

当用 gcc 编译时,函数 sum_of_squares 返回 0。我做错了什么还是这是一个 gcc bug?我知道我不会处理 n 不能被 8 整除的情况。 #包括 用 gcc 编译时,函数 sum_of_squares 返回 0。我做错了什么还是这是 gcc bug?我知道我不会处理 n 不能被 8 整除的情况。 #include <stdio.h> #include <x86intrin.h> int sum_of_squares(int x[], int n) { int sum = 0; __m256i sum8 = _mm256_set1_epi32(0); for (int i = 0; i < n; i += 8) { __m256i x8 = _mm256_load_si256((__m256i *)&x[i]); x8 = _mm256_mul_epi32(x8, x8); sum8 = _mm256_add_epi32(x8, sum8); } int *_sum = (int *)&sum8; for (int i = 0; i < 8; i++) sum += _sum[i]; return sum; } int main() { _Alignas(32) int x[16]; for (int i = 0; i < 15; i++) { x[i] = i; } printf("%d", sum_of_squares(x, 16)); } 将 int* 指向 __m256i(long long 元素的 GNU C 向量)违反了严格别名规则。 因此,GCC14.2 -O2 将您的函数优化为 return 0;。 (xor eax,eax / ret). 我们可以通过使用 -fno-strict-aliasing 并看到非零结果来验证这是问题所在。 (请参阅 Godbolt )。 MSVC 始终允许所有别名,并且它并不总是在 GCC 或 Clang 上中断,因此有些人错误地认为像您这样的代码是安全的。 事实并非如此,正如本例所示。 不幸的是 -fsanitize=undefined 没有捕获此错误(或未初始化的 x[] 的最后一个元素)。 但一般来说,当您检查 asm 并看到您的函数优化为 return 0; 时,这通常意味着您要么返回了错误的变量,要么存在编译时可见的 UB。 (有时编译器甚至不设置返回值,甚至省略 ret 指令,因此执行会陷入接下来的情况。) 使用 _mm256_storeu_si256 到 int tmparr[8];(或者对齐 tmp 数组并使用 _mm256_store_si256)。 或者更好,请参阅 使用 AVX512 或 AVX2 计算所有打包 32 位整数之和的最快方法(一般来说 进行水平 SSE 向量和(或其他缩减)的最快方法) - 洗牌将低半部分向下与低半部分对齐并进行垂直 SIMD 加法,每一步减少一半的元素数量,直到你只剩下一个了。 (如果您避免使用 UB,GCC 实际上会将您的归约循环优化为一系列洗牌和添加。) 测试用例中其他不相关的错误 正如 Soonts 提到的,您还需要 vpmulld (_mm256_mullo_epi32) 非展宽 32 位乘法,而不是 vpmuldq (_mm256_mul_epi32) 展宽有符号乘法,后者仅读取偶数元素以产生 64 位结果。 你的严格别名错误就是你得到零的原因;解决这个问题对于获得您想要的非零结果也是必要的,而不仅仅是偶数元素(0,2等)的总和。 您还应该初始化第 16 个元素 (x[15]),正如 Soonts 指出的那样,您当前的代码无法做到这一点。 __attribute__((may_alias)) 让您可以键入 int 的版本,您可以指向任何东西 如果你真的想要,你可以使用 typedef int32_t aliasing_i32 __attribute__((may_alias)),你可以安全地指向任何对齐 4 或更多的东西,使用它代替 int 作为你的指针类型。 (或者如果您使用 __attribute__((may_alias, aligned(1))),则不对齐)。 有趣的事实:GCC 和 Clang 对 __m256i 的定义使用 may_alias,允许您将 __m256i* 指向任何东西,但反之则不然。 但这并没有什么好处;数组不占用“额外”存储空间; __m256i向量优化为仅YMM寄存器。 无论如何,归约循环都会优化为随机播放,但如果没有,无论哪种编写方式都会有 32 字节的堆栈空间,该空间由 vmovdqa 写入并由标量循环读取。 x8 = _mm256_mul_epi32(x8, x8); 指导并没有达到你期望的效果。它仅使用每个 64 位通道中的最低 32 位,并计算 4 个乘积,每个乘积 64 位。 要计算 8 个 32 位乘积,请考虑使用 _mm256_mullo_epi32。 for (int i = 0; i < 15; i++) 请注意,您仅初始化 15 个数字,然后加载 16 个。 int *_sum = (int *)&sum8; 这可行,但通常会编译成缓慢的代码,矢量存储然后标量加载。 要计算向量中所有数字的水平总和,请参阅答案。 #include <stdio.h> #include <x86intrin.h> int sum_of_squares(int x[], int n) { if( 0 != (n+1)%8 ) { // Here n needs to be multiples of 8 - 1 printf( "sum_of_squares data size parameter needs to be multiples of 8-1\n"); printf( "data size n: %d n-1: %d\n", n, n-1); printf( "Allowed values for n: 7, 15, 23, ...\n"); return -1; } int sum = 0; __m256i sum8 = _mm256_set1_epi32(0); for (int i = 0; i < n; i += 8) { __m256i initVal = _mm256_load_si256((__m256i *)&x[i]); __m256i x8 = _mm256_load_si256((__m256i *)&x[i]); // x8 = _mm256_mul_epi32(x8, x8); x8 = _mm256_mullo_epi32( initVal, x8); sum8 = _mm256_add_epi32(x8, sum8); } int *_sum = (int *)&sum8; for (int i = 0; i < 8; i++) sum += _sum[i]; return sum; } int main() { { _Alignas(32) int x[8]; for (int i = 0; i < 8; i++) { x[i] = i; } printf( "sum_of_squares of 0^2+1^2+2^2+..7^2 elements: %d\n", sum_of_squares(x, 8-1)); int n = 8-1; printf( "%d*(%d+1)*(2*%d+1)/6 = %d*%d*(%d+1)/6 = %d*%d*%d/6 = %d\n", n, n, n, n, n+1, 2*n, n, n+1, 2*n+1, n*(n+1)*(2*n+1)/6 ); } { _Alignas(32) int x[16]; for (int i = 0; i < 16; i++) { x[i] = i; } printf( "sum_of_squares of 0^2+1^2+2^2+..15^2 elements: %d\n", sum_of_squares(x, 16-1)); int n = 16-1; printf( "%d*(%d+1)*(2*%d+1)/6 = %d*%d*(%d+1)/6 = %d*%d*%d/6 = %d\n", n, n, n, n, n+1, 2*n, n, n+1, 2*n+1, n*(n+1)*(2*n+1)/6 ); } { _Alignas(32) int x[24]; for (int i = 0; i < 24; i++) { x[i] = i; } printf( "sum_of_squares of 0^2+1^2+2^2+..23^2 elements: %d\n", sum_of_squares(x, 24-1)); int n = 24-1; printf( "%d*(%d+1)*(2*%d+1)/6 = %d*%d*(%d+1)/6 = %d*%d*%d/6 = %d\n", n, n, n, n, n+1, 2*n, n, n+1, 2*n+1, n*(n+1)*(2*n+1)/6 ); } { _Alignas(32) int x[4]; for (int i = 0; i < 4; i++) { x[i] = i; } printf( "sum_of_squares of 0^2+1^2+2^2+..23^2 elements: %d\n", sum_of_squares(x, 4-1)); int n = 4-1; printf( "%d*(%d+1)*(2*%d+1)/6 = %d*%d*(%d+1)/6 = %d*%d*%d/6 = %d\n", n, n, n, n, n+1, 2*n, n, n+1, 2*n+1, n*(n+1)*(2*n+1)/6 ); } { _Alignas(32) int x[13]; for (int i = 0; i < 13; i++) { x[i] = i; } printf( "sum_of_squares of 0^2+1^2+2^2+..23^2 elements: %d\n", sum_of_squares(x, 13-1)); int n = 13-1; printf( "%d*(%d+1)*(2*%d+1)/6 = %d*%d*(%d+1)/6 = %d*%d*%d/6 = %d\n", n, n, n, n, n+1, 2*n, n, n+1, 2*n+1, n*(n+1)*(2*n+1)/6 ); } // I feel better to use mathematical formula instead of wasting memories at RAM and process handlers. return 0; } /* $ /usr/bin/gcc.exe -mavx2 -g -Wall sum_of_squares.c -o ./a.out $ ./a.out sum_of_squares of 0^2+1^2+2^2+..7^2 elements: 140 7*(7+1)*(2*7+1)/6 = 7*8*(14+1)/6 = 7*8*15/6 = 140 sum_of_squares of 0^2+1^2+2^2+..15^2 elements: 1240 15*(15+1)*(2*15+1)/6 = 15*16*(30+1)/6 = 15*16*31/6 = 1240 sum_of_squares of 0^2+1^2+2^2+..23^2 elements: 4324 23*(23+1)*(2*23+1)/6 = 23*24*(46+1)/6 = 23*24*47/6 = 4324 sum_of_squares data size parameter needs to be multiples of 8-1 data size n: 3 n-1: 2 Allowed values for n: 7, 15, 23, ... sum_of_squares of 0^2+1^2+2^2+..23^2 elements: -1 3*(3+1)*(2*3+1)/6 = 3*4*(6+1)/6 = 3*4*7/6 = 14 sum_of_squares data size parameter needs to be multiples of 8-1 data size n: 12 n-1: 11 Allowed values for n: 7, 15, 23, ... sum_of_squares of 0^2+1^2+2^2+..23^2 elements: -1 12*(12+1)*(2*12+1)/6 = 12*13*(24+1)/6 = 12*13*25/6 = 650 */

回答 3 投票 0

在 Rust 中使用 SIMD 执行矩阵乘积时出现访问冲突

我正在为我的 opengl 项目制作自己的 linalg 库,并且正在考虑使用 simd 加速 matmul。 最小可重现示例: 使用 std::arch::x86_64::*; #[导出(调试、克隆、复制)] 圣...

回答 1 投票 0

在 Rust 中使用 SIMD 执行矩阵生成时出现访问冲突

我正在为我的 opengl 项目制作自己的 linalg 库,并且正在考虑使用 simd 加速 matmul。 最小可重现示例: 使用 std::arch::x86_64::*; #[导出(调试、克隆、复制)] 圣...

回答 1 投票 0

将 32 位整数的向量相乘,仅取高 32 位

我想将 16 个无符号 32 位整数的两个 512 位 __m512i 向量相乘,并仅从乘法的 64 位结果中取出高 32 位。虽然英特尔内在函数...

回答 2 投票 0

使用 SIMD 并行化 4x4 行主矩阵的矩阵乘法

我目前在尝试并行化 4x4 矩阵乘法算法时面临着极其困难的时期。我正在尝试创建一个库以在学校的最小光线追踪器项目中使用,所以我正在尝试...

回答 1 投票 0

从 __m512i/__m256i 向量中提取非零元素

给定一个包含 64 个 char 元素的 __m512i 向量: 索引:0、1、2、3、4、5、6、7、8、9、10、... 值:1、-1、1、0、0、-1、1、1、0、0、1、... (注:元素的值在[-1, 1]之间)....

回答 1 投票 0

ARM 固有:在每个复数浮点样本后插入复数零

我有以下输入: [1i+2j]、[3i+4j]、[5i+6j]、... 输出应该是: [1i+2j]、[0i+0j]、[3i+4j]、[0i+0j]、[5i+6j]、[0i+0j]、... 我写了以下代码: void Extract (ComplexFloat *pIn,

回答 1 投票 0

C 中是否有用于 add-with-carry 的 ARM 内在函数?

ARM C 编译器是否存在内置函数来进行加进位操作,或者是否需要使用汇编语言? 在 x86 上,有 _addcarry_u64 用于 add-with-carry。 (还有新...

回答 2 投票 0

如何破译神秘的英特尔内部名称和首字母缩略词

当您开始处理 SIMD 指令时,您会注意到内在函数的名称如下 _mm_dp_pd _mm_mul_pd 在仔细查看文档一段时间(或几年)后,您开始注意到一些

回答 1 投票 0

最新问题
© www.soinside.com 2019 - 2025. All rights reserved.