除SSE-copy, AVX-copy and std::copy performance之外。假设我们需要以下列方式对一些循环进行矢量化:1)通过AVX向量化第一个循环批次(多次乘8)。 2)将循环的剩余部分分成两批。通过SSE矢量化批次为4的倍数。 3)通过串行程序处理整个循环的剩余批次。让我们考虑复制数组的例子:
#include <immintrin.h>
template<int length,
int unroll_bound_avx = length & (~7),
int unroll_tail_avx = length - unroll_bound_avx,
int unroll_bound_sse = unroll_tail_avx & (~3),
int unroll_tail_last = unroll_tail_avx - unroll_bound_sse>
void simd_copy(float *src, float *dest)
{
auto src_ = src;
auto dest_ = dest;
//Vectorize first part of loop via AVX
for(; src_!=src+unroll_bound_avx; src_+=8, dest_+=8)
{
__m256 buffer = _mm256_load_ps(src_);
_mm256_store_ps(dest_, buffer);
}
//Vectorize remainder part of loop via SSE
for(; src_!=src+unroll_bound_sse+unroll_bound_avx; src_+=4, dest_+=4)
{
__m128 buffer = _mm_load_ps(src_);
_mm_store_ps(dest_, buffer);
}
//Process residual elements
for(; src_!=src+length; ++src_, ++dest_)
*dest_ = *src_;
}
int main()
{
const int sz = 15;
float *src = (float *)_mm_malloc(sz*sizeof(float), 16);
float *dest = (float *)_mm_malloc(sz*sizeof(float), 16);
float a=0;
std::generate(src, src+sz, [&](){return ++a;});
simd_copy<sz>(src, dest);
_mm_free(src);
_mm_free(dest);
}
同时使用SSE和AVX是否正确?我需要避免AVX-SSE过渡吗?
答案 0 :(得分:8)
您可以随意混合使用SSE和AVX内在函数。
您唯一要确保的是指定正确的编译器标志以启用AVX。
-mavx
/arch:AVX
如果不这样做将导致代码不编译(GCC),或者在Visual Studio的情况下, 这种废话:
标志的作用是强制所有SIMD指令使用VEX编码来避免上述问题中描述的状态转换惩罚。
答案 1 :(得分:1)
我谦卑地求求不同 - 我建议尝试不混合SSE和AVX, 请阅读Mystical写的链接,它警告不要这样的混合物(尽管没有足够强调)。根据AVX的支持,问题在于不同的机器有不同的代码路径,所以没有混合 - 在你的情况下,混合是非常细粒度的并且是破坏性的(由于微架构实现而导致内部延迟)。
澄清 - 神秘是关于编译中的vex前缀是正确的,没有它你会因为你的YMM寄存器的上半部分不能被忽略而导致SSE2AVX每次助攻都很糟糕(除非明确使用vzeroupper)。但是,即使使用128b AVX与256b AVX混合,也会产生更微妙的效果。
我也没有看到在这里使用SSE的好处,你有一个很长的循环(比如N> 100)你可以从大部分AVX中获益,并在标量代码中完成其余的工作到7次迭代(你的代码可能仍然需要做3次)。与混合AVX / SSE相比,性能损失无关紧要