根据英特尔软件开发人员手册(第14.9节),AVX放宽了内存访问的对齐要求.如果数据直接加载到处理指令中,例如
vaddps ymm0,ymm0,YMMWORD PTR [rax]
Run Code Online (Sandbox Code Playgroud)
加载地址不必对齐.但是,如果使用专用的对齐加载指令,例如
vmovaps ymm0,YMMWORD PTR [rax]
Run Code Online (Sandbox Code Playgroud)
必须对齐加载地址(为32的倍数),否则会引发异常.
令我困惑的是内在函数的自动代码生成,在我的例子中是gcc/g ++(4.6.3,Linux).请查看以下测试代码:
#include <x86intrin.h>
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#define SIZE (1L << 26)
#define OFFSET 1
int main() {
float *data;
assert(!posix_memalign((void**)&data, 32, SIZE*sizeof(float)));
for (unsigned i = 0; i < SIZE; i++) data[i] = drand48();
float res[8] __attribute__ ((aligned(32)));
__m256 sum = _mm256_setzero_ps(), elem;
for (float *d = data + OFFSET; d < data + SIZE - 8; d += 8) {
elem = _mm256_load_ps(d);
// …Run Code Online (Sandbox Code Playgroud) 这个问题与gcc(4.6.3 Ubuntu)及其在为具有即时操作数的SSE内在函数的展开循环中的行为有关.
具有立即操作数的内在函数的示例是_mm_blend_ps.它期望一个4位立即数整数,它只能是一个常数.但是,使用-O3选项,编译器显然会自动展开循环(如果循环计数器值可以在编译时确定)并生成具有不同立即值的相应混合指令的多个实例.
这是一个简单的测试代码(blendsimple.c),它贯穿了blend的立即操作数的16个可能值:
#include <stdio.h>
#include <x86intrin.h>
#define PRINT(V) \
printf("%s: ", #V); \
for (i = 3; i >= 0; i--) printf("%3g ", V[i]); \
printf("\n");
int
main()
{
__m128 a = _mm_set_ps(1, 2, 3, 4);
__m128 b = _mm_set_ps(5, 6, 7, 8);
int i;
PRINT(a);
PRINT(b);
unsigned mask;
__m128 r;
for (mask = 0; mask < 16; mask++) {
r = _mm_blend_ps(a, b, mask);
PRINT(r);
}
return 0;
}
Run Code Online (Sandbox Code Playgroud)
可以使用编译此代码
gcc -Wall -march=native -O3 -o blendsimple blendsimple.c …Run Code Online (Sandbox Code Playgroud) 使用SSE内在函数时,通常需要零向量.无论何时调用函数(每次有效调用某些xor向量指令),避免在函数内部创建零变量的一种方法是使用静态局部变量,如
static inline __m128i negate(__m128i a)
{
static __m128i zero = __mm_setzero_si128();
return _mm_sub_epi16(zero, a);
}
Run Code Online (Sandbox Code Playgroud)
似乎只在第一次调用函数时才初始化变量.(我通过调用一个真正的函数而不是_mm_setzero_si128()内在函数来检查这个.顺便说一句,它似乎只能在C++中,而不是在C中.)
(1)但是,一旦发生这种初始化:这是否阻止了xmm寄存器用于程序的其余部分?
(2)更糟糕的是:如果在多个函数中使用这样的静态局部变量,它会阻塞多个xmm寄存器吗?
(3)反过来说:如果它没有阻塞xmm寄存器,那么在调用函数时,零变量是否总是从内存中重新加载?那么静态局部变量将毫无意义,因为使用_mm_setzero_si128()会更快.
作为替代方案,我考虑将零置于一个全局静态变量中,该变量将在程序启动时初始化:
static __m128i zero = _mm_setzero_si128();
Run Code Online (Sandbox Code Playgroud)
(4)程序运行时,全局变量是否会保留在xmm寄存器中?
非常感谢你的帮助!
(由于这也适用于AVX内在函数,我还添加了AVX标记.)
我想使用并行版本,std::sort我可以在其中指定执行策略,例如std::execution::par_unseq.
我目前正在 Ubuntu Linux 下使用clang++-10和g++ 7.5.0,但是两者都没有找到所需的包含文件execution,因此显然这些编译器版本尚不支持并行算法。
有人可以告诉我哪个版本clang支持gcc此功能吗?
我有以下问题(g ++(Ubuntu 4.8.4-2ubuntu1~14.04)4.8.4):
当我_mm256_slli_si256()直接使用时,例如:
__m256i x = _mm256_set1_epi8(0xff);
x = _mm256_slli_si256(x, 3);
Run Code Online (Sandbox Code Playgroud)
代码编译没有问题(g++ -Wall -march=native -O3 -o shifttest shifttest.C).
但是,如果我将它包装成一个函数
__m256i doit(__m256i x, const int imm)
{
return _mm256_slli_si256(x, imm);
}
Run Code Online (Sandbox Code Playgroud)
编译器抱怨说
/usr/lib/gcc/x86_64-linux-gnu/4.8/include/avx2intrin.h: In function '__m256i doit(__m256i, int)':
/usr/lib/gcc/x86_64-linux-gnu/4.8/include/avx2intrin.h:651:58: error: the last argument must be an 8-bit immediate
return (__m256i)__builtin_ia32_pslldqi256 (__A, __N * 8);
Run Code Online (Sandbox Code Playgroud)
无论是否使用该功能.
这对于立即操作数来说不是问题,因为如果我使用eg _mm256_slli_si32(x, imm)而不是函数doit()编译,并且_mm256_slli_si32()还需要立即操作数.
有一个相关的错误报告
https://gcc.gnu.org/bugzilla/show_bug.cgi?format=multiple&id=54825
但它已经很老了(2012)并且与gcc 4.8.0有关,所以我认为这个补丁已经被整合到g ++ 4.8.4中了.
这个问题有解决方法吗?
英特尔的矢量扩展SSE,AVX等为每个元素大小提供了两个解包操作,例如SSE内在函数是_mm_unpacklo_*和_mm_unpackhi_*.对于向量中的4个元素,它执行此操作:
inputs: (A0 A1 A2 A3) (B0 B1 B2 B3)
unpacklo/hi: (A0 B0 A1 B1) (A2 B2 A3 B3)
Run Code Online (Sandbox Code Playgroud)
解压缩的等价物vzip在ARM的NEON指令集中.但是,NEON指令集也提供了与之vuzp相反的操作vzip.对于向量中的4个元素,它执行此操作:
inputs: (A0 A1 A2 A3) (B0 B1 B2 B3)
vuzp: (A0 A2 B0 B2) (A1 A3 B1 B3)
Run Code Online (Sandbox Code Playgroud)
如何vuzp使用SSE或AVX内在函数有效实现?似乎没有针对它的指示.对于4个元素,我假设它可以使用shuffle和随后的unpack移动2个元素来完成:
inputs: (A0 A1 A2 A3) (B0 B1 B2 B3)
shuffle: (A0 A2 A1 A3) (B0 B2 B1 B3)
unpacklo/hi 2: (A0 A2 B0 B2) (A1 A3 B1 B3)
Run Code Online (Sandbox Code Playgroud)
使用单个指令是否有更高效的解决方案?(也许对于SSE优先 …
在 NASM (2.14.02) 中,指令add rbx, 0xffffffff导致
警告:有符号双字值超出界限 [-w+number-overflow]
我知道 64 位模式下的算术逻辑运算仅接受 32 位常量,但 0xffffffff 仍然是 32 位宽。
为什么 NASM 发出警告,为什么它假设一个有符号常量?它是否将 32 位符号扩展-1为 64 位-1(0xffffffffffffffff)并因此出现溢出?0x7fffffff 工作时不会发出警告。
我能以某种方式说服 NASM 这不是一个有符号常量,而是一个无符号常量吗?
我想探索 gcc (10.3) 的自动矢量化。我有以下简短的程序(请参阅https://godbolt.org/z/5v9a53aj6),它计算向量所有元素的总和:
#include <stdio.h>
#define LEN 1024
// -ffast-math -march=tigerlake -O3 -fno-unroll-loops
int
main()
{
float v[LEN] __attribute__ ((aligned(64)));
float s = 0;
for (unsigned int i = 0; i < LEN; i++) s += v[i];
printf("%g\n", s);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
我用选项编译-ffast-math -march=tigerlake -O3 -fno-unroll-loops。由于 Tigerlake 处理器具有 avx512,我希望 gcc 自动向量化使用 zmm 寄存器,但它实际上在最内层循环中使用 ymm 寄存器(avx/avx2):
vaddps ymm0, ymm0, YMMWORD PTR [rax]
Run Code Online (Sandbox Code Playgroud)
如果我替换-march=tigerlake为-mavx512f,则使用 zmm 寄存器:
vaddps zmm0, zmm0, ZMMWORD PTR [rax]
Run Code Online (Sandbox Code Playgroud)
如果我只是指定,为什么不使用 …
Tcl 中测试数组元素是否存在的最快方法是什么?
info exists ::myArray($myKey)是,效率高吗?llength [array names ::myArray -exact $myKey],这样会更快吗?这些也是 Nadkarni 在 Tcl 书中列出的可能性。还有其他更有效的想法吗?
感谢您的帮助!