CISC- і RISC-процессори
Часто доводиться стикатися з нерозумінням терміну RISC,
загальноприйнята розшифровка якого — Reduced Instruction Set Computer (комп'ютер
із зменшеною системою команд). Який же, говорять, SPARC або POWERPC
-RISC, якщо у нього кількість код команд не поступається або майже не
поступається кількості команд в х8б? Чому тоді х86 не RISC, адже у нього
команд значно менше і вони набагато простіші, ніж біля VAX 11/780, що вважається
класичним прикладом CISC-архитектуры. Та і технології підвищення продуктивності
біля сучасних х86 і RISC-процессоров використовуються приблизно ті ж, що
і біля великих комп'ютерів 70-х: множинні АЛУ, віртуальні регістри,
динамічне перепланування команд.
Насправді, початково абревіатура RISC розшифровувалася трохи
інакше, а саме як Rational Instruction Set Computer (RISC, комп'ютер
з раціональною системою команд). RISC-процессоры, таким чином протиставлялися
процесорам з необов'язково складною (CISC - Complex Instruction Set Computer,
комп'ютер із складною системою команд), але "ірраціональною",
такою, що історично склалася архітектурою, в якій, через вимоги
бінарної і асемблерної сумісності з попередніми поколіннями, накопичена
безліч команд, спеціалізованих регістрів і концепцій, загалом і не потрібних,
але раптом відміниш команду двійково-десяткової корекції, а якесь поширене
застосування "зламається"? А ми заявляли бінарну сумісність.
Скандал!
Зрозуміло,
що бути "раціональними" в такому розумінні можуть ті, що
лише освоюють новий ринок розробники, яких не турбує та сама
бінарна сумісність. Вже зараз, наприклад, фірма Sun, одним з головних
достоїнств своїх пропозицій на основі процесорів ULTRASPARC рахує повну
бінарну сумісність з ранішими машинами сімейства SPARC. Нові процесори
вимушені підтримувати бінарну сумісність з 64-розрядними молодшими
родичами і режим сумісності з 32-розрядними. Де вже тут піклуватися
про раціональність.
З іншого боку, раціональність теж можна розуміти по-різному. В кінці
70-х і першій половині 80-х років загальноприйнятим розумінням "раціональності"
вважалася своєрідна (з висоти сьогоднішнього дня) орієнтація на мови
високого рівня. Відносно примітивні транслятори тих часів кодували
багато операцій, наприклад прологи і епілоги процедур, доступ до елементу
масиву по індексу, обчислювані переходи (switch
у З Case у Pascal) за допомогою стандартних послідовностей
команд. Оскільки все менше і менше коди писалося уручну і все більше
і більше — генерувалося трансляторами, розробники процесорів вирішили
піти творцям компіляторів назустріч.
Цей
крок назустріч виразився в прагненні замінити там, де це можливо, послідовності
операцій, що часто зустрічаються в коді, що
відкомпілювався, однією командою. Серед комерційно успішної архітектури апофеозом
цього підходу слід вважати сімейство мінікомп'ютерів VAX фірми DEC, в
якому однією командою реалізовані не лише пролог Функції і копіювання
рядка символів, але і, скажімо, операції видалення і вставки елементу в
одинзв'язний список. Приведена як приклад шестиадресної команди команда INDEX
— реальна команда цього процесора. Окремі прояви цієї тенденції
без зусиль просліджуються і в системах команд MC68000 і 8086. Абревіатура
CISC пізніше використовувалася саме для характеристики процесорів цього
покоління.
- Іншої сторони, невміння трансляторів цього покоління ефективне
Розміщувати змінні і проміжні значення по регістрах вважалося Аргументом на
користь того, що від регістрів слід відмовлятися і замінювати їх
Регістровими стеками або кеш-пам'яттю. (Втім, і біля VAX, і біля MC68000 з Регістрами
загального призначення було все гаразд, по 16 штук.)
До другої половини 80-х розвиток технологій
трансляції дозволив замінити генерацію стандартних послідовностей
команд більш інтелектуальним і відповідним до конкретного випадку кодом.
Розроблені технології оптимізації виразів і пошуку інваріантів циклу дозволяли,
зокрема, позбавлятися від зайвих перевірок. Наприклад, якщо цикл виконується
фіксоване число разів, а лічильник циклу використовується як індекс масиву, не
треба вставляти перевірку кордонів індексу в тіло циклу — досить
переконатися, що обмежувач лічильника не перевершує розміру масиву. Більш
того, якщо лічильник використовується лише як індекс, можна взагалі позбавитися
і від нього, і від індексації, а замість цього використовувати вказівну арифметику.
Нарешті, якщо верхній кордон лічильника фіксований і невеликий, цикл можна
розвернути (приклад 2.6).
Приклад 2.6. Еквівалентні перетворення
програми
/* Приклад можливої стратегії оптимізації.
*
Код, що вставляється компілятором для перевірки кордонів індексу
* виділений за допомогою нестандартного вирівнювання. */
int array[100];
int bubblesort(int size)) int count; do {
count=0;
for(i= l; i<100; i++){
if (i<0 || i>100) raise(IndexOverflow); if (i-l<0 || i-l>100)
raise(IndexOverflow); if (array[i-1]<array[i]) { if (i<0 || i>100)
raise(IndexOverflow);
int t=array[i];
if (i<0 || i>100) raise(IndexOverflow); if (i-l<0 || i-l>100)
raise(IndexOverflow);
array[i]=array[i-1];
if (i-l<0 II i-l>100) raise(IndexOverflow); array[i-1]=t; count++;
I
while (count != 0) ;
// оптимізований внутрішній цикл може виглядати так: register int
*ptr=array; register int *limit=ptr; register int t=*ptr++;
if (size<100) limit+=size; else limit+=100;
while (ptr<limit) { if (t<*ptr) { ptr[-l]=*ptr;
*ptr++=t; count++; ) else t=*ptr++;
}
if (size>100) raise (IndexOverf low) ;
У міру поширення в міні- і мікрокомп'ютерах кешів
команд і даних, а також конвеєрного виконання команд, об'єднання безлічі
дій в один код операції стало менш вигідним з точки зору продуктивності.
Це привело до радикальної зміни поглядів на те, яким має
бути ідеальний процесор, орієнтований на виконання
коди, що відкомпілювалася. По-перше, компілятору не потрібна ні бінарна, ні
навіть асемблерна сумісність з чим би то не було
(звідси "раціональність"). По-друге, йому потрібно багато взаємозамінних регістрів —
мінімум тридцять два, а насправді чим більше, тим краще. По-третє, складні комбіновані
команди ускладнюють апаратуру процесора, а товчу від них все одно немає,
або мало.
Комерційний успіх процесорів, побудованих відповідно до цих поглядів
(SPARC, MIPS, PA-RISC) привів до того, що абревіатура
USC стала вживатися
до місця і не до місця — наприклад, вже згадуваний Transputer (регістровий стек,
що мав, і реалізований на рівні системи команд планувальник,
тобто що є живим втіленням описаного раніше CISC-подхода) в
документації називали RISC-процессором, фірма Intel хвалилася, що її
новий процесор Pentium побудований на RISC-ядре (що під цим не малося на
увазі?) і так далі
|