while (condition) {
...
}
Рабочий процесс:
- проверить состояние;
- если false, перейти за пределы цикла;
- выполнить одну итерацию;
- перейти наверх.
if (condition) do {
...
} while (condition);
Рабочий процесс:
- проверить состояние;
- если false, перейти за пределы цикла;
- выполнить одну итерацию;
- проверить состояние;
- если это так, переходите к шагу 3.
Сравнивая эти два, вы можете легко увидеть, что последний может вообще не совершать никаких прыжков при условии, что цикл проходит ровно один шаг, и, как правило, количество прыжков будет на один меньше количества итераций. Первому придется вернуться назад, чтобы проверить условие, только чтобы выйти из цикла, когда условие ложно.
Переходы в современных конвейерных архитектурах ЦП могут быть довольно дорогостоящими: поскольку ЦП завершает выполнение проверок перед переходом, инструкции после этого перехода уже находятся в середине конвейера. Вся эта обработка должна быть отброшена, если предсказание ветвления не удается. Дальнейшее выполнение откладывается, пока конвейер перезагружается.
Объяснение упомянутого предсказания перехода: для каждого вида условного перехода у ЦП есть две инструкции, каждая из которых включает ставку на результат. Например, в конце цикла можно поместить инструкцию прыгать, если не ноль, ставка не ноль, потому что прыжок должен быть выполнен на всех итерациях, кроме последней. Таким образом, ЦП начинает прокачивать свой конвейер инструкциями, следующими за целью перехода, а не инструкциями, следующими за самой инструкцией перехода.
Важная заметка
Пожалуйста, не воспринимайте это как пример оптимизации на уровне исходного кода. Это было бы совершенно ошибочным, поскольку, как уже ясно из вашего вопроса, преобразование из первой формы во вторую - это то, что JIT-компилятор делает в обычном порядке, полностью самостоятельно.
person
Marko Topolnik
schedule
29.12.2013