Saya pikir saya sedang mencari jawaban untuk pertanyaan trivia. Saya mencoba memahami mengapa arsitektur MIPS menggunakan nilai "nol" eksplisit dalam register ketika Anda dapat mencapai hal yang sama dengan hanya XOR'ing register apa pun terhadap dirinya sendiri. Orang bisa mengatakan bahwa operasi sudah dilakukan untuk Anda; Namun, saya tidak bisa membayangkan situasi di mana Anda akan menggunakan banyak nilai "nol". Saya membaca makalah asli Hennessey, dan hanya menetapkan nol sebagai fakta tanpa pembenaran nyata.
Apakah alasan logis untuk memiliki tugas biner kode-nol nol ada?
pembaruan: Dalam 8k dari executable dari xc32-gcc untuk inti MIPS di PIC32MZ, saya punya satu contoh "nol".
add t3,t1,zero
jawaban aktual: Saya memberikan hadiah kepada orang yang memiliki informasi tentang MIPS dan kode kondisi. Jawabannya sebenarnya terletak pada arsitektur MIPS untuk kondisi. Meskipun pada awalnya saya tidak ingin menetapkan waktu untuk ini, saya meninjau arsitektur untuk opensparc , MIPS-V , dan OpenPOWER (dokumen ini bersifat internal) dan di sini adalah ringkasan temuan. Daftar R0 diperlukan untuk perbandingan pada cabang karena arsitektur pipa.
- bilangan bulat dibandingkan dengan nol dan cabang (bgez, bgtz, blez, bltz)
- integer membandingkan dua register dan cabang (beq, bne)
- integer membandingkan dua register dan trap (teq, tge, tlt, tne)
- integer bandingkan register dan segera dan trap (teqi, tgei, tlti, tnei)
Itu hanya datang ke bagaimana hardware terlihat dalam implementasi. Dari manual MIPS-V, ada kutipan tanpa referensi di halaman 68:
Cabang bersyarat dirancang untuk mencakup operasi perbandingan aritmatika antara dua register (seperti yang juga dilakukan dalam PA-RISC dan Xtensa ISA), daripada menggunakan kode kondisi (x86, ARM, SPARC, PowerPC), atau hanya membandingkan satu register dengan nol ( Alpha, MIPS), atau dua register only for equality (MIPS). Desain ini dimotivasi oleh pengamatan bahwa gabungan perintah bandingkan dan cabang ke dalam pipa biasa, menghindari status kode kondisi tambahan atau penggunaan register sementara, dan mengurangi ukuran kode statis dan instruksi dinamis mengambil trac. Poin lain adalah bahwa perbandingan terhadap nol memerlukan penundaan sirkuit non-trivial (terutama setelah pindah ke logika statis dalam proses lanjutan) dan karenanya hampir semahal perbandingan besarnya aritmatika. Keuntungan lain dari instruksi membandingkan-dan-cabang menyatu adalah bahwa cabang diamati sebelumnya dalam aliran instruksi front-end, dan dengan demikian dapat diprediksi sebelumnya. Mungkin ada keuntungan untuk desain dengan kode kondisi dalam kasus di mana beberapa cabang dapat diambil berdasarkan kode kondisi yang sama, tetapi kami percaya kasus ini relatif jarang.
Dokumen MIPS-V tidak mengenai penulis bagian yang dikutip. Saya berterima kasih kepada semua orang atas waktu dan pertimbangan mereka.
sumber
Jawaban:
Daftar nol pada RISC CPU bermanfaat karena dua alasan:
Ini adalah konstanta yang berguna
Bergantung pada batasan ISA, Anda tidak dapat menggunakan literal dalam beberapa instruksi penyandian, tetapi Anda dapat yakin Anda dapat menggunakannya
r0
untuk mendapatkan 0.Ini dapat digunakan untuk mensintesis instruksi lain
Ini mungkin poin paling penting. Sebagai perancang ISA, Anda dapat menukar register tujuan umum dengan register nol untuk dapat mensintesis instruksi berguna lainnya. Instruksi mensintesis itu baik karena dengan instruksi yang kurang aktual, Anda memerlukan lebih sedikit bit untuk meng-encode operasi dalam opcode, yang membebaskan ruang di ruang instruksi encoding. Anda dapat menggunakan ruang itu untuk memiliki mis. Alamat dan / atau literal alamat yang lebih besar.
Semantik register nol seperti
/dev/zero
pada sistem * nix: semua yang ditulis untuk itu dibuang, dan Anda selalu membaca kembali 0.Mari kita lihat beberapa contoh bagaimana kita dapat membuat instruksi semu dengan bantuan daftar
r0
nol:Kasus MIPS
Saya melihat lebih dekat pada set instruksi MIPS. Ada beberapa instruksi palsu yang menggunakan
$zero
; mereka terutama digunakan untuk cabang. Berikut adalah beberapa contoh dari apa yang saya temukan:Adapun mengapa Anda hanya menemukan satu contoh
$zero
register dalam pembongkaran Anda, mungkin pembongkaran Anda yang cukup pintar untuk mengubah urutan instruksi yang dikenal menjadi instruksi semu yang setara.Apakah daftar nol itu benar - benar bermanfaat?
Well, rupanya, ARM menemukan memiliki register nol cukup berguna sehingga pada (ARMv8-A core baru mereka, yang mengimplementasikan AArch64, sekarang ada register nol dalam mode 64-bit; tidak ada daftar nol sebelumnya. (Register agak istimewa, dalam beberapa konteks penyandian, ini adalah register nol, sedangkan register lain menunjuk stack pointer )
sumber
slt
,slti
,sltu
).Sebagian besar implementasi ARM / POWER / SPARC memiliki register RAZ tersembunyi
Anda mungkin berpikir bahwa ARM32, SPARC dll tidak memiliki 0 register tetapi kenyataannya mereka melakukannya! Pada tingkat mikro-arsitektur, sebagian besar insinyur desain CPU menambahkan register 0 yang mungkin tidak terlihat oleh perangkat lunak (register nol ARM tidak terlihat) dan menggunakan register nol itu untuk merampingkan decode instruksi.
Pertimbangkan desain ARM32 modern khas yang memiliki register perangkat lunak tidak terlihat, katakan R16 berkabel ke 0. Pertimbangkan beban ARM32, banyak kasus instruksi memuat ARM32 termasuk dalam salah satu bentuk ini (Abaikan pengindeksan pra-posting sementara waktu untuk membuat diskusi tetap sederhana ) ...
Di dalam prosesor, ini diterjemahkan ke jenderal
sebelum memasuki tahap masalah di mana register dibaca. Perhatikan bahwa rx mewakili register untuk menulis kembali alamat yang diperbarui. Berikut ini beberapa contoh dekode:
Pada level sirkuit, ketiga beban sebenarnya adalah instruksi internal yang sama dan cara mudah untuk mendapatkan ortogonalitas semacam ini adalah dengan membuat ground register R16. Karena R16 selalu di-ground, instruksi ini secara alami memecahkan kode dengan benar tanpa logika tambahan. Memetakan kelas instruksi ke format internal tunggal sangat membantu dalam implementasi superscalar karena mengurangi kompleksitas logika.
Alasan lain adalah cara efisien untuk membuang menulis. Instruksi dapat dinonaktifkan dengan hanya mengatur register tujuan dan bendera ke R16. Tidak perlu membuat sinyal kontrol lain untuk menonaktifkan write-back dll.
Sebagian besar implementasi prosesor terlepas dari arsitektur berakhir dengan model register RAZ di awal dalam pipa. Pipa MIPS pada dasarnya dimulai pada titik yang akan di arsitektur lain menjadi beberapa tahap di.
MIPS membuat pilihan yang tepat
Dengan demikian, register read-as-zero hampir wajib dalam setiap implementasi prosesor modern dan MIPS membuatnya terlihat oleh perangkat lunak jelas merupakan poin plus mengingat bagaimana ia merampingkan logika decode internal. Desainer prosesor MIPS tidak perlu menambahkan register RAZ tambahan karena $ 0 sudah tersedia. Karena RAZ tersedia untuk assembler, banyak instruksi psuedo tersedia untuk MIPS dan orang dapat menganggap ini sebagai mendorong bagian dari logika decode ke assembler itu sendiri alih-alih membuat format khusus untuk setiap jenis instruksi untuk menyembunyikan register RAZ dari perangkat lunak seperti arsitektur lainnya. Register RAZ adalah ide yang bagus dan itulah sebabnya ARMv8 menyalinnya.
Jika ARM32 memiliki register $ 0, logika decode akan menjadi lebih sederhana dan arsitektur akan jauh lebih baik dalam hal kecepatan, luas, dan daya. Misalnya, dari tiga versi LDR yang disajikan di atas, hanya 2 format yang diperlukan. Demikian pula, tidak perlu cadangan logika dekode untuk instruksi MOV dan MVN. Juga, CMP / CMN / TST / TEQ akan menjadi berlebihan. Juga tidak perlu membedakan antara short (MUL) dan multiplication panjang (UMULL / SMULL) karena multiplikasi pendek dapat dianggap sebagai multiplikasi panjang dengan register tinggi ditetapkan ke $ 0 dll.
Karena MIPS pada awalnya dirancang oleh tim kecil, kesederhanaan desain adalah penting dan dengan demikian $ 0 secara eksplisit dipilih dalam semangat RISC. ARM32 mempertahankan banyak fitur CISC tradisional di tingkat arsitektur.
sumber
Disclamer: Saya tidak benar-benar tahu assembler MIPS, tetapi register 0-nilai tidak unik untuk arsitektur ini, dan saya kira itu digunakan dengan cara yang sama seperti pada arsitektur RISC lainnya yang saya tahu.
XORing sebuah register untuk mendapatkan 0 akan dikenakan biaya satu instruksi, sementara menggunakan register 0-nilai yang ditetapkan tidak akan dikenakan biaya.
Sebagai contoh,
mov RX, RY
instruksi sering diterapkan sebagaiadd RX, RY, R0
. Tanpa register bernilai 0, Anda harusxor RZ, RZ
setiap kali ingin menggunakannyamov
.Contoh lain adalah
cmp
instruksi dan variannya (seperti "bandingkan dan lompati", "bandingkan dan pindahkan", dll), di manacmp RX, R0
digunakan untuk menguji angka negatif.sumber
MOV Rx,Ry
sebagaiAND Rx,Ry,Ry
?mov RX, Imm
ataumov RX, mem[RY]
jika set instruksi Anda hanya mendukung nilai langsung tunggal dan akses memori tunggal per instruksi.mov
adalah contoh yang buruk; Anda bisa menerapkannya dengan 0 langsung, bukan nol register. misori dst, src, 0
. Tapi ya, Anda akan memerlukan opcode untuk mendaftar segera jika Anda belum memilikinyaaddiu $dst, $zero, 1234
, sepertilui
tetapi untuk 16 bit yang lebih rendah daripada 16 bagian atas. Dan Anda tidak dapat menggunakannor
atausub
untuk membangun satu-operan bukan / neg .Mengikat beberapa petunjuk ke tanah di ujung bank register Anda adalah murah (lebih murah daripada menjadikannya sebagai daftar lengkap).
Melakukan xor yang sebenarnya membutuhkan sedikit daya dan waktu untuk mengganti gerbang dan untuk kemudian menyimpannya di register, mengapa membayar biaya itu ketika nilai 0 yang ada dapat dengan mudah tersedia.
CPU modern juga memiliki register bernilai 0 (tersembunyi) yang dapat mereka gunakan sebagai hasil
xor eax eax
instruksi melalui penggantian nama register.sumber
R0
adalah tidak membumikan beberapa kabel tetapi pada kenyataan bahwa Anda harus memesan kode untuk itu dalam setiap instruksi yang berkaitan dengan register.std::memory_order_consume
) memerlukan XOR untuk menyebarkan dependensi.lui
tapi tidak bergeser ke kiri oleh 16. Jadi Anda masih bisa memasukkan nomor kecil dalam register dengan satu instruksi. Membiarkan hanya nol dengan ketergantungan salah akan menjadi gila. (MIPS normal menciptakan nilai-nilai non-nol denganaddiu $dst, $zero, 1234
atauori
, sehingga argumen "biaya daya" Anda rusak. Jika Anda ingin menghindari menyalakan ALU, Anda akan menyertakan opcode untuk segera bergerak untuk mendaftar daripada memiliki peranti lunak ADD atau OR langsung dengan nol.)