Как я могу изменить код MIPS, чтобы минимизировать количество необходимых NOP вручную? - PullRequest
1 голос
/ 08 февраля 2020

Я столкнулся со следующим кодом MIPS, в котором есть данные и опасности использования нагрузки.

0 addi $t0,$a0,4
1 addi $t1,$a1,4
2 sub  $t2,$t0,$t1                #data hazard $t0, data hazard $t1
3 sll  $t3,$a2,2  
4 add  $t4,$t0,$t3                #data hazard $t3
5 add  $t5,$t1,$t3                #data hazard $t3
6 sw   $t2,0($t4)                 #data hazard $t4

Чтобы устранить опасности, я мог бы добавить 5 NOPs (2 после строки 1, 2 после строки 3 и 1 после строки 5), или я мог бы переписать код, избегая при этом опасности. Переставляя код, чтобы свести к минимуму число NOPs, я получаю:

0 addi $t0,$a0,4
1 addi $t1,$a1,4
3 sll  $t3,$a2,2
2 sub  $t2,$t0,$t1                #data hazard $t1
4 add  $t4,$t0,$t3                
5 add  $t5,$t1,$t3                
6 sw   $t2,0($t4)                 #data hazard $t4

Затем две опасности будут устранены путем добавления 1 NOP после строки 3 и 1 NOP после строки 5. Однако этот код относительно прост и короток. Что если мне дадут 20 строк кода MIPS на экзамене? Есть ли более быстрый способ или правило, которое может сделать перестановку кода проще и быстрее (вручную)?

1 Ответ

1 голос
/ 08 февраля 2020

Для алгоритма планирования команд сначала необходимо определить цепочки зависимостей. (То же самое, что и при определении критических путей задержки для exe-порядка exe c.)

Чтобы запланировать инструкции для машины порядка: чередуйте инструкции из разных цепочек dep, начиная с самой длинной .

При ручной настройке (или в оптимизирующем компиляторе) вы даже можете выполнять такие вещи, как перестановка ассоциативных операций (например, add), чтобы создавать различные временные эффекты, создавая больше ILP (параллелизм на уровне команд). например, превращение a+b+c+d в (a+b)+(c+d). Целочисленная математика ассоциативна; математика с плавающей запятой, как правило, не.

Конечно, это безопасно, только если код использует addu / addiu, а не переполнение ловушки при подписи MIPS add / addi. C компиляторы никогда не используют trapping add / sub, поэтому они могут свободно оптимизировать арифметику c с временными значениями, отличными от источника C. Вы также должны, если вы специально не хотите инструкцию, которая может перехватить переполнение со знаком.


Очевидно, что ассемблеры classi c MIPS могли бы перестроить ваш код для вас заполнить слоты загрузки и задержки ; это руководство по сборке Silicon Graphics от 1992 г. содержит некоторые подробности об агрессивном переупорядочении команд ассемблером (если только вы не используете .set noreorder, а затем не видны слоты задержки ветвления.) Книга См. MIPS Run может также упомянуть об этом.

Предположительно, ассемблер SGI обнаруживает блоки basi c с точки зрения меток и инструкций ветвления и выполняет планирование команд внутри отдельных блоков.

Конечно, хорошо компиляторы для языков высокого уровня также выполняют планирование команд. (Например, G CC). Я не думаю, что ассемблер GNU имеет оптимизирующий режим переупорядочения; он разработан как бэкэнд для компилятора, который сам расписывает инструкции.


В отличие от вашего игрушечного примера с многоцикловой задержкой, прежде чем вы сможете использовать результат add, real classi c MIPS представлял собой classi c 5-ступенчатый RIS C с переадресацией обхода и задержкой ALU с одним циклом. У первого поколения не было блокировок, поэтому был интервал задержки загрузки 1 цикл, и слоты задержки ветвления оставались архитектурно видимыми. Но простые инструкции ALU имеют задержку в 1 цикл. Таким образом, настоящие MIPS имели гораздо меньше опасностей, которых следует избегать при планировании инструкций. Но даже в этом случае, более поздняя версия MIPS убрала слот задержки загрузки для лучшей плотности кода, когда относительно примитивные компиляторы того времени не могли найти что-либо, что можно было бы там разместить. (Остановка вместо необходимости в NOP.)

Реальная машина с таким количеством временных интервалов задержки (без аппаратной блокировки для блокировки) была бы очень непрактичной для плотности кода / занимаемой памяти L1i, а также из-за плохой производительности. Есть причина, по которой реальные коммерческие проекты обходят пересылку вместо остановки. Но ваш пример действительно многоцикловой задержки - это реалистичность c для плавающей запятой.

(забавный факт: MIPS может переадресовать целевой адрес ветвления с первой половины EX на полупериод IF в общей сложности только 1 цикл задержки ветвления.

MIPS застрял с интервалами задержки ветвления до тех пор, пока в основном (и не обратно совместимом) реорге кодов операций не появятся ветки без задержки () MIPS32 / 64r6 в 2014 г.). Инструкция в слоте задержки ветвления выполняется независимо от того, занято ветвление или нет, поэтому позднее аппаратное обеспечение MIPS не могло удалить его так же, как для слотов задержки загрузки. RIS C -V избежал этой ошибки.

...