나는이 질문에서 유용한 것을 배웠다. 일부 스칼라 코드
extern foo2(int x, int y);
void foo(int x, int y) {
if((x || y)!=0) foo2(x,y);
}
에서하자 첫 모습이 gcc -O3 -S -masm=intel test.c
같은이를 컴파일하고 중요한 어셈블리는
mov eax, edi ; edi = x, esi = y -> copy x into eax
or eax, esi ; eax = x | y and set zero flag in FLAGS if zero
jne .L4 ; jump not zero
이제
의이 SIMD 제로를 등록 테스트를 살펴 보자입니다. 스칼라 코드와 달리 SIMD FLAGS 레지스터는 없다. 그러나 SSE4.1에는 스칼라 FLAGS 레지스터에 제로 플래그 (및 캐리 플래그)를 설정할 수있는 SIMD 테스트 명령어가있다. c99 -msse4.1 -O3 -masm=intel -S test_SSE.c
과 중요한 어셈블리
extern foo2(__m128i x, __m128i y);
void foo(__m128i x, __m128i y) {
__m128i z = _mm_or_si128(x,y);
if (!_mm_testz_si128(z,z)) foo2(x,y);
}
컴파일이 한 번 더 명령을 소요
movdqa xmm2, xmm0 ; xmm0 = x, xmm1 = y, copy x into xmm2
por xmm2, xmm1 ; xmm2 = x | y
ptest xmm2, xmm2 ; set zero flag if zero
jne .L4 ; jump not zero
공지 사항 때문에 압축 된 비트 단위 OR 제로 플래그를 설정하지 않습니다. 스칼라 버전과 SIMD 버전 모두 추가 레지스터 (스칼라의 경우 eax
, SIMD의 경우 xmm2
)를 사용해야합니다. 질문에 대한 답변을 얻으려면 현재 해결 방법이 최선입니다.
그러나 SSE4.1 이상 프로세서가없는 경우 _mm_movemask_epi8
을 사용해야합니다. 단지 SSE2를 필요로 또 다른 대안은 중요한 조립이가 SSE4.1 ptest
명령으로 다음 한 번 더 교육을 필요로하는
movdqa xmm2, xmm0
por xmm2, xmm1
pmovmskb eax, xmm2
test eax, eax
jne .L4
공지 사항입니다 _mm_movemask_epi8
extern foo2(__m128i x, __m128i y);
void foo(__m128i x, __m128i y) {
if (_mm_movemask_epi8(_mm_or_si128(x,y))) foo2(x,y);
}
사용하는 것입니다.
지금까지는 ptest
보다 대기 시간이 더 우수하기 때문에 pmovmaskb
명령을 사용했습니다. 그러나, Haswell 전에 이것을 깨달았습니다. Haswell에서 대기 시간이 pmovmaskb
은 대기 시간이 ptest
보다 나쁩니다. 둘 다 동일한 처리량을가집니다. 하지만이 경우에는별로 중요하지 않습니다. 중요한 것은 (전에는 깨닫지 못했지만) pmovmaskb
은 FLAGS 레지스터를 설정하지 않았기 때문에 다른 명령이 필요하다는 것입니다. 이제 중요한 루프에서 ptest
을 사용할 것입니다. 질문 해 주셔서 감사합니다.
편집 : OP에서 제안한 것처럼 다른 SSE 레지스터를 사용하지 않고이 작업을 수행 할 수있는 방법이 있습니다.
extern foo2(__m128i x, __m128i y);
void foo(__m128i x, __m128i y) {
if (_mm_movemask_epi8(x) | _mm_movemask_epi8(y)) foo2(x,y);
}
GCC에서 관련 조립체는 :
pmovmskb eax, xmm0
pmovmskb edx, xmm1
or edx, eax
jne .L4
대신 다른 XMM이 두 스칼라 레지스터를 사용하는 레지스터 사용.
지침이 적을수록 반드시 더 나은 성능을 의미하지는 않습니다. 다음 중 가장 적합한 솔루션은 무엇입니까? 찾아 내기 위해 각자를 테스트해야합니다.
더 나은 무엇을 희망 할 수 있습니까? OR을 최대한 활용하십시오. –
'_mm_testz_si128' 대신'_mm_movemask_epi8'을 사용했지만 실제로는 _mm_testz_si128'이 일반적으로 더 좋습니다. '_mm_movemask_epi8'는 Nahalem과 Westmere에서만 지연 시간이 짧습니다. 그러나 Haswell에 더 나쁘다. 하지만 더 중요한 것은 FLAGS 레지스터에 0이나 carry 플래그를 설정하지 않지만'_mm_testz_si128'는 플래그를 설정한다는 것입니다. 이제 네가 가진 것이 아마도 최고 일 것이다. –
사실 이것은 내가 찾고있는 토론 유형이었습니다. 나는 그것을 답으로 표시 하겠지만 그것은 논평이다. – ChipK