由于使用MSVC14和AVX进行未对齐访问导致的特征崩溃

时间:2018-06-06 14:37:47

标签: visual-studio crash alignment eigen avx

我有一段代码可以利用SIMD。它在Linux + GCC上工作正常但是我已经在墙上撞了一段时间了,因为当我使用启用了AVX的MSVC构建它时崩溃了。

template <>
void NewtonRaphson<double, InstructionSet::AVX>::initializeLu(const int elements)
{
    std::cerr << "EDE " << EIGEN_DEFAULT_ALIGN_BYTES << "\n";
    std::cerr << "Allocations are already aligned = " << EIGEN_MALLOC_ALREADY_ALIGNED << "\n";

    m_luCalc = new Eigen::PartialPivLU<SolverMatrix<double>>(elements);
}

template <>
typename NewtonRaphson<double, InstructionSet::AVX>::TX const & NewtonRaphson<double, InstructionSet::FMA3>::ASolve()
{
    m_iteration = 0;
    m_stuckCounter = 0;

    AInit();

    // DOIT

    std::cerr << "EDE WKR" << EIGEN_DEFAULT_ALIGN_BYTES << "\n";
    std::cerr << "...WKR Allocations are already aligned = " << EIGEN_MALLOC_ALREADY_ALIGNED << "\n";

    while (true)
    {
        // !2
        ACalculateF(m_f, *m_px);
        ACalculateJ(m_j, *m_px);

        ZCalculateMeasures(m_f, m_fMin, m_fMax);
        ZCalculateMeasures(m_dx, m_dxMin, m_dxMax);                                  // 1

        ZCheckStatus();

        if (m_status != Status::CONTINUE)
            return *m_px;

        this->m_iteration++;

        m_luCalc->compute(m_j);
        m_dx = m_luCalc->solve(m_f);

        *m_px -= m_dx;
    };

    return *m_px;
}

代码驻留在一个单独的.cpp文件中,该文件使用适当的优化标志集进行编译。崩溃发生在PartialPivLU :: compute()函数的开头。快速浏览MSVC为违规函数生成的程序集,可以看出:

5D43D243  jle         Eigen::PartialPivLU<Eigen::Matrix<double,-1,-1,0,-1,-1> >::compute<Eigen::Map<Eigen::Matrix<double,-1,-1,0,-1,-1>,32,Eigen::Stride<0,0> > >+0E9h (5D43D269h)  
5D43D245  nop         word ptr [eax+eax]  
5D43D250  mov         eax,dword ptr [ebp-1Ch]  
5D43D253  vmovupd     ymm0,ymmword ptr [eax+ecx*8]  
5D43D258  vmovapd     ymmword ptr [edi+ecx*8],ymm0 

崩溃发生在vmovapd指令处,该指令尝试从16字节对齐的地址读取。 EIGEN_DEFAULT_ALIGN_BYTES设置为32,EIGEN_MALLOC_ALREADY_ALIGNED为0.当我将SIMD优化调低到SSE2时,此代码正常工作。

为了与MSVC正确对齐,我有什么遗漏吗?

1 个答案:

答案 0 :(得分:0)

好吧,我想我已经深究了这一点。我的代码检测运行时可用的CPU指令集,并动态地将执行分派给使用可用指令集的函数。我将使用不同SIMD指令的部分代码移动到不同的TU以实现这一点。这工作正常,直到我决定在直接使用Eigen的代码部分中启用矢量化。虽然每个TU再次重新包含所有Eigen,因此其内部值也相应地设置,但Eigen的分配器不是模板化的,而是定义为内联。因此,编译器将handmade_aligned_malloc的所有定义合并为一个函数,即使它们实际上并不执行相同的操作,因为根据设置的编译器标志,EIGEN_DEFAULT_ALIGN_BYTES的值在每个TU中是不同的。它在Linux下与GCC一起工作的事实可能是偶然的。虽然我仍然需要找到一个适当的解决方案,但我相信这可以解决导致崩溃的原因。