2014-10-09 9 views
0

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); 
//... 
} 
+0

사이드 노트 일 수도 있지만'y = avx_or (m_lt, avx_ones()); '는 실제로 일이 올바르게 실행되도록 허용합니까? 그것은 모든 것들의 가치를 제공해야합니다 ...? –

+0

@JoachimIsaksson 오, 죄송합니다. 실수입니다. 나는 고쳤다. – Neo1989

+1

intrinsics가 직접 할당보다 빠르지 않습니까? 당신이 벌레를 치지 않았다고 말하는 것은 아니지만 실제로 벌레를 피하는 것이 더 빠를 수도 있습니다. –

답변

1

컴파일러는 것 떨어져 할당은 코드의 라인 죽은코드 수 있다고 믿는 아마도하는 이유. 따라서 CMPComparator::kLess이 아닙니다.

해결 방법으로 시도한 할당은 __asm__ volatile 문을 사용하여 구현할 수 있으며 최적화 할 수 없습니다.

volatile로 선언하면 성능에 큰 영향을 미치지 않지만 문제를 해결하기 위해서는 더러운 마약을 사용해야합니다. 나는 CMP 변수에 대해 더 자세히 살펴보고 kLess 값을 취할 수 있는지 확인합니다.

+0

성능면에서는 좋지 않습니다. –

+0

알림을 보내 주셔서 감사합니다.그러나 요점은 컴파일러가 최적화하기를 원하지만 정확성을 잃지 않고 당연히해야한다는 것입니다. – Neo1989

+0

"m_lt"변수에서 휘발성을 시도 할 수 있습니다. y 변수는 여전히 최적화됩니다. 그러나 두 경우 모두 시도해보십시오 y는 휘발성입니다. 나는이 최적화에서 코드가 많이 나올 것을 기대하지 않는다. 당신이 SIMD를 사용하기 때문에 퍼포먼스가 커집니다. – VAndrei