# Поддерживаемые MCST директивы #pragma и !dir$

- Общая информация

- Директивы #pragma языков C/C++

  - Директивы #pragma для заголовочных файлов

  - Директивы #pragma для управления диагностическими сообщениями

  - Директивы #pragma для для задания идентификационной строки

  - Директивы #pragma для оптимизации ассемблерных вставок

  - Директивы #pragma для оптимизации ассемблерных вставок

  - Директивы #pragma, указывающие компилятору свойства процедур

  - Директивы #pragma для оптимизации циклов

- Директивы !dir$ языка Fortran

  - Директивы !dir$ для оптимизации кода

- Побочные эффекты оптимизационных директив #pragma и !dir$

## Общая информация

В данном документе описываются только собственные директивы #pragma и !dir$. Директивы #pragma, описанные в каких-либо стандартах, описаны в статье Поддерживаемые стандартные директивы #pragma. Те директивы #pragma, которые позаимствованы у gcc, описаны в статье Поддерживаемые GNU директивы #pragma

## Директивы #pragma языков C/C++

### Директивы #pragma для заголовочных файлов

`#pragma` once

> Запрет повторного включения заголовочного файла. По действию сходно с include guard. Добавляется в самое начало файла

### Директивы #pragma для управления диагностическими сообщениями

Настроить можно только те диагностические сообщения, которые являются предупреждением (warning) или замечанием (remark). Под `<msg>` подразумевается номер диагностического сообщения, который печатается в компиляторе при выдаче

`#pragma` diag_suppress `<msg>`

> Подавить вывод диагностического сообщения

`#pragma` diag_remark `<msg>`

> Поменять уровень диагностического сообщения на “замечание”

`#pragma` diag_warning `<msg>`

> Поменять уровень диагностического сообщения на “предупреждение”

`#pragma` diag_error `<msg>`

> Поменять уровень диагностического сообщения на “ошибка”

`#pragma` diag_default `<msg>`

> Установить для диагностического сообщения поведение по умолчанию

`#pragma` diag_once `<msg>`

> Установить для диагностического сообщения режим, в котором оно выдается не более одного раза

`#pragma` diagnostic push

> Сохранить текущие настройки диагностических сообщений в виртуальный стек

`#pragma` diagnostic pop

> Извлечь настройки диагностических сообщений из виртуального стека

### Директивы #pragma для для задания идентификационной строки

`#ident "string"`
`#pragma` ident `"string"`

> Игнорируются

### Директивы #pragma для оптимизации ассемблерных вставок

`#pragma` asm_inline
`#pragma` no_asm_inline

> Управление inline-подстановкой ассемблерных вставок

`#pragma` asm_length `(length)`

> Доступно только для архитектуры E2K. Указание длительности ассемблерной вставки, выраженной в количестве машинных тактов. Для параметра `length` учитываются только значения от 0 до 14. Значения 15 и выше игнорируются

### Директивы #pragma для оптимизации ассемблерных вставок

`#pragma` unknown_control_flow `(func_name)`

> Обработка функции `func_name` аналогично функции `setjmp`

`#pragma` no_instrument_function `(func_name)`

> Отказ от инструментирования функции `func_name`

### Директивы #pragma, указывающие компилятору свойства процедур

`#pragma` no_inline `(func_list)`

> Запрещает компилятору делать inline-подстановку функций в списке

`#pragma` hot `(func_list)`

> Указывает компилятору, что представленные в списке функции являются “горячими”

`#pragma` no_side_effect `(func_list)`

> Указывает, что функции не имеют посторонних эффектов (не меняют состояние программы, невидимое в точке вызова). Игнорируется

### Директивы #pragma для оптимизации циклов

`#pragma` unroll `(N)`

> Применить Loop Unrolling на N к ближайшему после объявления директивы циклу. Если параметр опущен, то компилятор это воспринимает, как желание пользователя полностью раскрутить цикл в скалярный код. Дополнительным эффектом применения прагмы является увеличение оценочного количества итераций указанного цикла, если оно не известно точно. Количество итераций вычисляется как `min_ovl * N`, где `min_ovl` - минимальное количество итераций, при котором применится оптимизация аппаратного наложения итераций цикла. Для более точного определения количества итераций цикла рекомендуется использовать эту прагму в комбинации с `#pragma loop_count (N)`

`#pragma` split_fuse `(N)`

> Игнорируется

`#pragma` loop count `(N)`

> Установить у ближайшего после объявления директивы цикла количество итераций равное N. Игнорируется, если подан реальный профиль через `-fprofile-use`

`#pragma` vector `always`

> Форсирует применение векторизации к ближайшему после объявления директивы циклу, даже если эвристики оптимизации говорят, что её применение нецелесообразно

`#pragma` vector `aligned`

> Говорит компилятору, что все обращения к памяти в ближайшем после объявления директивы цикле являются выровненными, так что векторизация может примениться к этому циклу более эффективно. Величина выравнивания зависит от целевой архитектуры: для Elbrus V1-V4 это 8 байт, для V5 и далее - 16 байт.

`#pragma` vector `unaligned`

> Говорит компилятору, что все обращения к памяти в ближайшем после объявления директивы цикле являются невыровненными, поэтому строить динамические проверки выровненности операций обращения к памяти не следует.

`#pragma` vector `nontemporal`

> Запрет заведения в кэш-память всех уровней и включение режима write combining (объединение операций в store-буфере) для операций записи в ближайшем после объявления директивы цикле.

`#pragma` novector

> Запрет применения векторизации к ближайшему после объявления директивы циклу

`#pragma` reduce `recurrence`

> Форсирует разрыв рекурентностей в ближайшем после объявления директивы цикле

`#pragma` prefetch

> Форсирует включение аппаратной предподкачки данных для регулярных операций чтения из памяти в ближайшем после объявления директивы цикле, даже если эвристики оптимизации говорят, что это нецелесообразно; не влияет на автоматическую генерацию операций программной предподкачки

`#pragma` noprefetch

> Запрет аппаратной предподкачки данных для регулярных операций чтения из памяти в ближайшем после объявления директивы цикле; не влияет на автоматическую генерацию операций программной предподкачки

`#pragma` comb_oper

> Форсирует комбинирование пар арифметических операций в двухэтажные операции в ближайшем после объявления директивы цикле, даже если эвристики оптимизации говорят, что это нецелесообразно

`#pragma` no_comb_oper

> Запрещает комбинирование пар арифметических операций в двухэтажные операции в ближайшем после объявления директивы цикле

`#pragma` ivdep

> Указывает, что в ближайшем после объявления директивы цикле, если для пары операций чтения/записи не удалось статически определить их зависимость или независимость, то следует считать, что межитерационные зависимости для этих операций отсутствуют

`#pragma` no_dam

> Запрещает применение динамического разрыва зависимостей (DAM) к ближайшему после объявления директивы циклу. Может быть полезной в случае, когда в цикле есть maybe-зависимости между операциями доступа к памяти, из-за которых применение DAM приводит к частому уходу на компенсирующий код. Прагма имеет эффект только для архитектуры Elbrus.

`#pragma` swp

> Форсирует применение оптимизаций конвейеризации к ближайшему после объявления циклу, выключая проверки эффективности конвейеризации для этого цикла

`#pragma` noswp

> Запрещает применение оптимизаций конвейеризации к ближайшему после объявления циклу

`#pragma` spmv

> Позиционирует ближайший цикл как цикл умножения разреженных матриц. Это даёт возможность лучше настроить оптимизации и оценки компилятора для указанного цикла

## Директивы !dir$ языка Fortran

### Директивы !dir$ для оптимизации кода

`!dir$` unroll `(N)`

> Применить Loop Unrolling на N к ближайшему после объявления директивы циклу. Дополнительным эффектом применения прагмы является увеличение оценочного количества итераций указанного цикла, если оно не известно точно. Количество итераций вычисляется как `min_ovl * N`, где `min_ovl` - минимальное количество итераций, при котором применится оптимизация аппаратного наложения итераций цикла. Для более точного определения количества итераций цикла рекомендуется использовать эту прагму в комбинации с `!dir$ loop count (N)`

`!dir$` loop count `(N)`

> Установить у ближайшего после объявления директивы цикла количество итераций равное N. Игнорируется, если подан реальный профиль через `-fprofile-use`

`!dir$` vector `always`

> Форсирует применение векторизации к ближайшему после объявления директивы циклу, даже если эвристики оптимизации говорят, что её применение нецелесообразно

`!dir$` vector `aligned`

> Говорит компилятору, что все обращения к памяти в ближайшем после объявления директивы цикле являются выровненными, так что векторизация может примениться к этому циклу более эффективно. Величина выравнивания зависит от целевой архитектуры: для Elbrus V1-V4 это 8 байт, для V5 и далее - 16 байт.

`!dir$` vector `unaligned`

> Говорит компилятору, что все обращения к памяти в ближайшем после объявления директивы цикле являются невыровненными, поэтому строить динамические проверки выровненности операций обращения к памяти не следует.

`!dir$` vector `nontemporal`

> Запрет заведения в кэш-память всех уровней и включение режима write combining (объединение операций в store-буфере) для операций записи в ближайшем после объявления директивы цикле.

`!dir$` novector

> Запрет применения векторизации к ближайшему после объявления директивы циклу

`!dir$` reduce `recurrence`

> Форсирует разрыв рекурентностей в ближайшем после объявления директивы цикле

`!dir$` inline

> Рекомендует inline-подстановку всех функций в следующую за директивой строку или в тело следующего за директивой цикла. Обычно компилятор игнорирует такие подсказки, однако, вместе с опциями `-finline-only-native` или `-fforce-inline` они могут стать более весомыми.

`!dir$` forceinline

> Обязывает компилятор произвести inline-подстановку всех функций в следующую за директивой строку или в тело следующего за директивой цикла.

`!dir$` noinline

> Запрещает компилятору производить inline-подстановку в следующую за директивой строку или в тело следующего за директивой цикла.

`!dir$` ivdep

> Указывает, что в ближайшем после объявления директивы цикле, если для пары операций чтения/записи не удалось статически определить их зависимость или независимость, то следует считать, что межитерационные зависимости для этих операций отсутствуют

`!dir$` no_dam

> Запрещает применение динамического разрыва зависимостей (DAM) к ближайшему после объявления директивы циклу. Может быть полезной в случае, когда в цикле есть maybe-зависимости между операциями доступа к памяти, из-за которых применение DAM приводит к частому уходу на компенсирующий код

`!dir$` spmv

> Позиционирует ближайший цикл как цикл умножения разреженных матриц. Это даёт возможность лучше настроить оптимизации и оценки компилятора для указанного цикла

`!dir$` swp

> Форсирует применение оптимизаций конвейеризации к ближайшему после объявления циклу, выключая проверки эффективности конвейеризации для этого цикла

`!dir$` noswp

> Запрещает применение оптимизаций конвейеризации к ближайшему после объявления циклу

`!dir$` comb_oper

> Форсирует комбинирование пар арифметических операций в двухэтажные операции в ближайшем после объявления директивы цикле, даже если эвристики оптимизации говорят, что это нецелесообразно

`!dir$` no_comb_oper

> Запрещает комбинирование пар арифметических операций в двухэтажные операции в ближайшем после объявления директивы цикле

`!dir$` expect_prob `P`

> Задает вероятность перехода на ветку THEN в операторе IF в следующей за директивой строке. Вероятность P должна быть в диапазоне [0..1]. Это позволяет компилятору лучше настроить оптимизации для данного перехода.

## Побочные эффекты оптимизационных директив #pragma и !dir$

Почти все оптимизационные директивы `#pragma` и `!dir$` для циклов приводят к отключению оптимизации Loop Jam (слияние независимых смежных циклов с одинаковым количеством итераций). Это вызвано тем, что во многих случаях после слияния циклов невозможно точно исполнить предписание директив `#pragma` и `!dir$`. В число таких директив входят:

- `#pragma` unroll `(N)`

- `#pragma` loop count `(N)`

- `#pragma` vector

- `#pragma` novector

- `#pragma` reduce `recurrence`

- `#pragma` prefetch

- `#pragma` noprefetch

- `#pragma` comb_oper

- `#pragma` ivdep

- `#pragma` no_dam

- `#pragma` spmv

- `!dir$` unroll `(N)`

- `!dir$` loop count `(N)`

- `!dir$` vector

- `!dir$` novector

- `!dir$` reduce `recurrence`

- `!dir$` comb_oper

- `!dir$` ivdep

- `!dir$` no_dam

- `!dir$` spmv