- •4. Предикация, поток управления и поток инструкций
- •4.1. Краткий обзор
- •4.2. Предикация
- •4.2.1. Стоимость эффективности переходов
- •4.2.1.1. Ресурсы предсказания
- •4.2.1.2. Планирование инструкций
- •4.2.2. Предикация в архитектуре IntelItanium
- •4.2.3. Оптимизация эффективности программы использующей предикацию
- •4.2.3.1. Применение преобразования типа if
- •4.2.3.2. Предикация вне пути
- •4.2.3.3. Перемещение кода вверх.
- •4.2.3.4. Перемещение кода вниз
- •4.2.3.5. Сокращение засорения кэша.
- •4.2.4. Соображения о предикации
- •4.2.4.1. Несбалансированные пути выполнения.
- •4.2.4.2. Случай 1
- •4.2.4.3. Случай 2
- •4.2.4.4. Случай 3
- •4.2.4.5. Использование наложения ресурсов
- •4.2.4.6. Случай 1
- •4.2.5. Рекомендации по удалению ветвей
- •4.3. Оптимизация потока управления
- •4.3.1. Уменьшение критического пути при параллельном сравнении
- •4.3.2. Сокращения критического пути с помощью ветвлений.
- •4.3.3. Выбор множества значений для одной переменной или регистра с предикацией
- •4.3.3.1. Выбор одного из нескольких значений
- •4.3.3.2. Уменьшение использования регистров.
- •4.3.4. Улучшение выборки потока инструкций
- •4.3.4.1. Выравнивание потока инструкций.
- •4.4. Подсказки перехода и предвыборки
- •4.5. Итоги
4.3. Оптимизация потока управления
Обычно в программе есть несколько потоков управления сходящихся в одной точке или несколько потоков управления исходящих из одной точки. В первом случае, несколько потоков управления вычисляют значение одной и той же переменной или регистра, а в точке объединения, программа, прежде чем двигаться дальше, должна выбрать правильное значение. Во втором случае, множество потоков может начинаться в точке, где на основании набора условий выбирается несколько независимых путей.
В дополнение к этим множественным объединениям и разветвлениям, вычисление сложных составных условий обычно требует, чтобы древовидное вычисление свело несколько условий к одному. Архитектура Itaniumобеспечивает специальные инструкции, которые позволяют вычислять такие условия при уменьшении уровней дерева.
Третья оптимизация, относящаяся к управлению потоком, использует предикацию для улучшения выборки инструкций с помощью преобразования типа if, для генерации прямолинейных (straight-line) последовательностей, которые могут быть эффективно выбраны. Использование этих случаев и их оптимизация, описаны в остальной части данного раздела.
4.3.1. Уменьшение критического пути при параллельном сравнении
Вычисление составного условия перехода показанное ниже, требует нескольких инструкций в процессоре без специальных инструкций:
if ( rA || rB || rC || rD ) {
/* Инструкции блока If */
}
/* Нечто, следующее за блоком If*/
Следующий псевдокод показывает одно из возможных решений, использующее последовательность переходов:
cmp.ne p1,p0 = rA,0
cmp.ne p2,p0 = rB,0
(p1) br.cond if_block // Переход к инструкциям блока If
(p2) br.cond if_block
cmp.ne p3,p0 = rC,0
cmp.ne p4,p0 = rD,0
(p3) br.cond if_block
(p4) br.cond if_block
// Нечто, следующее за блоком If
Во многих реализациях основанных на архитектуре Itanium, эта последовательность, вероятно, будет требовать, по крайней мере, двух тактов выполнения, если все условия ложны, плюс, возможно, еще какое-то количество тактов, из-за одного или нескольких неправильно предсказанных переходов. Другая возможная последовательность вычисляет сокращение дерева ИЛИ.
or r1 = rA, rB
or r2 = rC, rD ;;
or r3 = r1, r2 ;;
cmp.ne p1,p2 = r3,0
(p1) br if_block
Это решение требует трех тактов для вычисления условия перехода, который, затем, может использоваться для перехода к блоку if.
Примечание. Его также можно использовать как предикатp1используемый блокомif, для того, чтобы избежать неправильного предсказания перехода.
Для уменьшения стоимости сложных условных выражений, архитектура Itaniumимеет специальные инструкции параллельного сравнения для оптимизации выражений имеющих операции И и ИЛИ. Эти инструкции сравнения являются специальными в том смысле, что многие инструкции сравнения позволяют адресовать один и тот же предикат в пределах одной группы инструкций. Это свойство дает возможность решить за один такт непростое условное выражение.
Чтобы эта модель использования работала должным образом, архитектура требует, чтобы программист гарантировал, что пока выполняется данный код, все инструкции, приемник которых является данным предикатным регистром:
либо записывают одно и то же значение (0 или 1),
либо вовсе не записывают приемный регистр.
Эта модель использования означает, что иногда параллельное сравнение не может обновить значение своих приемных регистров и таким образом, в отличие от обычного сравнения, предикаты, используемые в параллельном сравнении, должны быть инициализированы до параллельного сравнения. Для полной информации об операциях параллельного сравнения см. «Часть I. Руководство по прикладной архитектуре».
Код инициализации должен быть помещен в группу инструкций до параллельного сравнения. Однако, поскольку код инициализации никак не зависит от предыдущих значений, то он вообще-то может планироваться без учета критического пути кода.
Инструкции ниже показывают, как генерировать код для вышеприведенного примера, используя инструкции параллельного сравнения:
cmp.ne p1,p0 = r0,r0;; // инициализируем p1 в 0
cmp.ne.or p1,p0 = rA,r0
cmp.ne.or p1,p0 = rB,r0
cmp.ne.or p1,p0 = rC,r0
cmp.ne.or p1,p0 = rD,r0
(p1) br.cond if_block
Также возможно использовать p1 для предикации встроенного блокаif, чтобы избежать возможного промаха предсказания. Параллельным сравнением, также, могут быть сгенерированы более сложные выражения:
if ((rA < 0) && (rB == -15) && (rC > 0))
/* Инструкции If-блока */
Ниже показана возможная последовательность ассемблерного псевдокода для вышеприведенного кода C:
cmp.eq p1,p0=r0,r0;; // инициализируем p1 в 1
cmp.ne.and p1,p0=rB,-15
cmp.ge.and p1,p0=rA,r0
cmp.le.and p1,p0=rC,r0
При корректном использовании, сравнения И/ИЛИ, либо запишут в оба предикатных приемника одно и то же значение, либо ничего не запишут в предикатные приемники. Для другого варианта использования параллельного сравнения нужны обе части сложного условного выражения и if, иelse:
if ( rA == 0 || rB == 10 )
r1 = r2 + r3;
else
r4 = r5 - r6;
Параллельные инструкции имеют вариант andcm, который одновременно вычисляет и предикат, и его дополнение.
cmp.ne p1,p2 = r0,r0;; // инициализация p1,p2
cmp.eq.or.andcm p1,p2 = rA,r0
cmp.eq.or.andcm p1,p2 = rB,10;;
(p1) add r1=r2,r3
(p2) sub r4=r5,r6
Очевидно, что эти инструкции могут использоваться и в других комбинациях, для создания более сложных условных выражений.