Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
MProc / M9 / Оптимизация часть 3..doc
Скачиваний:
17
Добавлен:
16.04.2013
Размер:
148.99 Кб
Скачать

3.3.2.2. Зависимость по данным в архитектуре IntelItanium

Архитектура Itaniumтребует от программиста включать стопы между регистровыми зависимостямиRAWиWAW, чтобы быть уверенном в корректном результатах кода. Например, в следующем коде инструкцияaddвычисляет значение вr4, которое необходимо для инструкцииsub.

add r4=r5,r6 ;; // Группа инструкций 1

sub r7=r4,r9 // Группа инструкций 2

Стоп после инструкции addзавершает одну группу инструкций, таким образом, инструкцияsubможет легально читатьr4.

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

mov r16=1

mov r17=2 ;;

st8 [r15]=r16

st8 [r14]=r17;;

Если адрес в r14равен адресу вr15, то однопроцессорная система гарантирует, что это место памяти будет содержать значение изr17(2). Следующая зависимостьRAW, тоже является легальной внутри одной группы инструкций, даже если программа не способна определить накладываются лиr1иr2.

st8 [r1]=x

ld4 y=[r2]

3.3.2.3. Планирование инструкций и зависимости по данным

Правила зависимости являются достаточными для того, чтобы генерировать корректный код, но для генерации эффективного кода, компилятор должен принять во внимание время выполнения инструкций. Например, характерное выполнение имеет два такта для кэша данных первого уровня. В приведенном ниже примере, стоп обслуживает корректное упорядочивание, но использование r2планируется только один такт после его загрузки:

add r7=r6,1 // Такт 0

add r13=r25,r27

cmp.eq p1,p2=r12,r23;;

add r11=r13,r29 // Такт 1

ld4 r2=[r3];;

sub r4=r2,r11// Такт 3

Таким образом, задержка загрузки составит два такта, а инструкция subбудет простаивать до третьего такта. Чтобы избежать простоя компилятор может передвинуть загрузку ранее в очереди, так, чтобы машина могла выполнять полезную работу в каждом такте:

ld4 r2=[r3] // Такт 0

add r7=r6,1

add r13=r25,r27

cmp.eq p1,p2=r12,r23;;

add r11=r13,r29;;// Такт 1

sub r4=r2,r11// Такт 2

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

Теперь предположим, что первоначальная последовательность кода содержала неоднозначную зависимость по памяти между инструкцией сохранения и инструкцией загрузки:

add r7=r6,1 // Такт 0

add r13=r25,r27

cmp.ne p1,p2=r12,r23;;

st4 [r29]=r13// Такт 1

ld4 r2=[r3];;

sub r4=r2,r11// Такт 3

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

В отсутствие другой архитектурной поддержки, сохранения могут препятствовать перемещениям загрузок и зависимых от них инструкций. Следующие операторы языка Cне могут быть переупорядочены, если не известно, чтоptr1 иptr2 указывают на независимые места памяти:

*ptr1 = 6;

x = *ptr2;