2016-06-24 6 views
0

내장 함수를 사용하여 부동 소수점 변수 두 개를 비교하고 싶습니다. 비교가 사실이라면 다른 작업을 수행하십시오. 나는 정상적인 if..else 조건으로 이것을하고 싶다. intrinsics를 사용하는 방법이 있습니까?내장 함수에서 조건을 사용하는 방법

//normal code 
vector<float> v1, v2; 
for(int i = 0; i < v1.size(); ++i) 
if(v1[i]<v2[i]) 
{ 
    //do something 
} 
else 
{ 
    //do something 
) 

SSE2 또는 AVX를 사용하여이를 수행하는 방법은 무엇입니까?

+0

사용하는 내장 함수에 따라 달라집니다. 일반적인 방법은 마스크를 생성 한 다음 해당 마스크를 사용하여 두 가지 가능한 시나리오 중에서 사용할 값을 결정하는 것입니다. –

+0

왜 내장 함수를 사용하여이 작업을 수행합니까? 컴파일러가 내장 된 비교 연산자를 사용하여 최적의 코드를 생성하지 못하는 이유는 무엇입니까? 너 해봤 니? –

+0

실제 코드를 게시하는 것이 확실히 도움이 될 것입니다 ... –

답변

1

SIMD 조건부 연산은 분기없는 기술로 수행됩니다. packed-compare 명령을 사용하여 모두 0이거나 모두 1 인 벡터의 벡터를 가져옵니다.

분명히

__m128i match_counts = _mm_setzero_si128(); 

for (...) { 
    __m128 fvec = something; 
    __m128i condition = _mm_castps_si128(_mm_cmplt_ps(fvec, _mm_setzero_ps())); // for elements less than zero 
    __m128i masked_constant = _mm_and_si128(condition, _mm_set1_epi32(4)); 
    match_counts = _mm_add_epi32(match_counts, masked_constant); 
} 

이는 잘 작동 당신이 양쪽을 할 수있는 무점포 방법을 마련 할 수있는 경우 : 해당 요소가 같은 코드와 조건을 일치 할 때 당신은 조건부 어큐뮬레이터의 요소에 4를 추가 할 수 있습니다 분기. 종종 혼합 지시가 도움이 될 수 있습니다.

분기의 각면에서 너무 많은 작업이있는 경우 특히 요소 크기가 4 바이트 이상인 경우 속도가 향상되지 않을 가능성이 높습니다. (SIMD는 4 개의 32 비트 요소에서 4 개의 연산을 수행 할 때 16 개의 별도 바이트로 병렬로 16 개의 연산을 수행 할 때 매우 강력합니다.

+1

왜'1'을 사용하여'_mm_sub_epi32 (match_counts, condition)'를 사용하여'-1'을 빼고 명령을 저장할 수 있습니다. 그것이 내가하는 방법이다. –

+0

@Zboson : 그렇기 때문에'set1 (4)'와 논쟁을 벌이기 때문에 필자의 예는 여전히 사소하지만이 최적화는 직접적으로 적용되지 않았습니다. (물론, 서브 카운트와 매치 카운트를 사용하면 루프 외부에서'_mm_psrli_epi32 (match_counts, 2)'가 더 좋을 것입니다.) –

1

v1[i] < v2[i]이 거의 사실이 아니거나 거의 항상 사실이거나 장기간 (일반적으로 특정 편향이 없을지라도) 일반적으로 동일하게 유지 될 것으로 예상되는 경우 "true"를 제공하는 다른 기술이 적용될 수 있습니다 조건 "(즉,"둘 다하지 말고 하나의 결과 무시 ")는 물론 가격이지만, 일부 결과를 무시하는 대신 실제로 작업을 건너 뛰게됩니다.

기술은 매우 간단 즉, 비교 (벡터화)을 수행 _mm_movemask_ps과 비교 마스크를 수집 한 다음 3 케이스를 가지고 :

  • 모든 비교는 같은 방식으로 가서 그들은 모두 false을했다, 실행 적절한 "do something"코드는 조건이 없어지기 때문에 벡터화하기가 더 쉬울 수도 있습니다.
  • 모든 비교는 같은 방식으로 수행되었으며 모두 true입니다.
  • 혼합되면 더 복잡한 논리를 사용하십시오. 당신이 필요에 따라 개별적으로 모든 비트를 확인할 수 있습니다 아니라 (를 결합 (스칼라 코드로 다시 하락,하지만 지금은 단지 1 FP는 훨씬에 대한 비교), 또는 "반복 만 이상 (UN) 설정 비트"트릭 중 하나를 사용 bitscan을 사용하여 실제 색인을 복구 할 수 있습니다.) 또는 가끔 마스킹 및 병합을 수행 할 수 있습니다.

3 가지 경우 모두 항상 관련이있는 것은 아닙니다. 일반적으로 조건부가 항상 같은 방식으로 적용되기 때문에 보통 3 가지 경우 모두 해당되는 것은 아니므로 "모두 같은"사례 중 하나를 매우 희귀하게 만들기 때문에 매우 간단합니다. "혼합".

이 기술은 항상 확실히 유용하지 않습니다. "혼합 된"사례는 복잡하고 느립니다. 빠른 경로는 일반성이 있어야하고 테스트 할 가치가있는 속도 여야합니다. 지점의 다른 측면에 비해 긴 모든 것을 고려하지 않습니다 좋은 간단한 벡터화 코드가있는 동안

는하지만 유용 할 수 있습니다, 측면 어쩌면 하나는, 매우 느리고 성가신입니다.예를 들어, 느린 쪽은 빠른 근사화 된 초월 함수에 대한 인수 축소를 수행해야 할 수도 있고, 아니면 내적을 취하기 전에 일부 벡터를 정규화하거나 행렬을 직교 화해야 할 수도 있습니다.

또는 양쪽면 모두 정확히 속도가 느리지 만 캐시에서 서로 다른 데이터를 제거 할 수 있습니다 (양 측면은 캐시에 들어있는 배열에 대한 루프이지만 배열은 함께 맞지 않습니다). 그래서 무조건적으로 수행하면 양쪽 모두가 느려집니다 그 (것)들의 아래로. 이것은 아마 진짜 일이지만, 나는 야생에서 그것을 보지 못했습니다 (아직).

또는 아마도 한쪽면 일 수 있습니다. 무조건 실행해야합니다. 일반적으로 파괴적인 일을 수행하고, 일부 IO는 수행합니다. 예를 들어, 오류 조건을 확인하고 로그하는 경우.