Как оптимизировать эту функцию с помощью компилятора? - PullRequest
2 голосов
/ 14 апреля 2011

Я проходил курс по компилятору и инструментам (в этом семестре). Я читал до генерации промежуточного кода, а также видел DAG представление для оптимальности. С компилятором ясно одно: что бы ни создавался промежуточный код, он должен быть сопоставлен с набором инструкций системы, чтобы мы могли запустить нашу программу.

Допустим, у меня есть написать компилятор для конкретной архитектуры (скажем, A), где сложение между двумя числами равно ADD R1, R2, R3 (из набора инструкций A), где R1 - это пункт назначения, R2, R3 являются источниками. И я сопоставил с этой инструкцией, то есть, когда я хочу добавить два числа (независимо от их типа, для простоты), которые представлены в промежуточном коде, я буду запускать код операции ADD !.

Предположим, что на рынке появилась новая архитектура, в которой сложение двух чисел имеет различный набор команд, скажем, AD R1, R2, R3 . Теперь, очевидно, мой компилятор не будет добавлять числа!

Теперь мой вопрос: когда я пишу свой компилятор для моего языка программирования, я должен добавить всю архитектуру с их набором инструкций, чтобы мой компилятор делал правильно, что ему нужно делать? Если так, что все методы Оптимизировать этот эффект? Потому что добавление всего набора инструкций почти снизило бы мою производительность.

Исправьте, если я ошибаюсь!

Ответы [ 2 ]

4 голосов
/ 14 апреля 2011

Вы создаете компилятор для определенного набора команд, который является подмножеством выбранной «архитектуры набора команд (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. Они разделяют всю логику внешнего интерфейса и генерируют и оптимизируют код. Они полностью меняются на последних этапах.

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

1 голос
/ 15 апреля 2011

Все зависит от того, насколько велико изменение. Допустим, у вас есть ISA X 1.0 с инструкцией ADD R1, R2, R3. Если вы получаете новую версию X 1.1, которая заменяет инструкцию ADD R1, R2, R3 на AD R1, R2, R3, это небольшое изменение. По сути, у вас есть одна и та же инструкция с другим именем. Вы можете разместить это изменение с флагом cc -arch X1.1, который будет выдавать «AD» вместо «ADD».

Если изменение больше, чем в AD R1, R2 (R2 <- R1 + R2), то новая инструкция отличается от старой ADD. В этом случае вам нужно изменить генератор кода и включить эту инструкцию в свой набор доступных инструкций. Снова cc -arch X1.1 должен сообщить генератору, что эта инструкция доступна. </p>

Если изменение еще больше, чем при перенаправлении компилятора на ISA Y, вам нужно изменить все инструкции, сгенерированные генератором кода. Это может быть много работы.

Теперь вопрос о том, будут ли существующие низкоуровневые оптимизации компилятора работать с новой целью, также под вопросом. В общем, четко определенный бэкэнд (например, gcc) может поддерживать многие ISA. Он использует промежуточное представление низкого уровня (IR), где ваша инструкция имеет несколько свойств, включая имя кода операции («ADD» или «AD»). Однако оптимизаторы низкого уровня не очень озабочены именем, так как другие свойства инструкции, т. Е. Сколько у него операндов? Какие операнды читаются / пишутся? Доступ к памяти? Это меняет ход программы? и т.д.

Если вы можете адаптировать свою целевую архитектуру в платформу компилятора, тогда вы можете успешно использовать существующие оптимизации.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...