Мені завжди було цікаво, чому процесори зупиняються на 32 регістрах. Це далеко найшвидший шматок машини, чому б просто не зробити більші процесори з більшою кількістю регістрів? Хіба це не означало б менше відвідування оперативної пам’яті?
Мені завжди було цікаво, чому процесори зупиняються на 32 регістрах. Це далеко найшвидший шматок машини, чому б просто не зробити більші процесори з більшою кількістю регістрів? Хіба це не означало б менше відвідування оперативної пам’яті?
Відповіді:
По-перше, не всі архітектури процесорів зупинилися на 32 регістрах. Майже всі архітектури RISC, які мають 32 регістри, відкриті в наборі інструкцій, насправді мають 32 цілочисельні регістри та ще 32 регістри з плаваючою точкою (так 64). (Плаваюча точка "додати" використовує різні регістри, ніж ціле число "додати".) В архітектурі SPARC є вікна реєстру. У SPARC ви можете отримати доступ до 32 цілочисельних регістрів одночасно, але регістри діють як стек, і ви можете одночасно натискати та виконувати нові регістри 16. В архітектурі Itanium від HP / Intel було встановлено 128 цілочисельних та 128 регістрів з плаваючою точкою, відкритих у наборі інструкцій. Сучасні графічні процесори від NVidia, AMD, Intel, ARM та Imagination Technologies, всі експонують величезну кількість регістрів у своїх файлах реєстрів. (Я знаю, що це стосується архітектури NVidia та Intel. Я не дуже знайомий з наборами інструкцій AMD, ARM та Imagination, але я думаю, що файли реєстру там також великі.)
По-друге, більшість сучасних мікропроцесорів реалізують перейменування регістрів, щоб усунути непотрібну серіалізацію, викликану необхідністю повторного використання ресурсів, тому базові файли фізичного реєстру можуть бути більшими (96, 128 або 192 регістри на деяких машинах). Це (і динамічне планування) усуває деякі з потреба у компіляторі генерувати стільки унікальних імен реєстру, при цьому надаючи більший файл реєстру для планувальника.
Існує дві причини, через які може бути важко збільшити кількість реєстрів, викритих у наборі інструкцій. По-перше, ви повинні мати можливість вказати ідентифікатори регістрів у кожній інструкції. 32 регістри потребують 5-бітового специфікатора регістрів, тому 3-адресні інструкції (звичайні для архітектури RISC) витрачають 15 з 32 бітів інструкцій саме для того, щоб вказати регістри. Якщо ви збільшили це до 6 або 7 біт, у вас було б менше місця для визначення опкодів і констант. Графічні процесори та Itanium мають значно більші інструкції. Більш великі інструкції коштують: потрібно використовувати більше пам'яті інструкцій, тому поведінка кеш-інструкцій менш ідеальна.
Друга причина - час доступу. Чим більше ви робите пам'ять, тим повільніше отримувати доступ до даних з неї. (Просто з точки зору основної фізики: дані зберігаються у двовимірному просторі, тому якщо ви зберігаєте біт, середня відстань до певного біта становить . Файл реєстру - це просто невелика багатопортова пам'ять, і одне з обмежень для її збільшення полягає в тому, що в кінцевому підсумку вам доведеться починати тактирувати свою машину повільніше, щоб вмістити файл більшого реєстру. Зазвичай з точки зору загальної продуктивності це втрата. O ( √
Ще дві причини обмеження кількості регістрів:
Багато коду має багато доступу до пам'яті (30% - типова цифра). З цього, як правило, приблизно 2 / 3rds є доступом до читання, а 1/3ds є доступом до запису. Це пов’язано не з тим, що стільки закінчуються регістри, скільки доступ до масивів, доступ до змінних членів об'єкта тощо.
Це має бути зроблено в пам'яті (або кеш даних) завдяки тому, як C / C ++ зроблено (все, що ви можете отримати вказівник, має мати адресу, яку необхідно потенційно зберігати в пам'яті). Якщо компілятор може здогадатися, що ви не будете записувати до змінних вольово-невільно, використовуючи шалені хитрості непрямих покажчиків, він поставить їх у регістри, і це чудово підходить для змінних функцій, але не для глобально доступних (як правило, все, що виходить з малока ()) тому що по суті неможливо здогадатися, як зміниться глобальна держава.
Через це, звичайно, що компілятор зможе зробити що-небудь із більш ніж приблизно 16 загальними регістрами використання. Тому всі популярні архітектори мають приблизно стільки (ARM має 16).
MIPS та інших RISC, як правило, мають 32, оскільки не так складно мати стільки регістрів - вартість досить низька, так що це трохи "чому б і ні?". Більше 32 здебільшого марно і має мінус у тому, щоб зробити файл реєстру довшим доступом (кожне подвоєння кількості регістрів потенційно додає додатковий шар мультиплексорів, що додає трохи більше затримки ...). Це також робить інструкції в середньому трохи довшими - це означає, що при запуску програм, які залежать від пропускної здатності пам'яті інструкцій, ваші додаткові регістри насправді сповільнюють вас!
Якщо ваш процесор є в порядку і не перейменовує реєстр, і ви намагаєтесь робити багато операцій за цикл (більше 3), то теоретично вам потрібно більше реєстрів, оскільки кількість ваших операційних сил за цикл збільшується. Ось чому Itanium має стільки регістрів! Але на практиці, окрім коду, орієнтованого на число з плаваючою комою або SIMD (у якому Itanium був дуже хороший), більшість кодів матиме багато пам’яті, що читає / записує та стрибає, що робить цю мрію більш ніж на 3 ops за цикл неможливою . Це те, що потопило Itanium.
Все зводиться до різниці між обчисленням та виконанням!
Хто вам каже, що у процесора завжди є 32 регістри? x86 має 8, ARM 32-розрядний, а x86_64 16, IA-64 128 та багато інших чисел. Ви можете подивитися тут . Навіть MIPS, PPC або будь-які архітектури, які мають 32 регістри загального призначення в наборі інструкцій, кількість набагато більша, ніж 32, оскільки завжди є регістри прапор (якщо такі є), контрольні регістри ..., не включаючи перейменовані регістри та апаратні регістри
Все має свою ціну. Чим більша кількість реєстрів, тим більше роботи ви робите при перемиканні завдань, тим більше місця потрібно в кодуванні інструкцій. Якщо у вас менше зареєстровано, вам не доведеться багато зберігати та відновлювати під час виклику та повернення з функцій чи перемикання завдань із відключенням відсутності регістрів у деякому обчислювальному коді
Причому, чим більший файл реєстру, тим він буде дорожчим і складнішим. SRAM - це найшвидша і найдорожча оперативна пам'ять, тому вона використовується лише в кеш-процесорі. Але це набагато дешевше і займає менше площі, ніж файл реєстру з однаковою ємністю.
Наприклад, типовий процесор Intel має "офіційно" 16 цілочисельних і 16 векторних регістрів. Але насправді є ще багато: Процесор використовує "реєструвати перейменування". Якщо у вас є інструкція reg3 = reg1 + reg2, у вас виникли б проблеми, якщо інша інструкція з використанням reg3 ще не закінчилася - ви не змогли виконати нову інструкцію, якщо вона перезаписала reg3 до того, як вона була прочитана попередньою інструкцією.
Тому реальних регістрів існує близько 160 . Отже, проста інструкція, наведена вище, змінюється на "regX = reg1 + reg2, і пам'ятайте, що regX містить reg3". Без реєстру перейменованих видань, поза виконанням порядку було б абсолютно мертвим у воді.
Я не інженер-електрик, але думаю, що інша можливість з причини обмеження кількості регістрів - це маршрутизація. Існує обмежена кількість арифметичних одиниць, і вони повинні мати можливість приймати дані з кожного реєстру та виводити їх до кожного реєстру. Це особливо актуально, коли у вас є конвеєрні програми, які можуть виконувати багато інструкцій за цикл.
Проста версія цього матиме складність, роблячи збільшення кількості регістрів незмінним або інакше вимагає перепроектувати маршрутизацію на щось набагато складніше для маршрутизації всього з кращою складністю.
Я отримав ідею для цієї відповіді, переглянувши кілька переговорів Івана Годарда на процесорі Mill. Частина нововведення процесора Mill полягає в тому, що ви не можете виводити в довільні регістри - всі виводи висуваються на стек реєстру або "пояс", що, таким чином, зменшує проблеми з маршрутизацією, оскільки ви завжди знаєте, куди піде вихід. Зауважте, у них все ще виникає проблема маршрутизації для отримання вхідних регістрів до арифметичних одиниць.
Див. «Архітектура процесора Mill - пояс» (2 з 9) для постановки проблеми та рішення Мілла.