g ++ -O2错误地优化了SIMD变量赋值

时间:2014-10-09 09:03:23

标签: c++ optimization g++ sse avx2

我正在使用英特尔AVX2指令编写程序。我在我的程序中发现了一个错误,它只显示优化级别-O2或更高(使用-O1它很好)。经过大量调试后,我缩小了有缺陷的区域。现在这个错误似乎是因为编译器错误地优化了 __ m256i 变量的简单复制分配。

请考虑以下代码段。 Foo是一个模板化的函数。我用CMP = kLess, OPT=kSet进行测试。我知道优化器可能会优化开关。它甚至可以优化变量y

越野车行是y = m_lt;。使用-O2编译时,此行似乎被忽略。然后y没有得到正确的值,程序会生成错误的结果。但是程序与-O1是正确的。

为了验证我的判断,我用两个替代方案替换y = m_lt;

y = avx_or(m_lt, avx_zero());采用m_lt的按位OR和全0的向量

y = _mm256_load_si256(&m_lt);使用SIMD加载指令从m_lt的地址加载数据。

两者都应该在语义上等同于y = m_lt;我的意图是通过添加一些函数来阻止某些优化。在所有优化级别下,该程序可以正确使用这两个替换。所以问题很奇怪。据我所知,SIMD变量的直接分配肯定是可以的(我以前用了很多)。这会是与编译器有关的问题吗?

typedef __m256i AvxUnit;

template <Comparator CMP, Bitwise OPT>
void Foo(){
    AvxUnit m_lt;
    //...

assert(!avx_iszero(m_lt));   //always pass

AvxUnit y;

switch(CMP){
    case Comparator::kEqual:
        y = m_eq;
        break;
    case Comparator::kInequal:
        y = avx_not(m_eq);
        break;
    case Comparator::kLess:
        y = m_lt;   //**********Bug?*************
        //y = avx_or(m_lt, avx_zero());   //Replace with this line is good.
        //y = _mm256_load_si256(&m_lt);   //Replace with this line is good too.
        break;
    case Comparator::kGreater:
        y = m_gt;
        break;
    case Comparator::kLessEqual:
        y = avx_or(m_lt, m_eq);
        break;
    case Comparator::kGreaterEqual:
        y = avx_or(m_gt, m_eq);
        break;
}

switch(OPT){
    case Bitwise::kSet:
        break;
    case Bitwise::kAnd:
        y = avx_and(y, bvblock->GetAvxUnit(bv_word_id));
        break;
    case Bitwise::kOr:
        y = avx_or(y, bvblock->GetAvxUnit(bv_word_id));
        break;
}

assert(!avx_iszero(y));   //pass with -O1, fail with -O2 or higher

bvblock->SetAvxUnit(y, bv_word_id);
//...
}

1 个答案:

答案 0 :(得分:1)

编译器离开分配的原因可能是它认为代码行 dead 代码。因此,CMP可能不是Comparator::kLess

您尝试作为变通方法的分配可以使用__asm__ volatile语句实现,但无法对其进行优化。

m_lt声明为volatile可能不会对您的性能造成太大影响,但修复它是一个肮脏的黑客攻击。我会在CMP变量上查看更多内容并查看它是否也可以使用kLess值。