C++ c++;在GCC内联程序集中封装单个vmovups的内联函数
我试图解决clang编译器中的一个明显缺陷,即使用AVX固有的_mm256_loadu_ps会导致在汇编中输出不必要的指令。特别是,首先,它对输入向量的前半部分执行vmovups操作,将其放入xmm寄存器,然后使用vinsertf128指令将后半部分与前半部分合并,从而使程序的速度降低一点。相反,我希望编译器分配的ymm寄存器中有一条vmovups指令 我对SSE/AVX内部函数一直很熟悉,但一旦我需要转到内联汇编,我就迷路了 我想要一个内联函数,它的功能与下面的相同,但是vmovups应该在内联程序集中C++ c++;在GCC内联程序集中封装单个vmovups的内联函数,c++,assembly,clang,inline,avx,C++,Assembly,Clang,Inline,Avx,我试图解决clang编译器中的一个明显缺陷,即使用AVX固有的_mm256_loadu_ps会导致在汇编中输出不必要的指令。特别是,首先,它对输入向量的前半部分执行vmovups操作,将其放入xmm寄存器,然后使用vinsertf128指令将后半部分与前半部分合并,从而使程序的速度降低一点。相反,我希望编译器分配的ymm寄存器中有一条vmovups指令 我对SSE/AVX内部函数一直很熟悉,但一旦我需要转到内联汇编,我就迷路了 我想要一个内联函数,它的功能与下面的相同,但是vmovups应该在内
inline __mm256 V8fLoadU(const float* pf)
{
return _mm256_loadu_ps(pf);
}
这是我到目前为止尝试过的,但不起作用(似乎将*pf single float移动到堆栈上,然后加载该空间):
提前感谢。通过将指针作为输入参数传递,您正在加载指针的值,而不是它所指向的值。您需要传递要加载的值
__m256 V8fLoadU(const float* pf)
{
__m256 m;
__asm__("vmovups %1, %0" : "=x" (m) : "m" (*pf));
return m;
}
通过将指针作为输入参数传递,您正在加载指针的值,而不是它指向的对象。您需要传递要加载的值
__m256 V8fLoadU(const float* pf)
{
__m256 m;
__asm__("vmovups %1, %0" : "=x" (m) : "m" (*pf));
return m;
}
这不是一个错误,这是故意的。在当代x86体系结构上,256位未对齐的访问在某些情况下可能非常慢。事实上,速度足够慢,可以更快地进行2次128位访问并将它们缝合在一起,正如您在这里看到的clang所做的那样。根据特定访问模式的详细信息,执行256位未对齐的访问可能会稍微快一点,但编译器在合成代码时只有这么多信息。如果使用对齐访问,则应始终看到256位移动指令。至少90%的时间,进入此函数的数据都已对齐。在使用发出单个vmovups指令的不同编译器对对齐和未对齐的加载进行性能比较之后,我发现只要传入的指针是预对齐的,性能就与使用对齐的变量几乎相同。这里有一些关于256b加载为何拆分的信息:。通常可以通过
-march=which
避免,而不仅仅是-mavx2
。。。至少在海湾合作委员会。不太清楚叮当声。这不是虫子,是故意的。在当代x86体系结构上,256位未对齐的访问在某些情况下可能非常慢。事实上,速度足够慢,可以更快地进行2次128位访问并将它们缝合在一起,正如您在这里看到的clang所做的那样。根据特定访问模式的详细信息,执行256位未对齐的访问可能会稍微快一点,但编译器在合成代码时只有这么多信息。如果使用对齐访问,则应始终看到256位移动指令。至少90%的时间,进入此函数的数据都已对齐。在使用发出单个vmovups指令的不同编译器对对齐和未对齐的加载进行性能比较之后,我发现只要传入的指针是预对齐的,性能就与使用对齐的变量几乎相同。这里有一些关于256b加载为何拆分的信息:。通常可以通过-march=which
避免,而不仅仅是-mavx2
。。。至少在海湾合作委员会。不确定是否有叮当声。@Kumputer这意味着操作数可以在XMM/YMM寄存器中。严格来说,这是准确的,VMOVUPS支持注册到注册的移动,但在这种情况下,这不是您想要的。因此,只要使用“m”约束,它就应该按原样接受内存引用,并且不需要强制转换,因为“m”约束不关心引用的类型,它只需要有一个可表示的地址。好的,它可以工作!谢谢也就是说,代码输出看起来和我预期的一样,但性能完全相同。嗯,至少它保存了一个寄存器。@Kumputer它意味着操作数可以在XMM/YMM寄存器中。严格来说,这是准确的,VMOVUPS支持注册到注册的移动,但在这种情况下,这不是您想要的。因此,只要使用“m”约束,它就应该按原样接受内存引用,并且不需要强制转换,因为“m”约束不关心引用的类型,它只需要有一个可表示的地址。好的,它可以工作!谢谢也就是说,代码输出看起来和我预期的一样,但性能完全相同。嗯,至少它保存了一个寄存器。