Saya ingin setuju dengan Brian di sini, dan Wouter dan pjc50.
Saya juga ingin menambahkan bahwa untuk keperluan umum, terutama CISC, prosesor, instruksi tidak semua memiliki throughput yang sama - operasi yang rumit mungkin hanya membutuhkan lebih banyak siklus yang mudah.
Pertimbangkan X86: AND
(yang merupakan operasi "dan") mungkin sangat cepat. Sama berlaku untuk NOT
. Mari kita lihat sedikit pembongkaran:
Kode input:
#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);}
Perintah untuk menghasilkan perakitan:
gcc -O3 -c -S -mavx512f test.c
Majelis Output (disingkat):
.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
Seperti yang Anda lihat, untuk tipe data berukuran sub-64, semuanya ditangani dengan mudah (karenanya dan l dan bukan l ), karena itulah "bandwidth" asli dari kompiler saya, seperti yang terlihat.
Fakta bahwa ada mov
di antara hanya karena fakta bahwa eax
register yang berisi nilai pengembalian fungsi. Biasanya, Anda hanya perlu menghitung di edi
register tujuan umum untuk menghitung dengan hasilnya.
Untuk 64 bit, itu sama - hanya dengan kata "quad" (karenanya, tertinggal q
), dan rax
/ rsi
bukannya eax
/ edi
.
Tampaknya untuk operan 128 bit dan lebih besar, Intel tidak peduli untuk mengimplementasikan operasi "tidak"; sebagai gantinya, kompiler menghasilkan 1
register semua (perbandingan sendiri dari register dengan dirinya sendiri, hasil disimpan dalam register dengan vdcmpeqd
instruksi), dan xor
s itu.
Singkatnya: Dengan menerapkan operasi yang rumit dengan beberapa instruksi dasar, Anda tidak perlu memperlambat operasi - sama sekali tidak ada manfaatnya memiliki satu instruksi yang melakukan pekerjaan beberapa instruksi jika tidak lebih cepat.