Стандартные CONVEX компиляторы могут выполнять скалярную, векторную и параллельную оптимизацию программного кода (см. методическое руководство ``Оптимизация программ под архитектуру CONVEX C''). Поскольку в большинстве языков программирования компиляция каждой процедуры выполняется независимо от других, то оптимизация отдельной процедуры, зависящей от каких-то других процедур, может не привести к желаемому результату, т.к. информация об этих других процедурах не доступна компилятору.
Компилятор приложений (Application Compiler) позволяет учесть такую ситуацию, выполняя межпроцедурный анализ, отслеживающий и контролирующий поток данных между процедурами. Такой анализ дает возможность сгенерировать более эффективный код, учитывающий все зависимости. Информационная база данных о программе, которую строит межпроцедурный анализатор, помогает компилятору более эффективно выполнить проверку ошибок. Компилятор приложений функционально включает в себя стандартные компиляторы с языка Си и Фортран, а также модули, выполняющие анализ исходного программного кода и синтез данных, полученных после анализа, для дальнейшей полной оптимизации.
К компилятору приложений можно обратиться только с помощью build-утилиты. Эта утилита контролирует все компиляторные процессы. Build выполняется из командной строки с опциями и подобна make-утилите. Так же как и make, build использует текстовый файл, созданный пользователем. В случае make-утилиты текстовый файл называется makefile и определяет зависимости между исходными файлами, которые требуются компилятору для выполнения этих файлов в заданном порядке. Утилита build получает информацию о зависимостях автоматически, опрашивая назначения (target) исходных файлов. Build-файлы написать легче, чем make-файлы; часто в него включают только список опций, с которыми программист хочет использовать компилятор. Для создания этого файла можно использовать любой текстовый редактор.
Original code Optimized code PROGRAM MAIN PROGRAM MAIN REAL AR(128) REAL AR(128) N=128 N=128 CALL SB(AR,N) CALL SB(AR,N) END END SUBROUTINE SB(AR,N) SUBROUTINE SB(AR,N) REAL AR(*) REAL AR(*) INTEGER N INTEGER N !N=128 DO I=1,N DO I=1,128 AR(I)=AR(I)/3.1416 AR(I)=AR(I)/3.1416 ENDDO ENDDO END ENDКонстанты могут передаваться из подпрограммы верхнего уровня (вызывающей), между подпрограммами того же уровня или из подпрограммы нижнего уровня в подпрограмму верхнего. Константы могут передаваться через любое количество уровней процедурных вызовов. Во многих случаях передача констант между процедурами позволяет компилятору приложений опpеделить, есть ли рекурсия в цикле, можно ли делать векторную оптимизацию или нет. Позволяет не выполнять разбиение циклов (strip mines), если в этом нет необходимости, и исключает ненужную проверку условий внутри циклов.
Original code Inline code
PROGRAM MAIN PROGRAM MAIN
REAL A(1000) REAL A(1000)
REAL B(1000) REAL B(1000)
INTEGER N INTEGER N
CALL INIT(A) CALL INIT(A)
CALL INIT(B) CALL INIT(B)
DO N=1,5 DO N=1,5
CALL SUBA(A,B,N) DO I=1,1000-N
ENDDO A(I)=A(I+N)*B(I)
END ENDDO
ENDDO
SUBROUTINE SUBA(A,B,N) END
REAL A(1000)
REAL B(1000)
INTEGER N
DO I=1,1000-N
A(I)=A(I+N)*B(I)
ENDDO
ENDDO
END
Inline-подстановка также позволяет компилятору приложений провести дополнительную оптимизацию, например определяется, есть ли рекурсия в цикле (в примере, показанном выше, сделав inline-подстановку, компилятор определяет, что переменная N имеет положительное значение, а значит рекурсии нет и можно выполнить векторную оптимизацию). Таким же образом, анализируя переменные, компилятор может не делать лишних проверок условий. Например:
Original code With inline Optimized code
PROGRAM MAIN PROGRAM MAIN PROGRAM MAIN
REAL A(1000) REAL A(1000) REAL A(1000)
REAL B(1000) REAL B(1000) REAL B(1000)
INTEGER N INTEGER N INTEGER N
CALL INIT(A) CALL INIT(A) CALL INIT(A)
CALL INIT(B) CALL INIT(B) CALL INIT(B)
DO N=10,100,10 DO N=10,100,10 DO N=10,100,10
CALL SUBC(A,B,N) IF (N.LT.10) THEN DO I=1,1000-N
ENDDO DO I=1,1000-N,N A(I)=A(I+N)
END A(I)=A(I+N) ENDDO
ENDDO ENDDO
SUBROUTINE SUBC(A,B,N) ELSE END
REAL A(1000) DO I=1,1000-N
REAL B(1000) A(I)=A(I+N)
INTEGER N ENDDO
ENDIF
IF (N.LT.10) THEN ENDDO
DO I=1,1000-N,N END
A(I)=A(I+N)
ENDDO
ELSE
DO I=1,1000-N
A(I)=A(I+N)
ENDDO
ENDIF
END
Original code Optimized code
DO N=1,1000 DO N=1,1000
CALL CPDAG(AR,MA,N) CALL CPDAG(AR,MA,N)
DO I=1,1000 DO I=1,1000
MD(N,I)=AR(I) MD(N,I)=AR(I)
ENDDO ENDDO
ENDDO ENDDO
DO N=1,1000 DO N=1,1000
CALL CPDAG(AR,MD,1) CALL CPDAG$CLONE$1(AR,MD,1)
CALL MDDAG(MD) CALL MDDAG(MD)
ENDDO ENDDO
... ...
SUBROUTINE CPDAG(AR,MX,N) SUBROUTINE CPDAG(AR,MX,N)
REAL AR(1000) REAL AR(1000)
REAL MX(1000,1000) REAL MX(1000,1000)
INTEGER N INTEGER N
IF (N.GT.0) THEN IF (N.GT.0) THEN
DO I=1,1001-N DO I=1,1001-N
AR(I)=MX(I,I-1+N) AR(I)=MX(I,I-1+N)
ENDDO ENDDO
ELSE ELSE
DO I=1,1001+N DO I=1,1001+N
AR(I)=MX(I-N,I) AR(I)=MX(I-N,I)
ENDDO ENDDO
ENDIF ENDIF
END END
SUBROUTINE CPDAG$CLONE$1(AR,MX,N)
REAL AR(1000)
REAL MX(1000,1000)
INTEGER N ! N=1
DO I=1,1000
AR(I)=MX(I,I)
ENDDO
END
Подпрограмма CPDAG вызывается 2000 раз. Компилятор приложений распознает, что 1000 раз подпрограмма вызывается с параметром N=1, а еще 1000 раз - этот параметр зависит от некоторых других вычислений, и поэтому на этапе компиляции не может быть определен.
Компилятор приложений создает дупликат подпрограммы CPDAG, которому дает имя CPDAG$CLONE$1 и вызов CPDAG там, где N=1 заменяет на вызов процедуры CPDAG$CLONE$1. А саму подпрограмму CPDAG$CLONE$1 оптимизирует насколько возможно.
EQUIVALENCE A,B
DO I=2, N
A(I)=A(I)+B(I-1)
ENDDO
В этом цикле на первый взгляд рекурсии нет, но на самом деле, поскольку обращение идет к элементам, находящимся в одном месте в памяти, рекурсия присутствует, и если провести векторизацию, это может привести к ошибочным результатам.
Через межпроцедурный анализ, используя специальный механизм, компилятор приложений может отслеживать ячейки памяти, к которым обращается каждый указатель. Отслеживание указателей помогает уменьшить проблему скрытых алиасов. Например:
FORTRAN code C code
PROGRAM MAIN main()
{
REAL A(500),B(500) float A[500], b[500];
CALL CONFUSED (A,B,A,500) confused(A,b,A,500);
END }
SUBROUTINE CONFUSED (X,Y,Z,N) confused(x,y,z,n)
INTEGER N int n;
REAL X(*),Y(*),Z(*) float x[],y[],z[];
DO I=2,N {
Z(I)=Y(I)+X(I-1) int i;
ENDDO for (i=1; i < n; ++i)
RETURN z[i]=y[i]+x[i-1];
END }
Здесь процедура CONFUSED ожидает получить три отдельных массива, вместо этого массив A передается дважды. Стандартный компилятор не обнаружит алиасной связи между массивами X и Z (для программы на Си - если она скомпилирована с опцией -alias array_args) и цикл в подпрограмме будет векторизован, несмотря на присутствие рекурсии. Компилятор приложений отследит такую ситуацию.
Скрытые алиасы могут быть результатом использования COMMON-блоков. Например:
PROGRAM MAIN
INTEGER N
COMMON N
N=789
CALL CONFUSED(N)
END
SUBROUTINE CONFUSED(N)
DO I=1,2
N2=3*(N+1)
CALL CALC(N2)
WRITE(*,*) 'Iteration:',I,', N= ',N
WRITE(*,*) 'Iteration:',I,', N2=', N2
ENDDO
RETURN
END
SUBROUTINE CALC(N)
INTEGER K,N
COMMON K
K=N+1
END
Использование опции -show aliases заставляет компилятор приложений определить и вывести алиасную зависимость между формальными параметрами, между формальными параметрами и переменными COMMON-блоков.
Использование компилятора приложений предполагается в два этапа:
Пока выполняется компиляция и оптимизация компилятор выдает сообщения и отчеты о работе:
Некоторые опции (inline и cloning), а также распараллеливание могут изменять порядок компиляции.
Сообщения при анализировании синтаксиса языка такие же, как и в обычном компиляторе. Отчет по оптимизации в принципе одинаков с обычным компилятором, только добавляются сообщения, связанные с опциями inline и cloning.
Межпроцедурные сообщения об ошибках выводятся в том случае, когда ошибки не были обнаружены обычным компилятором. При опции -show в отчет будут включены любые заданные таблицы данных для анализа.
Отчет по межпроцедурной оптимизации (IPO-отчет) аналогичен стандартному отчету по оптимизации, но включает только межпроцедурную оптимизацию. IPO-отчет содержит 2 таблицы. Первая таблица показывает выполненную межпроцедурную оптимизацию: назначение констант, inline-вызовы и создание ``слепков'' (clones) для каждой процедуры. Вторая таблица показывает число ошибок и сообщений для каждой процедуры. Этот отчет сохраняется и можно его просмотреть позднее, используя pdbview-утилиту. (См. CONVEX PDB Viewer Guide.)
Можно управлять той информацией, которая будет отображаться. Чтобы выключить вывод сообщений по анализу языка и обычной оптимизации используется флаг -nw в build-файле. Чтобы выключить отчет об оптимизации обычного компилятора необходимо использовать -or none. Можно подавить большинство межпроцедурных сообщений использованием -s опции. Другие сообщения при анализе появляются, только если специально этого потребовать, например, используя опции -check или -show. Опция -nrep выключает весь IPO-отчет.
-c ``чистит'' (удаляет) базу данных программы (PDB - program database). PDB создается при компилировании, позволяет не анализировать или не компилировать всю программу заново, если изменена какая-либо простая процедура.
С этой опцией утилита build - не исполняемая. Все опции, кроме -path, вместе с -c игнорируются. Если PDB испортилась и ее невозможно удалить с помощью опции -c, то удаляют вручную, с помощью команды:
% rm -r PDB
Для решения задачи, какие процедуры нужно перекомпилировать, компилятор приложений учитывает не только исходную зависимость между процедурами, которые определяются make-файлом, но и зависимости, возникающие при оптимизации. После окончательной компиляции программы или нехватки памяти на диске, рекомендуется использовать команду build с опцией -c.
-f определяет имя build-файла. Если имя не задано, build-утилита ищет его сначала как buildfile, потом Buildfile. Если таких нет, то выдается сообщение об ошибке.
-i по умолчанию компилирование останавливается при обнаружении серьезной ошибки в исходном тексте. С помощью -i можно это игнорировать и продолжать компиляцию других исходных файлов.
-j определяет число одновременных подпроцессов компиляции, которые build может использовать (по умолчанию 1 или 2, в зависимости от фазы компиляции). -j должно быть следующим: -j n, где n*2. На машинах с несколькими доступными процессорами, параллельность при использовании компилятора приложений может уменьшить время компиляции. При тяжелой загрузке машины программист должен сам ограничивать число создаваемых подпроцессов, поэтому лучше использовать -j = 1.
% build -j 1
-n указывает, что не нужно перекомпилировать никакие файлы. Вместо этого генерируются сообщения, которые указывают, какие файлы необходимо перекомпилировать.
-o задает имя для выполняемого файла. Если не задано, то имя задается по названию текущей директории.
-s убирает всю диагностику на этапах анализа и синтеза.
-u выдает список всех опций для build и их использование.
-v задает печать имени каждой процедуры во время ее компиляции и анализа, а также межпроцедурных алгоритмов на фазе синтеза. Опции -s и -v взаимно исключающие.
-vn печатает номер версии компилятора приложений.
-assert subscripts_ok указывает компилятору приложений, что все индексы корректны.
-check определяет тип ошибок, которые следует проверить. Ниже перечисляются аргументы опции:
-clone all выполняет ``клонирование'' всех процедур.
-clone none предотвращает ``клонирование'' любой процедуры.
-display указывает компилятору приложений отразить все отчеты по опциям -check и -show для последней выполненной утилиты build. Команда build -display работает, только если существует программная база данных (PDB). Если ее нет (была удалена), появляется сообщение об этом.
-extend_dim указывает, как оптимизировать память для хранения массивов. Эта оптимизация не распространяется на одномерные массивы, а также на верхний индекс массивов в ФОРТРАНЕ и на нижний индекс в СИ.
-gprof/-prof компилятор приложений может использовать профиль программы для детальной информации о последовательности и продолжительности процедурных вызовов. Это позволяет принять более эффективнные решения по inline и link оптимизации. Например, build -gprof /mnt/me/prof.out Компилятор приложений использует выполняемый файл prof.out и на выходе - файл gmon.out как исходная информация для inline-оптимизации. Для случая -prof на выходе - файл mon.out.
-inline предлагает компилятору приложений выполнить inline-оптимизацию. По умолчанию задается умеренный уровень оптимизации, но можно этим управлять:
-link_sort указывает компилятору приложений, какой алгоритм оптимизации использовать при редактировании связей. Существует три возможных аргумента:
-library указывает утилите build создать APC-библиотеку вместо приложений.
-max_errors позволяет увеличить предельное число ошибок, которое может обнаружить компилятор приложений на отдельной фазе компилирования. По умолчанию, это число равно 100. Если появляется сообщение "too many errors", то следует воспользоваться этой опцией.
-nrep подавляет печать отчета межпроцедурной оптимизации.
-path указывает путь (имя директории), куда компилятор приложений будет записывать программную базу. Если не указывать, по умолчанию, в текущую директорию.
-pdb_size указывает максимальный размер программной базы данных. По умолчанию, это 250 МБ.
-permit dynamic_binding разрешает выполнять inline-оптимизацию для процедур на ФОРТРАНе, в которых аргументами являются массивы с динамическими границами.
-permit invalid_fortran позволяет компилятору приложений продолжать компилирование, даже если встретилась ошибка в межпроцедурном анализе. Рекомендуется использовать эту опцию при отладке новой программы, когда хочется увидеть все возможные межпроцедурные ошибки. Не используйте эту опцию на окончательном этапе компилирования.
-permit longjmp/-permit setjmp Использование этих опций (все равно какой) может помешать компилятору приложений получить успешный и корректный код. Если вы не хотите, чтобы компилятор рассматривал setjmp и longjmp как фатальную ошибку, вы должны использовать их.
-permit unannotated эта опция разрешает компилятору приложений использовать неописанный (unannotated) объектный код или ассемблерный файл при редактировании. Использование этого неописанного объектного или ассемблерного кода понижает уровень межпроцедурной оптимизации. Чтобы получить лучший выполняемый код вместо описания всех объектных или ассемблерных кодов используйте psum-файлы. Если компилировать неописанные объектные или ассемблерные файлы без этих опций, компилятор прерывает выполнение и выдается сообщение об ошибке. Если же с этой опцией, генерируется предупреждение и компиляция продолжается.
-show позволяет управлять выводимой информацией по межпроцедурной оптимизации. Имеет следующие параметры:
#Эта строка определяет файл, который должен быть откомпилирован, и
#опции, используемые при компиляции:
source.f -db -pa -02
#следующая строка определяет стандартную библиотеку, которую компилятор
#свяжет с программой:
link FORTRAN -db -pa
Утилита build понимает, что исходный файл, у которого расширение .f - это фортрановский файл, а у которого .c - это файл на языке С. Каждый исходный файл должен быть в отдельной строке. Опции компилятора следуют за именем файла. Компилятор приложений понимает большинство опций компиляторов с Си и Фортрана. Но он не поддерживает некоторых опций, например -с, которая подавляет связывание объектных файлов. Не используйте -с в build-файле. Не определяйте объектные файлы и библиотеки в той же строке, что и исходные файлы.
Компилятор приложений не поддерживает опции: -il, -is, -cxdb. Более полный список опций приведен в приложении А (Appendix A, CONVEX Application Compiler User's Guide).
Link-строка определяет объектные файлы и библиотеки, которые должны быть подключены к компилируемой программе. Главную программу вы должны откомпилировать компилятором приложений, если остальные подпрограммы откомпилированы им.
Компилятор приложений не воспринимает в качестве исходного для компиляции файла - файл на ассемблере. Если необходимо подсоединить программу на ассемблере, то сначала ассемблируйте исходную программу, а результирующий объектный файл (.o) включите в link-строку.
source.f -02 link FORTRAN obj.o /mnt/me/objs/obj2.o -lveclibКомпиляторные опции, которые воздействуют на выбор библиотек должны появляться также и в link-строке. К ним относятся:
Например:
foo.f -02 -cfc
link FORTRAN -cfc
Для более детального знакомства с этими опциями см. CONVEX Compiler User's Guide.
Для переименования выходного файла следует использовать -o опцию в link-строке:
link FORTRAN -o foo
или в команде:
options -o foo
или при вызове утилиты:
% build -o foo
Если компилировать требуется большое количество файлов, то можно указать только директорию, где эти файлы расположены. Компилятор приложений просмотрит ее, найдет исходные файлы и откомпилирует их. Например:
/mnt/me/zwork/prj/src -02 link FORTRAN
Если build-файл хранится в той же директории, что и исходные файлы, то синтаксис build-файла может быть еще проще:
. -02 link C
Можно определить опции для всей директории в одной строке, а для отдельных файлов - в другой:
. -02 foo.f -03 link FORTRAN
FFLAGS= -re -rl -db foo.f -01 bar.f -02 baz.f -02То же самое, что
foo.f -01 -re -rl -db bar.f -02 -re -rl -db baz.f -02 -re -rl -db
Ключевое слово options позволяет в build-файле указать опции для компилятора приложений вместо указания их в командной строке при вызове build-утилиты. Опции, указанные в командной строке, будут дополнительными к тем, что указаны в build-файле. Если опции, указанные в командной строке и опции в build-файле противоречат друг другу, то либо опции командной строки перекрывают опции build-файла, либо вырабатывается сообщение об ошибке и компиляция останавливается.
Компилятор приложений может проверять текст программы на нарушение фортрановских стандартов ANSI77 и ANSI90 с помощью опции -chk и одной из опций: ansi77 или ansi90. Не используйте эти опции в командной строке при вызове build-утилиты.
Если необходимо откомпилировать программу, которая использует и Си и Фортран, то нужно написать головную программу на Фортране и использовать FORTRAN в link-строке:
foo.c bar.c baz.c -02 main.f -02 link FORTRANЕсли необходимо головную программу написать на Си, то используйте в link-строке С и подсоедините Фортран-библиотеку с ключем -l:
link C -lF77
Кроме опций в build-файле можно использовать следующие операторы оптимизации:
inline
no_inline
clone
no_clone
no_alias
var_args
Каждый из этих операторов появляется в отдельной строке, в скобках за оператором указываются имена программ или переменных, на которые распространяются эти оптимизационные операторы. Их можно использовать вместо соответствующих директив.
Имена подпрограмм и переменных в скобках для Фортрана должны указываться большими буквами, а для Си такими, как они указаны в исходных файлах.
Оператор var_args также можно употреблять вместо соответствующей директивы в исходном build-файле. С помощью этого оператора можно указать компилятору приложений, сколько передавать аргументов в процедуру. Например, var_args(foo,4) - приказывает компилятору рассматривать только первые 4 аргумента процедуры foo. Если не указано число рассматриваемых аргументов, это означает, что все аргументы учитывать. Например, var_args(foo).
Стандартные библиотеки CONVEX содержат аннотированные версии. Но если вы используете собственные библиотеки или объектные модули, необходимо сгенерировать эти аннотации.
Есть два способа для генерации:
%build -library -o myarchv
тем самым создать библиотеку myarchv.apclib. Сгенерированная библиотека не требует link-строку.
Для использования APC-библиотек при создании выполняемого файла необходимо включить оператор apc_libraries в build-файл. Например:
apc_libraries foo.apclib boo.apclib hoo.apclib
Порядок следования библиотек определен, он зависит от того, как вызываются процедуры. Процедуры одной библиотеки могут вызывать любые процедуры из этой же библиотеки, а также из библиотеки, стоящей справа от вызывающей библиотеки и не могут вызывать из библиотеки, стоящей в строке слева. Например, запись
apc_libraries usesfoo.apclib foo.apclib
будет правильной, если программа из библиотеки usesfoo.apclib вызывает программу из foo.apclib.
Краткая процедура на языке FORTRAN будет иметь следующий формат:
< subroutine or function hearder> < argument declarations> < psum directives> end
Краткая процедура на языке Cи, имеет такой формат:
< function header>
< argument declarations>
{
< psum directives>
return;
}
Объявления переменных и заголовки процедур записываются стандартным образом. Psum-директивы появляются только в psum-файлах и никогда в исходных файлах. Можно использовать следующие директивы:
/*$dir psum_range_names(a,b,c,f) */;
char *foo()
{
int n;
char *p;
...
p=malloc(n);
...
return p;
}
Использование директивы
/*$dir psum_range_flags(foo, heap) */
говорит компилятору, что foo возвращает указатель к единственному объекту.
/* $dir psum_args_dealloc(arg_name) */;
Следующий пример показывает, как выглядят psum-файлы, написанные в формате языка Фортран:
SUBROUTINE SAXPY(N, A, X, INCX, Y, INCY)
REAL*4 A
REAL*4 X(*), Y(*)
INTEGER*4 N, INCX,INCY
C$DIR PSUM_NO_GLOBAL_MODS
C$DIR PSUM_ASGS(Y)
END
Директивы в этом файле говорят компилятору, что никакие глобальные переменные модифицироваться не будут, а аргументу Y будет назначено некоторое значение.
Пример psum-файла на языке Си:
float sdot(n, x, incx, y, incy)
float x[], y[];
int n, incx, incy
{
/*$dir psum_no_global_mods*/
/*$dir psum_no_arg_mods*/
sdot=1.0;
return;
}
Директивы в этом файле указывают, что не будут меняться не только никакие глобальные переменные, но и аргументы.
% annotate input_file psum-file
Описатель annotate преобразует информацию из psum-файла в двоичную форму и добавляет ее к соответствующему объектному файлу. Если объектный файл уже аннотирован, то описатель удаляет соответствующую аннотацию и добавляет новую.
Если описывать приходится ассемблерный текст, а не объектный файл, то описатель вызывает ассемблер для получения объектного файла и затем добавляет описание к этому объектному файлу.
Примеры использования:
% annotate foo.s foo.c
% annotate bar.o bar.c
% annotate phu.a phu.c
Если по каким-то причинам невозможно использовать аннотированные библиотеки или аннотированные объектные файлы, то используйте компилятор приложений с опцией permit_unannotated.
Inlining-директивы:
INLINE NO_INLINE INLINE_CALL NO_INLINE_CALLпредотвращают или принудительно заставляют делать inline процедур или процедурных вызовов.
Директива INLINE принудительно заставляет делать inline-подстановку. Если обращение к подпрограмме происходит редко или при выполнении директивы inline резко возрастает размер программного кода, то следует использовать директиву NO_INLINE. Эти директивы должны указываться перед телом процедуры (в FORTRANe - перед описанием переменных, в Си - внутри программных скобок, но после описания переменных).
С помощью директивы INLINE_CALL можно выполнить inline-подстановку только для отдельного вызова процедуры, а при остальных обращениях к этой процедуре - не делать. Директиву следует вставить перед конкретным обращением к процедуре:
C$DIR INLINE_CALL(ROS,FN1) B = ROS(DL)/FN(THETA)-FN1(B)Компилятор приложений обязательно сделает inline-подстановку для вызовов функций ROS и FN1, а для FN - только если этап анализа покажет, что это выгодно. Приоритет директивы INLINE_CALL выше, чем у NO_INLINE. Компилятор приложений не может выполнять inline-подстановку для косвенного обращения к функции. При этом генерируется предупреждающее сообщение.
Директива NO_INLINE_CALL отменяет inline-подстановку для конкретного обращения к процедуре. Аналогично директиве INLINE_CALL, директива NO_INLINE_CALL может указываться вместе со списком функций в скобках. Причем выше приоритет имеет та директива, у которой присутствует список функций в скобках.
Cloning-директивы:
CLONE NO_CLONEиспользуется, чтобы передать в качестве параметра константу в подпрограмму (см. раздел ``Основные понятия межпроцедурного анализа''). Аналогично INLINE директива CLONE должна указываться перед телом процедуры. Может указываться со списком аргументов-констант, заключенных в круглые скобки.
Хотя часто директивы CLONE и INLINE приводят к противоположным результатам, можно использовать их совместно. CLONE-директива перекрывает действие директивы INLINE, если возможна передача константы, и тогда компилятор приложений генерирует сообщение об этом. Если же передача константы невозможна, то INLINE заставляет компилятор приложений выполнить inline-подстановку этого вызова.
Директива NO_CLONE - отменяет действие CLONE.