Введение

В информатике выбор инструкций — это этап бэкенда компилятора, который преобразует промежуточное представление среднего уровня (IR) в промежуточное представление низкого уровня. В типичном компиляторе выбор инструкций предшествует планированию инструкций и распределению регистров; следовательно, выходной IR содержит бесконечное множество псевдорегистров (часто называемых временными переменными) и может, и обычно подвергается, оптимизации проходами. В остальном он тесно соответствует машинному коду целевой платформы, байт-коду или языку ассемблера. Например, для следующей последовательности кода IR среднего уровня:
t1 = a
t2 = b
t3 = t1 + t2
a = t3
b = t1

хорошей последовательностью инструкций для архитектуры x86 будет:

MOV EAX, a
XCHG EAX, b
ADD a, EAX

Для всестороннего обзора темы выбора инструкций см.

Макро-расширение

Самый простой подход к выбору инструкций известен как расширение макросов или генерация интерпретативного кода. Выборщик инструкций, основанный на расширении макросов, работает путем сопоставления шаблонов с промежуточным представлением (IR). При совпадении соответствующий макрос выполняется, используя сопоставленную часть IR в качестве входных данных, что приводит к генерации соответствующих целевых инструкций. Расширение макросов может выполняться либо непосредственно над текстовым представлением IR, либо IR может быть сначала преобразовано в графическое представление, которое затем обходится в глубину. В последнем случае шаблон сопоставляется с одним или несколькими смежными узлами в графе. Если целевая машина не очень проста, расширение макросов само по себе обычно генерирует неэффективный код. Чтобы смягчить это ограничение, компиляторы, использующие этот подход, обычно сочетают его с оптимизацией "peephole", заменяя комбинации простых инструкций более сложными эквивалентами, которые повышают производительность и уменьшают размер кода. Этот подход известен как подход Дэвидсона — Фрейзера и в настоящее время применяется в GCC.

Покрытие графика

Другой подход заключается в том, чтобы сначала преобразовать промежуточное представление высокого уровня в граф, а затем покрыть этот граф с помощью шаблонов. Шаблон – это образец, соответствующий части графа и реализуемый одной инструкцией целевой машины. Цель состоит в том, чтобы покрыть граф таким образом, чтобы общая стоимость выбранных шаблонов была минимальной, где стоимость обычно отражает количество циклов, необходимых для выполнения инструкции. Для графов, имеющих древовидную структуру, покрытие с наименьшей стоимостью можно найти за линейное время с помощью динамического программирования, но для DAG-графов и полноценных графов задача становится NP-полной и, следовательно, чаще всего решается с использованием жадных алгоритмов или методов комбинаторной оптимизации.