g ++ -O2 неверно оптимизирует назначение переменных SIMD

Я пишу программу, используя инструкции Intel 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 и вектор все-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);
//...
}

0

Решение

Причиной, по которой компилятор отменяет присвоение, является, вероятно, то, что он считает, что строка кода мертвых код. Так что ваши CMP вряд ли будет Comparator::kLess,

Задания, которые вы пытаетесь обойти, могут быть реализованы с помощью __asm__ volatile заявления и они не могут быть оптимизированы.

декларирование m_lt изменчивость, вероятно, не сильно повлияет на вашу производительность, но это грязный хак, чтобы исправить это. Я бы посмотрел больше на CMP переменная и посмотреть, может ли она также принять kLess значение.

1

Другие решения


По вопросам рекламы ammmcru@yandex.ru
Adblock
detector