Вы создаете компилятор для определенного набора команд, который является подмножеством выбранной «архитектуры набора команд (ISA)».
(Многие наборы команд имеют инструкции ввода / вывода, но компиляторы почти никогда не генерируют их).
Может быть несколько разных конструкций процессора, которые выполняют эту «архитектуру набора команд»
которая будет работать с выбранным вами подмножеством инструкций.
На практике происходят три вида эволюционных событий.
Вы определяете, что ваш компилятор будет лучше, если использовать еще несколько инструкций от ISA. Например, вы можете решить, что инструкция MULTIPLY позволит вашему компилятору генерировать более быстрый код, чем вызов подпрограммы, который вы использовали для умножения в прошлом. В этом случае вы немного расширяете свой компилятор.
Владельцы ISA (Intel, AMD, IBM, ...) добавляют в ISA совершенно новые наборы инструкций. Например, данные параллельные операции над строкой данных кэша («инструкции SIMD»). Вы можете решить добавить некоторые из них в ваш компилятор. Это событие может быть трудным, поскольку новые семейства инструкций обычно делают разные предположения о том, как данные выкладываются и обрабатываются.
Вы найдете совершенно другого ISA, с которым хотите работать. В этом случае вы собираетесь перестроить серверную часть вашего компилятора, поскольку набор инструкций полностью отличается с точки зрения того, какие регистры существуют, как они используются и т. Д.
Сборщики компиляторов часто создают компиляторы для поэтапной работы. Последний этап перед генерацией фактического машинного кода обычно представляет программу как абстрактный набор операций над данными довольно низкого уровня (например, операции со значениями размера фиксированного слова) с довольно стандартными абстрактными операциями (ADD, MULTIPLY, COMPARE, JUMP, CALL, STORE, LOAD, ...), которые не имеют никаких обязательств по отношению к фактическому ISA (особенно без обязательств по регистру или конкретным машинным инструкциям). Делая это таким образом, можно выполнять высокоуровневые оптимизации независимо от ISA; просто подумайте об этом как о хорошей модульности. Последние несколько этапов специализируются на ISA; обычно на этапе для выделения регистров, за которым следует этап, в котором шаблон сопоставляет фактические инструкции с абстрактными.
Есть целые книги, написанные по оптимизации на более высоком уровне, и другие книги, написанные по окончательным состояниям генерации кода (и часто книги, которые касаются обоих в отдельных главах). [Книга Aho & Ullman Dragon и Torczon's Engineering a Compiler - хорошие книги на обе темы). Существует множество технологий, позволяющих записывать окончательные наборы инструкций и регистры, и они генерируют большую часть последних этапов; GCC есть такой. Эта технология сложна и не вписывается в это предложение; лучше всего читать книги.
Как только вы получите компилятор, работающий для первого ISA таким образом, вы можете создать вариант, используя ту же технологию. Вы получите два физических компилятора, по одному для каждого ISA. Они разделяют всю логику внешнего интерфейса и генерируют и оптимизируют код. Они полностью меняются на последних этапах.
Что вам следует понять, так это то, что создание компилятора для использования наборов команд является сложным процессом.