Tôi muốn đồng ý với Brian ở đây, và Wouter và pjc50.
Tôi cũng muốn thêm rằng trên mục đích chung, đặc biệt là CISC, các bộ xử lý, các hướng dẫn đều không có cùng thông lượng - một thao tác phức tạp có thể chỉ cần thực hiện nhiều chu kỳ dễ dàng hơn.
Hãy xem xét X86: AND
(đó là một hoạt động "và") có thể rất nhanh. Cùng đi cho NOT
. Hãy xem xét một chút về sự tháo gỡ:
Mã đầu vào:
#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);}
Lệnh sản xuất lắp ráp:
gcc -O3 -c -S -mavx512f test.c
Đầu ra hội (rút ngắn):
.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
Như bạn có thể thấy, đối với các loại dữ liệu có kích thước dưới 64, mọi thứ chỉ đơn giản được xử lý dưới dạng dài (do đó và l và không phải l ), vì đó có vẻ là băng thông "gốc" của trình biên dịch của tôi.
Việc có mov
một ở giữa chỉ là do thực tế eax
là thanh ghi chứa giá trị trả về của hàm. Thông thường, bạn chỉ cần tính toán trong edi
đăng ký mục đích chung để tính toán với kết quả.
Đối với 64 bit, nó giống nhau - chỉ với các từ "quad" (do đó, trailing q
) và rax
/ rsi
thay vì eax
/ edi
.
Có vẻ như đối với các toán hạng 128 bit và lớn hơn, Intel đã không quan tâm đến việc thực hiện thao tác "không"; thay vào đó, trình biên dịch tạo ra một 1
thanh ghi tất cả (tự so sánh thanh ghi với chính nó, kết quả được lưu trong thanh ghi với vdcmpeqd
lệnh) và xor
s đó.
Tóm lại: Bằng cách triển khai một thao tác phức tạp với nhiều hướng dẫn cơ bản, bạn không nhất thiết phải làm chậm hoạt động - đơn giản là không có lợi thế nào khi có một lệnh thực hiện nhiều lệnh nếu không nhanh hơn.