РЕГИСТРЫ
Рассмотрим теперь файлы регистров IA-64. В их число входят: 128 регистров общего назначения GR; 128 регистров с плавающей запятой FR; 64 регистра предикатов PR; 8 регистров перехода BR; 128 прикладных регистра AR; не менее 4 регистров идентификатора процессора CPUID; cчетчик команд IP, указывающий на адрес связки, содержащей исполняемую команду; регистр маркера текущего окна CFM, описывающий окно стека регистров и др.
Регистры CPUID являются 64-разрядными. В CPUID-регистрах 0 и 1 лежит информация о производителе, в регистре 2 находится серийный номер процессора, а в регистре 3 задается тип процессора (cемейство, модель, версия архитектуры и т.п.) и число CPUID-регистров. Разряды регистра 4 указывают на поддержку конкретных особенностей IA-64, т.е. тех, которые реализованы в данном процессоре.
Прикладные регистры AR0-AR127 - специализированные (в основном 64-разрядные) регистры, применяемые в IA-64 и IA-32. AR0-7 называются регистрами ядра; запись в них привилегирована, но они доступны на чтение в любом приложении и используются для передачи приложению сообщений от операционной системы.
Среди других прикладных регистров укажем на AR16 (RSC) - регистр конфигурации стека регистров, используемый для управления работой "машиной" стека регистров IA-64 (RSE); AR17 (BSP), в котором находится адрес в памяти, где сохраняется положение GR32 в текущем окне стека; AR40 (FPSR) - регистр состояния для команд с плавающей запятой IA-64; AR44 (ITC) - интервальный таймер; AR64 (PFS) - регистр предыдущего состояния функции, куда автоматически копируются некоторые другие регистры при вызове подпрограмм; AR65 (LC), используемый для организации циклов со счетчиком, и, наконец, 6-разрядный регистр эпилога AR66 (EC). Ряд AR-регистров является фактически регистрами IA-32 (дескриптор сегмента кодов, дескриптор сегмента стека и др.).
64-разрядные регистры GR0-127 применяются не только для целочисленных операций IA-64; GR8-31 в режиме IA-32 используются также под целочисленные регистры и регистры селекторов и дескрипторов сегментов IA-32.
GR0-31 называются статическими регистрами (GR0 всегда содержит 0), а GR32-127 - стекируемыми регистрами. Статические регистры "видны" всем программам. Стекируемые регистры становятся доступными в программной единице через окно стека регистров, включающее локальные и выходные регистры, число которых задается командой alloc.
82-разрядные регистры с плавающей запятой FR0-127 также подразделяются на статические (FR0-31, причем всегда FR0=0.0, FR1=1.0) и вращаемые (FR32-127). FR8-31 в режиме IA-32 содержат числа с плавающей запятой и мультимедийные регистры.
Вращение регистров является в некотором роде частным случаем переименования регистров, применяемого во многих современных суперскалярных процессоров с внеочередным спекулятивным выполнением команд. В отличие от них, вращение регистров в IA-64 управляется программно. К обсуждению вращения регистров мы вернемся ниже, а содержимое FR будет рассмотрено в разделе, посвященном операциям с плавающей запятой.
64-разрядные регистры переходов BR0-7 применяются для указания адреса перехода в соответствующих командах перехода (если адрес перехода не кодируется в команде явно). Регистры предикатов PR0-63 являются одноразрядными; в них помещаются результаты команд сравнения. Обычно эти команды устанавливают сразу два геистра PR в зависимости от условия - соответственно истинность условия и его отрицания. Такая избыточность обеспечивает дополнительную гибкость.
В отечественном микропроцессоре E2K [3] предикатных регистров в два раза меньше. Хотя это позволяет хранить столько же условий, сколько в IA-64, в последней предикатные регистры применяются еще и для организации программно конвейеризованных циклов (Software Pipelining - SWP). Использование предикатных регистров - важнейшая особенность, кардинально отличающая IA-64 от всех других микропроцессоров, кроме E2K.
PR0-15 являются статическими (PR0 всегда равен 1), а PR16-63 - вращаемыми. Статические предикатные регистры используются в командах условного перехода. Кроме того, почти все команды IA-64 могут быть выполнены "под предикатом".
Работа стека регистров
Файл регистров GR отличается от FR и PR тем, что последние содержат фиксированные подмножества статических и вращаемых регистров, в то время как в файле GR вне подмножества статических регистров применяется стек регистров, и программной единице доступна лишь его часть - окно стека регистров. В отличие от статических регистров, стекируемое подмножество локально для любой программной единицы и может иметь размер от 0 до 96 регистров, начиная с GR32.
Использование этого механизма в IA-64 позволяет, как мы увидим, избежать накладных расходов, связанных с сохранением/восстановлением большого числа регистров при вызовах подпрограмм и возвратах из них (однако статические регистры при необходимости все-таки приходится сохранять и восстанавливать, явно кодируя соответствующие команды). Автоматическое сохранение/восстановление стекируемого подмножества регистров осуществляет RSE, и в программе об этом заботиться не надо. В режиме IA-32 работа с этим стеком регистров, естественно, отключается.
Мы до сих пор не рассматривали один из важнейших регистров IA-64 - 38-разрядный регистр CFM, в котором как раз сохраняется состояние "текущего" окна стека регистров. Как и другие маркеры окна, CFM содержит общий размер окна стека, число локальных регистров и (кратное 8) число вращаемых регистров в окне, а также 3 значения базы для переименования регистров - соответственно rrb.gr, rrb.fr и rrb.pr.
Итак, окно стека имеет две области переменного размера - локальную и выходную. Рассмотрим вызов процедур подробнее. При переходе типа "вызов процедуры" CFM вызывающей подпрограммы сохраняется в поле PFM (Previous Frame Marker) регистра PFS, и создается CFM вызываемой подпрограммы. Сразу после вызова размер локальной области вызываемой подпрограммы равен размеру выходной области вызывающей и перекрывается с ней. При этом стекируемые регистры автоматически переименовываются таким образом, что первый регистр выходной области вызывающей подпрограммы становится регистром GR32 вызываемой (рис.2, где procA - это вызывающая, а procB - вызываемая подпрограмма).
Перекрытие их выходных областей позволяет эффективно передавать параметры через регистры.
Рис. 2. Стек регистров при вызове procB из procA
Как мы уже указывали, вызываемая подпрограмма может изменить размеры своих локальной и выходной областей командой alloc; cоответствующим образом будут изменены и поля в CFM. Команда alloc обычно используется вызываемой подпрограммой для того, чтобы распределить себе определенное число локальных регистров и заиметь выходную область для передачи параметров уже собственному "потомку". Если запрошенное в команде alloc количество регистров оказывается недоступным (переполнение стека), alloc приостанавливает процессор и RSE будет сохранять регистры вызывающей подпрограммы, пока запрошенное alloc число регистров не будет доступным.
При переходе типа "возврат из процедуры" CFM восстанавливается из PFM, а обратное переименование регистров восстанавливает состояние вызывающей подпрограммы. Если некоторые ее регистры были ранее "сброшены" RSE, то при возврате RSE приостановит процессор до тех пор, пока не будут восстановлены эти регистры.