Итак, компилятор может свободно переупорядочивать фрагменты кода из соображений производительности. Предположим, что какой-то фрагмент кода, переведенный непосредственно в машинный код без применения оптимизаций, выглядит так:
machine_instruction_1
machine_instruction_2
machine_instruction_3
machine_instruction_4
machine_instruction_5
но умный компилятор решает, что первоначальный порядок крайне неэффективен, и переупорядочивает тот же код так, чтобы новый порядок результирующих машинных инструкций был следующим:
machine_instruction_5
machine_instruction_4
machine_instruction_3
machine_instruction_2
machine_instruction_1
Все идет нормально.
Вот где начинается сложная часть. Результирующие машинные инструкции будут выполняться процессором, который может снова перетасовать их любым способом, который он сочтет подходящим для соображений производительности, до тех пор, пока сохраняется логика кода. Поскольку мы имеем дело с двумя «слоями» переупорядочения инструкций:
- первый из-за оптимизации компилятора
- второй, из-за внеочередного выполнения процессора
что вообще делает переупорядочивание инструкций во время компиляции актуальным? Все, что видит процессор, — это последовательность необработанных машинных инструкций без каких-либо указаний на какие-либо предшествующие оптимизации, выполненные компилятором. Если процессор вводит свой собственный «уровень» переупорядочения, почему он не делает недействительным порядок инструкций, установленный компилятором? По сути, что заставляет процессор соблюдать оптимизацию компилятора? Как переупорядочение во время компиляции и переупорядочение во время выполнения «взаимодействуют», как последнее дополняет первое?