나는 Brian, Wouter와 pjc50에 동의하고 싶습니다.
또한 범용, 특히 CISC 프로세서에서 명령어는 처리량이 모두 같지 않다는 점을 추가하고 싶습니다. 복잡한 작업은 단순히 더 많은주기를 필요로 할 수 있습니다.
X86 : AND
( "and"연산) 매우 빠르다고 생각하십시오. 동일합니다 NOT
. 약간의 분해를 살펴 보겠습니다.
입력 코드 :
#include <immintrin.h>
#include <stdint.h>
__m512i nand512(__m512i a, __m512i b){return ~(a&b);}
__m256i nand256(__m256i a, __m256i b){return ~(a&b);}
__m128i nand128(__m128i a, __m128i b){return ~(a&b);}
uint64_t nand64(uint64_t a, uint64_t b){return ~(a&b);}
uint32_t nand32(uint32_t a, uint32_t b){return ~(a&b);}
uint16_t nand16(uint16_t a, uint16_t b){return ~(a&b);}
uint8_t nand8(uint8_t a, uint8_t b){return ~(a&b);}
어셈블리 생성 명령 :
gcc -O3 -c -S -mavx512f test.c
출력 어셈블리 (단축 됨) :
.file "test.c"
nand512:
.LFB4591:
.cfi_startproc
vpandq %zmm1, %zmm0, %zmm0
vpternlogd $0xFF, %zmm1, %zmm1, %zmm1
vpxorq %zmm1, %zmm0, %zmm0
ret
.cfi_endproc
nand256:
.LFB4592:
.cfi_startproc
vpand %ymm1, %ymm0, %ymm0
vpcmpeqd %ymm1, %ymm1, %ymm1
vpxor %ymm1, %ymm0, %ymm0
ret
.cfi_endproc
nand128:
.LFB4593:
.cfi_startproc
vpand %xmm1, %xmm0, %xmm0
vpcmpeqd %xmm1, %xmm1, %xmm1
vpxor %xmm1, %xmm0, %xmm0
ret
.cfi_endproc
nand64:
.LFB4594:
.cfi_startproc
movq %rdi, %rax
andq %rsi, %rax
notq %rax
ret
.cfi_endproc
nand32:
.LFB4595:
.cfi_startproc
movl %edi, %eax
andl %esi, %eax
notl %eax
ret
.cfi_endproc
nand16:
.LFB4596:
.cfi_startproc
andl %esi, %edi
movl %edi, %eax
notl %eax
ret
.cfi_endproc
nand8:
.LFB4597:
.cfi_startproc
andl %esi, %edi
movl %edi, %eax
notl %eax
ret
.cfi_endproc
보시다시피, 64 크기 이하의 데이터 유형의 경우 모든 것이 단순히 긴 것으로 처리되므로 (따라서 l이 아닌 l ) 컴파일러의 "네이티브"비트 폭이므로 보입니다.
거기에 있다는 사실은 mov
사실로 인해 아니라 사이에요 eax
함수의 반환 값이 들어있는 레지스터입니다. 일반적 edi
으로 범용 레지스터에서 계산하여 결과를 계산합니다.
단지 "쿼드"(따라서, 후행 - 64 비트의 경우, 동일의 q
) 단어 및 rax
/ rsi
대신 eax
/ edi
.
128 비트 피연산자 이상에서는 인텔이 "비"연산을 구현하지 않았던 것 같습니다. 대신, 컴파일러는 모든 1
레지스터 (자체와 레지스터의 자체 비교, vdcmpeqd
명령어 와 함께 레지스터에 저장된 결과 )를 생성 xor
합니다.
간단히 말해서 : 여러 기본 명령으로 복잡한 작업을 구현하면 작업 속도가 느려질 필요는 없습니다. 여러 명령이 더 빠르지 않은 경우 여러 명령을 수행하는 명령 하나만 있으면 이점이 없습니다.