Часть II –
ветвления
Крис Касперски
Сегодня мы продолжим сравнение Linux-компиляторов, начатое в прошлом
номере журнала, и рассмотрим оптимизацию условных переходов и операторов типа switch.
Механизмы их трансформации достаточно многочисленны и разнообразны. За
последнее время было предложено множество новых идей, воплощенных в
компиляторах GCC 3.3.4 и Intel C++ 8.0 (сокращенно icl), однако
древний Microsoft Visual C++ 6.0 (сокращенно msvc) не сдает
своих позиций, так что не спешите списывать его в утиль и сдавать на свалку.
Оптимизация ветвлений/branch
Ветвления (по-английски branch, они же условные/безусловные переходы)
относятся к фундаментальным основам любого языка, без которых не обходится ни
одна программа. Даже «hello, world!»! Ведь выход из функции main – это тоже
ветвление, пусть и неявное (однако ж процессор синтаксисом языка не
проведешь!). А сколько ветвлений содержит сама функция printf? А библиотека
времени исполнения?
Суперскалярные микропроцессоры, построенные по
конвейерной архитектуре (а все современные микропроцессоры именно так и
устроены), быстрее всего выполняют линейный код и ненавидят ветвления. В лучшем
случае они дезориентируют процессор, слегка приостанавливая выполнение
программы, в худшем же – полностью очищают конвейер. А на последних Pentium он
очень длинный (и с каждой последующей моделью становится все длиннее и
длиннее). Быстро его не заполнишь… на это может уйти не одна сотня тактов, что
вызовет обвальное падение производительности.
Оптимизация переходов дает значительный выигрыш,
особенно если они расположены внутри циклов (кстати говоря, циклы – это те же
самые переходы), поэтому качество компилятора не в последнюю очередь
определяется его умением полностью или частично избавляться от ветвлений.