O (1)
복잡도 기능이 고정 입력 크기 인 경우 memcmp()
과 유사해야하므로 내장 함수를 사용하여 약간 놀았습니다. 컴파일,내장 함수를 사용할 때 생성 된 어셈블리가 재정렬되는 이유는 무엇입니까?
#include <stdint.h>
#include <emmintrin.h>
int64_t f (int64_t a[4], int64_t b[4]) {
__m128i *x = (void *) a, *y = (void *) b, r[2], t;
int64_t *ret = (void *) &t;
r[0] = _mm_xor_si128(x[0], y[0]);
r[1] = _mm_xor_si128(x[1], y[1]);
t = _mm_or_si128(r[0], r[1]);
return (ret[0] | ret[1]);
}
이로 바뀝니다 : :이 작성 결국하지만
f:
movdqa xmm0, XMMWORD PTR [rdi]
movdqa xmm1, XMMWORD PTR [rdi+16]
pxor xmm0, XMMWORD PTR [rsi]
pxor xmm1, XMMWORD PTR [rsi+16]
por xmm0, xmm1
movq rdx, xmm0
pextrq rax, xmm0, 1
or rax, rdx
ret
http://goo.gl/EtovJa (Godbolt 컴파일러 탐색기) 그 후
을, 나는에 호기심이되었다 내재적 함수를 사용해야하는지 아니면 유형을 필요로하는지 여부와 상관없이 일반 연산자를 사용할 수 있습니다. 나는 그 (정말 만 세 SSE 라인) 위의 코드를 수정이와 함께 결국 :
#include <stdint.h>
#include <emmintrin.h>
int64_t f (int64_t a[4], int64_t b[4]) {
__m128i *x = (void *) a, *y = (void *) b, r[2], t;
int64_t *ret = (void *) &t;
r[0] = x[0]^y[0];
r[1] = x[1]^y[1];
t = r[0] | r[1];
return (ret[0] | ret[1]);
}
대신에 컴파일한다 :
f:
movdqa xmm0, XMMWORD PTR [rdi+16]
movdqa xmm1, XMMWORD PTR [rdi]
pxor xmm0, XMMWORD PTR [rsi+16]
pxor xmm1, XMMWORD PTR [rsi]
por xmm0, xmm1
movq rdx, xmm0
pextrq rax, xmm0, 1
or rax, rdx
ret
http://goo.gl/oDHF3z (Godbolt 컴파일러 탐색기)
이제 기능적으로 (AFAICT) 두 컴파일 된 어셈블리 출력이 동일합니다. 사실, 그들은 똑같은 시간과 자원을 필요로하는 것처럼 보입니다. 그들은 똑같이 수행 할 것입니다. 그러나 처음 네 명령어의 피연산자가 왜 움직여 졌는지 궁금합니다. 한 방향으로 다른 방향으로 향하는 이유에 대한 특별한 이유가 있습니까?
주 : 두 기능 모두 동일한 플래그로 GCC로 컴파일되었습니다.
표준은 이러한 경우에 평가 순서를 지정하지 않고 컴파일러에서 변경하거나 임의로 인터리브 할 수 있습니다. – Leeor
아,하지만 그건 질문의 대상이 아니에요.이 질문은 어떤 규칙이 그것을 허락 하는지를 묻지는 않지만, 컴파일러가 정확히 그런 방식으로 행동하도록 동기를 부여합니다. – haneefmubarak
그래, 그게 그냥 코멘트 (그것은 첫 번째 코멘트 btw에 대한 답변 아니 었 downvote),하지만 그것은 극도로 특정 컴파일러 및 버전 (및 플래그 집합)에 대한 로컬 질문을 만듭니다. 컴파일러가 코드를 움직이는 데는 여러 가지 이유가있을 수 있습니다. 이는 완전히 다른 최적화 단계로 인해 발생할 수 있습니다. gcc '-fdump-tree-all을 사용하고 어떤 패스가 다른지 확인할 수 있습니다. – Leeor