Mik*_*keF 8 x86 sse simd avx avx512
通常有两种类型的SIMD指令:
A.使用对齐的内存地址的那些,如果地址未在操作数大小边界上对齐,则会引发一般保护(#GP)异常:
movaps xmm0, xmmword ptr [rax]
vmovaps ymm0, ymmword ptr [rax]
vmovaps zmm0, zmmword ptr [rax]
Run Code Online (Sandbox Code Playgroud)
B.以及使用未对齐内存地址的那些,不会引发此类异常:
movups xmm0, xmmword ptr [rax]
vmovups ymm0, ymmword ptr [rax]
vmovups zmm0, zmmword ptr [rax]
Run Code Online (Sandbox Code Playgroud)
但是我只是好奇,为什么我要用脚射击自己并使用第一组的对齐记忆指令呢?
Had*_*ais 11
movups/vmovups可使用.对齐访问案例中讨论的相同处罚(见下文)也适用于此.此外,跨越高速缓存行或虚拟页面边界的访问总是会对所有处理器造成损害.movups/vmovups在前端和管道的后端消耗更多资源(最多两倍).换句话说,在延迟和/或吞吐量方面movups/vmovups可以高达两倍的速度movaps/vmovaps.因此,如果您不关心较旧的微体系结构,则两者在技术上是等效的.虽然如果您知道或希望数据对齐,您应该使用对齐的指令来确保数据确实对齐,而无需在代码中添加显式检查.
我认为这是使用之间的细微差别_mm_loadu_ps,并_mm_load_ps甚至在"英特尔Nehalem处理器和更高版本(包括Silvermont和更高版本)和AMD推土机和以后",这可能会对性能产生影响.
将加载和另一个操作(例如乘法)折叠成一条指令的操作只能通过而load不是loadu内在函数来完成,除非您在启用AVX的情况下编译以允许未对齐的内存操作数.
请考虑以下代码
#include <x86intrin.h>
__m128 foo(float *x, float *y) {
__m128 vx = _mm_loadu_ps(x);
__m128 vy = _mm_loadu_ps(y);
return vx*vy;
}
Run Code Online (Sandbox Code Playgroud)
这会转换为
movups xmm0, XMMWORD PTR [rdi]
movups xmm1, XMMWORD PTR [rsi]
mulps xmm0, xmm1
Run Code Online (Sandbox Code Playgroud)
但是如果使用了对齐的load intrinsics(_mm_load_ps),则将其编译为
movaps xmm0, XMMWORD PTR [rdi]
mulps xmm0, XMMWORD PTR [rsi]
Run Code Online (Sandbox Code Playgroud)
这节省了一条指令.但是如果编译器可以使用VEX编码的加载,那么它只有两个未对齐的指令.
vmovups xmm0, XMMWORD PTR [rsi]
vmulps xmm0, xmm0, XMMWORD PTR [rdi]
Run Code Online (Sandbox Code Playgroud)
因此,虽然在使用说明书movaps和movupsIntel Nehalem及更高版本或Silvermont及更高版本或AMD Bulldozer及更高版本时性能没有差异,但仍然可以进行对齐访问.
但是在没有启用AVX的情况下进行编译时使用和内在函数时性能可能会有所不同,在编译器的权衡不对比的情况下,它是在ALU指令之间或将负载折叠到ALU指令之间.(当向量仅用作一个事物的输入时会发生这种情况,否则编译器将使用加载将结果存入寄存器以供重用.)_mm_loadu_ps_mm_load_ps movapsmovupsmovupsmov*
| 归档时间: |
|
| 查看次数: |
755 次 |
| 最近记录: |