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

.. contents::
   :local:

.. toctree::
   :hidden:

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

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


Директивы #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**
