- •5. Программная конвейерная обработка и поддержка циклов
- •5.1. Краткий обзор
- •5.2. Терминология циклов и основная поддержка циклов
- •5.3. Оптимизация циклов
- •5.3.1. Развертывание цикла
- •5.3.2. Программная конвейерная обработка
- •5.4. Особенности поддержки циклов в архитектуре Intel Itanium
- •5.4.1. Ротация регистров
- •5.4.3. Переходы циклов с программной конвейерной обработкой
- •5.4.3.1. Переходы счетных циклов
- •5.4.2. Замечание об инициализации ротации предикатов
- •5.4.3.2. Пример счетного цикла
- •5.4.3.3. Переходы while-циклов
- •5.4.4. Краткий обзор терминологии
- •5.5. Оптимизация циклов в архитектуре Intel Itanium
- •5.5.1. While-циклы
- •5.5.2. Циклы с инструкциями, имеющими предикаты
- •5.5.3. Циклы с множеством выходов
- •5.5.3.1. Преобразование циклов с несколькими выходами в циклы с одним выходом.
- •5.5.3.2. Конвейерная обработка с явными многократными выходами
- •5.5.4. Соображения о программной конвейерной обработке
- •5.5.5. Программная конвейерная обработка и предварительные загрузки
- •5.5.5.1. Ограничения емкости
- •5.5.5.2. Конфликты в alat
- •5.5.6. Предварительное разворачивание циклов для программной конвейерной обработки
- •5.5.7. Осуществление сокращений
- •5.5.8. Явный пролог и эпилог
- •5.5.9. Устранение избыточной загрузки в циклах
- •5.6. Итоги
5.4.4. Краткий обзор терминологии
В предыдущих разделах представлены следующие термины:
Интервал инициализации (ИИ) – Initiation Interval (II). Количество тактов между началами последовательных исходных итераций в программном конвейерном цикле.
Пролог – Prolog. Первая фаза программного конвейерного цикла, в которой конвейер заполняется.
Ядро – Kernel. Вторая фаза программного конвейерного цикла, в которой конвейер полон.
Эпилог – Epilog. Третья фаза программного конвейерного цикла, в которой конвейер опустошается.
Исходная итерация – Source Iteration. Итерация первоначального исходного кода цикла.
Ядерная итерация – Kernel Iteration. Итерация цикла, осуществляемого программным конвейером.
Переменная индукции – Induction Variable. Значение, которое инкрементируется или декрементируется в каждой итерации один раз и на одно и то же значение.
5.5. Оптимизация циклов в архитектуре Intel Itanium
Ротация регистров, предикация и переходы программных конвейерных циклов, позволяют генерировать компактный, но в то же время высоко параллельный код. Спекулятивность может еще больше увеличить эффективность цикла, удаляя барьеры зависимости, которые ограничивают производительность программных конвейерных циклов. Ротация регистров устраняет необходимость в развертывании ядерных циклов для того, чтобы позволить программное переименование регистров. Однако, в некоторых случаях, эффективность может быть увеличена путем развертывания исходного цикла в виде программной конвейерной обработки, либо путем генерирования явных блоков пролога и эпилога. В оставшейся части этой главы обсуждается оптимизация цикла.
5.5.1. While-циклы
Схема программирования для while-циклов зависит от структуры цикла. В этом разделе обсуждаются do-while-циклы, в которых условие цикла вычисляется в конце цикла. Оптимизирующие трансляторы часто преобразуют while-циклы (где условие вычисляется вверху цикла) в do-while-циклы, перемещая вычисление условия в подножие цикла и размещая перед циклом копию вычисления условия, чтобы уменьшить количество переходов в цикле. Остальная часть этого раздела описывает такие циклы, просто, как while-циклы. Ниже приведен простой while-цикл.
L1: ld4 r4 = [r5],4;; // Такт 0
st4 [r6] = r4,4 // Такт 2
cmp.ne p1,p0 = r4,r0 // Такт 2
(p1) br L1;; // Такт 2
Концептуальное представление конвейерной итерации этого цикла с ИИ равным единице, выглядит так:
stage 1: ld4 r4 = [r5],4
stage 2: --- // пустая стадия
stage 3: st4 [r6]= r4,4
cmp.ne.unc p1,p0 = r4,r0
(p1) br L1
Далее следует концептуальное представление четырех накладывающихся исходных итераций, считаем, что загрузки и сохранения обращаются к памяти независимо. Инструкции сохранения, сравнения и перехода на второй стадии представлены псевдоинструкцией scb:
-
1
2
3
4
Такт
ld4
X
ld4.s
X+1
scb
ld4.s
X+2
scb
ld4.s
X+3
scb
X+4
scb
X+5
Обратите внимание, что загрузка для второй исходной итерации выполняется до сравнения и перехода первой исходной итерации. То есть, загрузка (и модификация r5) является спекулятивной. Условие цикла не вычисляется до такта Х+2, но чтобы максимизировать использование ресурсов, желательно запустить вторую исходную итерацию на такте Х+1. Без поддержки спекуляции по управлению, имеющейся в Itanium архитектуре, вторая исходная итерация не смогла бы начаться до такта Х+3.
Вычисление условия цикла для while-циклов очень отличается от такового для счетных циклов. В счетных циклах, можно вычислить условие цикла за один такт, используя подсчет циклических переходов. Это то, что делает инструкция br.ctop, когда устанавливает р16. В while-циклах, сравнение должно вычислить условие цикла и установить предикаты стадий. Стадии, предшествующие первому сравнению, называются спекулятивными стадиями конвейера, поскольку здесь не возможно сравнение для полного управления выполнением этих стадий. Поэтому, предикат стадии, установленный сравнением, используется (после ротации) для управления первой не спекулятивной стадией конвейера.
Ниже показана конвейерная версия предыдущего while-цикла. Для спекулятивной загрузки вставлена проверка:
mov ec = 2
mov pr.rot = 1 << 16;; // PR16 = 1, остальные = 0
L1:
ld4.s r32 = [r5],4 // Такт 0
(p18) chk.s r34, recovery // Такт 0
(p18) cmp.ne p17,p0 = r34,r0 // Такт 0
(p18) st4 [r6] = r34,4 // Такт 0
(p17) br.wtop.sptk L1;; // Такт 0
L2:
Чтобы объяснить, почему ядерный цикл запрограммирован таким образом, полезно исследовать трассу выполнения цикла (в предположении, что имеется 200 исходных итераций), показанную в табл. 5.2.
Здесь нет предиката стадии предназначенного для загрузки, потому что она спекулятивна. Сравнение устанавливает р17. Он является предикатом перехода для текущей итерации, а после ротации – предикатом стадии для первой не спекулятивной стадии (стадии 3) следующей исходной итерации. В течение стадии пролога, сравнение не может быть выполнено, его первый правильный результат появится со второго такта. Инициализация предикатов обеспечивает конвейер, который запрещает сравнение до тех пор, пока первая исходная итерация не достигнет стадии два на втором такте. В этой точке сравнение начнет генерировать предикаты стадий для управления не спекулятивными стадиями конвейера. Обратите внимание, что сравнение условно. Если бы оно было безусловным, то всегда записывало бы 0 в р17, и конвейер не начался бы правильно.
Табл. 5.1. Трассировка цикла wtop
Цикл |
Порт/Инструкции |
Состояние перед br.wtop |
|||||||
M |
I |
I |
M |
B |
p16 |
p17 |
p18 |
EC |
|
0 |
ld4.s |
|
|
|
br.wtop |
1 |
0 |
0 |
2 |
1 |
ld4.s |
|
|
|
br.wtop |
0 |
1 |
0 |
1 |
2 |
ld4.s |
cmp |
chk |
st4 |
br.wtop |
0 |
1 |
1 |
1 |
3 |
ld4.s |
cmp |
chk |
st4 |
br.wtop |
0 |
1 |
1 |
1 |
… |
… |
… |
… |
… |
… |
… |
… |
… |
… |
100 |
ld4.s |
cmp |
chk |
st4 |
br.wtop |
0 |
1 |
1 |
1 |
… |
… |
… |
… |
… |
… |
… |
… |
… |
… |
199 |
ld4.s |
cmp |
chk |
st4 |
br.wtop |
0 |
1 |
1 |
1 |
200 |
ld4.s |
cmp |
chk |
st4 |
br.wtop |
0 |
1 |
1 |
1 |
201 |
ld4.s |
cmp |
chk |
st4 |
br.wtop |
0 |
0 |
1 |
1 |
|
|
|
|
|
|
0 |
0 |
0 |
0 |
Выполнение br.wtop в двух первых тактах пролога, не соответствует ни какой исходной итерации. Их цель – просто продолжить выполнение до тех пор, пока не будет произведено первое правильное условие цикла. На первом такте предикат перехода р17 равен 1. Для этой схемы программирования, предикат перехода br.wtop всегда единица в течение последней спекулятивной стадии первой исходной итерации. В течение всех предшествующих стадий предикат перехода равен нулю. Если предикат перехода – ноль, то br.wtop продолжает ядерный цикл, только если ЕС больше единицы. Здесь же ЕС декрементируется. Таким образом, регистр ЕС должен инициализироваться значением равным количеству стадий эпилога, плюс количество спекулятивных конвейерных стадий. В вышеупомянутом примере, это будет: 0 + 2 = 2.
В такте 201, выполняется сравнение для 200-ой исходной итерации. Поскольку это финальная исходная итерация, то результат сравнения – ноль, а р17 не модифицируется. Ноль, который ротируется из р17 в р16, вызывает проход через br.wtop к выходу из цикла. ЕС декрементируется, а регистры ротируются последний раз.
В вышеприведенном примере нет стадий эпилога. Как только предикат становиться нулевым – выходим из ядерного цикла.
