Burada Brian ve Wouter ve pjc50 ile aynı fikirdeyim.
Ayrıca, genel amaçlı olarak, özellikle CISC, işlemciler, talimatların hepsinde aynı verim bulunmadığını da eklemek isterim - karmaşık bir işlem basit bir işlemden daha fazla döngü alabilir.
X86'yı göz önünde bulundurun: AND
("ve" olan bir işlemdir) muhtemelen çok hızlıdır. Aynı şey için de geçerli NOT
. Biraz sökmeye bakalım:
Giriş kodu:
#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);}
Montaj üretme komutu:
gcc -O3 -c -S -mavx512f test.c
Çıkış Meclisi (kısaltılmış):
.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
Gördüğünüz gibi, 64 alt boyuttaki veri türleri için, işler sadece derleyicimin "yerel" bit genişliği gibi göründüğü kadar uzun sürüyor (dolayısıyla ve l ve l değil ).
Arada var olduğu gerçeği mov
, yalnızca eax
bir işlevin dönüş değerini içeren register olduğu gerçeğinden kaynaklanmaktadır . Normalde, edi
sonucu hesaplamak için genel amaçlı kayıt defterinde hesaplamanız gerekir.
64 bit için, aynı - sadece "quad" (dolayısıyla, sonunda q
) kelimeleriyle ve rax
/ rsi
yerine eax
/ ile edi
.
Görünüşe göre 128 bit operand ve daha fazlası için Intel bir "değil" işlemi gerçekleştirmeyi umursamadı; bunun yerine, derleyici bir all- 1
register üretir (yazmacın kendisiyle karşılaştırılması, kayıtlarda vdcmpeqd
talimat ile saklanan sonuç ), ve xor
s.
Kısacası: Birden fazla temel talimatla karmaşık bir işlem uygulayarak, işlemi yavaşlatmanız gerekmez - daha hızlı değilse, birden fazla talimatın işini yapan tek bir talimatın olması hiçbir avantajı yoktur.