Ada banyak alasan mengapa Anda tidak hanya memiliki register dalam jumlah besar:
- Mereka sangat terkait dengan sebagian besar tahapan pipeline. Sebagai permulaan, Anda perlu melacak masa hidup mereka, dan meneruskan hasil kembali ke tahap sebelumnya. Kompleksitas menjadi sulit diselesaikan dengan sangat cepat, dan jumlah kabel (secara harfiah) yang terlibat tumbuh dengan kecepatan yang sama. Ini mahal di area, yang pada akhirnya berarti mahal pada daya, harga, dan kinerja setelah titik tertentu.
- Ini membutuhkan ruang pengkodean instruksi. 16 register membutuhkan 4 bit untuk sumber dan tujuan, dan 4 bit lainnya jika Anda memiliki instruksi 3-operan (misalnya ARM). Itu banyak sekali ruang pengkodean set instruksi yang digunakan hanya untuk menentukan register. Ini pada akhirnya berdampak pada decoding, ukuran kode, dan lagi kompleksitas.
- Ada cara yang lebih baik untuk mencapai hasil yang sama ...
Hari-hari ini kami benar-benar memiliki banyak register - mereka tidak diprogram secara eksplisit. Kami memiliki "register renaming". Meskipun Anda hanya mengakses set kecil (8-32 register), sebenarnya mereka didukung oleh set yang jauh lebih besar (misalnya 64-256). CPU kemudian melacak visibilitas setiap register, dan mengalokasikannya ke set yang diubah namanya. Misalnya, Anda dapat memuat, memodifikasi, lalu menyimpan ke register berkali-kali berturut-turut, dan masing-masing operasi ini benar-benar dilakukan secara independen bergantung pada cache yang terlewat, dll. Di ARM:
ldr r0, [r4]
add r0, r0, #1
str r0, [r4]
ldr r0, [r5]
add r0, r0, #1
str r0, [r5]
Core Cortex A9 melakukan penggantian nama register, jadi pemuatan pertama ke "r0" sebenarnya masuk ke register virtual yang diubah namanya - sebut saja "v0". Pemuatan, penambahan, dan penyimpanan terjadi pada "v0". Sementara itu, kami juga melakukan pemuatan / modifikasi / penyimpanan ke r0 lagi, tetapi itu akan diganti namanya menjadi "v1" karena ini adalah urutan yang sepenuhnya independen menggunakan r0. Katakanlah beban dari pointer di "r4" terhenti karena cache tidak ditemukan. Tidak apa-apa - kita tidak perlu menunggu "r0" siap. Karena namanya diganti, kita dapat menjalankan urutan berikutnya dengan "v1" (juga dipetakan ke r0) - dan mungkin itu adalah cache hit dan kita baru saja meraih kemenangan kinerja yang besar.
ldr v0, [v2]
add v0, v0, #1
str v0, [v2]
ldr v1, [v3]
add v1, v1, #1
str v1, [v3]
Saya pikir x86 adalah hingga sejumlah besar register berganti nama hari ini (rata-rata 256). Itu berarti memiliki 8 bit dikalikan 2 untuk setiap instruksi hanya untuk mengatakan apa sumber dan tujuannya. Ini akan secara besar-besaran meningkatkan jumlah kabel yang dibutuhkan di seluruh inti, dan ukurannya. Jadi ada sweet spot sekitar 16-32 register yang telah ditetapkan sebagian besar desainer, dan untuk desain CPU yang rusak, penggantian nama register adalah cara untuk menguranginya.
Sunting : Pentingnya eksekusi out-of-order dan register penggantian nama ini. Begitu Anda memiliki OOO, jumlah register tidak terlalu menjadi masalah, karena itu hanyalah "tag sementara" dan diganti namanya menjadi set register virtual yang jauh lebih besar. Anda tidak ingin angkanya terlalu kecil, karena sulit untuk menulis urutan kode yang kecil. Ini adalah masalah untuk x86-32, karena 8 register yang terbatas berarti banyak sementara yang berakhir melalui tumpukan, dan inti membutuhkan logika ekstra untuk meneruskan baca / tulis ke memori. Jika Anda tidak memiliki OOO, Anda biasanya berbicara tentang inti kecil, dalam hal ini kumpulan register besar adalah manfaat biaya / kinerja yang buruk.
Jadi ada sweet spot alami untuk ukuran bank register yang maksimal sekitar 32 register yang dirancang untuk sebagian besar kelas CPU. x86-32 memiliki 8 register dan pastinya terlalu kecil. ARM menggunakan 16 register dan ini adalah kompromi yang bagus. 32 register sedikit terlalu banyak jika ada - Anda akhirnya tidak membutuhkan 10 atau lebih yang terakhir.
Tak satu pun dari sentuhan ini pada register tambahan yang Anda dapatkan untuk SSE dan koprosesor titik mengambang vektor lainnya. Itu masuk akal sebagai set tambahan karena berjalan secara independen dari inti integer, dan tidak menumbuhkan kompleksitas CPU secara eksponensial.