logo search
Методичка

9.2 Особенности архитектуры epic

Работа стека регистров

Файл регистров GR отличается от FR и PR тем, что последние содержат фиксированные подмножества статических и вращаемых регистров, в то время как в файле GR вне подмножества статических регистров применяется стек регистров, и программной единице доступна лишь его часть – окно стека регистров. В отличие от статических регистров, стекируемое подмножество локально для любой программной единицы и может иметь размер от 0 до 96 регистров, начиная с GR32.

Использование этого механизма в IA-64 позволяет избежать накладных расходов, связанных с сохранением/восстановлением большого числа регистров при вызовах подпрограмм и возвратах из них (однако статические регистры при необходимости все-таки приходится сохранять и восстанавливать, явно кодируя соответствующие команды). Автоматическое сохранение/восстановление стекируемого подмножества регистров осуществляет RSE и в программе об этом заботиться не надо. В режиме IA-32 работа с этим стеком регистров, естественно, отключается.

Мы до сих пор не рассматривали один из важнейших регистров IA 64 – 38-разрядный регистр CFM, в котором как раз сохраняется состояние текущего окна стека регистров. Как и другие маркеры окна, CFM содержит общий размер окна стека, число локальных регистров и кратное 8 число вращаемых регистров в окне, а также 3 значения базы для переименования регистров – соответственно gr, fr и pr.

Окно стека имеет две области переменного размера – локальную и выходную. Рассмотрим вызов процедур подробнее. При переходе типа “вызов процедуры” CFM вызывающей подпрограммы сохраняется в поле PFM (Previous Frame Marker) регистра PFS, и создается CFM вызываемой подпрограммы. Сразу после вызова размер локальной области вызываемой подпрограммы равен размеру выходной области вызывающей и перекрывается с ней. При этом стекируемые регистры автоматически переименовываются таким образом, что первый регистр выходной области вызывающей подпрограммы становится регистром GR32 вызываемой. Перекрытие их выходных областей позволяет эффективно передавать параметры через регистры.

Вызываемая подпрограмма может изменить размеры своих локальной и выходной областей командой alloc; cоответствующим образом будут изменены и поля в CFM. Команда alloc обычно используется вызываемой подпрограммой для того, чтобы захватить себе определенное число локальных регистров и зарезервировать выходную область для передачи параметров уже собственному “потомку”. Если запрошенное в команде alloc количество регистров оказывается недоступным (переполнение стека), alloc приостанавливает процессор и RSE будет сохранять регистры вызывающей подпрограммы, пока запрошенное командой alloc число регистров не будет доступным.

При переходе типа “возврат из процедуры” CFM восстанавливается из PFM, а обратное переименование регистров восстанавливает состояние вызывающей подпрограммы. Если некоторые ее регистры были ранее “сброшены” RSE, то при возврате RSE приостановит процессор до тех пор, пока не будут восстановлены эти регистры.

Система команд IA-64

Рассмотрим кратко систему команд IA‑64, а точнее, ее “непривилегированной части”. Именно это подмножество команд определяет наиболее принципиальные особенности IA-64. Среди этих принципиальных особенностей следует особо отметить спекулятивное выполнение команд и применение предикатов.

Все рассматриваемые команды можно подразделить на: команды работы со стеком регистров (например, alloc); целочисленные команды; команды сравнения и работы с предикатами; команды доступа в память; команды перехода; мультимедийные команды; команды пересылок между регистрами; “разные” (операции над строками и подсчет числа единиц в слове); команды работы с плавающей запятой.

Целочисленные команды IA-64 включают арифметические операции (add, sub и др.), логические операции (and, or, xor и др.), операции над битами и сдвиги, а также 32-разрядные операции. Большинство этих команд трехадресные, а их аргументы лежат в регистрах; однако встречается и литеральное представление аргументов. Имеются также модификации команд add и sub, которые являются четырехадресными: в них к сумме/разности регистров прибавляется/вычитается 1.

Отметим, что команда умножения целых чисел в регистрах GR отсутствует; для перемножения необходима пересылка целых в регистры FR и применение операции умножения, выполняемой в одном из FPU. Некоторые эксперты считают это “наименее удачной” чертой системы команд IA-64.

Команды сравнения и работа с предикатами – это одна из принципиально новых особенностей IA-64 по сравнению с RISC-архитектурой. Приведем сначала несколько типичных примеров команд этой группы. Команда cmp сравнивает два регистра GR (или регистр GR и литерал) на одно из 10 возможных условий (больше, меньше или равно и т.п.). Команда tbit тестирует заданный бит GR. Команда fcmp сравнивает два числа с плавающей запятой. Однако результатом сравнения является не единственный код условия, что типично для обычных процессоров. Логический результат сравнения (1 – истина, 0 – ложь) записывается обычно в пару предикатных регистров (во второй пишется отрицание первого).

Эти значения предикатных регистров используются затем не только в командах условного перехода, как в обычных микропроцессорах. Почти все команды IA-64 выполнимы “под предикатом”, т.е. могут выполняться или нет в зависимости от значения указанного в команде PR-регистра. Это позволяет во многих случаях избежать применения условных переходов, которые, как известно, отрицательно сказываются на производительности микропроцессоров. Вместо этого процессор IA-64, имеющий большое число регистров и функциональных исполнительных устройств, может исполнить обе ветви программы.

Спекулятивная загрузка данных и выполнение команд

Механизм спекулятивной загрузки предназначен для снижения простоев процессора, связанных с ожиданием выполнения команд загрузки из относительно медленной основной памяти. Компилятор, анализируя исходный текст программы, добавляет служебные команды упреждающей загрузки необходимых данных в такое место исходного кода, которое выполнится до того момента, когда эти данные понадобятся какой либо пользовательской команде.

Рассмотрим команды доступа в память. Прежде всего, это команды загрузки регистров и записи из них в оперативную память. Команда ld загружает в GR 1-, 2-, 4- и 8-байтные целочисленные величины; аналогично ldf загружает в FR числа с плавающей запятой размером 4, 8, 10 байт, а также пары 4-байтных чисел. В этих командах можно указать также на тонкие особенности работы с оперативной памятью и кэшем. Имеются и специальные команды работы с КЭШем!

Принципиальной является возможность кодирования указанных команд загрузки в специальных спекулятивных формах. Различают загрузку спекулятивную по управлению и спекулятивную по данным.

Спекулятивное по управлению выполнение означает возможность заранее выполнить команды, расположенные за командой условного перехода, до того, как будет известно, будет ли осуществляться этот условный переход на соответствующую ветвь программы. При наличии большого числа ресурсов процессора это позволяет заранее запускать на выполнение команды, которые начнут выполняться одновременно с уже начавшими выполняться другими командами (в других функциональных исполнительных устройствах). Однако позднее может выясниться, что эти спекулятивно выполненные команды оказались выполненными напрасно, так как переход на эту ветвь не произошел, и нужно произвести “откат”.

Поскольку эти спекулятивно выполненные команды могут привести к прерыванию, в IA-64 предусмотрен механизм, позволяющий зафиксировать, что возникло прерывание, но само прерывание отложить до тех пор, пока не будет затребован опрос его наличия. Признак отложенного прерывания записывается в регистр результата (затем его можно опросить специальной командой chk.s). В дальнейшем признак отложенного прерывания последовательно распространяется на регистры результатов спекулятивных команд, в регистрах исходных данных которых взведён признак отложенного прерывания.

Все команды можно разделить на спекулятивно выполнимые и спекулятивно невыполнимые. Последние могут вызывать прерывания, которые не могут быть отложены. Обычные вычислительные команды, имеющие GR или FR в качестве регистров результата, – спекулятивные. Если же команда изменяет другие типы регистров, она неспекулятивная.

Кроме обычных неспекулятивных команд (ld, ldf...) в IA-64 имеются их спекулятивные модификации (ld.s, ldf.s...). Вычислительные команды в общем случае не вызывают прерываний (операции с плавающей запятой обрабатывают прерывания специальным образом), поэтому единственным способом сгенерировать признак отложенного прерывания являются команды спекулятивной загрузки. Другие команды это отложенное прерывание могут только распространять.

В точке программы, где надо использовать результат спекулятивного выполнения, следует применять спекулятивную команду chk.s, проверяющую признак отложенного прерывания. Если оно имелось, chk.s передаст управление по указанному в ней адресу, по которому программист должен расположить коды обработки ситуации. Поскольку стало ясно, что спекулятивное выполнение команды действительно понадобилось, можно закодировать копию спекулятивно выполненного фрагмента программы, но уже с неспекулятивными командами загрузки.

Другой тип спекулятивного выполнения может иметь место, когда вслед за записью в память идет команда загрузки регистра, и невозможно заранее определить, не будут ли перекрываться в памяти используемые этими командами данные. В IA-64 имеются спекулятивные команды загрузки (ld.a, ldf.a...), которые называются усовершенствованными (advanced) командами загрузки. Аналогично взаимозависимости между командами по управлению, “расшиваемой” применением спекулятивных команд с 'постфиксом' .s, продвинутые команды загрузки вместе с соответствующей командой проверки chk.a (аналог chk.s) позволяют исключить задержки выполнения при наличии взаимозависимости по данным.

Обратимся теперь к командам перехода. Адрес перехода выравнивается всегда на границу связки, т.е. управление передается на ее слот 0. Имеется команда перехода относительно счетчика команд, в которой явно кодируется 21-разрядное смещение. Эти переходы осуществимы в пределах +/-16 Мбайт относительно счетчика. В непрямых командах перехода адрес перехода задается в регистре BR.

Обычный условный переход br.cond, или просто br, использует значение кодируемого в команде предикатного регистра PR для определения истинности условия. Указав в команде PR0, в котором всегда лежит 1, можно получить безусловный переход. PR0 кодируется также в командах вызова процедур/возврата (br.call/br.ret). Имеется 5 типов команд перехода, применяемых для организации циклов. Команда br.cloop используется для организации циклов со счетчиком, в которых адрес перехода кодируется относительно RIP. В команде используется регистр LC (Loop Counter): если он не равен 0, его содержимое уменьшается на 1, и выполняется переход; если LC = 0, перехода не будет. Применение команд работы с циклами мы рассмотрим позже при обсуждении программно конвейеризованных циклов.

В расширении кода операции команды перехода можно закодировать подсказку для процессора о стратегии динамического или статического предсказания этого перехода.

Операции с плавающей запятой

Программная модель вычислений с плавающей запятой в IA-64, в отличие от IA-32, ориентирована на работу с регистрами FR, а не со стеком, что уже само по себе облегчает создание более высокопроизводительных программ. В IA-64 непосредственно поддерживается 6 типов данных, в том числе три стандарта IEEE754 (одинарная точность SP, двойная точность DP и двойная расширенная точность DE), 82-разрядный формат FR и 64-разрядные целые – со знаком и без знака. Формат DE, также как и формат с размещением двух чисел (SP) с плавающей запятой, используемый в векторных мультимедийных командах, унаследован архитектурой IA-64 от IA-32. Формат регистров FR включает 64-разрядную мантиссу, 17-разрядный порядок и 1 бит под знак числа. Кроме того, на уровне подпрограмм предлагается поддержка учетверённой точности.

В 64-разрядном регистре FPSR указываются признаки деления на ноль, переполнения порядка, исчезновения порядка, потери значимости, формат данных и другая информация о состоянии.

FP-команды загрузки имеют модификации, соответствующие всем аппаратно поддерживаемым типам данных, которые в ассемблере задаются последним символом мнемокода (ldfs – для SP, ldfd – для DP и т.д.). Арифметические команды включают операции типа 'умножить-и-сложить' и 'умножить-и-вычесть', команды вычисления максимума/минимума, а также команды расчета обратной величины и обратного квадратного корня. Применение двух последних вместо команд деления и квадратного корня соответственно упрощает работу с конвейерами. Реализация команды обращения вместо деления была применена, как известно, еще в легендарном Cray-1.

Явный параллелизм машинного кода

Поиск зависимостей между командами выполняется не процессором, а компилятором. Команды процессора IA-64 группируются компилятором в связки (bundle) по три команды (LIW). Три связки объединяются в очень длинное командное слово (VLIW). Команда микропроцессора имеет фиксированную длину 41 бит: 14-битное поле кода операции, 6-битное поле предиката (26=64 регистра pr), три 7-битных поля идентификатора РОН (27=128 РОН-ов r или fr).

Связка из трёх команд содержит 128 бит: три команды по 41 бит и 5-битное поле шаблона, в котором указана зависимость между командами по данным (2 бита), типы команд (3 бита): ALU, FPU, обращение к памяти, ALU неарифметические (адресные), переходы, расширенные.

Масштабируемость

Масштабируемость по количеству функциональных устройств означает возможность увеличения числа функциональных устройств в последующих моделях микропроцессоров. Эта возможность обусловлена приспособлением набора команд процессора к большому количеству функциональных устройств. Например, одна связка из трёх команд соответствует набору из трёх функциональных устройств процессора. Процессоры IA-64 могут содержать разное количество таких функциональных устройств, оставаясь при этом совместимыми по программному коду. Это объясняется тем, что во VLIW указана зависимость между тремя связками, поэтому 9 команд могут выполняться на любом количестве функциональных устройств. При этом процессор сам планирует параллельное выполнение такого количества команд, какое количество свободных функциональных устройств есть у него в распоряжении в данный момент времени.

Условное выполнение (предикация)

Предикация – способ обработки условных ветвлений, при котором команды из разных ветвей дополняются компилятором предикатными полями и выполняются в процессоре параллельно. Результаты команд записываются в память временного хранения (бит NaT). Когда определяется условие ветвления, то предикатный регистр, соответствующий “правильной” ветви, устанавливается в единицу, остальные – в ноль. Перед сохранением результатов команд ветвления процессор проверяет предикатное поле каждой команды и записывает результаты только тех команд, предикатное поле которых содержит единицу. Предикация позволяет увеличить быстродействие кода инструкции “if-then-else”. Не все ветвления отмечаются компилятором для параллельного выполнения, а только короткие альтернативные ветви. Если ветвление не отмечается, оно предсказывается процессором так, как это делается в архитектуре IA-64.

Аппаратная поддержка циклов

Цикл разделяется на три фазы: пролог, ядро, эпилог. Используется механизм “вращения регистров”, служебные команды и прикладные регистры – счётчик циклов LC и счётчик эпилогов (EС). Фрейм регистров тела цикла на каждом витке цикла изменяет базу на величину, равную количеству регистров во фрейме.

Типы данных

IA-64 поддерживает следующие типы данных

Конвейер команд IA-64 (pipeline)

Конвейер команд содержит 10 ступеней.

Предварительная обработка:

  1. IPG – Instruction pointer generation (генерация адресов команд).

  2. FET – Fetch (выборка).

  3. ROT – Rotation (вращение регистров).

Получение команд:

  1. EXP – Expand (расширение).

  2. Ren – Rename (переименование регистров).

Получение операндов:

  1. WLD – Word-line decode (пословное декодирование).

  2. REG – Register read (загрузка регистров данными).

Выполнение:

  1. EXE – Execute (выполнение).

  2. DET – Exception detect (обнаружение исключений).

  3. WRB – Write back (сохранение).