TGViewer
Грокаем C++ Грокаем C++ @grokaemcpp · 9.37K subscribers
Post #1078 3.88K
​​Loop unrolling. pragma unroll
#опытным

Компилятор конечно умный и сам умеет разворачивать циклы. Но делает он это не во всех случаях. Когда-то уровень оптимизации не позволяет(агрессивная развертка делается на O3) или количество итераций цикла неизвестно.

Если же вы хотите вручную контролировать развертку, но не писать код развертки руками - для вас есть один вариант. Это #pragma unroll.

Правда, есть загвоздка. Стандартного синтаксиса этой директивы не существует, для каждого компилятора чуть свой синтаксис:

-👉🏿GCC и Clang: Используется #pragma GCC unroll Для Clang существует более детализированный синтаксис #pragma clang loop unroll.

👉🏿 MSVC (Microsoft Visual C++): здесь все, как не у всех: в msvc нет прямого аналога директивы #pragma unroll. Есть #pragma loop, но она контролирует скорее автовекторизацию, чем развертку.

👉🏿 Intel и NVIDIA компиляторы: Используют #pragma unroll.

👉🏿 ARM компилятор: Поддерживает #pragma unroll.

Раз у всех все свое, то в примерах будет использовать некую усредненную версию.

По сути есть 2 возможных варианта использования директивы:

🙈 Полная развертка

#pragma unroll
for (int i = 0; i < 12; ++i) {
p1[i] += p2[i] * 2;
}


В этом случае компилятор обязан знать число итераций цикла, чтобы полностью его развернуть.

Плюс чем больше итераций, тем сильнее распухает код бинаря.

Поэтому в данном виде директива встречается не так часто.

☃️ Частичная развертка

Это именно та история, которую мы обсуждаем всю серию статей. #pragma unroll N позволяет развернуть цикл так, чтобы за одну итерацию тело цикла выполнялось N раз.

#pragma GCC unroll 4
for (size_t i = 0; i < n; ++i) {
sum += arr[i];
}


Как прагма работает?

1️⃣ Препроцессор оставляет #pragma unroll после препроцессинга в единице трансляции для того, чтобы компилятор смог ее учесть.

2️⃣ На этапе семантического анализа компилятор встречает #pragma unroll и связывает его со следующим за ним циклом.

3️⃣ Специальная сущность в компиляторе, отвечающая за развертку циклов, слушает и повинуется прагме и делает столько операций в цикле, сколько сказал разработчик. Плюс добавляет обработку хвоста.

Здесь можно посмотреть примерчики с gcc-шной версией прагмы.

Напомню, что компилятор сам хорошо умеет оптимизировать циклы, особенно на O3. Используйте прагму только тогда, когда вы сами ручками проверили, что компилятор в вашем случае бессилен или делает что-то неправильно.

Плюс обязательно делайте перфоманс тестирование, чтобы выявить действительно лучший по производительности вариант.

Measure your performance. Stay cool.

#compiler #optimization #performance
  • ❤ 25
  • 👍 11
  • 🔥 3
  • 😁 3
  • 👏 1
More from @grokaemcpp
  1. Oct 12, 2026​​WAT #новичкам Как вы думаете, результат выражения: bool math = -1 < 1U; будет правдой ил…
  2. Oct 8, 2026​​Strict weak ordering #опытным На первый взгляд, всё выглядит рабочим: мы создаём 40 зака…
  3. Oct 7, 2026​​Где-то баг... #опытным Вот вам код: struct Order { int price; int id; }; int main() { st…
  4. Oct 5, 2026Откуда spurious wakeup на кондваре? #опытным У кондваров есть метод std::condition_variabl…
  5. Oct 1, 2026​​Stacktrace. Tips #опытным Чтобы полноценно работать со стандартными трейсами, нужно знат…
  6. Sep 28, 2026​​Stacktrace #опытным Одна из проблема исключений - непонятно, откуда оно прилетело. Ну да…
Threads Profile ViewerView any public Threads profile without an account.Open ThreadLook →Writing with AI? Make it sound human.Metric37 rewrites AI drafts so they read naturally. Free AI detector, 1,500 words free.Try Metric37 →