В информатике движение кода , также известное как подъем кода, опускание кода, инвариантное к циклу движение кода или факторинг кода, представляет собой общий термин для любого процесса, который перемещает код внутри программы для повышения производительности или размера, и является общей оптимизацией . выполняется в большинстве оптимизирующих компиляторов . Различать разные типы движения кода может быть сложно из-за противоречивого значения окружающих его терминов.
Движение кода имеет множество применений и преимуществ, многие из которых перекрывают друг друга в своей реализации.
Code Sinking , также известный как ленивое движение кода , — это термин, обозначающий метод, который уменьшает количество ненужных инструкций путем перемещения инструкций в ветки, в которых они используются: [1] Если операция выполняется перед ветвью и только один из путей ветвления использовать результат этой операции, тогда погружение кода влечет за собой перемещение этой операции в ветку, где она будет использоваться.
Этот метод является формой устранения мертвого кода в том смысле, что он удаляет код, когда его результаты отбрасываются или не используются, но в отличие от устранения мертвого кода он может удалять бессмысленные инструкции, даже если существует возможность использования результатов этой инструкции в путь выполнения кода.
Факторинг кода — это термин, обозначающий метод оптимизации размера, который объединяет общие зависимости в ветвях с веткой над ней. [2] Точно так же, как факторизация целых чисел разлагает число на наименьшие возможные формы (как факторы), факторизация кода преобразует код в наименьшую возможную форму путем объединения общих «факторов» до тех пор, пока не останутся дубликаты.
Глобальное движение кода , локальное движение кода , планирование кода , планирование инструкций и подъем/опускание кода — все это термины, обозначающие метод, при котором инструкции перестраиваются (или «планируются») для повышения эффективности выполнения внутри ЦП. [3] [4] Современные процессоры способны планировать пять или более инструкций за такт. Однако ЦП не может запланировать инструкцию, основанную на данных текущей (или еще не выполненной) инструкции. Компиляторы будут чередовать зависимости таким образом, чтобы максимизировать количество инструкций, которые ЦП может обработать в любой момент времени. [5]
В несуществующей архитектуре Intel Itanium инструкция прогнозирования ветвления (BRP) вручную поднимается компилятором над ветвями, чтобы ЦП мог немедленно выполнить ветвь. Itanium полагается на дополнительное планирование кода со стороны ЦП для максимизации эффективности процессора. [6]
Движение кода, инвариантного к циклу, — это процесс перемещения кода, инвариантного к циклу, в позицию вне цикла, что может сократить время выполнения цикла, предотвращая выполнение некоторых вычислений дважды для одного и того же результата.
LLVM имеет понижающий проход в своей единственной статической форме назначения. LLVM 15.0 не будет прерывать операцию, если какой-либо из ее путей кода содержит инструкцию сохранения или если она может выдать ошибку. [7] Кроме того, LLVM не помещает инструкцию в цикл.
Коллекция компиляторов GNU реализует перемещение кода под названием «факторинг кода» с целью уменьшения размера скомпилированной программы. [8] GCC переместит любой код вверх или вниз, если он «[не] аннулирует существующие зависимости и не вводит новые». [9]
LuaJIT использует понижение кода под названием «Поглощение выделения», чтобы уменьшить количество времени, которое скомпилированный код тратит на выделение и сбор временных объектов в цикле. [10] Снижение выделения перемещает выделения на пути выполнения, где выделенный объект может избежать исполняемого кода и, таким образом, потребует выделения кучи . Все удаленные распределения заполняются пересылкой от загрузки к хранилищу по их полям. [11]