Mengapa desainer x86 (atau arsitektur CPU lainnya juga) memutuskan untuk tidak memasukkannya? Ini adalah gerbang logika yang dapat digunakan untuk membangun gerbang logika lain, sehingga cepat sebagai instruksi tunggal. Daripada chaining not
dan and
instruksi (keduanya dibuat dari nand
), mengapa tidak ada nand
instruksi?
52
BIC
instruksi, yaitua & ~b
. Arm Thumb-2 memilikiORN
instruksi yaitu~(a | b)
. ARM cukup modern. Pengkodean instruksi dalam set instruksi CPU memiliki biayanya. Jadi hanya yang paling "berguna" yang masuk ke ISA.~(((a << 1) | (b >> 1)) | 0x55555555)
instruksi. Tujuannya adalah agar~(((a << 1) | (b >> 1)) | 0x55555555)
dapat diterjemahkan ke dalam satu instruksi, bukan 6. Jadi, mengapa tidak?Jawaban:
http://www.ibm.com/support/knowledgecenter/ssw_aix_61/com.ibm.aix.alangref/idalangref_nand_nd_instrs.htm : POWER memiliki NAND.
Tetapi umumnya CPU modern dibangun untuk mencocokkan pembuatan kode otomatis oleh kompiler, dan bitwise NAND sangat jarang diperlukan. Bitwise AND dan OR digunakan lebih sering untuk memanipulasi bitfield dalam struktur data. Faktanya, SSE memiliki AND-NOT tetapi tidak NAND.
Setiap instruksi memiliki biaya dalam logika decode dan mengkonsumsi opcode yang dapat digunakan untuk sesuatu yang lain. Khususnya dalam penyandian panjang variabel seperti x86, Anda dapat kehabisan opcode pendek dan harus menggunakan yang lebih lama, yang berpotensi memperlambat semua kode.
sumber
if(windowType & ~WINDOW_RESIZABLE) { ... do stuff for variable-sized windows ... }
foo
adalah uint64_t, pernyataanfoo &= ~something;
tersebut terkadang dapat menghapus lebih banyak bit daripada yang dimaksudkan, tetapi jika ada&~=
operator masalah seperti itu dapat dihindari.WINDOW_RESIZABLE
adalah konstanta, maka pengoptimal harus mengevaluasi~WINDOW_RESIZABLE
pada waktu kompilasi, jadi ini hanya DAN pada waktu berjalan.Biaya fungsi ALU tersebut adalah
1) logika yang melakukan fungsi itu sendiri
2) pemilih yang memilih hasil fungsi ini, bukan yang lain dari semua fungsi ALU
3) biaya memiliki opsi ini dalam set instruksi (dan tidak memiliki beberapa fungsi bermanfaat lainnya)
Saya setuju dengan Anda bahwa biaya 1) sangat kecil. Namun biaya 2) dan 3) hampir tidak tergantung pada fungsinya. Saya pikir dalam hal ini 3) biaya (bit yang digunakan dalam instruksi) adalah alasan untuk tidak memiliki instruksi khusus ini. Bit dalam instruksi adalah sumber daya yang sangat langka untuk perancang CPU / arsitektur.
sumber
Putar balik - pertama-tama lihat mengapa Nand populer dalam desain logika perangkat keras - ia memiliki beberapa properti yang berguna di sana. Kemudian tanyakan apakah properti itu masih berlaku dalam instruksi CPU ...
TL / DR - tidak, jadi tidak ada kerugian untuk menggunakan Dan, Atau atau Tidak sebagai gantinya.
Keuntungan terbesar untuk logika Nand yang ditanamkan adalah kecepatan, diperoleh dengan mengurangi jumlah level logika (tahap transistor) antara input dan output sirkuit. Dalam CPU, kecepatan clock ditentukan oleh kecepatan operasi yang jauh lebih kompleks seperti penambahan, jadi mempercepat operasi DAN tidak akan memungkinkan Anda untuk meningkatkan laju jam.
Dan berapa kali Anda perlu menggabungkan instruksi lain semakin kecil - cukup sehingga Nand benar-benar tidak mendapatkan ruang di set instruksi.
sumber
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 untukNOT
. Mari kita lihat sedikit pembongkaran:Kode input:
Perintah untuk menghasilkan perakitan:
Majelis Output (disingkat):
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 bahwaeax
register yang berisi nilai pengembalian fungsi. Biasanya, Anda hanya perlu menghitung diedi
register tujuan umum untuk menghitung dengan hasilnya.Untuk 64 bit, itu sama - hanya dengan kata "quad" (karenanya, tertinggal
q
), danrax
/rsi
bukannyaeax
/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 denganvdcmpeqd
instruksi), danxor
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.
sumber
Pertama jangan bingung operasi bitwise dan logis.
Operasi bitwise biasanya digunakan untuk mengatur / menghapus / beralih / memeriksa bit dalam bitfields. Tak satu pun dari operasi ini memerlukan nand ("dan tidak", juga dikenal sebagai "bit clear" lebih berguna).
Operasi logis dalam sebagian besar bahasa pemrograman modern dievaluasi menggunakan logika hubung singkat. Jadi biasanya diperlukan pendekatan berbasis cabang untuk mengimplementasikannya. Bahkan ketika kompiler dapat menentukan bahwa hubungan pendek vs evaluasi lengkap tidak membuat perbedaan pada perilaku program, operan untuk operasi logis biasanya tidak dalam bentuk yang mudah untuk mengimplementasikan ekspresi menggunakan operasi asm bitwise.
sumber
NAND sering tidak diimplementasikan secara langsung karena memiliki instruksi AND secara implisit memberi Anda kemampuan untuk melompat pada kondisi NAND.
Melakukan operasi logis dalam CPU sering menetapkan bit dalam register bendera.
Sebagian besar register bendera memiliki bendera NOL. Bendera nol diatur jika hasil operasi logis adalah nol, dan dihapus jika tidak.
Kebanyakan CPU modern memiliki instruksi lompatan yang melompat jika flag nol diatur. Mereka juga memiliki istruction yang melompat jika bendera nol tidak diatur.
DAN dan NAND adalah pelengkap. Jika hasil dari operasi AND adalah nol maka hasil dari operasi NAND adalah 1, dan sebaliknya.
Jadi jika Anda ingin lompat atau NAND dari dua nilai benar maka cukup lakukan operasi DAN, dan lompat jika bendera nol diatur.
Jadi jika Anda ingin lompat atau jika NAND dari dua nilai salah maka lakukan saja operasi AND, dan lompat jika bendera nolnya jelas.
sumber
Hanya karena sesuatu itu murah tidak berarti itu hemat biaya .
Jika kami menggunakan argumentasi ad absurdum Anda, kami akan mencapai kesimpulan bahwa CPU sebagian besar terdiri dari ratusan rasa instruksi NOP - karena mereka adalah yang termurah untuk diterapkan.
Atau bandingkan dengan instrumen keuangan: apakah Anda akan membeli obligasi $ 1 dengan pengembalian 0,01% hanya karena Anda bisa? Tidak, Anda lebih suka menyimpan dolar itu sampai Anda memiliki cukup uang untuk membeli obligasi $ 10 dengan pengembalian yang lebih baik. Hal yang sama berlaku dengan anggaran silikon pada CPU: itu efektif untuk memotong banyak ops murah tapi tidak berguna seperti NAND, dan menempatkan transistor yang diselamatkan menjadi sesuatu yang jauh lebih mahal tetapi benar-benar berguna.
Tidak ada perlombaan untuk memiliki ops sebanyak mungkin. Seperti RISC vs CISC telah membuktikan apa yang Turing ketahui sejak awal: lebih sedikit lebih banyak. Sebenarnya lebih baik memiliki ops sesedikit mungkin.
sumber
nop
tidak dapat mengimplementasikan semua gerbang logika lainnya, tetapinand
ataunor
dapat, secara efektif membuat kembali setiap instruksi yang diimplementasikan dalam CPU dalam perangkat lunak. Jika kita mengambil pendekatan RISC, itu adalah ..gate
daninstruction
. Gates digunakan untuk mengimplementasikan instruksi, bukan sebaliknya.NOP
adalah instruksi, bukan gerbang. Dan ya, CPU mengandung ribuan atau bahkan mungkin jutaan gerbang NAND untuk mengimplementasikan semua instruksi. Hanya saja bukan instruksi "NAND".nand
ada satu gerbang yang bisa digunakan untuk mengimplementasikan gerbang lain; tetapi Anda sudah memiliki semua instruksi lainnya . Menerapkannya kembali menggunakannand
instruksi akan lebih lambat . Dan mereka digunakan terlalu sering untuk mentolerir itu, tidak seperti contoh spesifik cherry-pick Anda di mananand
akan menghasilkan kode lebih pendek (bukan kode lebih cepat , hanya lebih pendek); tapi itu sangat jarang, dan manfaatnya tidak sebanding dengan biayanya.((((()))))
bukannya 5, kan? Lima hanya satu nomor tertentu, itu terlalu membatasi - set jauh lebih umum: Pnand
mengimplementasikan semua gerbang, oleh karena itu secara implisitnand
dapat mengimplementasikan semua instruksi lainnya. Kemudian, jika seorang programmer memilikinand
instruksi yang tersedia, ia dapat menemukan instruksinya sendiri ketika berpikir di gerbang logika. Apa yang saya maksud dari awal adalah bahwa jika itu sangat mendasar, mengapa tidak diberikan instruksi sendiri (yaitu, opcode dalam logika decoder), sehingga seorang programmer dapat menggunakan instruksi tersebut. Tentu saja setelah saya dijawab, sekarang saya tahu itu tergantung pada penggunaan perangkat lunak.Pada tingkat perangkat keras, baik nand atau tidak adalah operasi logika dasar. Bergantung pada teknologinya (atau tergantung apa yang Anda panggil 1 dan apa yang Anda panggil 0), baik nand atau pun tidak dapat diimplementasikan dengan cara yang sangat sederhana dan sederhana.
Jika kita mengabaikan kasus "tidak", semua logika lain dibangun dari nand. Tetapi bukan karena ada beberapa bukti ilmu komputer bahwa semua operasi logika dapat dibangun dari dan - alasannya adalah bahwa tidak ada metode dasar untuk membangun xor, atau, dan lain-lain yang lebih baik daripada membangunnya dari nand's.
Untuk instruksi komputer, situasinya berbeda. Instruksi nand dapat diimplementasikan, dan itu akan menjadi sedikit lebih murah daripada mengimplementasikan xor, misalnya. Tetapi hanya sedikit, karena logika yang menghitung hasilnya kecil dibandingkan dengan logika yang menerjemahkan kode, memindahkan operan, memastikan bahwa satu operasi hanya dihitung, dan mengambil hasilnya dan mengirimkannya ke tempat yang tepat. Setiap instruksi membutuhkan satu siklus untuk dieksekusi, sama dengan penambahan yang sepuluh kali lebih rumit dalam hal logika. Penghematan nand vs xor akan diabaikan.
Yang penting kemudian adalah berapa banyak instruksi yang diperlukan untuk operasi yang sebenarnya dilakukan oleh kode biasa . Nand tidak ada di dekat bagian atas daftar operasi yang biasa diminta. Adalah jauh lebih umum bahwa dan, atau, tidak diminta. Perancang prosesor dan set instruksi akan memeriksa banyak kode yang ada dan menentukan bagaimana instruksi yang berbeda akan mempengaruhi kode itu. Mereka kemungkinan besar menemukan bahwa menambahkan instruksi nand akan menyebabkan pengurangan sangat sedikit dalam jumlah instruksi prosesor yang mengeksekusi untuk menjalankan kode khas, dan mengganti beberapa instruksi yang ada dengan nand akan meningkatkan jumlah instruksi yang dilakukan.
sumber
Hanya karena NAND (atau NOR) dapat mengimplementasikan semua gerbang dalam logika kombinasional, tidak menerjemahkan ke operator bitwise yang efisien dengan cara yang sama. Untuk menerapkan DAN hanya menggunakan operasi NAND, di mana c = a DAN b, Anda harus memiliki c = a NAND b, lalu b = -1, lalu c = c NAND b (untuk TIDAK). Operasi bitwise logika dasar adalah AND, OR, EOR, NOT, NAND, dan NEOR. Itu tidak banyak untuk dibahas, dan empat yang pertama biasanya dibangun. Dalam logika kombinasional, sirkuit logika dasar hanya dibatasi oleh jumlah gerbang yang tersedia, yang merupakan permainan bola yang sepenuhnya berbeda. Jumlah interkoneksi yang mungkin dalam array gerbang yang dapat diprogram, yang terdengar seperti apa yang benar-benar Anda cari, akan menjadi jumlah yang sangat besar. Beberapa prosesor memang memiliki larik gerbang bawaan.
sumber
Anda tidak menerapkan gerbang logika hanya karena memiliki kelengkapan fungsional, terutama jika gerbang logika lain tersedia secara native. Anda menerapkan apa yang cenderung paling sering digunakan oleh kompiler.
NAND, NOR dan XNOR sangat jarang dibutuhkan. Selain operator bitwise klasik AND, OR dan XOR, hanya ANDN (
~a & b
) - yang bukan NAND (~(a & b)
) - yang memiliki utilitas praktis. Jika ada, CPU harus mengimplementasikannya (dan memang beberapa CPU memang mengimplementasikan ANDN).Untuk menjelaskan utilitas praktis ANDN, bayangkan Anda memiliki bitmask yang menggunakan banyak bit, tetapi Anda hanya tertarik pada beberapa di antaranya, yaitu sebagai berikut:
Biasanya Anda ingin memeriksa tentang minat Anda pada bitmask apakah
Mari kita mulai dengan mengumpulkan sedikit minat Anda:
1. Semua bit yang menarik ditetapkan: ANDN + bitwise TIDAK logis
Katakanlah Anda ingin tahu apakah minat Anda sudah ditentukan. Anda bisa melihatnya seperti
(my_bitmask & IT_IS_FRIDAY) && (my_bitmask & IT_IS_WARM) && (my_bitmask & THE_SUN_SHINES)
. Namun biasanya Anda akan menciutkannya menjadi2. Setidaknya satu bit minat ditetapkan: bitwise AND
Sekarang katakanlah Anda ingin tahu apakah setidaknya ada sedikit minat yang ditetapkan. Anda bisa melihatnya sebagai
(my_bitmask & IT_IS_FRIDAY) || (my_bitmask & IT_IS_WARM) || (my_bitmask & THE_SUN_SHINES)
. Namun biasanya Anda akan menciutkannya menjadi3. Setidaknya satu bit minat tidak disetel: ANDN bitwise
Sekarang, katakanlah Anda ingin tahu apakah setidaknya ada sedikit minat yang tidak ditetapkan. Anda bisa melihatnya sebagai
!(my_bitmask & IT_IS_FRIDAY) || !(my_bitmask & IT_IS_WARM) || !(my_bitmask & THE_SUN_SHINES)
. Namun biasanya Anda akan menciutkannya menjadi4. Tidak ada sedikit minat yang diatur: bitwise AND + logical NOT
Sekarang katakanlah Anda ingin tahu apakah semua bit yang menarik tidak ditetapkan. Anda bisa melihatnya sebagai
!(my_bitmask & IT_IS_FRIDAY) && !(my_bitmask & IT_IS_WARM) && !(my_bitmask & THE_SUN_SHINES)
. Namun biasanya Anda akan menciutkannya menjadiIni adalah operasi umum yang dilakukan pada bitmask, ditambah bitwise klasik OR dan XOR. Saya pikir meskipun bahasa (yang bukan CPU ) harus mencakup operator NAND, NOR dan XNOR bitwise (yang simbolnya akan
~&
,~|
dan~^
), meskipun jarang digunakan. Saya tidak akan menyertakan operator ANDN dalam bahasa, karena itu tidak komutatif (a ANDN b
tidak sama denganb ANDN a
) - lebih baik untuk menulis~a & b
daripadaa ANDN b
, mantan menunjukkan lebih jelas asimetri operasi.sumber