Статическое планирование ООО процессоров
Планировщик инструкций LLVM MISched использует декларативные описания TableGen функциональных блоков процессора, конвейеров и задержек. Представьте, что вы пытаетесь определить эквивалент рекомендаций по кодированию из Справочного руководства Intel по оптимизации на основе этих деклараций.
В общем, каковы цели / методы статического планирования ООО процессоров? Когда он будет планировать инструкцию A перед B и когда он будет планировать A после B для ООО процессора?
Суперскалярные процессоры могут одновременно выполнять более одной инструкции. Обработчик по порядку будет рассматривать инструкции только в их исходном порядке. Обработчик, вышедший из строя (ООО), может выполнять инструкции не в порядке, а затем фиксировать результаты по порядку. Предположения не имеют значения для этого вопроса, но я предполагаю, что эти процессоры конвейерные. Вспомните A53 (в порядке) и Haswell (ООО).
Какую команду ООО-процессор будет выполнять следующей - это решение по планированию, принимаемое процессором во время выполнения. Обычно это называется динамическим планированием. Какую команду выполняет упорядоченный процессор, было решено компилятором еще при компиляции программы. Следовательно, это обычно называется статическим планированием.
Однако компиляторы также статически выбирают / планируют обработчики ООО. Как в случае упорядоченного, так и в случае ООО, компилятор может просматривать большое окно инструкций; компилятору приходится иметь дело с давлением регистров; и в обоих случаях компилятор хочет, чтобы функциональные блоки были заняты. ООО процессоры обычно также могут переименовывать регистры, уменьшая давление на регистры.
Учитывая, что ООО-процессор динамически планирует инструкции, что должен сделать опережающий компилятор, чтобы помочь в этом?
1 ответ
В целом вы правы, но планирование времени компиляции все же может немного улучшить скорость выполнения. Это происходит потому, что компилятор может переставлять инструкции более оптимальным образом для ускорения декодирования (более старые варианты x86 могли декодировать несколько инструкций параллельно, только если последовательность удовлетворяет определенным ограничениям) или более плотно упаковать их в буфер инструкций процессора. Цитата из книги Роберта Моргана "Создание оптимизирующего компилятора":
The compiler should schedule the insns as if the processor were
not an out-of-order execution processor. The more effective this
schedule is, the larger the size of the effective insns buffer.
На практике выигрыши обычно довольно небольшие (несколько процентов).
На самом деле это не решение по планированию как таковое, а скорее оптимизация. По сути, просмотр проходов, которые addILPOpts () LLVM добавляет для ООО суперскалярных бэкендов, дает хорошее представление о том, что возможно. Раннее if-преобразование генерирует код, который будет выполняться параллельно, избегая кода, который должен выполняться последовательно.
LLVM имеет проход EarlyIfConverter для ООО суперскаляров. Он используется серверными модулями PowerPC, X86, AMDGPU, SystemZ и AArch64. EarlyIfConverter оценивает два выражения параллельно и вставляет select, чтобы выбрать одно: TII->insertSelect(...)
// Early if-conversion is for out-of-order CPUs that don't have a lot of
// predicable instructions. The goal is to eliminate conditional branches that
// may mispredict.
//
// Instructions from both sides of the branch are executed speculatively, and a
// cmov instruction selects the result.
Этот проход добавляется серверной частью в addILPOpts(). Он использует ILP для параллельной оценки двух альтернатив, а не для условной оценки одной, а затем другой.