Hardware - разное

CИСТЕМА КОМАНД IA-


В этом разделе статьи мы дадим краткий обзор системы команд IA-64, а точнее, ее "непривилегированной части". Именно это подмножество команд определяет наиболее принципиальные особенности IA-64. Cреди этих принципиальных особенностей следует особо отметить спекулятивное выполнение команд и применение предикатов.

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

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

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

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


Эти значения предикатных регистров используются затем не только в командах условного перехода, как в обычных микропроцессорах. Почти все команды IA-64 выполнимы "под предикатом", т.е. могут выполняться или нет в зависимости от значения указанного в команде PR-регистра. Это позволяет во многих случаях избежать применения условных переходов, которые, как известно, отрицательно сказываются на производительности микропроцессоров. Вместо этого процессор c архитектурой IA-64, имеющий большое число ресурсов (в частности, регистров и ФИУ), может исполнить обе ветви программы. Рассмотрим простейший Пример 1.

Пример 1.

Фрагмент программы в фортрановском представлении: IF(I.EQ.J) THEN K=K+1 ELSE L=L+1 ENDIF

в ассемблерном: cmp.eq p3,p4=r4,r5;; (p3) add r6=r6,r0,1 (p4) add r7=r7,r0,1

(мы используем, вслед за [1], "фортрановский" синтаксис). Предположим, что значения I, J, K, L уже лежат в r4, r5, r6, r7 cоответственно (так обозначаются регистры GR в ассемблере IA-64). Тогда мы получим следующий фрагмент программы...

Здесь команды сложения add использованы в четырехадресной форме; они помещают в регистр-результат (r6 и r7 соответственно) старое значение этого регистра плюс 1 (формально еще плюс значение в r0, которое равно нулю). Команды add используются с так называемыми квалифицирующими предикатами p3, p4. Если значения I и J совпадают, то получаем значения предикатных регистров (p3) = 1, а (р4) = 0. Тогда первая команда add выполняется, а вторая - нет.

Преимуществом такого подхода состоит в линейности выполняемого участка программы вместо ветвления. Обе команды add могут, кстати, выполниться параллельно. Возможности команд типа условной пересылки cmove в ряде RISC-процессоров, в общем случае значительно меньше, чем предикатный подход. Это преимущество IA-64 становится еще более существенным, если учесть расширенные возможности спекулятивного выполнения команд в 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 используется для организации циклов со счетчиком, в которых адрес перехода кодируется относительно IP. В команде используется регистр LC: если он не равен 0, его содержимое уменьшается на 1, и выполняется переход; если LC = 0, перехода не будет. Применение команд работы с циклами мы рассмотрим позже при обсуждении программно конвейеризованных циклов.

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

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

Программная модель вычислений с плавающей запятой в 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-команды загрузки имеют модификации, соответствующие всем аппаратно поддерживаемым типам данных, которые в ассемблере задаются последним символом мнемокода (lfds - для SP, ldfd - для DP и т.д.).


Арифметические команды включают операции типа "умножить-и-сложить" и "умножить-и-вычесть", команды вычисления максимума/минимума, а также команды расчета обратной величины и обратного квадратного корня. Применение двух последних вместо команд деления и квадратного корня соответственно упрощает работу с конвейерами. Реализация команды обращения вместо деления была применена, как известно, еще в легендарном Cray-1.

Приведем Пример 2, иллюстрирующий как работу с плавающей запятой, так и организацию циклов со счетчиком - сложение двух массивов чисел с плавающей запятой (DP).

Пример 2.

Фрагмент программы в фортрановском представлении: DO I=1,N C(I)=A(I)+B(I) ENDDO

в ассемблерном: Lbl: ldfd f6=[r6],8 //Загрузка в f6 A(I) ldfd f7=[r7],8;; //Загрузка в f7 B(I) fadd f8=f6, f7;; //Сложение f6 и f7 stfd [r8]=f8,8 //Запись C(I) br.cloop Lbl;; //Переход на метку

В его ассемблерном представлении приведено только собственно тело цикла.

В этом примере предполагается, что в регистре r6 лежит адрес начала массива A, в r7 - начала массива B, а в r8 - начала массива С. После выполнения каждой команды ldfd и команды stfd содержимое регистров r6-8 соответственно увеличивается на 8 (размер элемента массива в байтах), что указывается в последнем аргументе этих команд. Команда fadd складывает регистры f6 и f7, помещая результат в f8. Наконец, br.cloop обеспечивает переход на начало тела цикла. Не правда ли, очень похоже на старый добрый RISC? То ли еще будет...


Содержание раздела