Є багато причин, чому у вас не просто величезна кількість реєстрів:
- Вони тісно пов’язані з більшістю стадій трубопроводу. Для початку вам потрібно відстежувати тривалість їхнього життя і пересилати результати назад на попередні етапи. Складність стає дуже складною, і кількість задіяних проводів (буквально) зростає з однаковою швидкістю. Це дорого за площею, що в кінцевому рахунку означає, що це дорого за потужністю, ціною та продуктивністю після певного моменту.
- Це займає простір кодування інструкцій. 16 регістрів займають 4 біти для джерела та пункту призначення, і ще 4, якщо у вас є 3-операндні інструкції (наприклад, ARM). Це надзвичайно багато місця для кодування набору команд, зайнятого лише для того, щоб вказати регістр. Це врешті-решт впливає на декодування, розмір коду і знову ж складність.
- Є кращі способи досягти того самого результату ...
У наші дні у нас дійсно багато реєстрів - вони просто явно не запрограмовані. У нас є "перейменування реєстру". Хоча ви отримуєте доступ лише до невеликого набору (8-32 регістри), вони насправді підтримуються набагато більшим набором (наприклад, 64-256). Потім центральний процесор відстежує видимість кожного реєстру і розподіляє їх до перейменованого набору. Наприклад, ви можете завантажувати, модифікувати, а потім зберігати в реєстрі багато разів поспіль, і кожну з цих операцій фактично виконувати незалежно залежно від пропусків кешу тощо. В ARM:
ldr r0, [r4]
add r0, r0, #1
str r0, [r4]
ldr r0, [r5]
add r0, r0, #1
str r0, [r5]
Ядра Cortex A9 перейменовують регістри, тому перше завантаження до "r0" насправді надходить до перейменованого віртуального реєстру - назвемо його "v0". Навантаження, збільшення та збереження відбуваються на "v0". Тим часом ми також виконуємо завантаження / модифікацію / збереження до r0 знову, але це буде перейменовано на "v1", оскільки це цілком незалежна послідовність із використанням r0. Скажімо, навантаження від вказівника в "r4" зупинилося через пропуск кешу. Це нормально - нам не потрібно чекати, поки "r0" буде готовий. Оскільки вона перейменована, ми можемо запустити наступну послідовність з "v1" (також відображеною на r0) - і, можливо, це потрапило в кеш, і ми щойно отримали величезну перемогу в продуктивності.
ldr v0, [v2]
add v0, v0, #1
str v0, [v2]
ldr v1, [v3]
add v1, v1, #1
str v1, [v3]
Я думаю, що x86 до сьогоднішнього дня переростає гігантську кількість перейменованих реєстрів (стадіон 256). Це означало б мати 8 розрядів по 2 для кожної інструкції, щоб просто сказати, що таке джерело та пункт призначення. Це суттєво збільшило б кількість проводів, необхідних у сердечнику, і його розмір. Отож, навколо 16–32 реєстрів є чудова пляма, на яку погодились більшість дизайнерів, і для непрацюючих конструкцій процесорів перейменування регістрів - це спосіб пом’якшити його.
Змінити : Важливість виконуваного в порядку замовлення та перейменування реєстру щодо цього. Коли у вас є ТОВ, кількість реєстрів не має такого великого значення, оскільки вони є просто "тимчасовими тегами" і перейменовуються у набагато більший набір віртуальних регістрів. Ви не хочете, щоб число було занадто малим, тому що стає важко писати маленькі послідовності коду. Це проблема для x86-32, оскільки обмежені 8 регістрів означають, що в кінцевому підсумку безліч тимчасових пристроїв проходить через стек, і ядру потрібна додаткова логіка для пересилання зчитувань / записів в пам'ять. Якщо у вас немає ТОВ, ви, як правило, говорите про невелике ядро, і в цьому випадку великий набір регістрів - це низька вигода / ефективність.
Отже, є природне солодке місце для розміру банку реєстрів, яке становить близько 32 архітектурних регістрів для більшості класів процесорів. x86-32 має 8 регістрів, і це, безумовно, замало. ARM мав 16 реєстрів, і це хороший компроміс. 32 реєстрів - це занадто багато, якщо що - останні 10 вам не потрібні або близько того.
Ніщо з цього не стосується додаткових регістрів, які ви отримуєте для SSE та інших векторних співпроцесорів із плаваючою комою. Це має сенс як додатковий набір, оскільки вони працюють незалежно від цілочисельного ядра і не роблять складність центрального процесора в геометричній прогресії.