Почему компиляторы должны быть «умнее» для архитектуры набора инструкций RISC

Почему компиляторы должны быть «умнее» для архитектуры набора инструкций RISC

Архитектура с сокращенным набором инструкций (RISC) направлена ​​на сокращение количества инструкций, тем самым повышая производительность. Единственным недостатком этого подхода является то, что компиляторы должны быть «умнее».

Что имела в виду моя преподавательница, когда сказала, что «компиляторы должны быть умнее» и почему это так?

решение1

Если говорить честно, RISC означает «уменьшенная сложность набора инструкций» — количество инструкций не обязательно уменьшается, но каждая инструкция становится проще с точки зрения машинных циклов, необходимых для ее выполнения, и с точки зрения количества вентилей (или памяти микрокода), выделенных для ее реализации.

Теория (которая, по крайней мере, частично реализована) заключается в том, что за счет сокращения количества управляющей логики больше места на чипе доступно для регистров и пути данных. Поэтому машины RISC обычно имеют в 2-4 раза больше регистров, чем их аналоги CISC.

Это оставляет компилятору работу над этой пропущенной логикой управления, включая операции «планирования» (их последовательность), так что, скажем, вы не делаете два сложения подряд, а делаете сложение, а затем сдвиг (и на разных регистрах), чтобы и сумматор, и сдвигатель использовались оптимально. И компилятор также должен управлять набором регистров, чтобы оптимизировать перемещение в регистры и из них, минимизируя доступ к хранилищу. Плюс компилятор должен знать, как лучше всего использовать странные инструкции (такие как «сдвиг влево на один и маска с литералом»), поскольку они обычно имеют некоторые (возможно, странные) сценарии, где они относительно эффективны.

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

(Для тех, кто, по-видимому, не верит, что я знаю, о чем говорю: я впервые занялся RISC-процессором IBM 801 в начале 70-х, и был знаком с Джорджем Радином и Марти Хопкинсом.)

решение2

Поскольку в RISC-процессоре меньше инструкций, меньше вероятность того, что один высокоуровневый оператор будет правильно преобразован в один код операции на машинном языке.

Синонимом RISC CPU является «архитектура загрузки-хранения». По сути, это означает, что инструкции RISC, которые действительно работают, обычно работают только с регистрами. Если вы хотите работать со значениями, хранящимися в ОЗУ, вам нужно выдать явные инструкции LOAD, тогда как у CISC CPU, таких как x86, есть инструкции, которые делают это автоматически. RISC CPU исторически имели больше регистров, чем x86, и хороший код будет хорошо управлять доступными регистрами, чтобы избежать ненужного доступа к памяти, то есть компилятор должен это учитывать.

Другое дело, что RISC-процессоры обычно предоставляют только минимальную «инфраструктуру», необходимую для связи.

Например, процессоры x86 имеют понятие «стека», куда вы можете помещать значения, а затем «выталкивать» их (есть инструкции PUSHи POP). Также есть CALLинструкция — она помещает текущий указатель инструкций в стек, а затем переходит к адресу назначения — обычно подпрограмме или функции. RETЗатем позже может быть выдана инструкция для выталкивания этого сохраненного указателя инструкций и возобновления работы с исходной функции. Вложение подпрограмм удобно, и вы можете использовать PUSHи POPдля легкого добавления параметров для подпрограмм.

На MIPS, например, все, что у вас есть, это jalfor "Jump and Link" - он помещает текущий указатель инструкции в регистр, а затем переходит по этому адресу. Если вы хотите сделать что-то вроде стека или CALLинструкции x86, вам придется сделать это вручную. Это требует большего интеллекта от компилятора.

решение3

Процессоры CISC (вычислительные со сложным набором инструкций) имеют более широкий спектр доступных им инструкций, чем процессоры RISC (вычислительные со сокращенным набором инструкций).

Примером умножения в CISC может быть: MUL 1:3, 4:2 (Умножение 1:3 и 2:4). Эта команда загрузит значение в позицию 1:3 в своем регистре, загрузит значение в 4:2, умножит их вместе и сохранит обратно в 1:3

Процессоры RISC могут иметь следующие возможности:

  • НАГРУЗКА А, 1:3
  • НАГРУЗКА B, 4:2
  • ПРОД А, Б
  • МАГАЗИН 1:3, А

...4 операции RISC на 1 операцию CISC.

Поскольку RISC требует больше операций даже для выполнения простейших вычислений умножения — представьте, насколько больше работы требуется для таких вещей, как рендеринг видео или игры?

Учитывая это, компиляторы, которые создают программное обеспечение из кода, введенного программистом, должны быть «умнее», чтобы знать, как упрощать сложные части кода и сложные команды для архитектуры RISC.

Надеюсь, это имеет смысл. Для дальнейшего чтения, возможно, стоит взглянуть на: http://www.engineersgarage.com/articles/risc-and-cisc-architecture?page=5

Связанный контент