Intel AVX2 명령어를 사용하여 프로그램을 작성하고 있습니다. 내 프로그램에서 최적화 수준 -O2 이상에서만 나타나는 버그를 발견했습니다 (-O1은 좋았습니다). 광범위한 디버깅 후에 버그가있는 영역을 좁 힙니다. 이제이 버그는 컴파일러가 __m256i 변수의 간단한 복사본 할당을 최적화하지 못하게하여 잘못된 것 같습니다.g ++ -O2가 SIMD 변수 할당을 잘못 최적화합니다.
다음 코드 단편을 고려하십시오. Foo는 템플릿 기능입니다. 나는 CMP = kLess, OPT=kSet
으로 시험한다. 최적화 프로그램이 아마 스위치를 최적화 할 것임을 알고 있습니다. 변수 y
을 최적화 할 수도 있습니다.
버그가있는 줄은 y = m_lt;
입니다. -O2로 컴파일하면 이 줄은 무시됩니다.. 그런 다음 y
이 올바른 값을 얻지 못하고 프로그램이 잘못된 결과를 생성합니다. 그러나 프로그램은 -O1과 맞습니다.
내 판단을 확인하기 위해, 나는 두 가지 대안과 y = m_lt;
대체 :
y = avx_or(m_lt, avx_zero());
는 OR m_lt
의 비트와 모든 공의 벡터
y = _mm256_load_si256(&m_lt);
소요 m_lt
의 주소에서 데이터를로드 할 SIMD의로드 명령을 사용하여 .
둘 다 의미 상으로 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);
//...
}
사이드 노트 일 수도 있지만'y = avx_or (m_lt, avx_ones()); '는 실제로 일이 올바르게 실행되도록 허용합니까? 그것은 모든 것들의 가치를 제공해야합니다 ...? –
@JoachimIsaksson 오, 죄송합니다. 실수입니다. 나는 고쳤다. – Neo1989
intrinsics가 직접 할당보다 빠르지 않습니까? 당신이 벌레를 치지 않았다고 말하는 것은 아니지만 실제로 벌레를 피하는 것이 더 빠를 수도 있습니다. –