C, C++ и Objective C версии компилятора объединены; компилятор GNU C может компилировать программы написанные на C, C++ или Objective C.
"GCC" - общее стандартное обозначение для компилятора GNU C. Это как наиболее общее название компилятора, так и название, используемое, когда акцент делается на компиляции C программ.
Когда ссылаются на C++ компиляцию, обычно называют компилятор "G++". Поскольку есть только один компилятор, будет точным называть его "GCC" вне зависимости от языка; однако термин "G++" более полезен, когда ударение стоит на компиляции С++ программ.
Мы используем имя "GNU CC" для ссылки на всю систему компиляции в целом и более конкретно к языковонезависимой части компилятора. Например, мы говорим об опциях оптимизации, как о влияющих на поведение "GNU CC" или, иногда, просто "компилятора".
Внешние интерфейсы с других языков, таких как Ada 9X, Fortran, Modula-3 и Pascal, находятся в развитии. Эти front end'ы, также как и front end с C++, построенны в поддиректориях GNU CC и связанны с ним. В результате получается интегрированный компилятор, который может компилировать программы написанные на C, C++, Objective C или на любых других языках, для которых вы установили внешние интерфейсы.
В данном руководстве мы рассматриваем только опции для C, Objective C и C++ компиляторов, а также опции ядра GNU CC. Обращайтесь к документации по другим внешним интерфейсам, чтобы узнать об опциях, используемых при компиляции программ, написанных на других языках.
G++ - это компилятор, а не просто препроцессор. G++ строит объектный код прямо из вашей исходной C++ программы. Никакой промежуточной C версии программы не порождается. (К примеру, некоторые другие реализации напротив используют программу, которая порождает C программу из вашей C++ программы.) Избегание промежуточного C представления программы означает, что вы получаете более хороший объектный код и более хорошую отладочную информацию. Отладчик GNU, GDB, использует эту информацию в объектном коде, чтобы дать вам все возможности работы на уровне исходного C++ текста (см. раздел "C и C++" в "Отладка с GDB").
Когда вы вызываете GNU CC, он обычно выполняет препроцессирование, компиляцию, ассемблирование и линковку. "Общие опции" позволяют вам остановить этот процесс на промежуточной стадии. Например, опция '-c' говорит не запускать линкер. Тогда вывод состоит их объектных файлов, порожденных ассемблером.
Другие опции передаются на одну из стадий обработки. Одни опции управляют препроцессором, другие самим компилятором. Все еще имеются опции, управляющие ассемблером и линкером; большинство из них не документировано здесь, поскольку вам редко требуется использовать какую-нибудь из них.
Большая часть опций командной строки, которые вы можете использовать с GNU CC полезны для C программ; если опция полезна только для других языков (обычно C++), в объяснениии сказано об этом прямо. Если в описании какой-либо опции не упоминается исходный язык, вы можете использовать эту опцию со всеми поддерживаемыми языками.
См. раздел [Компиляция C++ программ], чтобы найти сводку опций для компиляции C++ программ.
Программа gcc принимает опции и имена файлов как операнды. Многие опции имеют многобуквенные имена; следовательно, многочисленные однобуквенные опции не могут быть сгруппированны: '-dr' очень отличается от '-d -r'.
Вы можете смешивать опции и другие аргументы. По большей части, используемый порядок не имеет значения. Порядок важен, когда вы используете несколько опций одного вида; например, если вы указываете '-L' больше чем один раз, директории просматриваются в порядке указания.
Многие опции имеют длинные имена, начинающиеся с '-f' или с '-W' - например, '-fforce-mem', '-fstrength-reduce', '-Wformat' и так далее. Большинство из них имеет положительную и отрицательную формы; отрицательной формой '-ffoo' будет '-fno-foo'. Это руководство документирует только одну из этих форм - ту, которая не принимается по умолчанию.
Здесь изложена сводка всех опций, сгруппированная по типу. Пояснения расположены в следующих разделах.
См. раздел [Опции, Управляющие Видом Вывода].
-c -S -E -o FILE -pipe -v -язык
См. раздел [Опции, Управляющие Диалектом C].
-ansi -fallow-single-precision -fcond-mismatch -fno-asm
-fno-builtin -fsigned-bitfields -fsigned-char
-funsigned-bitfields -funsigned-char -fwritable-strings
-traditional -traditional-cpp -trigraphs
См. раздел [Опции для Включения или Подавления Предупреждений].
-fsyntax-only -pedantic -pedantic-errors
-w -W -Wall -Waggregate-return -Wbad-function-cast
-Wcast-align -Wcast-qual -Wchar-subscript -Wcomment
-Wconversion -Wenum-clash -Werror -Wformat
-Wid-clash-LEN -Wimplicit -Wimport -Winline
-Wlarger-than-LEN -Wmissing-declarations
-Wmissing-prototypes -Wnested-externs
-Wno-import -Woverloaded-virtual -Wparentheses
-Wpointer-arith -Wredundant-decls -Wreorder -Wreturn-type -Wshadow
-Wstrict-prototypes -Wswitch -Wsynth -Wtemplate-debugging
-Wtraditional -Wtrigraphs -Wuninitialized -Wunused
-Wwrite-strings
См. раздел [Опции для Отладки Вашей Программы или GNU CC].
-a -dбуквы -fpretend-float
-g -gуровень -gcoff -gdwarf -gdwarf+
-ggdb -gstabs -gstabs+ -gxcoff -gxcoff+
-p -pg -print-file-name=библиотека -print-libgcc-file-name
-print-prog-name=программа -print-search-dirs -save-temps
См. раздел [Опции, которые Управляют Оптимизацией].
-fcaller-saves -fcse-follow-jumps -fcse-skip-blocks
-fdelayed-branch -fexpensive-optimizations
-ffast-math -ffloat-store -fforce-addr -fforce-mem
-finline-functions -fkeep-inline-functions
-fno-default-inline -fno-defer-pop -fno-function-cse
-fno-inline -fno-peephole -fomit-frame-pointer
-frerun-cse-after-loop -fschedule-insns
-fschedule-insns2 -fstrength-reduce -fthread-jumps
-funroll-all-loops -funroll-loops
-O -O0 -O1 -O2 -O3
См. раздел [Опции, Управляющие Препроцессором].
-Aвопрос(ответ) -C -dD -dM -dN
-Dмакрос[=значение] -E -H
-idirafter директорий
-include файл -imacros файл
-iprefix файл -iwithprefix директорий
-iwithprefixbefore директорий -isystem директорий
-M -MD -MM -MMD -MG -nostdinc -P -trigraphs
-undef -Uмакрос -Wp,опция
См. раздел [Передача Опции Ассемблеру].
-Wa,опция
См. раздел [Опции Линковки].
имя-объектного-файла -lбиблиотека
-nostartfiles -nodefaultlibs -nostdlib
-s -static -shared -symbolic
-Wl,опция -Xlinker опция
-u символ
См. раздел [Опции для Поиска в Директориях].
-Bпрефикс -Iдиректорий -I- -Lдиректорий
См. раздел [Указание Целевой Машины и Версии Компилятора].
-b машина -V версия
См. раздел [Модели и Конфигурации Машин].
Опции i386
-m486 -m386 -mieee-fp -mno-fancy-math-387
-mno-fp-ret-in-387 -msoft-float -msvr3-shlib
-mno-wide-multiply -mrtd -malign-double
-mreg-alloc=список -mregparm=число
-malign-jumps=число -malign-loops=число
-malign-functions=число
См. раздел [Опции Соглашений о Генерации Кода].
-fcall-saved-регистр -fcall-used-регистр
-ffixed-регистр -finhibit-size-directive
-fno-common -fno-ident -fno-gnu-linker
-fpcc-struct-return -fpic -fPIC
-freg-struct-return -fshared-data -fshort-enums
-fshort-double -fvolatile -fvolatile-global
-fverbose-asm -fpack-struct +e0 +e1
Компиляция может включать до четырех стадий: препроцессирование, собственно компиляцию, ассемблирование и линковку, всегда в этом порядке. Первые три стадии применяются к отдельному исходному файлу и заканчиваются получением объектного файла; линковка объединяет все объектные файлы (заново откомпилированные или полученные как входные) в исполняемый файл.
Для любого имени входного файла суффикс определяет какая компиляция требуется:
file.c Исходный код на C, который нуждается в препроцессировании.
file.i Исходный код на С, который не нуждается в препроцессировании.
file.ii Исходный код на C++, который не нуждается в препроцессировании.
file.m Исходный код на Objective C. Заметим, что вам необходимо
подключить библиотеку 'libobjc.a', чтобы заставить
Objective C программу работать.
file.h C заголовочный файл (не для компиляции или линковки).
file.cc
file.cxx
file.cpp
file.C Исходный код на C+, который нуждается в препроцессировании.
file.s Ассемблерный код.
file.S Ассемблерный код, который нуждается в препроцессировании.
другие Объектный файл, который нужно отдать прямо на линковку. Так
поступают с любым именем файла с нераспознанным суффиксом.
Вы можете прямо указать входной язык при помощи опции '-x':
Прямо специфицирует язык последующих входных файлов (даже если компилятор может выбрать язык на основании суффикса имени файла). Эта опция действует на все входные файлы вплоть до следующего появления опции '-x'. Возможными значениями для языка являются:
c objective-c c++
c-header cpp-output c++-cpp-output
assembler assembler-with-cpp
Выключает любое указание языка так, что последующие файлы обрабатываются в соответствии с суффиксами имен файлов (как если бы '-x' не указывалось бы вовсе).
Если вам нужны лишь некоторые из стадий компиляции, вы можете использовать '-x', чтобы указать gcc где начать, и одну из опций '-c', '-S' или '-E', чтобы указать, где gcc должен остановиться. Заметим, что некоторые комбинации (например, '-x cpp-output -E' указывают gcc ни делать вообще ничего).
Компилировать или ассемблировать исходные файлы, но не линковать. Стадия ликовки просто не выполняется. Конечный вывод происходит в форме объектного файла для каждого исходного файла.
По умолчанию, имя объектного файла делается из имени исходного файла заменой суффикса '.c', '.i', '.s', и.т.д. на '.o'.
Нераспознанные входные файлы, не требующие компиляции или ассемблирования, игнорируются.
Остановиться после собственно компиляции; не ассемблировать. Вывод производится в форме файла с ассемблерным кодом для каждого не ассемблерного входного файла.
По умолчанию, имя файла с ассемблерным кодом делается из имени исходного файла заменой суффикса '.c', '.i', и.т.д. на '.s'.
Входные файлы, которые не требуют компиляции игнорируются.
Остановиться после стадии препроцессирования; не запускать собственно компилятор. Вывод делается в форме препроцессированного исходного кода, который посылается на стандартный вывод.
Входные файлы, которые не требуют препроцессирования игнорируются.
Поместить вывод в файл 'файл'. Эта опция применяется вне зависимости от вида порождаемого файла, есть ли это выполнимый файл, объектный файл, ассемблерный файл или препроцессированный C код.
Поскольку указывается только один выходной файл, нет смысла использовать '-o' при компиляции более чем одного входного файла, если вы не порождаете на выходе выполнимый файл.
Если '-o' не указано, по умолчанию выполнимый файл помещается в 'a.out', объектный файл для 'исходный.суффикс' - в 'исходный.o', его ассемблерный код в 'исходный.s' и все препроцессированные C файлы - в стандартный вывод.
Печатать (в стандартный вывод ошибок) команды выполняемые для запуска стадий компиляции. Также печатать номер версии управляющей программы компилятора, препроцессора и самого компилятора.
Использовать каналы вместо временных файлов для коммуникации между различными стадиями компиляции. Это может не работать на некоторых системах, где ассемблер не может читать из канала, но ассемблер GNU не имеет проблем.
Следующие опции управляют диалектами C (или или языков порожденных из C, таких как C++ и Objective C), которые воспринимает компилятор:
Поддерживает все ANSI C программы.
Эта опция выключает некоторые свойства GNU CC, которые несовместимы с ANSI C такие, как ключевые слова asm, inline и typeof, предопределенные макросы такие, как unix и vax, которые идентифицируют тип используемой вами системы. Она также включает нежелательные и редко используемые ANSI трехсимвольные последовательности, не разрешает '$' в идентификаторах и комментарии в стиле C++ '//'.
Альтернативные ключевые слова __asm__, __extension__, __inline__ и __typeof__ продолжают работать не смотря на '-ansi'. Вы, разумеется, не хотели бы использовать их в ANSI C программе, но полезно использовать их в заголовочных файлах, которые могут быть включены в компиляции с '-ansi'.
Опция '-ansi' не действует так, что не ANSI C программы беспричинно отбрасываются. Чтобы это было так, в добавление к '-ansi' требуется опция '-pedantic'. См. раздел [Опции Предупреждений], стр. 35.
Когда используется опция '-ansi', предопределен макрос __STRICT_ANSI__. Некоторые заголовочные файлы могут заметить этот макрос и воздерживаться от объявления определенных функций или определения определенных макросов, к которым ANSI стандарт не обращается; это делается, чтобы избежать помех программам, которые могут использовать эти имена для других целей.
Функции alloca, abort, exit и _exit не являются встроенными функциями при использовании '-ansi'.
Не распознаются как ключевые слова asm, inline и typeof, и они могут быть использованы в коде в качестве идентификаторов. Вы можете использовать вместо них ключевые слова __asm__, __inline__ и __typeof__. '-ansi' включает '-fno-asm'.
Не распознаются встроенные функции кроме тех, имена которых начинаются с двух подчеркиваний. На данный момент затрагиваемыми функциями являются abort, abs, alloca, cos, exit, fabs, ffs, labs, memcmp, memcpy, sin, sqrt, strcmp, strcpy и strlen.
GCC обычно генерирует специальный код, чтобы более эффективно обрабатывать некоторые встроенные функции; например, вызов alloca может стать просто последовательностью инструкций, которые прямо выравнивают стек, а вызов memcpy может превратиться просто в цикл копирования. Результирующий код является и более коротким, и более быстрым, но поскольку вызова функции как такового больше не существует, вы не можете ни поставить на него точку останова, ни изменить поведение функции прилинковав другую библиотеку.
Опция '-ansi' не дает функциям alloca и ffs быть встроенными, поскольку эти функции не имеют предопределенного значения в стандарте ANSI C.
Поддерживаются трехсимвольные последовательности ANSI C. Опция '-ansi' включает '-trigraphs'. Не забивайте себе голову этим сумасшедствием.
Пытается поддержать некоторые свойства традиционных компиляторов C. А именно:
Вы не можете использовать '-traditional', если вы включаете какие либо заголовочные файлы, которые полагаются на особенности ANSI C. Некоторые продавцы поставляют системы с ANSI C заголовочными файлами и вы не можете использовать '-traditional' на таких машинах для компиляции файлов, который включают системные заголовочные файлы.
В препроцессоре коментарии преобразуются в ничто, а не в пробел. Это разрешает традиционное объединение лексем.
В директиве препроцессора символ '#' должен быть первым в строке.
В препроцессоре аргументы макроса распознаются в строковых константах в определении макроса (их значения превращаются в строки, но без дополнительных кавычек, когда они появляются в соответствующем контексте).
Предопределенный макрос __STDC__ не определен, если вы используете '-traditional', но __GNUC__ определен (поскольку расширения GNU, о которых говорит __GNUC__ не затрагиваются опцией '-traditional'). Если вам нужно написать заголовочный файл, который работает по-разному в зависимости от того, используется ли опция '-traditional', проверив эти два макроса вы можете различить четыре ситуации: GNU C, традиционный GNU C, другие ANSI C компиляторы и другие компиляторы старого C. Предопределенный макрос __STDC_VERSION__ также не определен, когда вы используете '-traditional'. См. раздел "Стандартные Предопределенные Макросы" в 'Препроцессоре C' по поводу этих и других предопределенных макросов.
Препроцессор считает, что строковые константы всегда заканчиваются при переходе на новую строку (если только ему не предшествует '\'). (Без '-traditional' в строковых константах может быть символ новой строки так, как набрано.)
Пытается поддержать некоторые особенности традиционных препроцессоров C. Это включает в себя пять пунктов в таблице непосредственно выше, но без других эффектов '-traditional'.)
Позволяются условные выражения с не согласоваными типами второго и третьего аргументов. Значение такого выражения есть void.
Тип char считается беззнаковым, как unsigned char.
Каждая машина имеет умолчание - каким должен быть char, таким, как unsigned char или таким, как signed char.
В идеале, переносимая программа всегда должна использовать unsigned char или signed char, когда она зависит от знаковости объекта. Но многие программы были написаны с использованием простого char, в предположении, что он будет либо знаковым, либо беззнаковым, в зависимости от машины, для которой они были написаны. Эта опция и ей противоположная позволяют вам заставить такую программу работать при противоположном умолчании.
Тип char всегда отличен и от signed char, и от unsigned char, хотя его поведение всегда такое же, как у одного из этих двух типов.
Тип char считается знаковым, как signed char.
Заметим, что эта опция эквивалентна '-fno-unsigned-char', которая является отрицательной формой '-funsigned-char'. Анологично, опция '-fno-signed-char' эквивалентна '-funsigned-char'.
Эти опции управляют знаковостью поля битов, в том случае, если его объявление не использует signed или unsigned. По умолчанию такие поля считаются знаковыми, потому что это последовательно: базовые целые типы такие, как int являются знаковыми.
Однако, если используется опция '-traditional', битовые поля все беззнаковые - не важно какие.
Строковые константы сохраняются в сегменте, доступном для записи и не сливаются. Это нужно для совместимости со старыми программами, которые предполагают, что можно писать в строковую константу. Опция '-traditional' также имеет такой эффект.
Запись в строковые константы это очень плохая идея - "константы" должны быть константами.
Числа с плавающей точкой одинарной точности не расширяются до двойной при математических операциях, даже при компиляции с опцией '-traditional'. Классический C Кернигана и Риттчи расширяет все операции с плавающей точкой до двойной точности, вне зависимости от размеров операндов. На архитектуре, для которой вы компилируете одинарная точность может оказаться быстрее двойной. Если вы должны использовать '-traditional', но хотите использовать операции одинарной точности, когда операнды одинарной точности, используйте эту опцию. Эта опция не имеет эффекта при компиляции с ANSI или GNU C соглашениями.
Предупреждения - это диагностические сообщения, которые сообщают о конструкциях не являющихся заведомо ошибочными, но рискованных или, вероятно, содержащими ошибку.
Вы можете включить выдачу многих специфических предупреждений с помощью опций, начинающихся с '-W', например, '-Wimplicit', чтобы включить предупреждения на неявных объявлениях. Каждая из таких опций имеет отрицательную форму, которая начинается с '-Wno-', и служит для подавления выдачи предупреждений; например, 'Wno-implicit'. В этом руководстве указана только одна форма каждой опции - та, которая не является умолчанием.
Следующие опции управляют количеством и видом предупреждений, выдаваемых GNU CC.
Проверяется код на наличие синтаксических ошибок, но после этого не делается ничего.
Выдаются все предупреждения, требуемые строгим ANSI стандартом C, отбрасываются все программы, которые используют запрещенные расширения.
Правильные ANSI C программы корректно компилируются как с, так и без этой опции (хотя очень редкие и требуют опции '-ansi'). Однако, без этой опции поддерживаются также некоторые GNU расширения и свойства традиционного C. С этой опцией они отклоняются.
'-pedantic' не вызывает предупреждения при использовании альтернативных ключевых слов, начинающихся и заканчивающихся с '__'. Предупреждения также не появляются после выражений, переж которыми стоит '__extension__'. Однако, этот исключительный способ следует использовать только в системных заголовочных файлах; следует избегать его в прикладных программах. См. раздел 6.34 [Альтернативные Ключевые Слова].
Эта опция не претендует на полезность - она существует только чтобы удовлетворить педантов, которые в противном случае будут утверждать, что GNU CC не может поддерживать стандарт ANSI C.
Некоторые пользователи пытаются использовать '-pedantic', чтобы проверить программу на соответствие со строгим стандартом ANSI C. Они часто обнаруживают, что она делает не ровно то, что они хотят: она выявляет некоторые не ANSI C конструкции, но не все, а только те, для которых ANSI C требует диагностику.
Возможность выявить все несоответствия с ANSI C могла бы быть полезна во многих случаях, но потребовала бы гораздо больше дополнительной работы совершенно отличной от целей опции '-pedantic'. Мы скорее рекомендуем пользователю воспользоваться преимуществами расширений GNU C и игнорировать ограничения других компиляторов. Кроме некоторых суперкомпьютеров и крайне маленьких машин, есть весьма мало причин пользоваться каким либо другим компилятором C вместо раскручиваемого компилятора GNU CC.
Подобна опции '-pedantic', с тем отличием, что вместо предупреждений порождаются ошибки.
Отменяются все предупреждения.
Отменяются предупреждения об использовании '#import'.
Предупреждает, если индекс массива имеет тип char. Это частая причина ошибок, так как программисты часто забывают, что этот тип может быть знаковым на некоторых машинах.
Предупреждает при каждом появлении начала комментария '/*' в комментарии.
Проверяет вызовы к printf, scanf и т. д., чтобы проверить типы передаваемых параметров на соответствие со специфицированной строкой формата.
Предупреждает, когда функция или параметр объявляются неявно.
Предупреждает об отсутствии скобок в некоторых контекстах, таких как присваивание там, где нужно значение или вложенные операции, в приоритетах которых люди часто путаются.
Предупреждает, если функция объявлена с типом возвращаемого значения по умолчанию - int. Также предупреждает об операторах возврата без возвращаемого значения в функциях, чей возвращаемый тип не есть void.
Предупреждает, когда оператор switch имеет в качестве переключателя тип перечисления, и для одного или нескольких именованных кодов отсутствует case. (Присутствие метки default подавляет это предупреждение.) Метка case вне диапозона перечисления также вызывает прежупреждение при использовании этой опции.
Предупреждает, если встречается какая-либо трехсимвольная ANSI C последовательность (предполагается, что они включены).
Предупреждает, если переменная не используется вне ее описания, или если функция объявлена static, но нигде не определена, или если метка объявлена, но не используется, или если оператор вычисляет значение, которое точно нигде не используется.
Чтобы подавить выдачу такого предупреждения на выражении просто поставьте перед ним приведение к void. Для не используемых переменных и параметров используйте атрибут 'unused' (см. раздел 6.28 [Атрибуты Переменных]).
Автоматическая переменная используется без инициализации.
Это предупреждение возможно только в оптимизирующей компиляции, поскольку требуемый анализ потока данных выполняется только при оптимизации. Если вы не используете опцию '-O', вы просто не получите эти предупреждения.
Эти предупреждения выдаются только для переменных, которые являются кандидатами на выделение регистров. Следовательно, они не выдаются для тех переменных, которые объявлены volatile, или тех, чей адрес берется, или чей размер отличен от 1, 2, 4 или 8 байт. Они, также, не выдаются для структур, объединений и массивов, даже если они размещаются на регистрах.
Заметим, что может не быть предупреждения о переменной, которая используется только чтобы вычислить значение, которое более не используется, потому что это вычисление может быть удалено анализом потока данных раньше, чем печатаются предупреждения.
Эти предупреждения сделаны необязательными, потому что GNU CC недостаточно умен, чтобы видеть все случаи, при котрых код может быть правильным, несмотри на кажущуюся ошибку. Ниже показан один пример, как такое может случиться:
{
int x;
switch (y)
{
case 1: x = 1;
break;
case 2: x = 4:
break;
case 3: x = 5;
}
foo (x);
}
Если значение y всегда есть 1, 2 или 3, тогда x всегда
иниацализирована, но GNU CC не знает этого. Ниже показан другой общий
случай:
{
int save_y;
if (change_y) save_y = y, y = new_y;
...
if (change_y) y = save_y;
}
Здесь нет ошибки, потому что save_y используется, только если
она была установлена.
Некоторые ложные предупреждения могут быть устранены, если вы объявите все используемые функции, которые никогда не возвращают управление, как noreturn. См. раздел 6.22 [Атрибуты Функций].
Все вышеперечисленные опции '-W' вместе взятые.
Остающиеся опции '-W...' не включаются в '-Wall', потому что они предупреждают о конструкциях, которые мы считаем разумным использовать при случае в хороших программах.
Печатает дополнительные предупреждения при следующих случаях:
foo (a)
{
if (a > 0)
return a;
}
Предупреждает об определенных конструкциях, которые ведут себя неодинаково в классическом и ANSI C.
Предупреждает, когда одна локальная переменная затеняет другую локальную переменную.
Предупреждает, когда у двух различных идентификаторов совпадают первые символы в количестве, определяемым параметром "длина". Это может вам помочь подготовить программу к компиляции устаревшим, ненормальным компилятором.
Предупреждает, когда объявляется объект размелом больше чем "длина" байт.
Предупреждает обо всем, что зависит от размеров типа функции и типа void. GNU C назначает этим типам размер 1 для удобства вычислений с указателями на void и на функции.
Предупреждает, когда вызов функции приводится к несоответствующему типу. Например, вызов int malloc () приводится к указателю.
Предупреждает, когда указатель приводится так, чтобы убрать квалификатор типа. Например, const char * приводится к обычному char *.
Предупреждает, если указатель приводится так, что возрастают требования на выравнивание. Например, если char * приводится к int * на машине, где int может размещаться только по двух- или четырехбайтовой границе.
Дает строковым константам тип const char[длина] так, что копирование адреса в не константный указатель на char вызовет предупреждение. Эти предупреждения помогут вам найти код времени компиляции, который может пытаться писать в строковую константу, но только в том случае, если вы будете внимательно относиться к использованию const в объявлениях и прототипах. В противном случае это превратится только в неприятности; вот почему мы не заставляем '-Wall' вызывать эти предупреждения.
Предупреждает, если прототип вызывает преобразование типа отличное от того, которое было бы с тем же аргументом при отсутствии прототипа. Это включает преобразования целочисленных типов в плавающие и т. п., и преобразования, меняющие размер или знаковость целочисленного аргумента, кроме тех, которые совпадают с целочисленным расширением.
Также предупреждает, если отрицательная целая константа неявно приводится к беззнаковому типу. Например, предупреждает об присваивании x = -1, если x беззнаковое. Но не предупреждает об прямо указаном преобразовании типа (unsigned)-1.
Предупреждает, если определяется или вызывается функция, которая возвращает структуру. (В языках, где можно возвращать массивы, это также вызывает предупреждение.)
Предупреждает, если функция объявлена или определена без спецификации типов аргументов. (Определение функции в старом стиле не вызывает предупреждения, если перед ним было объявление с указанными типами аргументов.)
Предупреждает, если глобальная функция определена без предварительного объявления прототипа. Это предупреждение появляется, даже если само определение дает прототип. Цель этого предупреждения в том, чтобы выявить глобальные функции, которые не объявлены в заголовочных файлах.
Предупреждает, если нечто объявлено более чем один раз в одной области действия даже в тех местах, где многократные объявления допустимы и ничего не меняют.
Предупреждает, если extern объявление встречается дважды внутри функции.
Предупреждает, если функция не может быть сделана inline и при этом была объявлена inline, или же была дана опция '-finline-functions'.
Превращает все предупреждения в ошибки.
GNU CC имеет различные специальные опции, которые используются для отладки как вашей программы, так и GCC.
Порождает отладочную информацию в родном формате операционной системы (stabs, COFF, XCOFF или DWARF). GDB может работать с этой отладочной информацией.
В большинстве систем, которые используют формат stabs, '-g' включает использование дополнительной отладочной информации, которую может использовать только GDB; эта дополнительная отладочная информация делает работу отладки в GDB лучше, но может, вероятно испортить работу других отладчиков, или помешать им прочитать программу. Если вы хотите управлять тем, будет ли порождаться дополнительная информация, используйте '-gstabs+', '-gstabs', '-gxcoff+', '-gxcoff', '-gdwarf+', '-gdwarf' (см. ниже).
В отличие от большинства других компиляторов C, GNU CC позволяет использовать опцию '-g' вместе с '-O'. Сокращения кода сделанные при оптимизации могут случайно привести к неожиданным результатам: некоторые переменные, которые вы объявили могут не существовать вовсе; поток управления может переместиться, когда вы этого не ожидали; некоторые операторы могут не выполняться, потому что они производят постоянный результа, или же их результат уже известен; некоторые операторы могут выполняться в других местах, потому что их вынесли из циклов.
Тем не менее, GNU CC дает возможность отлаживать оптимизированный результат. Это делает разумным использование оптимизатора для отладки программ, которые могут содержать ошибки.
Следующие опции полезны, если GNU CC сгенерирован с возможностью использовать более чем один формат отладочной информации.
Порождает отладочную информацию в родном формате (если он поддерживается), включающую расширения GDB, если это вообще возможно.
Порождает отладочную информацию в формате stabs (если он поддерживается) без расширений GDB. Это формат, используемый DBX'ом в большинстве BSD систем. На MIPS, Alpha и в системе System V Release 4 эта опция порождает отладочную информацию в формате stabs, которую не понимает DBX или SDB. В системе System V Realease 4 эта опция требует ассемблера GNU.
Порождает отладочную информацию в формате stabs (если он поддерживается) с использованием расширений GNU, которые понимает только отладчик GNU (GDB). Использование этих расширений с другими отладчиками вероятно приведет к их краху или помешает прочитать программу.
Порождает отладочную информацию в формате COFF (если он поддерживается). Этот формат использовался SDB в системах System V до System V Release 4.
Порождает отладочную информацию в формате XCOFF (если он поддерживается). Это формат, используемый отладчиком DBX в системах IBM RS/6000.
Порождает отладочную информацию в формате XCOFF (если он поддерживается) с использованием расширений GNU, которые понимает только отладчик GNU (GDB). Использование этих расширений с другими отладчиками вероятно приведет к их краху или помешает прочитать программу, а также может привести ассемблер, отличный от ассемблера GNU (GAS), к ошибке.
Порождает отладочную информацию в формате DWARF (если он поддерживается). Этот формат используется SDB в большинстве систем System V Release 4.
Порождает отладочную информацию в формате DWARF (если он поддерживается) с использованием расширений GNU, которые понимает только отладчик GNU (GDB). Использование этих расширений с другими отладчиками вероятно приведет к их краху или помешает прочитать программу.
Включает отладочную информацию, а также использует 'уровень', чтобы определить как много информации требуется. По умолчанию используется уровень 2.
Уровень 1 выводит минимальную информацию, достаточную, чтобы отслеживать цепочку вызовов в частях программы, которые вы не собираетесь отлаживать. Она включает в себя описание функций и внешних переменных, но не содержит информации об локальных переменных и номерах строк.
Уровень 3 включает дополнительную информацию, такую как все макро определения встречающиеся в программе. Некоторые отладчики поддерживают макро расширения при использовании '-g3'.
Порождает дополнительный код для записи профилирующей информации, подходящей для анализирующей программы prof. Вы должны использовать эту опцию при компиляции исходного файла, о котором вы хотите получить информацию, и вы также должны использовать ее при линковке.
Порождает дополнительный код для записи профилирующей информации, подходящей для анализирующей программы gprof. Вы должны использовать эту опцию при компиляции исходного файла, о котором вы хотите получить информацию, и вы также должны использовать ее при линковке.
Порождает дополнительный код для записи профилирующей информации для базисных блоков, который будет записывать, сколько раз выполняется каждый базисный блок, его начальный адрес и имя функции, которая его содержит. Если используется опция '-g', будут также записываться номер строки и имя файла начала базисного блока. Если не изменено описанием архитектуры машины, то действием по умолчанию является добавление к текстовому файлу 'bb.out'.
Эти данные могут быть проанализированы программой вроде tcov. Заметим, однако, что формат данных не таков, как ожидает tcov. GNU gprof со временем будет расширен для обработки этих данных.
Делает отладочные дампы во время компиляции в моменты времени определяемые буквами. Они используются для отладки компилятора. Имена файлов для большинства дампов получаются из имени исходного файла добавлением слова (например, 'foo.c.rtl' или 'foo.c.jump'). Ниже указаны возможные буквы и их значения:
Дамп всех макро определений в конце препроцессирования; не порождать другого вывода.
Дамп всех макро определений в конце препроцессирования.
Дамп всех макро определений в конце препроцессирования, в добавление к нормалному выводу.
Дамп отладочной информации во время лексического разбора в стандартный вывод ошибок.
Дамп после генерации RTL в файл 'файл.rtl'.
Только генерировать RTL для функции вместо ее компиляции. Обычно используется вместе с 'r'.
Дамп после первой оптимизации переходов в файл 'файл.jump'.
Дамп после CSE (включая оптимизацию переходов, которая иногда следует за CSE) в файл 'файл.cse'.
Дамп после оптимизации циклов в файл 'файл.loop'.
Дамп после второго прохода CSE (включая оптимизацию переходов, которая иногда следует за CSE) в файл 'файл.cse2'.
Дамп после анализа потока в файл 'файл.flow'.
Дамп после комбинирования инструкций в файл 'файл.combine'.
Дамп после первого прохода планировщика в файл 'файл.sched'.
Дамп после локального распределения регистров в файл 'файл.lreg'.
Дамп после глобального распределения регистров в файл 'файл.greg'.
Дамп после второго прохода планировщика в файл 'файл.sched2'.
Дамп после последней оптимизации переходов в файл 'файл.jump2'.
Дамп после планировщика ветвей в файл 'файл.dbr'.
Дамп после преобразования регистров в стек в файл 'файл.stack'.
Порождает все дампы, перечисленные выше.
Печатает статистику использования памяти в конце исполнения в стандартный вывод ошибок.
Комментирует ассемблерный вывод комментариями, показывающими какой шаблон и какая альтернатива были использованы.
При запуске кросс-компилятора делает вид, что целевая машина использует тот же формат чисел с плавающей точкой, что и базовая машина. Это приводит к неверному выводу реыльных констант с плавающей точкой, но реальная последовательность инструкций будет, вероятно, такой же как и последовательность, порождаемая GNU CC при запуске на целевой машине.
Постоянно сохраняет промежуточные "временные" файлы; они помещаются в текущий каталог, а их имена основываются на имени исходного файла. Так, компилируя 'foo.c' с опциями '-c -save-temps', будут порождены файлы 'foo.i', 'foo.s', также как и 'foo.o'.
Печатает полное абсолютное имя библиотечного файла 'библиотека', которое использовалось бы при линковке, и не делает больше ничего. С этой опцией GNU CC ничего не компилирует и не линкует - он только печатает имя файла.
Подобна '-print-file-name', но ищет программу, такай как, например, 'cpp'.
Совпадает с '-print-file-name=libgcc.a'.
Эта опция полезна, когда вы используете '-nostdlib' или '-nodefaultlibs', но вы хотите линковать с 'libgcc.a'. Вы можете написать
gcc -nostdlib файлы... 'gcc -print-libgcc-file-name'.
Печатает имя сконфигурированной инсталяционной директории, список программ и библиотечных директориев, которые будет просматривать gcc и не делает больше ничего.
Эта опция полезна, когда gcc печатает сообщение об ошибке 'installation problems, cannot exec cpp: No such file or directory' ('проблемы инсталяции, невозможно выполнить cpp: Нет такого файла или директория'). Чтобы разрешить эту проблему, вы либо должны поместить 'cpp' и другие компоненты компилятора там, где gcc ожидает их найти, либо вы можете установить переменную окружения GCC_EXEC_PREFIX равной дериктории, где вы их поместили. Не забывайте сопутствующие символы '/'. См. раздел [Переменные Окружения].
Эти опции управляют различными видами оптимизаций:
Оптимизировать. Оптимизированная трансляции требует несколько больше времени и несколько больше памяти для больших функций.
Без `-O' цель компилятора состoит в том, чтобы уменьшить стоимость трансляции и выдать ожидаемые результаты при отладке. Операторы независимы: если вы останавливаете программу на контрольной точке между операторами, вы можете назначить новое значение любой переменной или поставить счетчик команд на любой другой оператор в функции и получить точно такие результаты, которые вы ожидали из исходного текста.
Без `-O' компилятор только распределяет переменные объявленные register в регистрах. Получающийся в результате откомпилированный код немного хуже чем произведенный PCC без `-O'.
С `-O' компилятор пробует уменьшить размер кода и время исполнения.
Когда вы задаете `-O', компилятор включает `-fthread-jumps' и `-fdefer-pop' на всех машинах. компилятор включает `-fdelayed-branch' на машинах, которые имеют щели задержки, и `-fomit-frame-pointer' на машинах, которые могут обеспечивать отладку даже без указателя фрейма. На некоторых машинах компилятор также включает другие флаги.
Оптимизирует даже больше. GNU CC выполняет почти все поддерживаемые оптимизации, которые не включают уменьшение времени исполнения за счет увеличения длины кода. Компилятор не выполняет раскрутку циклов или подстановку функций, когда вы указываете `-O2'. По сравнения с `-O' эта опция увеличивает как время компиляции, так и эффективность сгенерированного кода.
`-O2' включает все необязательные оптимизации кроме раскрутки циклов и подстановки функций. Она также включает опцию `-fforce-mem' на всех машинах и исключение указателя фрейма на машинах, где это не помешает отладке.
Оптимизирует еще больше. `-O3' включает все оптимизации, определяемые `-O2', а также включает опцию `inline-functions'.
Не оптимизировать.
Опции вида `-fфлаг' определяют машинно-независимые флаги. Большинство флагов имеют положительную и отрицательную формы; отрицательной формой `-ffoo' будет `-fno-foo'. В таблице, расположенной ниже, указана только одна из форм - та, которая не является умолчанием. Вы можете сконструировать другую форму удалением или добавлением '-no'.
Не позволяет сохранять переменные с плавающей точкой в регистрах и препятствует другим опциям, которые могут изменять, откуда берется значение с плавающей точкой - из регистра или из памяти.
Эта опция предотвращает нежелательную излишнюю точность на машинах типа 68000, где регистры с плавающей точкой (из 68881) хранят большую точность, чем имеет double. Для большинства программ, излишняя точность делает только лучше, но некоторые программы полагаются на точное описание плавающей точки IEEE. Используйте `-ffloat-store' для таких программ.
Всегда выталкивает параметры каждого вызова функции сразу после возврата из нее. Для машин, которые должны выталкивать параметры после обращения к функции, компилятор обычно позволяет параметрам накапливаться на стеке при нескольких вызовах функций, и выталкивает их все сразу.
Заставляет копировать операнды в памяти в регистры перед выполнением с ними арифметических операций. Это производит лучший код, поскольку все ссылки становятся потенциальными общими подвыражениями. Если они не являются общими подвыражениями, комбинацирование команд должно исключить отдельную загрузку регистров. Опция '-O2' включает эту опцию.
Заставляет копировать константные адреса памяти в регистры перед выполнением с ними арифметических операций. Это производит лучший код точно также как и '-fforce-mem'.
Не хранит указатель фрейма для функций, которые не нуждаются в нем. Это избегает команд сохранения, установки и восстановления указателя фрейма; это также делает доступным дополнительный регистр во многих функциях. Это делает отладку невозможной на некоторых машинах.
На некоторых машинах, таких как Vax, этот флажок не имеет эффекта, потому что стандартная вызывающая последовательность автоматически обрабатывает указатель фрейма, и ничего не экономится, если считается, что он не существует. Макрос `FRAME_POINTER_REQUIRED' в описании архитектуры управляет тем, обеспечивает ли целевая машина этот флаг или нет. См. раздел [Регистры].
Не обращать внимание на ключевое слово inline. Обычно эта опция используется, чтобы уберечь компилятор от подстановки любых функций. Обратите внимание что, если вы не оптимизируете, никакие функции не могут быть подставлены.
Интегрирует все простые функции в вызывающие функции. Компилятор эвристически решает, какие функции достаточно просты, чтобы их стоило интегрировать таким образом.
Если все вызовы к данной функции интегрированы, а функция обьявлена static, тогда ассемблерный код функции обычно не выводится в своем настоящем виде.
Даже если все вызовы к данной функции интегрированы, и функция обьявлена static, выводит, однако, отдельную вызываемую во время выполнения версию функции.
Не кладет адреса функций в регистры; каждая инструкция, которая вызывает постоянную функцию явно содержит адрес функции.
Эта опция приводит к менее эффективному коду, но некоторые странные куски, которые изменяют ассемблерный код, могут быть спутаны оптимизацией, выполняемой, когда эта опция не используется.
Эта опция позволяет GCC нарушать некоторые ANSI или IEEE правила и/или спецификации с целью оптимизации быстродействия кода. Наример, она позволяет компилятору считать, что параметры функции sqrt являются неотрицательными числами, и что никакие значения с плавающей точкой не являются NaNs.
Эта опция не должна никогда включаться любой из `-O' опций, так как она может приводить к неправильному результату для программ, которые зависят от точного выполнения правил/спецификаций IEEE или ANSI для математических функций.
Следующие опции управляют специфическими оптимизациями. Опция `-O2' включает все эти оптимизации за исключением `-funroll-loops' и `-funroll-all-loops'. На большинстве машин опция '-O' включает опции `-fthread-jumps' и `-fdelayed-branch', но отдельные машины могут обрабатывать ее по-другому.
Вы можете использовать следующие флаги в тех редких случаях, когда желательно выполнять "тонкую настройку" оптимизации.
Выполняет оптимизацию циклов: понижение силы операций и исключение итеративных переменных.
Выполняет оптимизацию условного перехода, если выясняется, что он переходит к участку, где находится другое сравнение подчиненное первому. Если так, то первый переход переназначается на точку назначения второго перехода или точку сразу после него, в зависимости от того, должно ли быть второе условие истинным или ложным.
В исключении общих подвыражений проходит через команду перехода, если точка назначения перехода не достигается никаким другим маршрутом. Например, когда CSE сталкивается с оператором if с ветвью else, CSE будет следовать переходу к случаю, когда проверяемое условие ложно.
Подобна `-fcse-follow-jumps', но заставляет CSE следовать переходам, которые условно пропускают блоки. Когда CSE сталкивается с простым оператором if без ветви else, `-fcse-skip-blocks' заставляет CSE следовать переходу вокруг тела if.
Повторно запускается общее удаление подвыражений после оптимизации циклов.
Выполняет ряд малых оптимизации, которые являются относительно дорогими.
Если поддерживается для целевой машины, пытается переупорядочивать инструкции так, чтобы эксплуатировать щели задержки доступные после задержанной команды перехода.
Если обеспечивается для целевой машины, пытается переупорядочить инструкции так, чтобы исключить простои исполнения из-за того, что отсутствуют требуемые данные. Это помогает машинам, которые имеют медленные инструкции с плавающей точкой или загрузки памяти, при разрешении другим командам выполняться, пока результат загрузки или инструкции с плавающей точкой не требуется.
Подобна `-fschedule-insns', но запрашивает дополнительный проход планировщика после того, как было выполнено распределение регистров. Это особенно полезно на машинах с относительно маленьким числом регистров и там, где команды загрузки памяти требуют больше чем один цикл.
Дает возможность распредять значения в регистрах, которые затираются вызовами функций, с порождением дополнительных команд сохранения и восстановления регистров вокруг таких вызовов. Такое распределение выполняется только тогда, когда кажется, что оно приводит к лучшему коду чем другое.
Эта опция включается по умолчанию на некоторых машинах, обычно на тех, которые не имеют никаких сохраняемых при вызове регистров для использования взамен.
Выполняет раскрутку циклов. Она выполненяется только для циклов, число итераций которых можно определить в процессе компиляции или во время выполнения. `-funroll-loop' подразумевает и `-fstrength-reduce' и `-frerun-cse-after-loop'.
Выполняет раскрутку циклов. Она выполняется для всех циклов и обычно делает программы более медленными. `-funroll-all-loops' подразумевает `-fstrength-reduce', также как и `-frerun-cse-after-loop'.
Отключает любые peephole-оптимизации специфические для машины.
Эти опции управляют препроцессором C, который обрабатывает каждый C исходный файл перед фактической компиляцией.
Если вы используете опцию `-E', ничего кроме препроцессирования не делается. Некоторые из этих опций имеют смысл только вместе с `-E', потому что они делают вывод препроцессора неподходящим для фактической компиляции.
Обрабатывает 'файл' как ввод перед обработкой обычного входного файла. Фактически, содержимое 'файла' компилируется сначала. Любая опция '-D' или '-U' из командной строки обрабатывается до '-include файл', вне зависимости от порядка, в котором они записаны. Все опции '-include' и '-imacros' обрабатываются в том порядке, в котором они записаны.
Обрабатывает 'файл' как ввод, отбрасывая возникающий в результате вывод до обработки обычного входного файла. Так как вывод сгенерированный из 'файла' отбрасывается, единственый эффект `-imacros файл' состоит в том, что макрокоманды определенные в 'файле' становятся доступны для применения в главном вводе.
Любая опция '-D' или '-U' из командной строки обрабатывается до '-imacros файл', вне зависимости от порядка, в котором они записаны. Все опции '-include' и '-imacros' обрабатываются в том порядке, в котором они записаны.
Добавляют каталог 'директорий' ко второму маршруту включения. В каталогах второго маршрута включения ищут, когда заголовочный файл не обнаружен ни в одном из каталогов в главном маршруте включения (маршрут, к которому добавляет опция `-I').
Определяет 'префикс' как префикс для нижеследующей опции `-iwithprefix'.
Добавляет каталог ко второму маршруту включения. Имя каталога получается объединением 'префикса' и 'директория', где 'префикс' определялся предварительно опцией `-iprefix'. Если вы еще не определили префикс, по умолчанию используется каталог, содержащий инсталированные проходы компилятора.
Добавляет каталог к главному маршруту включения. Имя каталога получается объединением 'префикса' и 'директория', как в случае `-iwithprefix'.
Добавляет каталог 'директорий' к началу второго маршрута включения, помечая его как системный каталог, так что он имеет ту же самую специальную обработку, что и стандартные системные каталоги.
Не ищет в стандартных системных каталогах для заголовочных файлов. Только каталоги, которые вы определили опциями `-I' (и текущий каталог, если подходит) используется для поиска. См. раздел [Опции Ди- ректорий] для информации об '-I'.
Используя `-nostdinc' и `-I-', вы можете ограничить маршрут поиска файлов включения только теми каталогами, которые вы задали явно.
Не предопределяет любые нестандартные макросы. (Включая флаги архитектуры).
Запускает только препроцессор C. Препроцессирует все указанные C исходные файлы и выводит результаты в стандартный вывод или в указанный выходной файл.
Говорит препроцессору не отбрасывать комментарии. Используется с опцией `-E'.
Говорит препроцессору не генерировать директивы `#line'. Используется с опцией '-E'.
Говорит препроцессору выводить правила для make, описывающие зависимости каждого объектного файла. Для каждого исходного файла, препроцессор выводит одно make-правило, чья цель - имя объектного файла, для которого исходный файл и чьими зависимостями являются все #include заголовочные файлы, которые он использует. Это правило может быть одиночной строкой или может быть продолжено с помощью `\'-новая строка, если оно длинное. Список правил печатается в стандартный вывод вместо препроцессированной C программы.
`-M' подразумевает `-E'.
Другой способ указать вывод make-правил - с помощью установки переменной окружения DEPENDENCIES_OUTPUT (См. раздел [Переменные Окружения]).
Подобна `-M', но вывод упоминает только заголовочные файлы пользователя, включенные с помощью `#include "файл"'. Системные заголовочные файлы, включенные с помощью `#include <файл>' опускаются.
Подобна `-M', но информация о зависимостях записывается в файл получающемуся при замене ".c" на ".d" на концах имен входных файлов. Это делается в добавление к указанной компиляции файла - `-MD' не запрещает обычную компиляцию, как это делает '-M'.
В Mach вы можете использовать утилиту `md', чтобы обьединить многочисленные файлы зависимостей в один файл, подходящий для использования с командой make.
Подобна `-MD', за исключением упоминания только пользовательских заголовочных файлов, но не системных заголовочных файлов.
Обрабатывать отсутствующие заголовочные файлы как генерируемые файлы и считать, что они находятся в том же самом каталоге, что и исходный файл. Если вы указываете `-MG', вы также должны указывать или `-M', или `-MM'. `-MG' не поддерживается с `-MD' или `-MMD'.
Печатает имя каждого используемого заголовочного файла в добавление к нормальным действиям.
Утвердить ответ 'ответ' для 'вопроса', в случае, если он проверяется условным выражением препроцессора типа `#if #вопрос(ответ)'. `-A-' отключает стандартные утверждения, которые обычно описывают целевую машину.
Определяет макрос 'макрос' со строкой `1' в качестве его определения.
Определяет макрос 'макрос' как 'определение'. Все экземпляры `-D' в командной строке обрабатываются до любых опций `-U'.
Отменяют определение макроса 'макрос'. Опции `-U' обрабатываются после всех опций `-D', но перед любыми `-include' и `-imacros' опциями.
Говорит препроцессору вывести только список макроопределений, которые имеют действие в конце препроцессирования. Используется с опцией `-E'.
Говорит препроцессору передать все макроопределения в вывод в их последовательности в другом выводе.
Подобна `-dD', за исключением того, что макроаргументы и содержание опускаются. В вывод включается только `#define имя'.
Поддерживает трехзнаковые последовательности ANSI C. Опция `-ansi' также имеет этот эффект.
Передает 'опцию' в качестве опции препроцессору. Если 'опция' содержит запятые, она расщепляется запятыми на многочисленные опции.
Вы можете передать опции ассемблеру.
Передает 'опцию' в качестве опции ассемблеру. Если 'опция' содержит запятые, она расщепляется запятыми на многочисленные опции.
Эти опции вступяют в игру тогда, когда компилятор линкует объектные файлы в выполнимый выходной файл. Они бессмысленны, если компилятор не выполняет шаг линковки.
Имя файла, которое не заканчивается специальным распознаным суффиксом, считается именем объектного файла или библиотеки. (Объектные файлы отличаются линкером от библиотек по содержимому файла.) Если выполняется линковка, эти объектные файлы используются в качестве ввода для линкера.
Если используется любая из этих опций, то линкер не запускается, и имена объектных файлов не должны использоваться в качестве параметров. См. раздел [Общие Опции].
Ищет при линковке библиотеку с именем 'библиотека'.
Есть различие в том, где в комадной строке вы записываете эту опцию; линкер ищет обрабатываемые библиотеки и объектные файлы в порядке, в котором они указаны. Таким образом, `foo.o -lz bar.o' ищет библиотеку `z' после файла `foo.o', но перед `bar.o'. Если `bar.o' ссылается на функции в `z', эти функции не могут быть загружены.
Линкер просматривает стандартный список каталогов в поиске библиотеки, который, фактически, является файлом с именем `libбиблиотека.a'. Затем линкер использует этот файл так, как будто бы он был точно специфицирован по имени.
Директории, в которых ищет линкер, включают несколько стандартных системных каталогов, плюс любые каталоги, которые вы определяете с помощью `-L'.
Обычно файлы, обнаруженные этим способом являются библиотечными файлами - архивными файлами, чьи элементы - объектные файлы. Линкер обрабатывает архивный файл, просматривая его в поиске элементов, которые определяют символы, на которые были ссылки, но которые до сих пор не определялись. Но, если оказывается, что обнаруженный файл - обычный объектный файл, то он линкуется в обычном порядке. Единственное различие между использованием опции `-l' и указанием имени файла в том, что `-l' добавляет к 'библиотеке' `lib' и `.a' и ищет в нескольких директориях.
Вам нужен этот специальный случай опции `-l' для линковки Objective C программ.
Не использует стандартные системные файлы начального запуска при линковке. Стандартные системные библиотеки используются как обычно, если не указано `-nostdlib' или `-nodefaultlibs'.
Не использует стандартные системные библиотеки при линковке. Линкеру передаются только те библиотеки, которые вы указываете. Стандартные файлы начального запуска используются как обычно, если не указано `-nostartfiles'.
Не использует стандартные системные файлы начального запуска и библиотеки при линковке. Никакие файлы запуска и только те библиотеки, которые вы указываете будут, переданы линкеру.
Одной из стандартных библиотек, обходимых `-nostdlib' и `-nodefaultlibs' является `libgcc.a' - библиотека внутренних подпрограмм, которые использует GNU CC, чтобы преодолевать изъяны конкретных машин, или для специальных потребностей некоторых языков. (См. Главу 13 [Интерфейс к выводу GNU CC] для подробного рассмотрения `libgcc.a'.) В большинстве случаев, вы нуждаетесь в `libgcc.a', даже когда вы хотите избегать других стандартных библиотек. Другими словами, когда вы указываете `-nostdlib' или `-nodefaultlibs', вы должны обычно также указывать `-lgcc'. Это гарантирует, что нет никаких нарушеных ссылок к внутренним библиотечным подпрограммам GNU CC. ( Например, `__main' , используемая, чтобы гарантировать вызов конструкторов C++.)
Удаляет все символьные таблицы и информацию о перемещениях из исполняемого файла.
В системах, которые поддерживают динамическую линковку, предотвращает линковку с разделяемыми библиотеками. В других системах, эта опция не имеет никакого эффекта.
Производит разделяемый объект, который может затем быть слинкован с другими объектами, чтобы сформироваться исполнимый файл. Только некоторые системы поддерживают эту опцию.
Связывает ссылки к глобальным символам при формировании разделяемого объекта. Предупреждает о любых неразрашенных ссылок (если не отменено опцией редактора связей `-Xlinker -z -Xlinker определения' ). Только некоторые системы поддерживают эту опцию.
Передает 'опцию' в качестве опции линкеру. Вы можете использовать ее, чтобы поддерживать специфические для системы опции линкера, о которых GNU CC не знает как распознавать.
Если вы хотите передать опцию, которая имеет параметр, вы должны использовать `-Xlinker' дважды: один раз для опции и один раз для параметра. Например, чтобы передать `-assert описания', вы должны написать `-Xlinker -assert -Xlinker описания'. Не срабатывает, если написать `-Xlinker " -assert описания " ', потому что это передает всю cтроку как единый параметр, который не ожидается линкером.
Передает 'опцию' в качестве опции линкеру. Если 'опция' содержит запятые, она расщепляется запятыми на многочисленные опции.
Делает вид, что символ 'символ' неопределен, вынуждая линкуемые библиотечные модули определять его. Вы можете использовать `-u' много разы с различными символами, чтобы вызвать загрузку дополнительных библиотечных модулей.
Эти опции определяют каталоги для поиска заголовочных файлов, библиотек и частей компилятора:
Добавляет каталог 'директория' в начало списка каталогов, используемых для поиска заголовочных файлов. Ее можно использовать для подмены системных заголовочных файлов, подставляя ваши собственные версии, поскольку эти директории просматриваются до директорий системных заголовочных файлов. Если вы используете более чем одну опцию '-I', директории просматриваются в порядке слева направо; стандартные системные директории идут после.
Любые каталоги, которые вы указываете с опциями `-I' до опции `-I-' просматриваются только в случае `#include "файл"'; они не просматриваются для `#include <файл>'.
Если дополнительные каталоги указаны с опциями `-I' после опции `-I-', эти каталоги просматриваются для всех директив `#include'. (Обычно все `-I' директории используются таким способом.)
Кроме того, опция `-I-' запрещает использование текущего каталога (откуда пришел текущий входной файл) в качестве первого каталога для поиска `#include "файл"'. Нет никакого способа отменить этот эффект опции `-I-'. С помощью `-I.' вы можете указать поиск в каталоге, который был текущим, когда вызывался компилятор. Это не точно то же самое, что делает препроцессор по умолчанию, но часто подходит.
'-I-' не запрещает использование стандартных системных директориев для заголовочных файлов. Таким образом, '-I-' и '-nostdinc' являются независимыми.
Эта опция указывает где искать выполнимые, библиотечные и заголовочные файлы, а также файлы данных для самого компилятора.
Управляющая программа компилятора запускает одну или больше программ 'cpp', 'cc1', 'as' и 'ld'. Он пытается использовать 'префикс' в качестве префикса для каждой программы, которую он запускает, как с так и без 'машина/версия/' (см. раздел [Целевые Опции]).
Для каждой запускаемой программы компилятор сначала пытается использовать префикс '-B', если указан. Если такое имя не найдено, или опция '-B' не указана, компилятор пытается использовать два стандартных префикса: '/usr/lib/gcc/' и '/usr/local/lib/gcc-lib/'. Если ни один из этих префиксов не дает результата, не модифицированное имя программы ищется с использованием директорий указанных в вашей переменной окружения 'PATH'.
Префикс '-B', который эффективно указывает имена директорий, также применяется к библиотекам в линкере, поскольку компилятор преобразует эти опции в опции '-L' для линкера. Они, также, применяются к заголовочным файлам в препроцессоре, поскольку компилятор преобразует эти опции в опции '-isystem' для препроцессора. В этом случае компилятор добавляет 'include' к префиксу.
Файл поддержки времени выполнения 'libgcc.a' может также искаться, если нужно, с использованием префикса '-B'. Если он не найден там, используются два стандартных префикса, указанных выше, и это все. Файл пропадает из линковки, если он не найден таким способом.
Другой способ указать префикс очень сходный с префиксом '-B' - использовать переменную окружения GCC_EXEC_PREFIX. См. раздел [Переменные Окружения].
По умолчанию, GNU CC компилирует код для той же самой машины, которую вы используете. Однако, он также может быть инсталлирован как кросс-компилятор, чтобы компилировать для какого-нибудь другого типа машин. В действительности, несколько различных конфигураций GNU CC, для различных целевых машин, могут быть установлены бок о бок. Затем, вы указываете, какую конфигурацию использовать с помощью опции '-b'.
Кроме того, более старые и более новые версии компилятора могут быть установлены бок о бок. Одина из них (вероятно, самая новая) будет являться умолчанием, но вы можете захотеть иногда использовать другую.
Аргумент 'машина' указывает целевую машину для компиляции. Она полезна, когда вы установили GNU CC в качестве кросс-компилятора.
Значение, используемое в качастве аргумента 'машина' - то же, что было указано при конфигурировании GNU CC в качестве кросс-компилятора. Например, если кросс-компилятор конфигурировался с 'configure i386v', означающем компиляцию для 80386 с System V, тогда вы должны указать '-b i386v', чтобы запустить этот кросс-компилятор.
Когда вы не указываете '-b', это обычно означает компиляцию для того же самого типа машины, который вы используете.
Аргумент 'версия' указывает, какую версию компилятора запускать. Она полезна, когда установлены многочисленные версии. Например, 'версия' может быть '2.0', означая запуск GNU CC версии 2.0.
Версией по умолчанию, когда вы не указываете '-V', является последняя версия GNU CC, которую вы установили.
Таким образом, можно установить действие опций '-b' и '-V', либо изменив имена этих директорий, либо добавив альтернативные имена (или символические ссылки). Если в деректории '/usr/local/lib/gcc-lib/' файл '80386' является символической ссылкой на файл 'i386v', тогда '-b 80386' становиться синонимом '-b i386v'.
С одной стороны, опции '-b' и '-V' не совсем переключают на другой компилятор: управляющая программа верхнего уровня gcc, которую вы первоначально вызвали, продолжает выполняться и вызывать другие исполнимые файлы (препроцессор, сам компилятор, ассемблер и линкер), которые и выполняют реальную работу. Однако, поскольку никакой реальной работы не выполняется в управляющей программе, обычно не важно, что используемая управляющая программа не является программой для указанной машины и версии.
Единственное место, в котором управляющая программа зависит от целевой машины, в разборе и обработке специальных машинозависимых опций. Однако, это контролируется файлом, который находится, вместе с другими выполнимыми файлами, в директории для указанной версии и целевой машины. В результате, одна установленная управляющая программа адаптируется к любым указанным целевой машине и версии компилятора.
Выполнимый файл управляющей программы, однако, управляет одной важной вещью: версией компилятора и целевой машиной по умолчанию. Следовательно, вы можете установить различные экземпляры управляющей программы, скомпилированные для разных целевых машин и версий, под различными именами.
Например, если управляющая программа для версии 2.0 установлена как ogcc, а для версии 2.1 - как gcc, тогда команда gcc будет, по умолчанию, использовать версию 2.1, а ogcc - версию 2.0. Однако, вы можете выбрать любую версию с любой командой с помощью опции '-V'.
Ранее мы обсуждали стандартную опцию '-b', которая выбирает среди различных инсталлированных компиляторов для совершенно различных типов целевых машин, таких как Vax, 68000, 80386.
В добавление, каждый из этих типов машин может иметь свои собственные специальные опции, начинающиеся с '-m', для выбора между различными моделями и конфигурациями машин. Например, 68010 или 68020, плавающий сопроцессор или нет. Одна установленная версия компилятора может компилировать для любой модели и конфигурации, в соответствии с указанными опциями.
Некоторые конфигурации компилятора также поддерживают дополнительные специальные опции, обычно для совместимости с другими компиляторами для той же платформы.
Эти опции определяются с помощью макроса TARGET_SWITCHES в описании архитектуры. Умолчания для опций также определяются этим макросом, который позволяет вам менять умолчания.
Эти '-m' опции определены для семейства i386 компьютеров:
Управляет тем, оптимизируется ли код для 486 вместо 386 или нет. Код сгенерированный для 486 будет работать на 386 и наоборот.
Управляет тем, использует или нет компилятор IEEE сравнения с плавающей точкой. Они корректно обрабатывают случай, когда результат сравнения неопределен.
Порождает выход, содержащий библиотечные вызовы для плавающей точки. Предупреждение: необходимая библиотека не является частью GNU CC. Обычно используются способности обыкновенных компиляторов C, но это не может быть сделано прямо в кросс-компиляции. Вы должны провести свое собственное мероприятие, чтобы обеспечить подходящюю библиотеку функций для кросс-компиляции.
На машинах, где функции, возвращающие значение с плавающей точкой, выдают результат на регистровом стеке 80387, некоторые инструкции с плавающей точкой могут порождаться даже при использовании '-msoft-float'.
Не использует регистру плавающего сопроцессора для возврата значений из функций.
Обычная конвенция вызовов возвращает значения типов float и double на регистрах плавающего сопроцессора, даже, если плавающего сопроцессора нет. Идея состоит в том, что операционная система должна эмулировать плавающий сопроцессор.
Опция '-mno-fp-ret-in-387' заставляет вместо этого возвращать такие значения на обычных регистрах центрального процессора.
Некоторые эмуляторы 387 не поддерживают инструкции sin, cos и sqrt для 387. Указывая эту опцию, вы избегаете генерации этих инструкций. Эта опция включается по умолчанию на FreeBSD. В качестве исправления 2.6.1, эти инструкции не генерируются, если вы не используете, также, опцию '-ffast-math'.
Управляет тем, выравнивает ли GNU CC double, long double и long long переменные на границу двух слов или на границу одного слова. Выравнивание double переменных на границу двух слов порождает код, который выполняется немного быстрее на 'Pentium' при затрате большего количества памяти.
Предупреждение: Если вы используете опцию '-malign-double', структуры, содержащие выше перечисленные типы будут выравниваться не так, как в опубликованных спецификациях прикладного двоичного интерфейса для 386.
Управляет тем, куда GNU CC кладет неинициализированные локальные переменные - в bss или data. 'msvr3-shlib' кладет эти переменные в bss. Эти опции имеют смысл только в System V Release 3.
Управляет тем, использует ли GNU CC mul и imul, которые выдают 64-битный результат в eax:edx из 32-битных операндов для выполнения long long умножения и 32-битного деления на константы.
Использует другую конвенцию вызова функций, в которой функция, которая имеет фиксированное число аргументов возвращается с помощью инструкции 'ret число', которая выталкивает аргументы при возврате. Это сохраняет одну инструкцию в месте вызова, поскольку не надо выталкивать аргументы там.
Вы можете указать, что отдельная функция вызывается с этой конвенцией вызова с помощью атрибута функции 'stdcall'. Вы можете, также, отменить опцию '-mrtd', используя атрибут функции 'cdecl'. См. раздел 6.22 [Атрибуты Функций].
Предупреждение: эта конвенция вызова несовместима с обычно используемой в Unix, так что вы не можете использовать ее, если вам нужно вызывать библиотеки скомпилированные компилятором Unix.
Вы, также, должны обеспечить прототипы для всех функций, которые имеют переменное число аргументов (включая printf); иначе для вызова этих функций будет генерироваться неверный код.
Кроме того, очень некорректный код будет сгенерирован, если вы вызовите функцию со слишком большим числом аргументов. (Обычно, лишние аргументы без последствий игнорируются.)
Управляет порядком распределения по умолчанию целых регистров. Строка 'регистры' представляет собой ряд букв определяющих регистры. Поддерживаемыми буквами являются: a выделяет EAX, b выделяет EBX, c выделяет ECX, d выделяет EDX, S выделяет ESI, D выделяет EDI, B выделяет EBP.
Управляет тем, сколько регистров используется для передачи целых аргументов. По умолчанию, регистры для передачи параметров не используются, и максимум 3 регистра могут быть использованы. Вы можете управлять этим для конкретных функций используя атрибут функции 'regparm'. См. раздел 6.22 [Атрибуты Функций].
Предупреждение: если вы используете эту опцию, и 'число' не равно нулю, вы должны строить все модули с одним и тем же значением, включая все библиотеки. Это включает системные библиотеки и модули начальной загрузки.
Выравнивает циклы на границу степень двух с показателем 'число' байт. Если '-malign-loops' не указана, умолчанием является 2.
Выравнивает инструкции, на которые только переходят на границу степень двух с показателем 'число' байт. Если '-malign-jumps' не указана, умолчанием является 2 при оптимизации для 386, и 4 - для 486.
Выравнивает начала функций на границу степень двух с показателем 'число' байт. Если '-malign-functions' не указана, умолчанием является 2 при оптимизации для 386, и 4 - для 486.
Эти машинонезависимые опции управляют соглашениями об интерфейсе, используемыми при генерации кода.
Большинство из них имеет как положительную, так и отрицательную формы; отрицательной формой '-ffoo' будет '-fno-foo'. В таблице ниже, указывается только одна из этих форм - та, которая не является умолчанием. Вы можете получить другую форму, либо удалив 'no-', либо добавив его.
Возвращает "короткие" структуры и объединения в памяти, также как и длинные, а не на регистрах. Эта конвенция менее эффективна, но она имеет преимущество в совместимости вызовов между файлами, скомпилированными GNU CC, и файлами, скомпилированными другими компиляторами.
Точная конвенция возврата структур в памяти зависит от макросов описания архитектуры.
Короткими структурами и объединениями являются те, чей размер и выравнивание соответствует одному из целых типов.
Использует соглашение, что структуры и объединения возвращаются, когда возможно. на регистрах. Это более эффективно для малых структур, чем '-fpcc-struct-return'.
Если вы не указываете ни '-fpcc-struct-return', ни ее противоположность - '-freg-struct-return', GNU CC использует стандартную для данной архитектуры конвенцию. Если стандартной конвенции не существует, GNU CC использует '-fpcc-struct-return', кроме архитектур, где GNU CC является основным компилятором. В этом случае мы можем выбрать стандарт, и мы выбираем более эффективный вариант регистрового возврата.
Выделяет для типа перечисления только такое количество байтов, которое нужно для объявленного диапазона возможных значений. А именно, тип перечисления будет эквивалентен наименьшему целому типу, который имеет достаточно места.
Использует тот же размер для double, что и для float.
Требует, чтобы данные и неконстантные переменные этой единицы компиляции были разделяемыми данными, а не личными. Это различие имеет смысл только для некоторых операционных систем, где разделяемые данные разделяются между процессами, выполняющимися в одной программе, в то время как личные данные существуют в одной копии на процесс.
Размешает даже неинициализированные глобальные переменные в секции bss объектного файла, вместо генерации их в качестве общих блоков.Это имеет эффект в том, что если одна и та же переменныя объявлена (без extern) в двух различных единицах компиляции, вы получети ошибку при их линковке. Единственной причиной, по которой это может быть полезно, является проверка того, что программа будет работать на других системах, которые всегда работают таким образом.
Игнорирует директиву '#ident'.
Не выводит ассемблерную директиву '.size', или что-нибудь еще, что может вызвать проблемы, если функция расщепляется посередине, и две половинки размещаются в областях, далеко отстоящих друг от друга в памяти. Эта опция используется при компиляции 'crtstuff.c'; вам не должно понадобиться использовать ее для чего-нибудь еще.
Помещает дополнительную комментирующую информацию в ассемблерный код, чтобы сделать его более читаемым. Эта опция обычно нужна только тем, кому действительно нужно читать генерируемый ассемблерный код (может быть при отлаживании самого компилятора).
Считает все ссылки в память через указатели volatile.
Считает все ссылки в память на внешние и глобальные элементы данных volatile.
Порождает позиционно-независимый код (position-independent code - PIC), подходящий для использования в разделяемой библиотеке, если поддерживается для целевой машины. Такой код берет все константные адреса из глобальной таблицы смещений (global offset table - GOT). Если размер GOT для линкуемого выполняемого файла превышает специфичный для машины максимальный размер, вы получаете сообщение об ошибке от линкера, показывающее, что '-fpic' не работает; в этом случае перекомпилируйте с заменой на '-fPIC'. (Эти максимумы составляют: 16К на m88k, 8К на Sparc и 32К на m68k и RS/6000. 386 не имеет такого лимита.)
Позиционно-независимый код требует специальной поддержки, и, следовательно, работает толька на некоторых машинах. Для 386, GNU CC поддерживает PIC для System V, но не для Sun 386i. Код генерируемый для IBM RS/6000 всегда позиционно-независимый.
Ассемблер GNU не полностью поддерживает PIC. На данный момент, вы должны использовать какой-нибудь другой ассемблер, чтобы PIC работал. Мы бы приветствовали добровольцев, которые улучшили бы GAS, чтобы обрабатывать PIC; первой частью работы является изложить, что ассемблер должен делать иначе.
Если поддерживается для целевой машины, порождает позиционно независимый код, подходящий для динамической линковки и не имеющий никаких ограничений на размер глобальной таблицы смещений. Эта опция дает отличие на m68k, m88k и Sparc.
Позиционно-независимый код требует специальной поддержки, и, следовательно, работает толька на некоторых машинах.
Обращается с регистром с именем 'регистр' как с фиксированным регистром; порождаемый код никогда не должен ссылаться на него (кроме, может быть, в качестве указателя стека, указателя фрейма или в какой-нибудь другой фиксированной роли).
'регистр' должно быть именем регистра. Допускаемые имена регистров являются машинозависимыми и определяются макросом REGISTER_NAMES в заголовочном файле описания архитектуры.
Эта опция не имеет отрицательной формы, потому что она определяет выбор из трех альтернатив.
Обращается с регистром с именем 'регистр' как с регистром, подходящим для распределения, который затирается вызовами функций. Он может выделяться для временных переменных или для переменных, которые не переживают вызов функции. Функции, откомпилированные с этой опцией, не будут сохранять и восстанавливать регистр 'регистр'.
'регистр' должно быть именем регистра. Допускаемые имена регистров являются машинозависимыми и определяются макросом REGISTER_NAMES в заголовочном файле описания архитектуры.
Эта опция не имеет отрицательной формы, потому что она определяет выбор из трех альтернатив.
Обращается с регистром с именем 'регистр' как с регистром, подходящим для распределения, который сохраняется функциями. Он может выделяться даже для временных переменных или обычных переменных, которые переживают вызов функции. Функции, откомпилированные с этой опцией, будут сохранять и восстанавливать регистр 'регистр', если они его используют.
Использование этого флага для регистра, который имеет фиксированную роль в машинной модели исполнения такую, как указатель стека или указатель фрейма, порождает разрушительный результат.
Различные бедствия могут произойти от использования этого флага для регистров, в которых могут возвращаться значения функций.
Эта опция не имеет отрицательной формы, потому что она определяет выбор из трех альтернатив.
Упаковывает все члены структур рядом без зазоров. Обычно, не хотелось бы использовать эту опцию, поскольку она делает код не оптимальным, а смещения членов структур несоответствующим системным библиотекам.
Этот раздел описывает несколько переменных окружения, которые затрагивают то как работает GNU CC. Они работают указывая директории и префиксы для использования при поиске различных типов файлов.
Заметим, что вы также можете указать места для поиска, используя опции, такие как '-B', '-I' и '-L' (см. раздел [Опции Директорий]). Они имеют приоритет перед местами, указанными с помощью переменных ок- ружения, которые, в свою очередь, имеют приоритет перед местами, ука- занными конфигурацией GNU CC. См. раздел 17.1 [Управляющая Программа].
Если TMPDIR установлена, она указывает директорию, используемую для временных файлов. GNU CC использует временные файлы чтобы держать выход одной стадии компиляции, которая должна использоваться в качестве входа для следующей стадии: например, выход препроцессора, который является входом для собственно компилятора.
Если GCC_EXEC_PREFIX установлена, она указывает префикс, используемый в именах программ, выполняемых компилятором. Косая черта не добавляется, когда этот префикс объединяется с именем программы, но вы можете указать префикс, который оканчивается косой чертой.
Если GNU CC не может найти программу, используя указанный префикс, он пытается смотреть в обычные места для программ.
Значением по умолчанию для GCC_EXEC_PREFIX является 'префикс/lib/gcc-lib/', где 'префикс' - значение prefix, когда вы запускали 'configure'.
Другие префиксы, указанные с помощью '-B', имеют приоритет перед этим префиксом.
Этот префикс также используется для нахождения файлов, таких как 'crt0.o', который используется для линковки.
Кроме того этот префикс используется необычным способом для нахождения директорий для поиска заголовочных файлов. Для каждой из стандартных директорий, чье имя обычно начинается с '/usr/local/lib/gcc-lib' (более точно, с значения GCC_INCLUDE_DIR), GNU CC пытается заменить это начало на указанный префикс, чтобы породить имя альтернативной директории. Таким образом, с '-Bfoo/' GNU CC будет искать 'foo/bar', если обычно он искал бы 'usr/local/lib/bar'. Эта альтернативная директория просматривается первой, затем идут стандартные директории.
Значением COMPILER_PATH является список директорий, разделенных двоеточиями, во многом схожий с PATH. GNU CC просматривает директории, указанные таким образом, при поиске программ, если он не может найти программы используя GCC_EXEC_PREFIX.
Значением LIBRARY_PATH является список директорий, разделенных двоеточиями, во многом схожий с PATH. Когда GNU CC сконфигурирован как родной компилятор, он просматривает директории, указанные таким образом, при поиске специальных файлов линкера, если он не может найти их используя GCC_EXEC_PREFIX. Линковка при использовании GNU CC также использует эти директории при поиске обычных библиотек для опции '-l' (но директории, указанные с '-L', идут первыми).
Эти переменные окружения относятся к конкретным языкам. Значением каждой переменной является список директорий, разделенных двоеточиями, во многом схожий с PATH. Когда GNU CC ищет заголовочные файлы, он просматривает директории, перечисленные в переменной для языка, который вы используете, после директорий указанных с помощью '-I', но до стандартных директорий заголовочных файлов.
Если эта переменная установлена, ее значение указывает как выводить зависимости для Make, основанные на заголовочных файлах, обработанных компилятором. Этот вывод во многом похож на вывод опции '-M' (см. раздел [Опции Препроцессора]), но он идет в отдельный файл и является добавлением к обычным результатам компиляции.
Значение DEPENDENCIES_OUTPUT может содержать только имя файла, в этом случае Make-правила пишутся в этот файл, а целевое имя извлекается из имени исходного файла. Или же, значение может иметь форму 'файл цель', в этом случае правила пишутся в файл 'файл' с использованием 'цели' в качестве целевого имени.
Программа protoize является необязательной частью GNU C. Вы можете использовать ее, чтобы добавить прототипы к программе, конвертируя, таким образом, программу к ANSI C в одном отношении. Сопутствующая программа unprotioze делает обратное: она удаляет типы аргументов из всех прототипов, которые она находит.
Когда вы запускете эту программу, вы должны указать набор исходных файлов в качестве аргументов командной строки. Программа конверсии начинает работу с того, что компилирует эти файлы, чтобы узнать, какие функции в них определены. Информация, собранная о файле foo, сохраняется в файле с именем 'foo.X'.
После сканирования идет реальное преобразование. Указанные файлы все могут быть преобразованы; любые файлы, которые они включают (исходные или только заголовочные) также могут быть преобразованы.
Но не все подходящие файлы преобразуются. По умолчанию, protoize и unprotoize преобразуют только исходные файлы и файлы заголовка в текущем каталоге. Вы можете указать дополнительные каталоги, файлы в которых должны преобразовываться, с помощью опции `-dдиректория'. Вы можете также указать отдельные исключаемые файлы с помощью опции '-xфайл'. Файл преобразуется, если он подходит, имя его каталога соответствует одному из указанных имен каталогов, и его имя в каталоге не исключалось.
Основное преобразование protoize состоит в переписывании большинства описаний функций и обьявлений функций, чтобы указывать типы параметров. Не перезаписываются только объявления и описания функций с переменным числом аргументов.
protoize по выбору вставляет обьявления прототипов в начало исходного файла, делая их доступными для любых вызовов, которые предшествуют описанию функции. Или она может вставлять обьявления прототипов с блочной областью действия в блоках, где вызывается необъявленная функция.
Основное преобразование unprotoize состоит в переписывании большинства обьявлений функций так, чтобы удалить типы параметров, и в приведении описаний функций к форме старого pre-ANSI стиля.
Обе программы преобразования печатают предупреждение для любого обьявления или описания функции, которое они не могут преобразовать. Вы можете подавить эти предупреждения с помощью `-q'.
Вывод protoize или unprotoize заменяет первоначальный исходный файл. Первоначальный файл переименовывается к имени, оканчивающемуся на `.save'. Если `.save' файл уже существует, исходный файл просто отбрасывается.
И protoize, и unprotoize требуется сам GNU CC, чтобы просматривать программу и собирать информацию о функциях, которые она использует. Так что, ни одна из этих программ не будет работать до инсталяции GNU CC.
Ниже расположена таблица опций, которые вы можете использовать с protoize и unprotoize. Каждая опция работает с обеими программами, если не сказано иначе.
Ищет файл `SYSCALLS.c.X' в 'директории', вместо обычного каталога (обычно `/usr/local/lib'). Этот файл содержит информацию информацию о прототипах стандартных системных функций. Эта опция применима только к protoize.
Использует 'опции-компиляции' в качастве опций при запуске gcc для порождения `.X' файлов. Специальная опция `-aux-info' всегда передается в добавление, говоря gcc записать `.X' файл.
Обратите внимание, что опции компиляции нужно передавать как одиночный параметр protoize или unprotoize. Если вы хотите указать несколько опций gcc, вы должны заключить весь набор опций трансляции в кавычки, чтобы сделать их одним словом для shell'а.
Есть определенные параметры gcc, которые вы не можете использовать, потому что они производят неправильный вид вывода. Они включают `-g', `-O', `-c', `-S' и `-o'. Если вы включаете их в 'опции-компиляции', они игнорируются.
Переименовывает файлы так, чтобы они заканчивались на `.C' вместо `.c'. Это удобно, если вы преобразуете C программу в C++. Эта опция применима только к protoize.
Добавляет явные глобальные обьявления. Это значит вставлять явные обьявления в начало каждого исходного файла для каждой функции, которая вызывается в нем, и не была обьявлена. Эти обьявления предшествуют первому описанию функции, которое содержит вызов к необъявленной функции. Эта опция применима только к protoize.
Выравнивает обьявления параметров в старом стиле с помощью строки 'строка'. Эта опция применима только к unprotoize.
unprotoize преобразовывает описание-прототип функции в описание функции старого стиля, где параметры обьявлены между списоком параметров и начальным `{'. По умолчанию, unprotoize использует пять пробелов в качестве выравнивания. Если вы хотите вместо этого выравнивать только с одним пробелом, используйте `-i " "'.
Сохраняет `.X' файлы. Обычно, они удаляются после завершения преобразования.
Добавляет явные локальные обьявления. protoize с опцией `-l' вставляет обьявления-прототипы для каждой функции в каждом блоке, который вызывает функцию без обьявления. Эта опция применима только к protoize.
Не делает никаких реальных изменений. Этот режим только печатает информацию о преобразованиях, которые были бы выполнены без `-n'.
Не делает `.save' файлов. Первоначальные файлы просто удаляются. Используйте эту опцию с осторожностью.
Использует программу 'программа' как компилятор. Нормально, используется имя `gcc'.
Работает молча. Большинство предупреждений подавляется.
Печатает номер версии, точно так же как `-v' для gcc.
gcc -Dfoo=bar file1.c -aux-info
protoize * .c
Вы должны включать специальные файлы наряду с остальными в
команде protoize, даже если их `.X' файлы уже существуют, потому что
иначе они не будут преобразовываться.
См. раздел [Предостережения Protoize], для большей информации о том, как успешно использовать prtoize.
Ниже изложена процедура установки GNU CC в системе Unix. См. раздел [Установка на VMS], для VMS систем. В этом разделе мы считаем, что вы компилируете в том же каталоге, который содержит исходные фай- лы; см. раздел [Другие Директории], чтобы выяснить, как компилировать в отдельном каталоге в системе Unix.
Вы не можете установить GNU C с помощью его самого в MS-DOS. Он не будет компилироваться никаким компилятором MS-DOS кроме его самого. Вы должны получить полный пакет компиляции DJGPP, который включает двоичные файлы, также как и исходные, и включает все необходимые инструментальные средства для компиляции и библиотеки.
./configure --build=sparc-sun-sunos4.1
Имя конфигурации может быть каноническим или более или менее
сокращенным.
Каноническиое имя конфигурации имеет три части, разделяемые
черточкой.
Оно выглядит следующим образом: `процессор-компания-система'.
(Три части могут сами содержать черточки, `configure' может выяснить,
какие черточки служат каким целям.) Например, `m68k-sun-sunos4.1'
определяет Sun 3.
Вы можете также заменять части конфигурации на прозвища или
псевдонимы. Например, `sun3' заменяет `m68k-sun', так
`sun3-sunos4.1' - другой способ указать Sun 3. Вы можете также
использовать просто `sun3-sunos', так как версия SunOS считается по
умолчанию равной четырем. `sun3-bsd' также работает, так как
`configure' знает, что единственный вариант BSD на Sun 3 - SunOS.
Вы можете указать номер версии после любого из типов систем и
после некоторых из типов процессоров. В большинстве случаев, версия
неуместна и игнорируется. Так что вы могли к тому же указать версию,
если вы знаете ее.
См. раздел [Конфигурации], за списком поддерживаемых имен конфи-
гураций и примечаний относительно многих из них. Вы должны посмотреть
примечания в этом разделе перед выполнением любых дальнейших действий
по установке GNU CC.
Имеются четыре дополнительные опции, которые вы можете указать
независимо, чтобы определить варианты аппаратных и программных
конфигураций. Это - `--with-gnu-as', `--with-gnu-ld', `--with-stabs' и
`--nfp'.
Если вы будете использовать GNU CC с ассемблером GNU (GAS), вы должны указать это с помощью `--c-gnu-as' опцией когда вы запускаете `configure'.
Использование этой опции не устанавливает GAS. Она только изменяет вывод GNU CC, чтобы он работал с GAS. Построение и установка GAS - это ваша задача.
Наоборот, если вы не хотите использовать GAS и не определяете `--with-gnu-as' при построении GNU CC, это ваша задача - удостовериться, что GAS не установлен. GNU CC ищет программу с именем as в различных каталогах; если программа, которую он находит - GAS, тогда он запускает GAS. Если вы не уверены, где GNU CC находит ассемблер, который он использует, попробуйте указать `-v', когда вы его запускаете.
Системы где важно, используете ли вы GAS: `hppa1.0-любая-любая', `hppa1.1-любая-любая', `i386-любая-sysv', `i386-любая-isc', `i860-любая-bsd', `m68k-bull-sysv', `m68k-hp-hpux', `m68k-sony-bsd', `m68k-altos-sysv', `m68000-hp-hpux', `m68000-att-sysv', `ANY-lynx-lynxos' и `mips-любая'). В любой другой системе `--with-gnu-as' не имеет никакого эффекта.
В системах перечисленных выше (кроме HP-PA, ISC на 386 и `mips-sgi-irix5.*'), если вы используете GAS, вы должны, также, использовать GNU линкер (и указывать `--with-gnu-ld').
Укажите опцию `--with-gnu-ld', если вы планируете использовать GNU линкер с GNU CC.
Эта опция не заставляет устанавливать GNU линкер; она только изменяет поведение GNU CC, чтобы он работал с GNU линкером. В частности, она запрещает установку `collect2' - программы, которая в противном случае служит в качестве внешнего интерфейса для линкера системы в большинстве конфигураций.
В системах, основанных на MIPS, и в системах на Alpha вы должны определять, должен ли GNU CC создавать нормальный отладочный формат ECOFF или использовать stab'ы BSD-стиля, передаваемые через символьную таблицу ECOFF. Нормальный отладочный формат ECOFF не может полностью обрабатывать языки, отличные от C. Формат BSD stab'ов может обрабатывать другие языки, но он работает только с отладчиком GNU - GDB.
Обычно, GNU CC использует отладочный формат ECOFF по умолчанию; если вы предпочитаете BSD stab'ы, укажите `--with-stabs', когда вы конфигурируете GNU CC.
Вне зависимости от того, какое умолчание вы выбираете, когда конфигурируете GNU CC, пользователь может использовать опции `-gcoff' и `-gstabs+', чтобы явно указывать отладочный формат для конкретной компиляции.
`--with-stabs' имеет значение также в системе ISC на 386, если используется '--with-gas'. Она включает применение отладочной информация stab'ов, встроенной в вывод COFF'а. Этот вид отладочной информации хорошо поддерживает C++; обычная отладочная информация COFF'а не делает этого.
`--with-stabs' имеет значение также в системах на 386, исполняющих SVR4. Она включает применение отладочной информация stab'ов, встроенной в вывод ELF'а. C++ компилятор в настоящее время (2.6.0) не поддерживает отладочную информацию DWARF, обычно используемую на 386 SVR4 платформах; stab'ы обеспечивают работающий вариант. Он требует gas и gdb, поскольку обычные инструментальные средства SVR4 не могут генерировать или интерпретировать stab'ы.
В некоторых системах вы должны указывать, имеет ли машина модуль плавающей точки. Эти системы включают `m68k-sun-sunos n' и `m68k-isi-bsd'. В любой другой системе, `--nfp' в настоящее время не имеет никакого эффекта, хотя, возможно, имеются другие системы, где она могла бы быть полезна.
make stage1
Файлы перемещаются в подкаталог с именем `stage1'. После того,
как установка будет закончена, вы можете захотеть удалить эти файлы с
помощью команды `rm -r stage1'.
make CC="stage1/xgcc -Bstage1/" CFLAGS="-g -O2"
Это называется созданием стадии 2 компилятора.
make stage2
make CC="stage2/xgcc -Bstage2/" CFLAGS="-g -O2"
Это называется созданием стадии 3 компилятора. Кроме опции `-B',
опции компилятора должны быть такими же самыми, как когда вы строили
стадию 2 компилятора.
make compare
Она будет упоминать любые объектные файлы, которые отличаются в
стадиях 2 и 3. Любое различие, неважно насколько малое, указывает на
то, что стадия 2 компилятора, компилировалась GNU CC неправильно, и
следовательно существует потенциально серьезная ошибка, которую вы
должны исследовать.
make install CC="stage2/xgcc -Bstage2/" CFLAGS="-g -O" LANGUAGES="LIST"
Она копирует файлы `cc1', `cpp' и `libgcc.a' в файлы `cc1', `cpp'
и `libgcc.a' в каталоге `/usr/local/lib/gcc-lib/цель/версия' - тот, в
котором управляющая программа компилятора ищет их. Здесь 'цель' - тип
целевой машины, указанный, когда вы выполняли `configure', а 'версия'
- номер версии GNU CC.
Она также копирует управляющую программу `xgcc' в
`/usr/local/bin/gcc', так что она появляется в типичном маршруте
поиска выполнения.
Ниже перечислены возможный типы центральных процессоров:
1750a, a29k, alpha, arm, cN, clipper, dsp16xx, elxsi, h8300,
hppa1.0, hppa1.1, i370, i386, i486, i586, i860, i960, m68000, m68k,
m88k, mips, mipsel, mips64, mips64el, ns32k, powerpc, powerpcle,
pyramid, romp, rs6000, sh, sparc, sparclite, sparc64, vax, we32k.
Ниже перечислены распознаваемые имена компаний. Как вы можете
видеть, обычные сокращения используются чаще, чем более длинные
официальные имена.
acorn, alliant, altos, apollo, att, bull, cbm, convergent, convex,
crds, dec, dg, dolphin, elxsi, encore, harris, hitachi, hp, ibm,
intergraph, isi, mips, motorola, ncr, next, ns, omron, plexus,
sequent, sgi, sony, sun, tti, unicom, wrs.
Имя компании имеет значение только для разрешения неоднозначностей, когда остальной указанной информации недостаточно. Вы можете опускать его, записывая только `процессор-система', если оно не необходимо. Например, `vax-ultrix4.2' эквивалентно `vax-dec-ultrix4.2'.
Ниже расположен список типов систем:
386bsd, aix, acis, amigados, aos, aout, bosx, bsd, clix, coff,
ctix, cxux, dgux, dynix, ebmon, ecoff, elf, esix, freebsd, hms,
genix, gnu, gnu/linux, hiux, hpux, iris, irix, isc, luna, lynxos,
mach, minix, msdos, mvs, netbsd, newsos, nindy, ns, osf, osfrose,
ptx, riscix, riscos, rtu, sco, sim, solaris, sunos, sym, sysv,
udi, ultrix, unicos, uniplus, unos, vms, vsta, vxworks, winnt,
xenix.
Вы можете опустить тип системы, тогда `configure' догадывается об операционной системе из процессора и компании.
Вы можете добавлять номер версии к типу системы; это может или не может давать различие. Например, вы можете писать `bsd4.3' или `bsd4.4', чтобы отличать версии BSD. Практически, номер версии наиболее необходим для `sysv3' и `sysv4', которые часто обрабатываются по-разному.
Если вы определяете невозможную комбинацию типа `i860-dg-vms', вы можете получить сообщение об ошибке от `configure', или же он может игнорировать часть информации и сделать лучшее, что возможно с остальным. `configure' всегда печатает каноническиое имя для варианта, который он использовал. GNU CC не обеспечивает все возможные варианты.
Часто индивидуальная модель машины имеет имя. Многие машинные имена распознаются как псевдонимы для комбинаций процессор/компания. Имеется таблица известных машинных имен:
3300, 3b1, 3bN, 7300, altos3068, altos, apollo68, att-7300,
balance, convex-cN, crds, decstation-3100, decstation, delta,
encore, fx2800, gmicro, hp7NN, hp8NN, hp9k2NN, hp9k3NN, hp9k7NN,
hp9k8NN, iris4d, iris, isi68, m3230, magnum, merlin, miniframe,
mmax, news-3600, news800, news, next, pbd, pc532, pmax, powerpc,
powerpcle, ps2, risc-news, rtpc, sun2, sun386i, sun386, sun3,
sun4, symmetry, tower-32, tower.
Не забудьте, что машинное имя определяет и тип центрального
процессора, и имя компании. Если вы хотите устанавливать ваши
собственные файлы конфигурации собственного производства, вы можете
использовать `local' как имя компании, чтобы обращаться к ним. Если вы
используете конфигурацию `процессор-local', то имя конфигурации без
префикса процессора используется, чтобы сстроить имя файла
конфигурации.
Таким образом, если вы указываете `m68k-local', конфигурация использует файлы `m68k.md', `local.h', `m68k.c', `xm-local.h', `t-local' и `x-local', все в каталоге `config/m68k'.
Если вы хотите построить объектные и выполнимые файлы в каталоге отличном, от содержащего исходные файлы, ниже указано, что вы должны делать по-другому:
make distclean
mkdir gcc-sun3
cd gcc-sun3
В системах, которые не поддерживают символические ссылки, этот
каталог должен быть в той же файловой системе, что и каталог исходных
текстов.
../gcc/configure ...
Это также сообщает `configure', где находить исходники
компилятора; `configure' берет каталог из имени файла, которое
использовалось, чтобы вызывать его. Но если вы хотите быть уверенными,
вы можете указать исходный каталог с помощью опции `--srcdir' :
../gcc/configure - srcdir= ../gcc другое опции
Каталог, который вы указываете с `--srcdir' не обязан быть тем же
каталогом, в котором находится `configure'.
Теперь, вы можете запускать `make' в этом каталоге. Вы не должны
повторять шаги конфигурации показанные выше, при обычном изменении
исходных файлов. Вы должны, однако, выполнить `configure' снова, при
изменении файлов конфигурации, если ваша система не поддерживает
символические ссылки.
GNU CC может функционировать как кросскомпилятор для многих машин, но не для всех.
Поскольку GNU CC генерирует ассемблерный код, вы, вероятно, нуждаетесь в кроссассемблере, чтобы GNU CC мог выполняться, порождая объектные файлы. Если вы хотите линковать не на целевой машине, вы к тому же нуждаетесь в кросслинкере. Вы также нуждаетесь в заголовочных файлах и библиотеках, подходящих для целевой машины, которые вы можете установить на хост-машине.
Компиляция и выполнение программ с использованием кросскомпилятора включает несколько шагов:
Чтобы построить GNU CC как кросскомпилятор, вы начинаете с выполнения `configure'. Используйте `--target=цель', чтобы указать тип целевой машины. Если `configure' оказался неспособен правильно идентифицировать систему, на которой вы его выполняете, также укажите '--build=строющая'. Например, ниже показано, как конфигурировать кросскомпилятор, который производит код для системы HP 68030 с системой BSD, которую `configure' может правильно идентифицировать:
./configure --target=m68k-hp-bsd4.3
Если у вас есть кроссассемблер и кросслинкер, вы должны их теперь установить. Поместите их в каталог `/usr/local/цель/bin'. Имеется таблица инструментальных средств, которые вы должны включить в этот каталог:
Это должен быть кроссассемблер.
Это должен быть кросслинкер.
Это должен быть кроссархиватор: программа, которая может управлять архивными файлами (библиотеками линкера) в формате целевой машины.
Это должна быть программа для создания таблицы идентификаторов в архивном файле.
Самый простой способ обеспечивать эти файлы состoит в том, чтобы построить пакет Binutils и GAS. Cконфигурируйте их с теми же самыми `--host' и '--target', которые вы используете для конфигурирования GNU CC, затем постройте и установите их. Они устанавливают свои выполнимые файлы автоматически в соответствующий каталог. Но они не поддерживают все целевые машины, которые поддерживает GNU CC.
Если вы хотите установить библиотеки, чтобы использовать с кросскомпилятором, такие, как стандарная библиотека C, поместите их в каталог `/usr/local/цель/lib'; установка GNU CC копирует все файлы в этом подкаталоге в соответствующее место, чтобы GNU CC мог находить их и линковать с ними. Ниже показан пример копирования некоторого количества библиотек с целевой машины:
ftp целевая-машина
lcd /usr/local/цель/lib
cd /lib
get libc.a
cd /usr/lib
get libg.a
get libm.a
quit
Точный набор библиотек, в которых вы нуждаетесь, и их
местоположения на целевой машине, очень зависят от операционной
системы.
Многие целевые машины требуют "файлы начала" типа `crt0.o' и `crtn.o', которые линкуются к каждому выполнимому файлу; они также должны помещаться в `/usr/local/цель/lib'. Могут иметься несколько вариантов для `crt0.o', для применения с профиляцией или другими опциями компиляции. Ниже показан пример копирования этих файлов с целевой машины:
ftp целевая-машина
lcd /usr/local/цель/lib
prompt
cd /lib
mget *crt*.o
cd /usr/lib
mget *crt*.o
quit
Сейчас вы можете продолжить также, как и при построении компилятора для одной машины построением stage 1. Если вы обеспечили какой-либо вариант 'libgcc1.a'. тогда компиляция будет прервана в точке, где нужен этот файл,
означает одно и то же для родного и кросс- компиляторов. Это место, где GNU CC сохраняет свои личные заголовочные файлы, а также где GNU CC сохраняет фиксированные заголовочные файлы. Кросскомпилирующий GNU CC запускает fixincludes над заголовочными файлами в '$(tooldir)/include'. (Если заголовочные файлы кросскомпиляции должны быть зафиксированы, они должны быть установлены до построения GNU CC. Если заголовочные файлы кросскомпиляции уже доступны для ANSI C и GNU CC, ничего специально делать не нужно.)
означает одно и то же для родного и кросс- компиляторов. Это место, где g++ смотрит в первую очередь, в поисках заголовочных файлов. libg++ устанавливает только машинонезависимые заголовочные файлы в этой директории.
используется только для родного компилятора. Обычно это '/usr/local/include'. GNU CC просматривает эту директорию, так что пользователи могут устанавливать заголовочные файлы в '/usr/local/include'.
используется только для кросскомпилятора. GNU CC ничего здесь не устанавливает.
используется как для родного, так и для кросскомпиляторов. Это место для инсталляции заголовочных файлов для других пакетов, которое GNU CC будет использовать. Для кросскомпилятора это '/usr/include'. Когда вы строите кросскомпилятор fixincludes обрабатывает все заголовочные файлы в этом каталоге.
GNU C обеспечивает некоторые языковые свойства, отсутствующие в стандарте ANSI C. (Опция `-pedantic` указывает GNU CC печатать предупреждающее сообщение, если какое-нибудь из этих свойств используется.) Чтобы проверить доступность этих свойств в условной компиляции, проверьте предопределенный макрос __GNUC__, который всегда определен под GNU CC.
Эти расширения доступны в C и в Objective C. Большая часть из них также доступна в C++.
Составной оператор, заключенный в скобки, может появляться в качестве выражения в GNU C. Это позволяет вам использовать циклы, операторы выбора и локальные переменные внутри выражения.
Напомним, что составной оператор - это последовательность операторов, заключенная в фигурные скобки; в этой конструкции скобки окружают фигурные скобки. Например:
({ int y = foo (); int z;
if (y > 0) z = y;
else z = - y;
z; })
является правильным (хотя и несколько более сложным чем необходимо)
выражением для абсолютной величины foo().
Последней вещью в составном операторе должно быть выражение, после которого следует точка с запятой; значение этого подвыражения служит значением всей конструкции. (Если вы используете какой-нибудь другой вид оператора последним внутри фигурных скобок, конструкция имеет тип void, и таким образом не имеет значения.)
Это свойство особенно полезно, чтобы делать макроопределения "надежными" (такими, что они вычисляют каждый операнд ровно один раз.) Например, функция "максимум" обычно определяется как макро в стандартном C так:
#define max(a,b) ((a) > (b) ? (a) : (b))
Но это определение вычисляет либо a, либо b дважды, с неправильными
результатами, если операнд имеет побочные эффекты. В GNU C, если вы
знаете тип операндов (здесь положим его int), вы можете безопасно
определить макро таким образом:
#define maxint(a,b) \
({int _a = (a), _b = (b); _a > _b ? _a : _b; })
Встроенные операторы недопустимы в константых выражениях, таких
как значения перечислимых констант, ширина битового поля или начальное
значение статической переменной.
Если вы не знаете тип операнда, вы все-таки можете сделать это, но вы должны использовать typeof (см. Раздел [Typeof]) или именование типов (см. Раздел [Именование Типов]).
Каждое выражение-оператор является областью, в которой могут быть объявлены локальные метки. Локальная метка - это просто идентификатор; вы можете делать переход на нее с помощью обычного оператора goto, но только изнутри выражения-оператора, к которому она принадлежит.
Объявление локальной метки выглядит так:
__label__ метка;
или
__label__ метка1, метка2, ...;
Объвления локальных меток должны идти в начале
выражения-оператора сразу после `({` до любого обычного объявления.
Объвление метки определяет имя метки, но не определяет саму метку. Вы должны сделать это обычным способом с помощью `метка:`, внутри выражения-оператора.
Локальные метки полезны, так как выражения-операторы часто используются в макросах. Если макрос содержит вложенные циклы, goto может быть полезен для выхода из них. Однако обычная метка, чьей областью действия является вся функция, не может быть использована: если макрос может быть использован несколько раз в одной функции, метка будет определена в этой функции многократно. Локальная метка избегает этой проблемы. Например:
#define SEARCH(array, target) \
({ \
__label__ found; \
typeof (target) _SEARCH_target = (target); \
typeof (*(array)) *_SEARCH_array = (array); \
int i, j; \
int value; \
for (i = 0; i < max; i++) \
for (j = 0; j < max; j++) \
if (_SEARCH_array[i][j] == _SEARCH_target) \
{ value = i; goto found; } \
value = -1; \
found: \
value; \
})
Вы можете взять адрес метки, определенный в текущей функции (или объемлющей функции) с помощью унарной операции `&&`. Значение имеет тип void *. Это значение является константой и может быть использовано везде, где допускается константа этого типа. Например:
void *ptr;
...
ptr = &&foo;
Чтобы использовать эти значения, вам нужно делать на них переход.
Это делается с помощью вычисляемого оператора goto, `goto *выражение;
`. Например:
goto *ptr;
Допустимо любое выражение типа void *.
Один из способов использования этих констант заключается в инициализации статического массива, который будет служить таблицей переходов:
static void *array[] = { &&foo, &&bar, &&hack };
Затем вы можете выбрать метку с помощью индексации таким образом:
goto *array[i];
Заметим, что здесь не проверяется, находится ли индекс в допустимых
границах - индексация массивов в C никогда не делает этого.
Такой массив значений меток служит цели во многом подобной цели оператора switch. Оператор switch является более понятным, так что используйте его вместо массива, если только задача не является неподходящей для оператора switch.
Другим использованием значений меток является интерпретатор шитого кода. Метки внутри функции интерпретатора могут быть записаны в шитый код для супербыстрой обработки.
Вы можете использовать этот механизм для перехода на код в различных функциях. Если вы так делаете, могут произойти совершенно непредсказуемые вещи. Лучший способ избежать этого - сохранять адреса меток только в автоматических переменных и никогда не передавать их в качестве параметров.
Вложенная функция - это функция, определенная внутри другой функции. Имя вложенной функции является локальным в блоке, где она определена. Например, здесь мы определяем вложенную функцию с именем square и вызываем ее дважды:
foo (double a, double b)
{
double square (double z) { return z * z; }
return square (a) + square (b);
}
Вложенная функция имеет доступ ко всем переменным объемлющей
функции, которые видны в точке ее определения. Это называется
"лексическая область действия". Например, ниже мы показываем вложенную
функцию, которая использует наследуемую переменную с именем offset:
bar (int *array, int offset, int size)
{
int access (int *array, int index)
{ return array[index + offset]; }
int i;
...
for (i = 0; i < size; i++)
... access (array, i) ...
}
Определения вложенных функций разрешаются внутри функций, где
допустимы определения переменных; то есть в любом блоке перед первым
оператором в блоке.
Можно вызвать вложенную функцию из точки вне области действия ее имени, сохранив ее адрес или передав адрес в другую функцию:
hack (int *array, int size)
{
void store (int index, int value)
{ array[index] = value; }
intermediate (store, size);
}
Здесь функция intermediate получает адрес функции store в
качестве параметра. Если intermediate вызывает store, аргумент,
передаваемый в store, используется для записи в array. Но эта техника
работает только до тех пор, пока объемлющая функция (в этом примере
hack) не возвратит управление.
Если вы пытаетесь вызвать вложенную функцию с помощью ее адреса после того, как объемлющая функция возвратила управление, все полетит к чертям. Если вы пытаетесь вызвать ее после того, как объемлющая область действия закончила работу, и если она ссылается на одну из переменных, которые больше не лежат в области действия, может вам и повезет, но неразумно рисковать. Однако, если вложенная функция не ссылается ни на что, вышедшее из области действия, вы в безопасности.
GNU CC выполняет взятие адреса вложенной функции, используя технику, называемую "trampolines". Бумага, описывающая ее, доступна из 'maya.idiap.ch' в директории 'pub/tmb' в файле 'usenix88-lexic.ps.Z'.
Вложенная функция может делать переход на метку, наследуемую от объемлющей функции, если метка явно объявлена в объемлющей функции (см. Раздел [Локальные Метки]). Такой переход немедленно возвращает в объемлющую функцию, покидая вложенную функцию, которая сделала goto, а также любые промежуточные функции. Пример:
bar (int *array, int offset, int size)
{
__label__ failure;
int access (int *array, int index)
{
if (index > size)
goto failure;
return array[index + offset];
}
int i;
...
for (i = 0; i < size; i++)
... access (array, i) ...
...
return 0;
/* Управление попадает сюда из access,
если обнаруживается ошибка. */
failure:
return -1;
}
Вложенная функция всегда имеет внутреннее связывание. Объявление
ее с extern является ошибочным. Если вам нужно объявить вложенную
функцию до ее определения, используйте auto (который в противном
случае бесполезен для объявлений функций).
bar (int *array, int offset, int size)
{
__label__ failure;
auto int access (int *, int);
...
int access (int *array, int index)
{
if (index > size)
goto failure;
return array[index + offset];
}
...
}
Используя встроенные функции, описанные ниже, вы можете записать полученные аргументы функции и вызвать другую функцию с теми же аргументами, не зная количество и типы аргументов.
Вы можете также записать возвращаемое значение этого вызова функции и позже вернуть это значение, не зная, какой тип данных функция пыталась вернуть (если вызывавшая функция ожидает этот тип данных).
Эта встроенная функция возвращает указатель типа void * на данные, описывающие, как выполнять вызов с теми же аргументами, которые были переданы текущей функции.
Функция сохраняет регистр указателя аргументов, адреса структурного значения и все регистры, которые могут быть использованы для передачи аргументов в функцию в блок памяти, выделяемый на стеке. Затем она возвращает адрес этого блока.
Эта встроенная функция вызывает 'функцию' (типа void (*)()) с копированием параметров, описываемых 'аргументами' (типа void *) и 'размером' (типа int).
Значение 'аргументы' должно быть значением, которое возвращено __builtin_apply_args (). Аргумент 'размер' указывает размер стековых данных параметров в байтах.
Эта функция возвращает указатель типа void * на данные, описывающие, как возвращать какое-либо значение, которое вернула 'функция'. Данные сохраняются в блоке памяти, выделенном на стеке.
Не всегда просто вычислить подходящее значение для 'размера'. Это значение используется __builtin_apply () для вычисления количества данных, которые должны быть положены на стек и скопированы из области входных аргументов.
Эта встроенная функция возвращает значение, описанное 'результатом' из объемлющей функции. Вы должны указать в качестве 'результата' значение, возвращенное __builtin_apply ().
Вы можете дать имя типу выражения, используя объявление typedef с инициализатором. Ниже показано, как определить имя как имя типа выражения:
typedef имя = выражение;
Это полезно в соединении с возможностью выражений-операторов.
Ниже показано, как эти две возможности могут бвть использованы, чтобы
определить безопасный макрос "максимум", который оперирует с любым
арифметическим типом:
#define max(a,b) \
({typedef _ta = (a), _tb = (b); \
_ta _a = (a); _tb _b = (b); \
_a > _b ? _a : _b; })
Смысл использования имен, которые начинаются с подчеркиваний для
локальных переменных в том, чтобы избегать конфликтов с именами
переменных, которые встречаются в выражениях, которые подставляются
вместо a и b. В конечном итоге, мы надеемся разработать новую форму
синтаксиса объявлений, которая позволит объявлять переменные, чьи
области действия начинаются только после их инициализаторов; это будет
более надежным способом предотвращения подобных конфликтов.
Другой способ сослаться на тип выражения - с помощью typeof. Синтаксис использования этого ключевого слова - такой же как и у sizeof, но семантически конструкция действует подобно имени типа, определенного с помощью typedef.
Есть два способа записи аргумента typeof: с выражением и с типом. Ниже показан пример с выражением:
typeof (x[0](1))
Здесь предполагается, что x является массивом функций; описанный тип
является типом значений этих функций.
Ниже показан пример с именем типа в качестве аргумента:
typeof (int *)
Здесь описанный тип является типом указателей на int.
Если вы пишете заголовочный файл, который должен работать при включении в ANSI C программы, пишите __typeof__ вместо typeof. См. Раздел [Альтернативные Ключевые Слова].
Конструкция typeof может использоваться везде, где допустимо typedef-имя. Например, вы можете использовать ее в объявлении, в приведении или внутри sizeof или typeof.
Составные выражения, условные выражения и приведения позволяются в качестве L-значений, при условии, что их операнды являются L-значениями. Это означает, что вы можете брать их адреса или сохранять в них значения.
Например, составному выражению может быть присвоено что-либо, при условии, что последнее выражение в последовательности является L-значением. Эти два выражения являются эквивалентными:
(a, b) += 5
a, (b += 5)
Таким же образом, может быть взят адрес составного выражения. Эти
два выражения являются эквивалентными:
&(a, b)
a, &b
Условное выражение является допустимым L-значением, если его
типом не является void, и при этом обе его ветви являются допустимыми
L-значениями. К примеру, эти два выражения являются эквивалентными:
(a ? b : c) = 5
(a ? b = 5 : (c = 5))
Приведение является допустимым L-значением, если его операнд
является L-значением. Простое присваивание, чьей левой частью является
приведение, работает, сначала преобразуя правую часть в указанный тип,
а затем к типу внутренней части выражения левой части. После того, как
это значение записывается, значение преобразуется обратно к указанному
типу, чтобы получить значение присваивания. Таким образом, если a
имеет тип char *, следующие два выражения являются эквивалентными:
(int)a = 5
(int)(a = (char *)(int)5)
Присваивание с арифметической операцией, такое как '+=',
примененное к приведению, выполняет арифметическую операцию, используя
тип, получающийся из приведения, и затем продолжает как и в
предыдущем случае. Следовательно, эти два выражения являются
эквивалентными:
(int)a += 5
(int)(a = (char *)(int) ((int)a + 5))
Вы не можете взять адрес L-значения приведения, потому что
использование его адреса не могло бы выполняться согласованно.
Средний операнд в условном выражении может быть опущен. Тогда, если первый операнд не равен нулю, его значение является значением условного выражения.
Следовательно, выражение
x ? : y
имеет значение x, если оно не равно нулю, в противном случае - значение y.
Этот пример полностью эквивалентен
x ? x : y
В этом простом случае, возможность опускать средний операнд не
особенно полезна. Она становится полезной, когда первый операнд
содержит, или может содержать (если это макроаргумент) побочные
эффекты. В этом случае повторение операнда в середине может выполнить
побочный эффект дважды. Опускание среднего операнда использует
уже вычисленное значение без нежелательных эффектов его перевычисления.
GNU C поддерживает типы данных для целых, которые вдвое длиннее long int. Просто пишите long long int для знакового целого, или unsigned long long int для беззнакового целого. Чтобы сделать целую константу типа long long int, добавьте суффикс LL к целому. Чтобы сделать целую константу типа unsigned long long int, добавьте суффикс ULL к целому.
GNU C поддерживает комплексные типы данных. Вы можете объявить как комплексные целые типы, так и комплексные плавающие типы, используя ключевое слово __complex__ .
Например, '__complex__ double x;' объявляет x как переменную, чьи вещественная и мнимая части имеют тип double; '__complex__ short int y;' объявляет y, имеющей вещественную и мнимую части типа short int.
Чтобы записать константу комплексного типа данных, используйте суффикс i или j (любой из них - они эквивалентны). Например, 2.5fi имеет тип __complex__ float, а 3i имеет тип __complex__ int. Такие константы всегда имеют чисто мнимое значение, но вы можете сформировать любое комплексное значение с помощью добавления вещественной константы.
Чтобы извлечь вещественную часть комплеснозначного выражения, пишите '__real__ выражение'. Аналогично, используйте __imag__ для извлечения мнимой части.
Операция '~' выполняет комплексное сопряжение, когда используется над значением комплексного типа.
Массивы нулевой длины разрешаются в GNU C. Они являются очень полезными в качестве последнего элемента структуры, который в действительности является заголовком объекта переменной длины:
struct line {
int length;
char contents[0];
};
{
struct line *thisline = (struct line *)
malloc (sizeof (struct line) + this_length);
thisline->length = this_length;
}
В стандартном C вы должны бы были дать contents длину 1, который
означает, что вы либо должны терять память, либо усложнять аргумент
malloc.
Автоматические массивы переменной длины допустимы в GNU C. Эти массивы объявляются подобно любым другим автоматическим массивам, но с длиной, которая не является константным выражением. Память выделяется в точке объявления и освобождается при выходе из блока. Например:
FILE *
concat_fopen (char *s1, char *s2, char *mode)
{
char str[strlen (s1) + strlen (s2) + 1];
strcpy (str, s1);
strcat (str, s2);
return fopen (str, mode);
}
Переход вне области действия массива освобождает память. Переход
в область действия недопустим.
Вы можете использовать функцию alloca, чтобы получить эффект во многом подобный массивам переменной длины. Функция alloca допустима во многих других реализациях C (но не во всех). С другой стороны, массивы переменной длины являются более элегантными.
Есть другие отличия между этими двумя методами. Место, выделяемое с помощью alloca, существует пока объемлющая функция не сделает возврат. Место для массива переменной длины освобождается, как только заканчивается область действия имени массива. (Если вы используете как массивы переменной длины, так и alloca в одной и той же функции, освобождение массива переменной длины так же освободит все выделенное после с помощью alloca.)
Вы можете также использовать массивы переменной длины в качестве аргумента функции:
struct entry
tester (int len, char data[len][len])
{
...
}
Длина массива вычисляется один раз при выделении памяти и
вспоминается в области действия массива, если вы берете ее с помощью
sizeof.
Если вы хотите передать массив первым, а длину после, вы можете использовать предварительное объявление в списке параметров - другое расширение GNU.
struct entry
tester (int len; char data[len][len], int len)
{
...
}
'int len' перед точкой с запятой является предварительным
объявлением параметра и служит тому, чтобы сделать имя len известным
при разборе объявления data.
Вы можете писать любое число таких предварительных объявлений параметров в списке параметров. Они могут разделяться запятыми или точками с запятыми, но последнее из них должно кончаться точкой с запятой, за которой следуют "реальные" объявления параметров. Каждое предварительное объявление должно соответствовать "реальному" объявлению в имени параметра и типе данных.
В GNU C макрос может получать переменное число аргументов, во многом подобно тому, как и функция. Синтаксис определения макроса выглядит очень похожим на используемый для функций. Пример:
#define eprintf(format, args...) \
fprintf (stderr, format , ## args)
Здесь args - это остаточный аргумент: он принимает ноль или
больше аргументов - столько, сколько содержит вызов. Все они вместе с
запятыми между ними образуют значение args, которое подставляется в
тело макроса там, где используется args. Таким образом, мы имеем
следующее расширение:
eprintf ("%s:%d: ", input_file_name, line_number)
==>
fprintf (stderr, "%s:%d: " , input_file_name, line_number)
Заметим, что запятая после строковой константы идет из определения
eprintf, в то время как последняя запятая идет из значения args.
Смысл использования '##' в обработке случая, когда args не соответствует ни одного аргумента. В этом случае args имеет пустое значение. Тогда вторая запятая в определении становится помехой: если она прошла бы через расширение макроса, мы бы получили что-нибудь подобное:
fprintf (stderr, "success!\n" , )
что является неправильным синтаксисом C. '##' освобождает от запятой,
так что мы получаем следующее:
fprintf (stderr, "success!\n")
Это специальное свойство препроцессора GNU C: '##' перед
остаточным аргументом, который пуст, отбрасывает предшествующую
последовательность непробельных символов из макроопределения.
Позволяется индексация массивов, которые не являются L-значениями, хотя даже унарная операция '&' не позволяется. Например, это является допустимым в GNU C, хотя и неверным в других диалектах C:
struct foo {int a[4];};
struct foo f();
bar (int index)
{
return f().a[index];
}
В GNU C поддерживаются операции сложения и вычитания с указателями на void и на функции. Это делается, принимая размер void или функции равным 1.
Следствием этого является то, что операция sizeof также позволяется над void и над типами функций и возвращает 1.
Опция '-Wpointer-arith' требует предупреждения, если это расширение используется.
Как в стандартном C++ элементы агрегатного инициализатора автоматической переменной не обязаны быть константными выражениями в GNU C. Ниже показан пример инициализатора с элементами, меняющимися во время выполнения:
foo (float f, float g)
{
float beat_freqs[2] = { f-g, f+g };
...
}
GNU C поддерживает выражения конструкторов. Конструктор выглядит как приведение, содержащее инициализатор. Его значение является объектом типа, указанного в приведении, содержащее элементы, указанные в инициализаторе.
Обычно указанный тип является структурой. Предположим, что struct foo и structure объявлены, как показано:
struct foo {int a; char b[2];} structure;
Ниже показан пример конструирования struct foo с помощью конструктора:
structure = ((struct foo) {x + y, 'a', 0});
Это эквивалентно написанному ниже:
{
struct foo temp = {x + y, 'a', 0};
structure = temp;
}
Вы можете также сконструировать массив. Если все элементы
конструктора являются (или получаются из) простыми константными
выражениями, подходящими для использования в инициализаторах, тогда
конструктор является L-значением и может быть приведен к указателю на
свой первый элемент, как показано ниже:
char **foo = (char *[]) { "x", "y", "z" };
Конструкторы массива, чьи элементы не являются простыми
константами, не очень полезны, потому что они не являются L-значениями.
Стандартный C требует, чтобы элементы инициализатора появлялись в фиксированном порядке, в том же самом, в котором элементы массива или структуры инициализируются.
В GNU C вы можете дать элементы в любом порядке, указывая индексы массива или имена полей структуры, к которым они применяются.
Чтобы указать индекс массива, напишите '[индекс]' или '[индекс] =' перед значением элемента. Например,
int a[6] = { [4] 29, [2] = 15 };
эквивалентно
int a[6] = { 0, 0, 15, 0, 29, 0 };
Значение индекса должно быть константным выражением, даже если
инициализируемый массив является автоматическим.
Чтобы инициализировать диапазон элементов одним и тем же значением, напишите '[первый ... последний] = значение'. Например:
int widths[] = { [0 ... 9] = 1, [10 ... 99] = 2, [100] = 3 };
Заметим, что длина массива равна максимальному указанному значению
плюс 1.
В инициализаторе структуры укажите имя инициализируемого поля с помощью 'имяструктуры:' перед значением элемента. Пусть, например, дана следующая структура:
struct point { int x, y; };
следующая инициализация
struct point p = { y: yvalue, x: xvalue };
эквивалентна
struct point p = { xvalue, yvalue };
Другой синтаксис, который имеет то же значение: '.имяструктуры
=', как показано ниже:
struct point p = { .y = yvalue, .x = xvalue };
Вы также можете использовать метку элемента при инициализации
объединения, чтобы указать, какой элемент объединения должен
использоваться. Например,
union foo { int i; double d; };
union foo f = { d: 4 };
преобразует 4 в double, чтобы записать его в объединение, использую
второй элемент. Напротив, приведение 4 к типу union foo сохранит его в
объединении как целое i, поскольку оно целое. (См. Раздел [Приведение
к Объединению].)
Вы можете скомбинировать эту технику именования элементов с обычной C инициализацией последовательных элементов. Каждый элемент инициализатора, который не имеет метки, приеняется к следующему элементу массива или структуры. Например,
int a[6] = { [1] = v1, v2, [4] = v4 };
эквивалентно
int a[6] = { 0, v1, v2, 0, v4, 0 };
Вы можете указать диапазон последовательных значений в одной метке case так:
case LOW ... HIGH:
Будьте внимательны: Пишите пробелы вокруг '...', в противном
случае оно может быть разобрано неправильно.
Приведение к типу объединения подобно другим приведениям, за тем исключением, что указываемый тип является типом объединения. Вы можете указать тип либо с помощью union тег, либо с помощью typedef имени. Приведение к объединению является в действительности конструктором, а не приведением, и, следовательно, не дает L-значения, как нормальное приведение. (См. Раздел [Конструкторы].)
Типы, которые могут быть приведены к типу объединения, являются типами членов объединения. Таким образом, если даны следующие объединение и переменные:
union foo { int i; double d; };
int x;
double y;
тогда и x, и y могут быть приведены к union foo.
Использование приведения в правой части присваивания переменной типа объединения эквивалентно записи в член объединения:
union foo u;
...
u = (union foo) x == u.i = x
u = (union foo) y == u.d = y
Вы можете также использовать приведение к объединению в качестве
аргумента функции:
void hack (union foo);
...
hack ((union foo) x);
В GNU C вы можете объявить определенные вещи о функциях, вызываемых в вашей программе, которые помогают компилятору оптимизировать вызовы функций и более внимательно проверять ваш код.
Ключевое слово __attribute__ позволяет вам указывать специальные атрибуты при создании объявлений. За этим ключеным словом следует описание атрибута в двойных скобках. В данный момент для функций определены восемь атрибутов: noreturn, const, format, section, constructor, destructor, unused и weak. Другие атрибуты, включая section, поддерживаются для объявлений переменных (см. Раздел [Атрибуты Переменных]) и для типов (см. Раздел [Атрибуты Типов]).
Вы можете указывать атрибуты с '__', окружающими каждое ключевое слово. Это позволяет вам использовать их в заголовочных файлах, не заботясь о том, что могут быть макросы с тем же именем. Например, вы можете использовать __noreturn__ вместо noreturn.
Несколько стандартных библиотечных функций, таких как abort и exit не могут вернуть управление. GNU CC знает это автоматически. Некоторые программы определяют свои собственные функции, которые никогда не возвращают управление. Вы можете объявить их noreturn, чтобы сообщить компилятору этот факт. Например:
void fatal () __attribute__ ((noreturn));
void
fatal (...)
{
... /* Печатает сообщение об ошибке. */ ...
exit (1);
}
Ключевое слово noreturn указывает компилятору принять, что
функция fatal не может возвратить управление. Тогда он может делать
оптимизацию, несмотря на то, что бы случилось, если бы fatal вернула
управление. Это делает код немного лучше. Более важно, что это
помогает избегать ненужных предупреждений об инициализированных
переменных.
Атрибут noreturn не реализован в GNU C версии ранее чем 2.5.
Многие функции не используют никаких значений, кроме своих аргументов, и не имеют эффекта, кроме возвращаемого значения. Такая функция может быть объектом исключения общих подвыражений и оптимизации циклов аналогично арифметической операции. Такую функцию следует объявить с атрибутом const. Например,
int square (int) __attribute__ ((const));
говорит, что гипотетическую функцию square безопасно вызывать меньшее
количество раз, чем сказано в программе.
Атрибут const не реализован в GNU C версии ранее 2.5.
Заметим, что функция, которая имеет параметром указатель и использует данные, на которые он указывает, не должна объявляться const. Аналогично, функция, которая вызывает не-const функцию, обычно не должна быть const.
Атрибут format указывает, что функция принимает аргументы в стиле printf или scanf, которые должны быть проверены на соответствие со строкой формата. Например, объявление
extern int
my_printf (void *my_object, const char *my_format, ...)
__attribute__ ((format (printf, 2, 3)));
заставляет компилятор проверять параметры в вызове my_printf на
соответствие printf-стилю строки формата my_format.
Параметр 'тип' определяет, как строка формата интерпретируется, и должен быть либо printf, либо scanf. Параметр 'строка-индекс' указывает, какой параметр является строкой формата (начиная с 1), а 'первый-проверяемый' является номером первого проверяемого аргумента. Для функций, у которых аргументы не могут быть проверены (таких как vprintf), укажите в качестве третьего параметра ноль. В этом случае компилятор только проверяет строку формата на корректность.
Компилятор всегда проверяет формат для функций ANSI библиотеки printf, fprintf, sprintf, scanf, vprintf, vfprintf, vsprintf, когда такие предупреждения запрашиваются (используя '-Wformat'), так что нет нужды модифицировать заголовочный файл 'stdio.h'.
Обычно, компилятор помещает генерируемый код в секцию text. Однако, иногда, вам нужны дополнительные секции или же вам нужно, чтобы определенные функции оказались в специальных секциях. Атрибут section указывает, что функция живет в определенной секции. Например, объявление
extern void foobar (void) __attribute__ ((section ("bar")));
помещает функцию foobar в секцию bar.
Атрибут constructor заставляет функцию вызываться автоматически перед выполнением main (). Аналогично, атрибут destructor заставляет функцию вызываться автоматически после того, как main () завершилась или вызвана exit (). Функции с этими атрибутами полезны для инициализации данных.
Этот атрибут, примененный к функции, означает, что функция, возможно, может быть неиспользуемой. GNU CC не будет порождать предупреждение для этой функции.
Атрибут weak приводит к тому, что объявление будет порождаться как слабый символ, а не глобальный. Это прежде всего полезно для определения бибилиотечных функций, которые могут быть переопределены пользовательским кодом, хотя это может быть использовано и с объявлениями не-функций.
Атрибут alias заставляет породить объявление как синоним другого символа, который должен быть указан. Например,
void __f () { /* делает что-либо */; }
void f () __attribute__ ((weak, alias ("__f")));
объявляет 'f' слабым синонимом для '__f'.
GNU C расширяет ANSI C, чтобы позволять прототипам функций перекрывать последующие определения старого стиля. Рассмотрим следующий пример:
/* Использует прототипы, если компилятор не является старым. */
#if __STDC__
#define P(x) x
#else
#define P(x) ()
#endif
/* Прототип объявления функции. */
int isroot P((uid_t));
/* Определение функции в старом стиле. */
int
isroot (x) /* ??? потеря здесь ??? */
uid_t x;
{
return x == 0;
}
Предположим тип uid_t оказался short. ANSI C не допускает этот
пример, потому что короткие аргументы в старом стиле определений
расширяются. Следовательно, в этом примере аргумент определения
функции в действительности int, который не соответствует типу
аргумента прототипа short.
В GNU C вы можете использовать комментарии C++ стиля, которые начинаются с '//' и продолжаются до конца строки. Многие другие реализации C позволяют такие комментарии, и они, вероятно, будут в будущем стандарте C. Однако, комментарии в C++ стиле не распознаются, если вы указываете '-ansi' или '-traditional', покольку они не совместимы с традиционными конструкциями типа ???.
В GNU C вы можете использовать знак доллара в идентификаторах. Это потому что многие традиционные реализации C позволяют такие идентификаторы.
На некоторых машинах, знак доллара разрешается в идентификаторах, если вы указываете '-traditional'. В некоторых системах они разрешаются по умолчанию, даже если вы не используете '-traditional'. Но он никогда не позволяется, если вы указываете '-ansi'.
Вы можете использовать последовательность '\e' в строковой или символьной константе в качестве ASCII символа ESC.
Ключевое слово __alignof__ позволяет вам узнавать, как выравниваются объекты, или минимальным выравниванием, требуемым для типа. Его синтаксис - такой же как у sizeof.
Например, если целевая машина требует, чтобы значение типа double выравнивалось на 8-байтную границу, тогда __alignof__ (double) равен 8. Это верно для большинства RISC машин. На более традиционных архитектурах __alignof__ (double) равен 4 или даже 2.
Некоторые машины в действительности никогда не требуют выравнивания, они позволяют ссылки на любой тип данных, даже по нечетному адресу. Для этих машин __alignof__ выдает рекомендуемое выравнивание типа.
Когда операндом __alignof__ является L-значение, а не тип, результатом является максимальное выравнивание, которое имеет L-значение. Оно может иметь это выравнивание из-за его типа данных, или потому что оно является частью структуры и наследует выравнивание от этой структуры. Например, после этого объявления
struct foo { int x; char y; } foo1;
значение __alignof__ (foo1.y) равно, вероятно, 2 или 4 - такое же как
__alignof__ (int) хотя тип данных foo1.y сам не требует выравнивания.
Связанное с этим свойство, которое позволяет вам указывать выравнивание объекта - это __attribute__ ((aligned (выравнивание))), см. следующий раздел.
Ключевое слово __attribute__ позволяет вам указывать специальные атрибуты переменных или полей структуры. За этим ключевым словом следует спецификация атрибута в двойных скобках. Восемь атрибутов поддерживаются в данный момент для переменных: aligned, mode, nocommon, packed, section, transparent_union, unused, weak. Другие атрибуты допустимы для функций (см. Раздел [Атрибуты Функций]) и для типов (см. Раздел [Атрибуты Типов]).
Вы можете указывать атрибуты с '__', окружающими каждое ключевое слово. Это позволяет вам использовать их в заголовочных файлах, не заботясь о том, что могут быть макросы с тем же именем. Например, вы можете использовать __aligned__ вместо aligned.
Этот атрибут определяет минимальное выравнивание для переменной или поля структуры, измеряемое в байтах. Например, объявление
int x __attribute__ ((aligned (16))) = 0;
заставляет компилятор размещать глобальную переменную x по 16-байтной
границе. На 68040 это может быть использовано вместе с asm выражением,
чтобы использовать инструкцию move16, которой требуются операнды,
выравненные на 16 байт.
Вы можете также указать выравнивание полей структуры. Например, для создания пары int, выравненной на границу двойного слова, вы могли бы написать:
struct foo { int x[2] __attribute__ ((aligned (8))); };
Это является альтернативой созданию объединения с double членом,
который заставляет выравнивать объединение на границу двойного слова.
Невозможно определять выравнивание функций, выравнивание функций определяется требованиями машины и не может быть изменено. Вы не можете указать выравнивание для typedef имени, потому что такое имя является только синонимом, а не отдельным типом.
Как в предыдущих примерах, вы можете явно указать выравнивание (в байтах), которое вы хотели бы, чтобы использовал компилятор для данной переменной или поля структуры. В качестве альтернативы, вы можете оставить размер выравнивания и только попросить компилятор выравнивать переменную или поле по максимальному полезному выравниванию для целевой машины, для которой вы компилируете. Например, вы могли бы написать:
short array[3] __attribute__ ((aligned));
Атрибут aligned может только увеличить выравнивание, но вы можете
уменьшить его с помощью указания packed. См. ниже.
Заметим, что эффективность атрибутов aligned может быть ограничена ограничениями вашего линкера. Во многих системах, линкер может только обрабатывать выравнивание переменных, не превышающее определенного предела. (Для некоторых линкеров максимальное поддерживаемое выравнивание может быть очень и очень малым.) См. документацию по вашему линкеру для дальнейшей информации.
Этот атрибут указывает тип данных для объявления - тип, который соответствует виду 'вид'. Это в действительности позволяет вам требовать целый или плавающий тип в соответствии с его размером. Вы можете также указать вид 'byte', чтобы указать вид, соответствующий однобайтовому целому, 'word' для вида однословного целого и 'pointer' для вида, используемого для представления указателей.
Этот атрибут указывает GNU CC помещать переменную "общей", а выделять место для нее прямо.
Атрибут packed указывает, что переменная или поле структуры должно иметь минимальное возможное выравнивание - один байт для переменной и один бит для поля, если вы не указали большее значение с помощью атрибута aligned.
Ниже показана структура, в которой поле x запаковано так, что оно непосредственно следует за a:
struct foo
{
char a;
int x[2] __attribute__ ((packed));
};
Обычно компилятор помещает объекты, которые он генерирует в секции типа data и bss. Однако, иногда вам нужны дополнительные секции, или вам нужно, чтобы определенные переменные оказались в специальных секциях, например, чтобы отобразить специальное оборудование. Атрибут section указывает, что переменная (или функция) живет в определенной секции. Например, эта маленькая программа использует несколько особых имен секций:
struct duart a __attribute__ ((section ("DUART_A"))) = { 0 };
struct duart b __attribute__ ((section ("DUART_B"))) = { 0 };
char stack[10000] __attribute__ ((section ("STACK"))) = { 0 };
int init_data_copy __attribute__ ((section ("INITDATACOPY"))) = 0;
main()
{
/* Инициализируем указатель стека */
init_sp (stack + sizeof (stack));
/* Инициализируем инициализированные данные */
memcpy (&init_data_copy, &data, &edata - &data);
/* Включаем последовательные порты */
init_duart (&a);
init_duart (&b);
}
Используйте атрибут section с инициализированным определением
глобальной переменной, как показано в примере. GNU CC выдает
предупреждение и игнорирует атрибут section в неинициализированном
объявлении переменной.
Этот атрибут, примененный к переменной-аргументу функции, который является объединением, означает передавать аргумент, таким же образом, каким передавался бы первый член объединения. Вы можете также использовать этот атрибут с typedef для типа данных объединения, затем он применяется ко всем аргументам функций с этим типом.
Этот атрибут, примененный к переменной, означает, что переменная, возможно, может быть неиспользуемой. GNU CC не будет порождать предупреждение для этой переменной.
Атрибут weak описан в Разделе [Атрибуты Функций].
Для указания многочисленных атрибутов разделяйте их запятыми внутри двойных скобок. Например: '__attribute__ ((aligned (16), packed))'.
Ключевое слово __attribute__ позволяет вам указывать специальные атрибуты struct и union типов при их определении. За этим ключевым словом следует спецификация атрибута в двойных скобках. Три атрибута поддерживаются в данный момент для типов: aligned, packed, transparent_union. Другие атрибуты допустимы для функций (см. Раздел [Атрибуты Функций]) и для переменных (см. Раздел [Атрибуты Переменных]).
Вы можете указывать атрибуты с '__', окружающими каждое ключевое слово. Это позволяет вам использовать их в заголовочных файлах, не заботясь о том, что могут быть макросы с тем же именем. Например, вы можете использовать __aligned__ вместо aligned.
Вы можете указывать атрибуты aligned и transparent_union либо в typedef объявлении, либо сразу после закрывающей скобки полного определения enum, struct или union типа, а атрибут packed - только после закрывающей скобки определения.
Этот атрибут определяет минимальное выравнивание (в байтах) для переменных указанного типа. Например, объявление
struct S { short f[3]; } __attribute__ ((aligned (8));
typedef int more_aligned_int __attribute__ ((aligned (8));
заставляет компилятор гарантировать, что каждая переменная, чей тип -
struct S или more_aligned_int будет размещаться и выравниваться на по
меньшей мере 8-байтовой границе.
Заметим, что выравнивание любого данного struct или union типа, требуемое стандартом ANSI C будет по меньшей мере максимальным выравниванием из выравниваний всех членов рассматриваемого struct или union типа.
Как в предыдущем примере, вы можете явно указать выравнивание (в байтах), которое вы хотите, чтобы использовал компилятор для данного типа. В качестве альтернативы, вы можете оставить размер выравнивания и только попросить компилятор выравнивать тип по максимальному полезному выравниванию для целевой машины, для которой вы компилируете. Например, вы могли бы написать:
struct S { short f[3]; } __attribute__ ((aligned));
Атрибут aligned может только увеличить выравнивание, но вы можете
уменьшить его с помощью указания packed. См. ниже.
Заметим, что эффективность атрибутов aligned может быть ограничена ограничениями вашего линкера. Во многих системах, линкер может только обрабатывать выравнивание переменных, не превышающее определенного предела. (Для некоторых линкеров максимальное поддерживаемое выравнивание может быть очень и очень малым.) См. документацию по вашему линкеру для дальнейшей информации.
Этот атрибут, примененный к определению enum, struct или union типа, указывает, что для представления этого типа должно быть использовано минимальное количество памяти.
Указание этого атрибута для enum, struct или union типа эквивалентно указанию атрибута packed для каждого члена структуры или объединения. Указание флага '-fshort-enums' в командной строке эквивалентно указанию атрибута packed для всех описаний enum.
Вы можете указывать этот атрибут только после закрывающей скобки описания enum, но не в typedef объявлении.
Этот атрибут, присоединенный к описанию типа union, показывает, что любая переменная этого типа при передаче функции должна передаваться также, как передавался бы первый член объединения. Например:
union foo
{
char a;
int x[2];
} __attribute__ ((transparent_union));
Для указания многочисленных атрибутов разделяйте их запятыми
внутри двойных скобок. Например: '__attribute__ ((aligned (16),
packed))'.
Основная цель GNU CC состояла в создании хорошего, быстрого транслятора для класса машин, на которых предполагается использование системы GNU: 32-битные машины, адресующие 8-битные байты и имеющие несколько регистров общего назначения. Элегантность, теоретическая мощность и простота стояли только на втором месте.
GNU CC получает большую часть информации относительно целевой машины из описания машины, которое дает алгебраическую формулу для каждой машинной команды. Это - очень чистый способ описать целевую машину. Но когда транслятор нуждается в информации, которую трудно выразить таким способом, я не колебался определять для данного случая параметр машинного описания. Цель переносимости - уменьшить общую работу, необходимую на трансляторе; само по себе это не представляет интереса.
GNU CC не содержит машинно-зависимого кода, но он содержит код, который зависит от машинных параметров типа endianness (имеет старший байт больший или меньший адрес в слове) и доступности адресации с автоматическим инкрементом. В проход генерации RTL часто необходимо иметь набор cтратегий для генерации кода для специфического вида дерева синтаксиса, cтратегий, пригодных для использования при различных комбинациях параметров. Часто я не пытался охватить все возможные случаи, а рассматривал только общие или только те, которые я встречал. В результате новая целевая машина может потребовать дополнительных cтратегий. Если такое случится, Вы узнаете об этом, потому что транслятор вызовет " abort ". К счастью, новые cтратегии могут быть добавлены машинно-независимым способом, и будет действовать только на тех целевых машинах, на которых они нужны.
Обычно GNU CC конфигурируется для использования того же самого соглашения о вызове функций, которое обычно используется в целевой системе. Это выполнено при помощи макрокоманд с машинным описанием (* См.: Целевые макрокоманды::.).
Однако, возврат значений структуры и объединения выполнен по-другому на некоторых целевых машинах. В результате, функции, скомпилированные PCC, возвращающие такие типы, не могут вызываться из кода, скомпилированного GNU CC, и наоборот. Но это не вызывает проблему часто, потому что мало библиотечных подпрограмм UNIX возвращает структуры или объединения.
GNU CC код возвращает структуры и объединения длины 1, 2, 4 или 8 байт в тех же самых регистрах, которые используются для возвращения значения " int " или " double ".( GNU CC обычно распределяет переменные таких типов тоже в регистрах.) Структуры и объединения других размеров возвращаются путем записи их по адресу, переданному вызывающей подпрограммой (обычно в регистре). Макрокоманды с машинным описанием " STRUCT_VALUE " и " STRUCT_INCOMING_VALUE " сообщают GNU CC, куда передать этот адрес.
Напротив, PCC на большинстве целевых машин возвращает структуры и объединения любого размера, копируя данные в область статической памяти, и затем возвращая адрес этого места как указатель на значение. Вызывающая подпрограмма должна скопировать данные из этой области памяти туда, куда требуется. Этот метод медленнее, чем используемый GNU CC, и его нельзя использовать повторно.
На некоторых целевых машинах, типа RISC машин и 80386, стандартное системное соглашение состоит в передаче подпрограмме адреса, куда надо возвращать значение. На этих машинах GNU CC конфигурован для совместимости со стандартным транслятором, когда используется этот метод. Он не может быть совместим для структур 1, 2, 4 или 8 байтов.
GNU CC использует стандартное соглашение системы для передачи параметров. На некоторых машинах первые несколько параметров передаются в регистрах; на других все передаются в стеке. Можно было бы использовать регистры для передачи параметров на любой машине, и это, вероятно, дало бы значительное ускорение. Но результатом была бы полная несовместимость с кодом, построенным по стандартному соглашению. Так что это изменение можно осуществлять, только если Вы используете лишь один GNU CC из трансляторов C для системы. Мы сможем выполнять регистровую передачу параметра на определенных машинах, как только у нас будет такая полная GNU система, что мы сможем компилировать библиотеки при помощи GNU CC.
На некоторых машинах (особенно Sparc), некоторые типы параметров передаются "невидимой ссылкой". Это означает, что значение сохраняется в памяти, и адрес ее расположения в памяти передается подпрограмме.
Если Вы используете " longjmp ", остерегайтесь автоматических переменных. ANSI C говорит,что автоматические переменные, которые не объявлены "volatile", имеют неопределенные значения после " longjmp ". И это - все, что GNU CC обещает делать, потому что очень трудно восстановить регистровые переменные правильно, и одна из особенностей GNU CC - то, он это может помещать переменные в регистры без вашего требования.
Если Вы хотите, чтобы переменная не изменялась после "longjmp", и Вы не хотите писать "volatile", потому что старые C трансляторы не воспринимают это, просто вычислите адрес переменной. Если адрес переменной когда-либо вычислялся, пусть только для того, чтобы вычислить его и игнорировать его, то переменная не может входить в регистр:
{
int careful;
$careful;
...
}
Код, компилируемый GNU CC, может вызывать некоторые библиотечные
подпрограммы. Большинство из них обрабатывают арифметику, для которой
не имеется никаких команд. Это включает умножение и деление на
некоторых машинах, и операции с плавающей точкой на любой машине, на
которой поддержка плавающей точки отключена с помощью "-msoft-float".
Некоторые стандартные части библиотеки C, типа "bcopy" или "memcpy",
также вызываются автоматически. Обычный интерфейс вызова функций
используется для вызова библиотечных подпрограмм.
Эти библиотечные подпрограммы должны быть определены в библиотеке "libgcc.a", которую GNU CC автоматически ищет всякий раз, когда линкует программу. На машинах, которые имеют команды умножения и деления при использовании аппаратной поддержки плавающей точки "libgcc.a" обычно не необходим, но ищется на всякий случай.
Каждая арифметическая функция определена в " libgcc1.c " для использования соответствующего арифметического оператора C. Как только файл будет скомпилирован другим транслятором C, который поддерживает все арифметические операторы C, этот файл будет работать машиннонезависимо. Однако, " libgcc1.c " не будет работать, если его скомпилировать GNU CC, потому что каждая арифметическая функция скомпилируется в обращение к себе!
Полная структура управления транслятора находится в "toplev.c". Это файл ответственен за инициализацию, декодирование параметров, открытие и закрытие файлов и последовательность проходов.
Проход синтаксического анализа вызывается только однажды для анализа всего ввода. Промежуточный код RTL для функции генерируется, когда функция анализируется. Обработка происходит пооператорно. Каждый оператор считывается как синтаксическое дерево и затем преобразуется в RTL; после этого память, содержащая дерево оператора, освобождается. Типы (и выражения для их размеров), объявления, представления связывания контуров и как они вкладываются сохраняются, пока функция не скомпилируется; все они необходимы, чтобы вывести информацию об отладке.
Каждый раз, когда при проходе синтаксического анализа читается полное определение функции или объявление верхнего уровня, вызывается функция " rest_of_compilation " или функция " rest_of_decl_compilation " в " toplev.c ", которые ответственны за всю дальнейшую необходимую обработку, заканчивающуюся выводом на языке ассемблера. Остальные проходы транслятора вызываются последовательно внутри " rest_of_compilation ". Когда эта функция возвращается из компиляции определения функции, память, используемая для трансляции этого определения, полностью освобождается, если это не встроенная функция (См.: Встроенная функция работает так же быстро, как Макрокоманда: Встраивание.).
Вот список всех проходов транслятора и их исходных файлов. Также включено описание того, как запросить отладочные дампы при помощи опции " -d ".
Большинство работы транслятора выполняется в промежуточном представлении, называемом register transfer language (RTL) .На этом языке команды, которые нужно выводить, описаны довольно подробно одна за другой в алгебраической форме, которая описывает то, что делает команда.
RTL построен на идеях списков Lisp. Он имеет как внутреннюю форму, состоящую из структур, которые указывают на другие структуры, так и текстовую форму, которая используется в машинном описании и в напечатанных дампах отладки. Текстовая форма использует вложенные круглые скобки, чтобы определить указатели во внутренней форме.
RTL использует пять видов объектов: выражения, целые числа, широкие целые числа, строки и векторы. Выражения - наиболее важные. Выражение RTL ("RTX", для краткости) - структура C, но оно обычно всречается как указатель; тип с именем " rtx ".
Целое число - просто " int "; его форма записи использует десятичные цифры. Широкое целое число - интегральный объект типа" HOST_WIDE_INT " (* См.: Конфигурация::.); его форма записи использует десятичные цифры.
Строка - последовательность символов. В ядре она представляется как " char * " обычным способом C, и синтаксис ее записи такой же, как в C. Однако, строки в RTL никогда не могут быть пустыми. Если Вы пишете пустую строку в машинном описании, она представляется в ядре скорее как пустой указатель, чем как указатель на нулевой символ . В определенном контексте эти пустые указатели могут употребляться вместо строк. Внутри кода RTL строки чаще всего находятся внутри выражений ` symbol_ref ', но они появляются и в других контекстах в выражениях RTL, которые создают машинные описания.
Вектор содержит произвольное число указателей на выражения. Число элементов в векторе явно указано в векторе. Форма записи вектора состоит из квадратных скобок (" [...] "), в которые заключаются элементы, записанные последовательно с пропусками, разделяющими их. Векторы длины ноль не создаются; вместо них используются пустые указатели.
Выражения классифицируются по "кодам выражения" (также называемым RTX кодами). Код выражения - имя, определенное в " rtl.def ", которое является также (в верхнем регистре) константой перечисления C. Возможные коды выражений и их значения машинно-независимы. Код RTX может быть получен с помощью макрокоманды " GET_CODE (X) " и изменен с помощью " PUT_CODE (X, NEWCODE) ".
Код выражения определяет, сколько операндов содержит выражение и какого они вида объектами являются. В RTL, в отличие от Lisp, Вы не можете сказать, глядя на операнд, какого это вида объект. Поэтому Вы должны узнавать это из контекста - из кода выражения выражения, содержащего объект. Например, в выражении с кодом " subreg " первый операнд должен быть выражением, а второй операнд - целым числом. В выражении кода " plus " два операнда, и оба они должны быть выражениями. В выражении " symbol_ref " один операнд, который должен быть строкой.
Выражения записываются как круглые скобки, содержащие имя типа выражения, его флаги и машинный тип, если они есть, а затем операнды выражения (разделяемые пробелами).
Имена кода выражения в файле " md " записаны строчными буквами, но когда они появляются в коде C, они записываются в верхнем регистре. В этом руководстве они пишутся следующим образом: " const_int ".
В нескольких контекстах пустой указатель может использоваться как выражение. Форма записи этого - " (nil) ".
Для каждого типа выражения " rtl.def " указывает количество содержащихся объектов и их виды следующим способом: " e " для выражения (фактически указателя на выражение), " i " для целого числа, " w " для широкого целого числа, " s " для строки и " E " для вектора выражений. Последовательность символов для кода выражения называется его форматом. Таким образом, форматом " subreg " является " ei ".
Иногда используются несколько других символов управления форматом:
" u " эквивалентно " e " за исключением того, что оно печатается по-другому в отладочных дампах. Это используется для указателей на insns.
" n " эквивалентно " i " за исключением того, что оно печатается по-другому в отладочных дампах. Это используется для номера строки или количества кода insn " note ".
" S " обозначает строку, которая является необязательной. В объектах RTL в ядре " S " эквивалентно " s ", но когда объект читается из " md " файла, строковое значение этого операнда может быть опущено. Опущенная строка считается пустой.
" V " обозначает вектор, который является необязательным. В объектах RTL в ядре " V " эквивалентно " E ", но когда объект читается из " md " файла, векторное значение этого операнда может быть опущено. Опущенный вектор - то же, что и вектор, не имеющий элементов.
" 0 " означает слот, чей содержание не попадает ни в какую нормальную категорию. " 0 " слоты не печатаются вообще в дампах, и часто используются специальными способами в маленьких частях транслятора.
Число операндов RTX кода CODE.
Формат RTX кода CODE как строка C.
Одиночный символ, представляющий тип операции RTX, которую выполняет код CODE.
RTX код, который представляет фактический объект, типа " reg " или " mem ". " subreg " не принадлежит к этому классу.
RTX код для сравнения. Коды в этом классе " NE ", " EQ ", " LE ", " LT ", " GE ", " GT ", " LEU ", " LTU ", " GEU ", " GTU ".
RTX код для унарной арифметической операции, типа " neg ".
RTX код для коммутативной бинарной операции, отличной от " NE " и " EQ " (которые имеют класс " < ").
RTX код для некоммутативной двоичной операции, типа " MINUS ".
RTX код для операции с битовым полем, " ZERO_EXTRACT " или " SIGN_EXTRACT ".
RTX код для трех других входных операций, типа " IF_THEN_ELSE ".
RTX код для машинного insn (" INSN ", " JUMP_INSN " и " CALL_INSN ").
RTX код для того,что соответствует insns, типа " MATCH_DUP ".
Все другие RTX коды.
XEXP (X, 2)
обращается к операнду 2 выражения X как к выражению.
XINT (X, 2)
обращается к тому же самому операнду как к целому числу. Макрокоманда" XSTR ",
использованная тем же самым способом, получила бы этот операнд как строку.
К любому операнду можно обращаться как к целому числу, выражению или строке. Вы должны выбрать правильный метод доступа для вида значения, фактически содержащегося в операнде. Это делается при помощи кода выражения, содержащего операнд. Таким же образом Вы можете узнать, сколько это выражение имеет операндов.
Например, если X - выражение " subreg ", Вы знаете, что оно имеет два операнда, к которым можно корректно обращаться как " XEXP (X, 0) " и " XINT (X,1) ". Если Вы напишете " XINT (X, 0) ", Вы получите адрес операнд выражения как целое число; это может быть иногда полезно, но чтобы получить такой результат, лучше писать " (int) XEXP (X, 0) ". " XEXP( X, 1) " тоже скомпилируется без ошибки и возвратит второй, целочисленный операнд,приведенный к указателю на выражение, обращение к которому, скорее всего, приведет к аварийному отказу. Ничто не запрещает Вам писать " XEXP( X, 28) ", но эта запись обратится к памяти после конца выражения с непредсказуемыми результатами.
Доступ к операндам, которые являются векторами, сложнее. Вы можете использовать макрокоманду " XVEC ", чтобы получить указатель на вектор непосредственно, или макрокоманды " XVECEXP " и " XVECLEN ", чтобы обратиться к элементам и длине вектора.
Получает указатель на вектор, который является операндом номер IDX в выражении EXP.
Получает длину (число элементов) в векторе, который является операндом номер IDX в выражении EXP. Это значение типа " int ".
Обращается к элементу номер ELTNUM в векторе, который является операндом номер IDX в выражении EXP. Это значение RTX.
При вызове этой макрокоманды нужно быть уверенным, что ELTNUM не меньше нуля и меньше чем " XVECLEN (EXP, IDX) ".
Выражения RTL содержат несколько флагов (битовых полей с одним битом), которые используются в некоторых типах выражений. Наиболее часто к ним обращаются следующими макрокомандами:
В выражениях " mem " отлично от нуля для переменных ссылок памяти. Сохраняется в поле " volatil " и печатается как " /v ".
В выражениях " mem " отлично от нуля для ссылки на всю структуру, объединение или массив, или на их компонент. Ноль для ссылки на скалярную переменную или через указатель на скаляр. Сохраняется в поле " in_struct " и печатается как " /s ".
В выражениях " reg " отлично от нуля, если этот регистр "живет" только в коде проверки на выход некоторого цикла. Сохраняется в поле " in_struct " и печатается как " /s ".
В " reg " отлично от нуля, если соответствует переменной, имеющейся в исходном тексте пользователя. Ноль для временных переменных, внутренне сгенерированных транслятором. Сохраняется в поле " volatil " и печатается как " /v ".
Отлично от нуля в " reg ", если это - место, в которое должно быть возвращено значение функции. (Это возможно только для аппаратного регистра.) Сохраняется в поле " integrated " и печатается как " /i ".
Тот же самый аппаратный регистр может использоваться также для значений функций, вызываемых этой, но " REG_FUNCTION_VALUE_P " - ноль для этого вида использования.
Отлично от нуля в " subreg ", если делается во время доступа к объекту, продвинутому на более широкий тип в соответствии с макрокомандой машинного описания " PROMOTED_MODE " (* См.: Размещение памяти::.). В этом случае тип " subreg " является объявленным типом объекта и тип " SUBREG_REG " является типом регистра, который содержит объект. Расширяемые ые переменные всегда расширяются нулем или знаком в более широкий тип при каждом присваивании. Сохраняется в поле " in_struct " поле и печатается как " /s ".
Отлично от нуля в " subreg " который имеет " SUBREG_PROMOTED_VAR_P " отличным от нуля, если вызываемый объект расширен нулем, и ноль, если он расширен знаком. Сохраняется в поле " unchanging " и печатается как " /u ".
Отлично от нуля в " reg " или " mem ", если значение не изменено. (Этот флаг не устанавливается для ссылок на константы через указатели. Такие указатели гарантируют только, что объект будет не изменен явно текущей функцией. Объект может бы быть изменен другими функциями или через совмещение имен.) Сохраняется в поле " unchanging " и печатается как " /u ".
Отлично от нуля в insn, если получено из вызова встроенной функции. Сохраняется в поле " integrated " и печатается как " /i ". Может быть удалено; в настоящее время от него ничего не зависит.
В " symbol_ref " указывает, что X использован. Обычно используется только для того, чтобы гарантировать, что X только однажды объявлен внешним. Сохраняется в поле " used ".
В " symbol_ref " используется как флаг для специфических для машины целей. Сохраняется в поле " volatil " и печатается как " /v ".
В выражениях ` label_ref ' отлично от нуля, если это - ссылка на метку, которая находится снаружи самого внутреннего цикла, содержащего ссылку на метку. Сохраняется в поле " in_struct " и печатается как " /s ".
В insn отлично от нуля, если insn был удален. Сохраняется в поле " volatil " и печатается как " /v ".
В " insn " в слоте задержки ветви insn указывает, что должна использоваться аннулирующая ветвь. См. обсуждение " sequence " ниже. Сохраняется в поле " unchanging " и печатается как " /u ".
В " insn " в слоте задержки ветви указывает, что insn - из адреса перехода. Если для ветви insn " INSN_ANNULLED_BRANCH_P " установлен, этот insn должен выполняться, только если переход производится. Для аннулированных ветвей с этим битом, равным 0, insn должен выполняться, если переход не производится. Сохраняется в поле " in_struct " и печатается как " /s ".
Отлично от нуля в " symbol_ref " если он ссылается на часть текущего "пула констант" функции. Это адреса, близкие к началу функции, и GNU CC предполагает, что они могут быть адресованы непосредственно (возможно, с помощью базовых регистров). Сохраняется в поле " unchanging " и печатается как " /u ".
В " call_insn " указывает, что insn представляет обращение к постоянной функции. Сохраняется в поле " unchanging " и печатается как " /u ".
В " code_label " указывает, что метка никогда не может быть удалена. Метки, вызываемые нелокальным переходом, будут иметь этот набор битов. Сохраняется в поле " in_struct " и печатается как " /s ".
В течение планирования команд в insn указывает, что предыдущий insn должен планироваться вместе с этим insn. Это используется, чтобы гарантировать, что определенные группы команд не будут разбиваться на части проходом планирования команд, например, " use " insns перед " call_insn " не могут отделяться от " call_insn ". Сохраняется в поле " in_struct " и печатается как " /s ".
Обычно этот флаг используется только в один момент, а именно - в конце генерации RTL функции, чтобы посчитать, сколько раз в insns появляется выражение. Выражения, которые появляются больше чем однажды, копируются, согласно правилам совместного использования структур (* См.: Совместное использование::.).
В " symbol_ref " он указывает что внешнее объявление для символа уже было написано.
В " reg " он используется регистром листа, перенумеровывающим код, чтобы гарантировать, что каждый регистр перенумеровывается только однажды.
Этот флаг используется в выражениях " mem ", " symbol_ref " и " reg " и в insns. В файлах дампа RTL он печатается как " /v ".
В выражении " mem " он равен 1, если ссылка памяти переменная. Переменные ссылки памяти нельзя удалять, переупорядочивать и объединять.
В выражении ` symbol_ref ', это используется для специфических для машины целей.
В выражении ` reg ' он равен 1, если значение - пользовательская переменная, и 0, если это внутренняя временная переменная транслятора.
В insn, значение 1 означает, что insn был удален.
В выражениях " mem " он равен 1, если данная величина ссылается на весь массив или структуру или их часть ; 0, если это - скалярная переменная (или может быть ею). Ссылке через указатель C соответствует 0, потому что указатель может указывать на скалярную переменную. Эта информация позволяет транслятору выяснить определенную информацию относительно возможных случаев совмещения имен.
В insn в слоте задержки перехода 1 означает, что этот insn - из адреса перехода.
Во время планирования команд в insn 1 означает, что этот insn должен планироваться как часть группы вместе с предыдущим insn.
В выражениях " reg " он равен 1, если регистр "живет" только в коде проверки на выход некоторого цикла.
В выражениях " subreg " 1 означает, что " subreg " обращается к объекту, который имел тип, полученный из более широкого типа.
В выражениях " label_ref " 1 означает, что ссылка на метку находится снаружи самого внутреннего цикла, содержащего insn, в котором было найдено " label_ref "
В выражениях ` code_label ' он равен 1, если метку никогда нельзя удалять. Это используется для меток, на которые имеются нелокальные переходы.
В дампе RTL этот флаг представляется как " /s ".
В выражениях " reg " и " mem " 1 означает, что значение выражения никогда не изменяется.
В выражениях " subreg " он равен 1, если " subreg " ссылается на объект без знака, чей тип был расширен до более широкого тип.
В insn 1 означает, что это - аннулирующая ветвь.
В выражении " symbol_ref ", 1 означает, что этот символ адресует что-то в пуле констант функции.
В " call_insn " 1 означает, что эта команда - обращение к постояннной функции.
В дампе RTL этот флаг представляется как " /u ".
В некоторых видах выражений, включая insns, этот флаг означает, что RTL был произведен интеграцией процедуры.
В выражении " reg " этот флаг указывает регистр, содержащий значение, которое будет возвращено текущей функцией. На машинах которые передают параметры в регистрах, то же количество регистров может использоваться и для параметров, но этот флаг не устанавливается при таком использовании.
Тип описывает размер данных объекта и представление его использования. В С-коде машинные рехимы (типы) представляются перечислимым типом `enum machine_mode', определенным в `machmode.def'. В каждом RTL выражение имеется место для типа. Также делается в некоторых типах tree-выражений (точнее в описанияхи типах).
В отладочных дампах и описаниях машинный тип RTL-выражения записан после кода выражения через двоеточие. Символ 'mode', который должен стоять в конце названия каждого типа опущен. Например, `(reg:SI 38)' - обозначает выражение 'reg' типа SImode. Если тип `VOIDmode' то это не пишется вообще.
Здесь представленна таблица типов. Далее "byte" - это объект размером `BITS_PER_UNIT' бит.
"Quarter-Integer" - тип, в котором байт рассматривается как целое.
"Half-Integer" - тип, представляющий целое двумя байтами.
"Partial Single Integer" - тип, представляющий целое, занимающее четыре байта, но все четыре реально не используются. На некоторых машинах это правильный режим для представления указателей.
"Single Integer" - тип, представляющий целое четырьмя байтами.
"Partial Double Integer"- тип, представляющий целое, занимающее восемь байт, но все четыре реально не используются. На некоторых машинах правильно представлять указатель этим типом.
"Double Integer" - тип, представляющий целое восьмью байтами.
"Tetra Integer" (?) - тип, представляющий целое шестнадцатью байтами.
"Single Floating" - тип числа с плавающей точкой, имеющего одинарную точность (четыре байта).
"Double Floating" - тип числа с плавающей точкой, имеющего двойную точность (восемь байт).
"Extended Floating" - тип числа с плавающей точкой, имеющег тройную точность (двенадцать байта). Этот тип используется для хранения чисел с плавающей точкой в формате IEEE. В некоторых системах не все биты реально используются.
"Tetra Floating"- тип числа с плавающей точкой, имеющего четверную точность (шестнадцать байт).
"Condition Code" - тип представляющий значение операций сравнения. Результат сравнения представляется, как набор бит на каждой машине по своему. Этот тип не используется на машинах, использующих `cc0'.
"Block" - тип, представляющий значение которое нельзя представить никаким другим типом. В RTL этот тип используется только для ссылок на память, и только в том сслучае если они используются в командах относяшихся к строкам и векторам. В машинах, не имеющих команд такого типа этот тип вообще не появляется.
Тип Void значит либо отсутствие типа либо неопределенный тип. Например, RTL-выражение `const_int' имеет тип VOIDmode, потому что его тип зависит от контекста. В отладочной информации RTL выражения типа `VOIDmode' обозначаются отсутствием какого бы то ни было типа.
Этот тип комплексных чисел, представляемый парой чисел с плавающей точкой. Значение числа с плавающей точкой будет соответственно типа 'SFmode', `DFmode', `XFmode', или `TFmode'.
Этот тип комплексных чисел, представляемый парой целых чисел. Значение целого числа будет соответственно типа `QImode', `HImode', `SImode', `DImode', `TImode', или `OImode'.
Единственный тип, который обязан поддерживаться машиной - `QImode' и типы соответствующие размерам `BITS_PER_WORD', `FLOAT_TYPE_SIZE' и `DOUBLE_TYPE_SIZE'. По умодчанию, транслятор быдет пытаться использовать для 8-байтных структур тип "DImode", но это может быть предотвращено с помошью отмены области определения `MAX_FIXED_MODE_SIZE'. Аналогично для 16-битных структур транслятор использует `TImode', и аналогично Вы можете принимать меры для указания С-типа 'short int', что бы избежать использования 'HImode'.
В компиляторе остается очень мало точных указаний типов, но скоро не останется даже этого. Вместо этого типы делятся на классы. Классы представляются перечислением `enum mode_class', определенным в `machmode.h'. Ниже приведены возможные классы:
Целые типы. По умолчанию это: `QImode', `HImode', `SImode',`DImode', и `TImode'.
Частичные целые (не все бтиы используются): `PSImode' and `PDImode'.
Типы чисел с плавающей точкой. По умолчанию это: `SFmode', `DFmode', `XFmode' и `TFmode'.
Комплексные целые. (Пока еще не реализованы).
Комплексные числа (с плавающей точкой). По умолчанию это: `SCmode', `DCmode', `XCmode', и `TCmode'.
Паскалевские и алголовские функцмональные переменные, включая статические цепочки. (Пока еще не реализованы).
Типы соответствующие результатам сравнений. Это `CCmode' и все типы, перечисленные в макросе `EXTRA_CC_MODES'. см. Образцы переходов, см. также *Note Код условия
Этот класс состовляют типы, не попавшие ни в один из вышеперечисленных классов. Пока что это типы `VOIDmode' и 'BLKmode'.
Далее идут некоторые макросы, относящиеся к типам:
Возвращает тип переменной X.
Меняет тип переменной X на NEWMODE.
Возвращает количество типов, доступных на машине, под которую происходит компиляция. Это число на единицу больше максимального номера доступного типа.
Возвращает название типа M в виде строки.
Возвращает класс типа M.
Возвращает следующий по размеру тип. Например, выражение `GET_MODE_WIDER_MODE (QImode)' возвращает `HImode'.
Возвращает количество байт, которое занимает объект типа M.
Возвращает количество бит, которое занимает объект типа M.
Возвращает битовую маску, содержащую 1 в тех битах, которые используются типом M. Этот макрос может быть использован только для типов чей размер не больше `HOST_BITS_PER_INT' бит.
Возвращает количество бит, необходимое для выравнивания объекта типа M.
Возвращает размер в байтах одного поля объекта типа M. Это тоже самое, что и `GET_MODE_SIZE' для всех некомплексных типов, для комплексных это размер вещественной или мнимой части.
Возвращает количество полей в типе M. Тоже самое что `GET_MODE_SIZE' поделенное на `GET_MODE_UNIT_SIZE'.
Возвращает narrowest тип в классе C.
Простейшее RTL-выражение - это выражение, описывающее константную величину.
Выражение такого типа представляет целую константу со значением I. К I обычно обращаются с помощью макроса `INTVAL' как в `INTVAL (EXP)', который эквивалентет `XWINT (EXP, 0)'.
Существует только один константный объект соответствующий целому значению ноль. Это значение переменной `const0_rtx'. Аналогично, целое значение 'единица' расположенна в `const1_rtx', а двойка в `const2_rtx'. Так же значение целой минус единицы расположенно в `constm1_rtx'. При создании целой константы со значением ноль, единица, двойка или минус единица будет соответственно возвращена константа `const0_rtx', `const1_rtx', `const2_rtx' или `constm1_rtx'.
Аналогично существует только одна целая константа со значением `STORE_FLAG_VALUE' - это `const_true_rtx'. Если `STORE_FLAG_VALUE' равен единице то `const_true_rtx' и `const1_rtx' будут указывать на одини тот же объект. Если `STORE_FLAG_VALUE' равен -1, то на один и тот же объект будут указывать `const_true_rtx' и `constm1_rtx'.
Может описывать как константу с плавающей точкой, так и целую константу слишком большую, что бы поместится в `HOST_BITS_PER_WIDE_INT' битах но достаточно маленькую, что бы поместится в 2*`HOST_BITS_PER_WIDE_INT' битах(GNU CC не предоставляет механизма для описания констант большего размера). В последнем случае константа будет иметь тип 'VOIDmode'.
ADDR используется, чтобы содержать выражение 'mem', которое указывает на расположение константы в памяти. Если память не была выделена память, но находится в цепочке всех выражений `const_double' в данной компиляции (поддерживающей использование неотображаемых полей), ADDR указывает на `const0_rtx'. Если же находится не в цепочке, ADDR указывает на `cc0_rtx'. К ADDR обычно обращаются через макрос `CONST_DOUBLE_MEM' а к полю цепи через `CONST_DOUBLE_CHAIN'.
Если M - "VOIDmode", то биты значения сохранены в I0 и I1. К I0 обычно обращаются с помощью макрокоманды "CONST_DOUBLE_LOW" а к I1 с помошью "CONST_DOUBLE_HIGH".
Если константа - константа с плавающей точкой (независимо от точности), то число целых чисел, исспользуемых для сохранения значения зависит от размера `REAL_VALUE_TYPE'. Целые числа представляют число с плавающей точкой, но не точно в формате целевой или главной машины. Чтобы преобразовать их (целые числа) в формат, используемый на целевой машине, используется макрос `REAL_VALUE_TO_TARGET_DOUBLE' и иже с ним (см.Data Output::. ).
Макрос `CONST0_RTX (MODE)' указывает на выражение типа MODE со значением ноль. Если тип MODE из класса `MODE_INT' то макрос будет указывать на `const0_rtx'. В другом случае он возращает выражение `CONST_DOUBLE' с типом MODE. Аналогично макрос `CONST1_RTX (MODE)' возвращает выражение со значением 1 типа MODE, тоже самое и для `CONST2_RTX'.
Описывает константную строку со значением STR. В настоящее время это используется только атрибутов insn (см. Атрибуты Insn.) с тех пор, как в С строчные константы размещаютсяс в памяти.
Описывает аасемблерную метку для данных. SYMBOL - это строка, содержащая название метки. Если она начинается с '*' то этот символ в название метки не включается. В противном случае к названию метки вначале добавляется символ `_'.
`symbol_ref' содержит тип, который обычно `Pmode'. Обычно это единственный тип в котором описание строки является коректным.
Описывает ассемблерную метку для кода. Она содержит один операнд - выражение, которое должно быть `code_label', которое появляется, в последовательности команд, идентифицируя место, куда указывает метка.
Особые метки для кода используются для того, чтобы их можно было бы отличить в момент оптимизации переходов.
Описывает константу, которая является результатом выражения, значение которого может быть найдено во время компиляционных вычисленний. Операнд EXP - это выражение которое содержит только константы (выражения типа 'const_int', `symbol_ref' и `label_ref') и операции `plus' и `minus'. Не все комбинации являются допустимыми, т.к. ассемблер не может выполнять произвольные арифметические выражения над перемещаемыми символами.
M должно быть типа `Pmode'.
Описывает старшие биты EXP, обычно - `symbol_ref'. Количество бит является машинно-зависимым и обычно оно определено в команде, которая инициализирует количество старших битов регистра. Эта команда используется с `lo_sum' для представления типичных последовательностей с двумя командами, используемых в RISC машинах, для согласования расположения в глобальной памяим.
M должно быть типа `Pmode'.
Ниже перечислены типы выражений для доступа к машинным регистрам и основной памяти.
Для небольших значений целого числа N (меньше, чем `FIRST_PSEUDO_REGISTER') это будет ссылка на машинный регистр с номером N - "аппаратный регист". Для больших значений числа N, возвращается ссылка на временное значение или "псевдо регистр". Принцип действия компилятора - создавать код, предполагая неограниченное число таких псевдо регистров, а поже заменять их на аппаратные регистры или на ячейки памяти.
M - тип ссылки. Это необходимо, т.к. обычно машина может использовать каждый регистр более чем в одном режиме. Например могут существовать инструкции, которые используют регистр, содержащий слово, как полслова или как байт, более того, могут быть инструкции, ссылающиеся на этот регистр как на число с плавающей точкой различной точности.
Тип необходимо указывать даже для регистра, который машина может использовать только одним способом.
Символ `FIRST_PSEUDO_REGISTER' определяется в соответствии с описанием машины, т.к. так как число аппаратных регистров на машине - инвариантная характеристика машины. Однако, обратите внимание, что не все машинные регистры обязаны быть регистрами общего назначения. Все машинные регистры, которые можно использовать для хранения данных учтены в числе аппаратных регистров, даже те, которые могут использоваться только в некоторых коммандах или содержать только орпеделенные типы данных. All
К аппаратным регистром можно обращатся в различных режимах в течении одной функции, но к псевдо регистру можно обращаться только в режиме, в котором он был описан. Если необходино описать доступ к псевдо регистру в другом режиме используйте выражение `subreg'.
Выражение 'reg' типа M, которое содржит более одного слова данных, может на самом деле состоять из нескольких последовательных регистров. Если кроме того номер регистра соответствует аппаратному регистру, то фактически он представляется несколькими последовательными аппаратными регистрами, начиная с данного.
Каждый номер псевдо регистра, используеммого коде RTL-функции представляется уникальным выражением `reg'.
Некоторые номера псевдо регистров, от `FIRST_VIRTUAL_REGISTER' до `LAST_VIRTUAL_REGISTER' появляются только в фазе RTL и уничтожаются перед фазой оптимизации. Пока не завершено RTL образование функций, они представляют расположение в стеке, которое не может быть определено пока не завершится RTL-генерация функций.
Определены следующие номера для регистров:
Указывает на первое слово аргументов, переданных в стек. Обычно это аргументы, переданные вызывающей программой, но вызывающая программа может положить в стек некоторые аргументы, которые до этого были в регистрах.
Когда RTL-фаза завершена, этот виртуальный регистр замещается суммой регистра, полученного с помощью `ARG_POINTER_REGNUM' и значения 'FIRST_PARM_OFFSET'.
Если `FRAME_GROWS_DOWNWARD' определен, то это указывает на место сразу после первой переменной в стеке. Иначе, это указывает на первую переменную в стеке.
`VIRTUAL_STACK_VARS_REGNUM' заменен на сумму регистра, полученного с помощю `FRAME_POINTER_REGNUM' и значения 'STARTING_FRAME_OFFSET'.
Указывает на расположение динамически распределенной памяти в стеке сразу после того, как указатель стека инициализирован достаточным объемом памяти.
Этот виртуальный регистр замещается суммой регистра, полученного с помощью `STACK_POINTER_REGNUM' и значения `STACK_DYNAMIC_OFFSET'.
Указывет на место в стеке, куда пишутся выходящие параметры, когда стек - pre-pushed (помещенные параметры, использующие push insn всегда используют `STACK_POINTER_REGNUM')
Этот виртуальный регист замещается на сумму регистра, полученного с помощью `STACK_POINTER_REGNUM' и значения `STACK_POINTER_OFFSET'.
выражение `subreg' используется для обращения к машинному регистру в режеме, отличном от естственного, или что бы обратится к мульти-регистру 'reg', который фактически является несколькими регистрами.
Каждый псевдо регистр имеет свой естественный режим. Если необходимо работать с этим регистром в другом режиме - например, выполнить команду перемещения слова над регистром, который содержит один байт, псевдо регистр должен быть включен в 'subreg'. В этом случае WORDNUM - ноль.
Обычно размер M по крайней мере не больше размера типа REG, тогда это ограничивает рассмотрение только тех бит REG, которые находятся в M.
Иногда разме M больше чем размер типа REG. Тогда эти выражения `subreg' часто называются "парадоксальными". Они используются в случаях, когда мы хотим обратиться к объекту в режиме с большим размером, но не заботиться, какое значение имеют дополнительные биты. Предварительный проход гарантирует, что "парадоксальные" ссылки сделаны только на аппаратные регистры.
Еще 'subreg' используется для извлечения одиночного регистра из значения мулти-регистра. Такие типы как `DImode' и `TImode' могут содержать число большее чем слово - число которое обычно размещается в двух или более регистрах. Чтобы обратится к одному из регистров используйте 'subreg' с режимом 'SImode' и WORDNUM, который показывает какой нужен регистр.
Записывание в не-парадоксальный 'subreg' дает неопределенный результат для битов тогоже слова, что и 'subreg'. Эта неточность делает генерацию кода для таких инструкций более эфективной. Для представления команды, которая сохраняет все биты 'subreg' используйте `strict_low_part' around the `subreg'.
Если параметр трансляции `WORDS_BIG_ENDIAN' установлен в 1, то это означает, что слово номер ноль наиболее значительная(significant) часть, иначе, что наименее значительная часть
Возможно между проходом комбинирования и проходом перезагрузки, что будут существовать пародоксальные 'subreg', которые содержат первым параметром 'mem' вместо 'reg'. После прохода перезагрузки возможно будут существовать непародоксальные 'subreg', которые содержат 'mem'; обычно это происходит, когда 'mem' является слотом стека, который заменил псевдорегистр.
Обратите внимание, что некорректно обращаться к числу в режиме `DFmode', как числу в режиме 'SFmode' через 'subreg'. На некоторых машинах наиболее значимая часть `DFmode' имеет другой формат, чем число с плавающей точкой одинарной точности.
Так же некорректно обращаться к одиночному слову аппаратного мульти регистра, который может содержать более одного слова. Например некоторые 32-битные машины имеют регистры вещественных чисел, которые могут содержать целое чило типа `DFmode'. Если бы например номер регистра был бы 10 то `(subreg:SI (reg:DF 10) 1)' было бы некорректным, т.к. не существует способа представить это указание как отдельный аппаратный регистр. Пргоход перезагрузки предотвращает формирование выражений такого типа.
К первому операнду 'subreg' обычно обращаются с помошью макрокоманды `SUBREG_REG' а ко второму с помошью `SUBREG_WORD'.
Описывает временный регистр, который требуется для выполнения одиночной комманды и не используется впоследствии. Он преобразуется в 'reg' либо локальным регистром allocator либо проходом перезагрузки.
`scratch' обычно описывается внутри операции `clobber'.
Обращение к регистру кода условия. Это обращение не имеет параметров и типа. Существует два способа для его использования:
Команды могут устанавливать код условия неявно. На многих машинах, почти все команды устанавливают код условия, в зависимости от значения, которое они вычислили или записали. Нет необходимости записывать эти действия в RTL явно, т.к. машинное описание включает предписание для распознавания таких команд (посредством макрокоманды "NOTICE_UPDATE_CC"). *см Код Условия. В упоминании нуждаются только те команды, которые ничего не делают, кроме установки или использования кода условия.
На некоторых машинах регистр кода условия является регистром с номером, и тогда вместо '(cc0)' используется`reg'. Обычно это более выгодный подход, если код условия изменяют тольео небольшое количество команд. На других машинах код условия сохраняется в общих регмстрах, в таком случае должны использоваться псевдо регистры.
Некоторые машины, типа Sparc и RS/6000, имеют два набора арифметических команд, один, который устанавливает, и другой, который не устанавливает код условия. Удобнее всего это использовать в случае, когда по умллчанию генерируются инструкции, не устонавливающие код условия, и есть образцы, которые и выполняют арифметику и устанавливают регистр кода условия, который в этом случае не `(cc0)'. Для примеров, поиск "addcc" и "andcc" в "sparc.md".
Он представляет машинный счетчик програм. Он не имеет операндов и может не иметь типа. '(pc)' может быть корректно использован только в некоторых специфических контекстах операторов перехода.
Существует только один объект, соответствующий коду '(pc)' это значение переменной `pc_rtx'. Любая попытка создать выражение с кодом `pc' вернет `pc_rtx'..
Все инструкции, которые не выполняют переход, изменяют счетчик программы неявно, увеличивая его, но упоминать это в RTL не нужно.
Это RTX представляет ссылку на основную память по адресу, представляемому выражением ADDR. M определяет, сколько ячеек памяти доступно.
4.7. RTL-Выражения для работы с арифметикой
Далее если не оговоренно противное, то все операнды в математическом выражении должны быть применимы к типу M. Операнд применим к типу M, если он имеет тип M, или это `const_int' или `const_double' а M - режим класса `MODE_INT'.
В бинарных коммутативных операциях константа должна быть вторым аргументом.
Возвращает сумму значений X и Y выполненыю в режиме M.
Тоже, что и `plus', только складывается X и биты младших разрядов Y. Количество бит младшего разряда является аппаратно зависимым, но обычно это количиство бит в типе 'Pmode' минус количество бит установленное с помошью 'high'. (*см. Constants::.).
M должно быть типа `Pmode'.
Как `plus' только описывает вычитание.
Представляет результат вычитания Y из X с целью сравнения. Результат вычисляется без переполнения, как если бы был с бесконечной точностью.
Конечно, машина не может вычитать с бесконечной точностью. Однако, когда нужен только знак, она может симулировать как будто делает это. И единственный способ, которым это выражение может быть корректно использоваться - это сохранение его в коде условия.
Тип М не связан с типами X и Y, а является типом значения кода условия. Если используется `(cc0)', то это `VOIDmode'. Иначе это какой-то тип класса `MODE_CC', обычно `CCmode'. см. Код условия.
Обычно X и Y должны иметь один и тот же тип. иначе сравнение корректно только в случае, когда тип X принадлежит классу `MODE_INT' а Y - `const_int' или `const_double' с типом `VOIDmode'. Тип X определяет в какком режиме будет выполнено сравнение, поэтому он не моднт быть 'VOIDMode'.
Если один из операндов - константа, то она должна быть вторым аргументом и тип сравнения корректируется как соответствующий.
Сравнение двух констант некорректно, так как невозможно узнать режим в котором проводить сравнение. Сравнение должно также быть свернуто в течение трансляции, или первый операнд должен быть загружен в регистр, в то время пока режим еще известен.
Возврашает X с обратным знаком (вычитание из нуля), операция выполняется в режиме M.
Возвращает произведение значений X и Y со знаком, вымолненое в режиме M.
Некоторые машимы поддерживают умножение, при котором произведение имеет больший размер, чем операнды. Для этого надо писать умножение в следующем формате:
(mult:M (sign_extend:M X) (sign_extend:M Y))
где M тип, больший, чем типы X и Y, которые не обязаны быть
одинаковыми.
Для расширяющего умножения без знака аналогично, только исспользуя `zero_extend' вместо 'sign_extend'.
Возвращает частное от деления со знаком X на Y, выполненого в режиме M. Если тип M - тип числа с плавающй точкой то возвращается точное частное, иначе округленное.
На некоторых машинах имеются инструкции деления в котором тип операндов и частного не одинаковые. Вы можете употреблять такие инструкции, исполльзуя `truncate' и `sign_extend' в них:
(truncate:M1 (div:M2 X (sign_extend:M2 Y)))
Подобно `div' но деление беззнаковое.
Подобно `div' и `udiv' но возвращает остаток, вместо частного.
Возвращает минимум и максимум соответственно. X и Y интрепретируются как целые числа со знаком типа М.
Подобно `smin' и `smax', но значение интрепретируется как беззнаковое целое.
Возвращает побитовое дополнние значения X, выполненое в режиме M, который должен быть режимом с фиксированной точкой.
Возвращает побитовое логическое 'и' значений X и Y, выполненое в режиме M, который должен быть режимом с фиксированной точкой.
Возвращает побитовое исключающее или значений X и Y, выполненое в режиме M, который должен быть режимом с фиксированной точкой.
Возвращает побитовый XOR значений X и Y, выполненое в режиме M, который должен быть режимом с фиксированной точкой.
Возвращает смещение знацения X на C бит влево. X имеет тип M - тип с фиксированной точкой. С должен иметь тип с фисированной точкой или быть константой типа 'VOIDmode', режим которой определяется из описания машины как тип для смещения вправо. Например, на Vax, режим C - 'QImode' независимо от M.
Подобно `ashift', но для сдвига вправо. В отличие от случая сдвига влево, эти две операции отличны.
Аналогично, но возвращает левое или правое вращение. Если C - константа, используйте - `rotate'.
Возвращает абсолютное значение (модуль) X, вычисленное в режиме M.
Возвращает квадратный корень из X, вычисленный в режиме M. Обычно M - тип с плавающей точкой.
Возвращает один плюс индекс младшего значащего бита в Х, представленное как целое число типа М. (Если Х-ноль, то возвращается ноль.) Тип Х не обязательно должен быть М; в зависимости от целевой машины, могут быть корректными различные комбинации типов.
Операторы сравнения проверяют отношение двух операндов и должны представлять машинно-независимое ненулевое значение, описываемое с помошью `STORE_FLAG_VALUE', но не обязательно ему равное (см. Разное) если отношение выполняется, или ноль, если не выполняется. Тип операции сравнения не зависит от типа данных, которые она сравнивает. Если результат операции сравнения используется в проверке (например первый операнд в `if_then_else'), то тип должен быть `VOIDmode'. Если операция сравнения генерирует данные, которые должны заноситься в некоторую переменную, то тип должен быть класса `MODE_INT'. Все операции сравнения, генерирующие данные должны использовать один тип, которвй зависит от машины.
Существуют два способа, как могут быть использованы операции сравнения. Операции сравнения могут быть использованы для сравнения кодов условия `(cc0)' с нулем, как в `(eq (cc0) (const_int 0))'. Такая конструкция в действительности ссылается на результат предыдущей инструкции, в которой были установлены коды условий. Инструкция, устанавлвающая код условия должна быть смежна с инструкцией, использующей код условия; их могут разделять только 'note' insn.
Напротив, операция сравнения может непосредственно сравнивать два объекта данных. Тип сравнения определяется операндами; их типы должны восприниматься как совместимые типы. Сравнение двух константных опрерандов некорректно, т.к. нельзя понять их тип, но тпкое выражение не должно появляться в RTL, т.к. оно сразу будет свернуто.
В упомянутом примере, если `(cc0)' был в последний раз установлен как `(compare X Y)', то операция сравнения идентична '(eq X Y)'. Обычно на конктретной машине поддерживается только один стиль сравнений, но проход комбинирования попытается соединить операции для генерации 'eq' в том случае, если это возможно в контексте данного insn.
Неравенства раздпляются на два типа: знаковые и беззнаковые. Таким образом, существуют различные коды выражений `gt' и `gtu' для знаковх и беззнаковых "больше". Они могут выдавать различные результаты для одинаковых пар целых чисел: например 1 знаково больше чем -1, но не беззнаково больше. Действительно, -1, когда рассматривается беззнаково есть `0xffffffff', что больше 1.
Знаковое сравнение используется также для плавающей точки. Вешественные сравнения различаются по типу операндов.
1 если значения X и Y равны, иначе 0.
1 если значения, представленные X и Y не равны, иначе 0.
1 если X больше Y. Если X и Y - числа с фиксированной точкой то сравнение выполняется с учетом знака .
Аналогично `gt' но на числах с фиксированной точкой сравнение беззнаковое.
Подобно `gt' и `gtu' но только для 'меньше'.
Подобно `gt' и `gtu' но проверяется 'больше или равен'.
Подобно `gt' и `gtu' но проверяется 'меньше или равен'.
Это - не операция сравнения, но перечислена здесь, потому что она всегда используется вместе с операциими сравнения. Точнее, COND - выражение сравнения. Это выражение согласно COND, возвращает значение THEN или значение ELSE.
На большинстве машин, выражения ` if_then_else ' корректны только, чтобы выразить условные переходы.
Аналогично 'if_then_else', но более обще. Каждый из TEST1, TEST2,... выполняется в свою очередь. Результат этого выражения - VALUE, соответствующее первому тесту отличному от нуля, или DEFAULT, если все тесты ноль.
Пока для образцов инструкций это еще некорректно и поддерживается только для insn атрибутов. см. Атрибуты Insn
Существуют специальные выражения для представления конструкций, т.е. они использующих битовые поля. Эти выражения в RTL являются lvalue - они могут стоять в левой части присвоения, означая размещения результатов в указанные битовые поля.
Это выражение представляет ссылку на знако-расширенное битовое поле, содержащиеся или начинающиеся в LOC (ячейка памяти или регистр). Битовое поле имеет ширину, равную SIZE, и начинается с бита POS. Опция трансляции `BITS_BIG_ENDIAN' говорит, с какого конца модуля памяти отсчитывается POS.
Если LOC находится в памяти, то этот тип должен быть типом однобайтного целого. Если же LOC - регистр, то используемый тип определяется с помощью операнда образца 'insv' или `extv' (см. Стандартные имена), и обычно это целый тип, занимающий слово.
Тип POS является машинно-зависимым и так же определяется в образце `insv' или `extv'.
Тип M такой же, какой должен был бы использоваться для LOC если бы это был регистр.
Как `sign_extract', но ссылается на беззнаковое или нуль-расширенное битовое поле. Извлекается та же самая последовательность битов, но она заполняет целое слово с нулями вместо знако-расширения.
Все преобразования типов должны быть представлены явными операциями преобразования. Например, выражение, которое является суммой байта и слова не может быть описана следующим образом: `(plus:SI(reg:QI 34) (reg:SI 80))' потому что операция 'plus' требует, что бы операнды имели одинаковый тип. Поэтому байтовый операнд включен в операцию преобразования как:
(plus:SI (sign_extend:SI (reg:QI 34)) (reg:SI 80))
Операция преобразования не просто 'placeholder', т.к. существует
более одного способа преобразования данного типа в конечный. Операция
преобразования указывает на то, как это делать.
Для всех опрераций преобразования X не должен иметь тип `VOIDmode', т.к. целевой режим в преобразовании должен быть известен. Преобразования должно быть сделано во время компиляции, или X должен быть помещен в регистр.
Представляет результат знакового расширения значения X до типа М. M должен быть типом с фиксированной точкой, а Х невешественным (с фиксированной точкой) значением с типом, более узким, чем M.
Представляет результат расширения нулем значения X до типа М. M должен быть типом с фиксированной точкой, а Х невешественным (с фиксированной точкой) значением с типом, более узким, чем M.
Представляет результат распространения значения X до типа М. M должен быть типом с плавающей точкой, а Х вешественным значением с типом, более узким, чем M.
Представляет результат усечения значения X до типа М. M должен быть типом с фиксированной точкой, а Х невешественным (с фиксированной точкой) значением с типом, более узким, чем M.
Представляет результат усечения значения X до типа М. M должен быть типом с плавающей точкой, а Х вешественным значением с типом, более узким, чем M.
Представляет результат перевода невешественного значения X, взятого как знаковое, в вешественный (с плавающей точкой) тип М.
Представляет результат перевода невешественного значения X, взятого как беззнаковое, в вешественный (с плавающей точкой) тип М.
Если M - невещественный тип, то представляет результат перевода вешественного значения Х, взятого как знаковое в тип M. Как происходит округление не определено, поэтому эта операция может быть корректно использована в коде компиляции С только для заведомо челых аргументов.
Если M - невещественный тип, то представляет результат перевода вешественного значения Х, взятого как беззнаковое в тип M. Как происходит округление не определено.
Если М - вещественный тип, то представляет результат преобазования вещественного значения Х (корректного в режиме М) к целому, оставаясь при этом вешественным значением с типом М. Округление происходит в сторону 0.
Выражения объявлений не представляют собой арифметические операции, но устанавливают утверждения относительно операндов:
Этот код выражения используется только в одном контексте: как операнд адресата выражения `set'. Кроме того, операнд этого выражения должен быть не-парадоксальным выражением `subreg '.
Присутствие " strict_low_part " говорит о том, что часть регистра, значимая в типе N (но не значимая в типе M) не может быть изменена. Обычно, назначение в такой 'subreg' может иметь неопределенное действие на остальную часть регистра, если тип М меньше чем слово.
Если M - невещественный тип, то представляет результат перевода вещественного значения Х, взятого как знаковое в тип M. Как происходит округление не определено, поэтому эта операция может быть корректно использована в коде компиляции С только для заведомо целых аргументов.
Если M - невещественный тип, то представляет результат перевода вещественного значения Х, взятого как беззнаковое в тип M. Как происходит округление не определено.
Если М - вещественный тип, то представляет результат преобразования вещественного значения Х (корректного в режиме М) к целому, оставаясь при этом вещественным значением с типом М. Округление происходит в сторону 0.
Коды выражения, описанные до сих пор, представляют значения, а не действия. Но машинные команды никогда не производят значения; они значимы только из-за их побочных эффектов на состоянии машины. Специальные коды выражения используются, чтобы представить побочные эффекты.
Тело команды - всегда один из этих кодов побочного эффекта; коды, описанные выше, которые представляют значения, появляются только как операнды этих.
Представляет действие сохранения значения X в место, представленное LVAL. LVAL должно быть выражением, представляющим место, в которое можно производить сохранение: " reg " (или " subreg " или " strict_low_part "), " mem ", " pc " или " cc0 ".
Если LVAL - " reg ", " subreg " или " mem ", оно имеет машинный тип; тогда X должен подходить для этого типа.
Если LVAL - " reg ", чей машинный тип меньше, чем полная ширина регистра, то это означает, что части регистра, определяемой машинным типом, присваивается указанное значение, а остатку регистра присваивается неопределенное значение. Аналогично, если LVAL - " subreg ", чей машинный тип меньше, чем тип регистра, то остальная часть регистра может измениться произвольным образом.
Если LVAL - " strict_low_part " для " subreg ", то части регистра, определенной машинным типом " subreg ", присваивается значение X, а остальная часть регистра не изменяется.
Если LVAL - " (cc0) ", оно не имеет машинного типа, и X может быть выражением " compare " или значением, которое может иметь любой тип. Последний случай представляет команду " test ". Выражение " (set (cc0) (reg:M N)) " эквивалентно выражению " (set (cc0) (compare (reg:M N) (const_int 0))) ". Используйте вышеупомянутое выражение, чтобы зарезервировать память во время трансляции.
Если LVAL - " (pc) ", мы имеем команду перехода, и возможности для X весьма ограничены. Это может быть выражение " label_ref " (безусловный переход). Это может быть " if_then_else " (условный переход), в этом случае второй или третий операнд должен быть " (pc) " (для случая, когда нет перехода), а другой из них должен быть " label_ref " (для случая, когда есть переход). X может также быть " mem " или " (plus: SI (pc) Y) ", где Y может быть " reg " или " mem "; эти необычные варианты используются для осуществления переходов через таблицы ветвлений.
Если LVAL не является ни " (cc0) ", ни " (pc) ", то тип LVAL должен не быть " VOIDmode " и тип X должен подходить для типа LVAL.
К LVAL обычно обращаются макрокомандой " SET_DEST ", а к X - макрокомандой " SET_SRC ".
Единственное выражение в образце, представляющее возврат из текущей функции, на машинах, где это может быть выполнено одной командой, типа Vaxes. На машинах, где для возвращения из функции должен быть выполнен многокомандный "эпилог" , возврат выполняется переходом к метке, которая предшествует эпилогу, и код выражения " return " никогда не используется.
Внутри выражения " if_then_else " представляет значение, которое должно быть помещено в " pc " для возврата в вызывающую функцию.
Обратите внимание, что образец insn " (return) " логически эквивалентен " (set (pc) (return)) ", но последняя форма никогда не используется.
Представляет обращение к функции. FUNCTION - выражение " mem ", чей адрес - адрес функции, которую нужно вызвать. NARGS - выражение, которое может использоваться для двух целей: на некоторых машинах оно представляет число байтов параметров в стеке; на других, оно представляет число регистров с параметрами.
Каждая машина имеет стандартный машинный тип, который должна иметь FUNCTION. Машинное описание определяет макрокоманду " FUNCTION_MODE ", преобразующуюся в необходимое имя типа. Цель этого типа - указать доступные виды адресации на машинах, где доступные виды адресации зависят от машинного типа.
Представляет сохранение или возможное сохранение непредсказуемого, неописанного значения в X, который должен быть выражением " reg ", " scratch " или " mem ".
Одно из мест, где это используется - в строковых командах, которые сохраняют стандартные значения в некоторые аппаратные регистры. Описывать сохраняемые значения не очень-то необходимо, но важно сообщить транслятору, что регистры будут изменены, чтобы это он не пытался хранить данные в них во время исполнения строковой команды.
Если X - " (mem: BLK(const_int 0)) ", это означает что всю память следует предполагать изменяемой во время вызова.
Обратите внимание, что машинное описание классифицирует определенные аппаратные регистры как "call-clobbered". Все вызовы функций считаются по умолчанию использующими эти регистры, так что не нужно использовать выражения " clobber ", чтобы указать этот факт. Также предполагается, что каждый вызов функции может изменить любую область памяти, если функция не объявлена " const ".
Если в последней группе выражений в " parallel " каждое является выражением " clobber ", с параметрами-выражениями " reg " или " match_scratch " (* См.: RTL Шаблон::.), при комбинировании могут добавляться соответствующие выражения " clobber " к создаваемому insn, если это потребуется для согласования.
Эта особенность может использоваться, например, на машине, которая имеет команды сложения и умножения, не использующие регистр MQ, но которая имеет команду добавления, которая задействует MQ регистр. Аналогично, скомбинированная команда могла бы требовать временный регистр, а ее составные части - нет.
Когда выражение " clobber " для регистра появляется внутри a " parallel " с другими побочными эффектами, распределитель регистров гарантирует, что регистр является незанятым, и до, и после этого insn. Однако, фаза перезагрузки может распределять регистр, используемый для одного из вводов, если для выбранного варианта не указано ограничение " & " (* См.: Модификаторы::.). Вы можете применять " clobber " для аппаратного регистр, псевдорегистра или выражения " scratch "; в последних двух случаях, GNU CC распределит доступный там аппаратный регистр для временного использования.
Для команд, которые требуют временного регистра, Вы должны использовать " scratch " вместо псевдорегистра, потому что это позволит фаза комбинирования добавить " clobber " когда требуется. Это делается кодированием (" clobber " (" match_scratch " ...)). Если Вы используете " clobber " для псевдорегистра, используйте тот, который больше нигде не появляется и генерируйте каждый раз новый. Иначе могут смешаться CSE.
Имеется другое известное использование затирания псевдорегистра в " parallel ": когда один из входных операндов insn также затирается insn. В этом случае, использование одного и того же псевдорегистра для затирания и в другом месте в insn приводит к ожидаемым результатам.
Представляет использование значения X. Это указывает, что значение X в этой точке программы необходимо, даже если это может быть неочевидно. Следовательно, транслятор не будет пытаться удалять предыдущие команды, которые приводят только к сохранению значения X. X, должен быть выражением " reg ".
В течение фазы планирования отсроченных переходов X может быть insn. Это указывает, что X предварительно был размещен в этом месте кода и зависимость его данных должна быть принята во внимание. Эти " use " insns будут удалено перед окончанием фазы планирования отсроченных переходов.
Представляет несколько побочных эффектов, выполняемых параллельно. Квадратные скобки обозначают вектор; операнд " parallel " является вектором из выражений. X0, X1 и так далее - индивидуальные выражения с побочным эффектом - выражения кода " set ", " call ", " return ", " clobber " или " use ".
" In parallel " означает что сначала все значения, используемые в Индивидуальные побочные эффекты вычислены, и секунда весь фактический Побочные эффекты выполняются. Например,
(parallel [(set (reg: SI 1) (mem: SI (reg: SI 1)))
(set (mem: SI (reg: SI 1)) (reg: SI 1))])
недвусмысленно говорит, что значения аппаратного регистра 1 и
области памяти, адресованной им, обмениваются местами. В обоих местах,
где " (reg: SI 1) " появляется как адрес памяти, это относится к
значению в регистре 1 *перед* выполнением insn.
Из этого следует, что *неправильно* использовать " parallel " и ожидать, что результат одного " set " будет доступен для следующего. Например, команду "перейти, если ноль" иногда пытаются представлять так:
(parallel [(set (cc0) (reg: SI 34))
(set (PC) (if_then_else
(eq (cc0) (const_int 0))
(label_ref ...)
(pc)))])
Но это неправильно, потому что такой код говорит, что условие перехода
зависит от значения кода условия *перед* этой командой, а не от
нового значения, которое устанавливается этой командой.
Решетчатая оптимизация, которая происходит вместе с заключительным выводом ассемблерного кода, может производить insns, чьи образцы состоят из " parallel ", элементы которых - операнды, необходимые для вывода возникающего в результате ассемблерного кода - часто " reg ", " mem " или константные выражения. Это не был бы правильно построенный RTL в любой другой стадии трансляции, но в этом случае все нормально, потому что в дальнейшем никакой оптимизации не производится. Однако, определение макрокоманды " NOTICE_UPDATE_CC ", если оно имеется, должно иметь дело с такими insns если Вы определяете какую-либо решетчатую оптимизацию.
Представляет последовательность insns. Каждое из INSNS, которое появляется в векторе, подходит для появления в цепочке insns, так что оно должно быть " insn ", " jump_insn ", " call_insn ", " code_label ", " barrier " или " note ".
" sequence " RTX никогда не помещается в фактический insn во время генерации RTL. Оно представляет последовательность insns, которые получаются " define_expand " *прежде*, чем те insns передаются " emit_insn " для вставки их в цепочку insns. При фактической вставке отдельные sub-insns выделяются и " sequence " исчезает.
После того, как планирование слотов задержки завершено, insn и весь insns, которые находятся в слотах задержки группируются вместе в " sequence ". Insn требует слот задержки первым insn в векторе; последующий insns должны быть помещены в слот задержки.
" INSN_ANNULLED_BRANCH_P " устанавливается на insn в слоте задержки, чтобы указать, что insn перехода должен использоваться, что будет условно аннулировать эффект insns в слотах задержки. В таком случае, " INSN_FROM_TARGET_P " указывает, что insn - из адреса перехода и должен выполняться только, если переход происходит; иначе insn должен выполняться только, если переход не происходит. * См.: Слоты Задержки::.
Эти коды выражения появляются вместо побочного эффекта, как тело insn, хотя, строго говоря, они не всегда описывают побочные эффекты как таковые:
Представляет литеральный код ассемблера с помощью строки S.
Представляет машинно-специфическую операцию над OPERANDS. INDEX задает машинно-специфическую операцию. " unspec_volatile " используется для volatile операций и операций, которые могут захватывать; " unspec " используется для остальных операций.
Эти коды могут появляться внутри " pattern " insn, внутри " parallel " или внутри выражения.
Представляет таблицу адресов перехода. Векторные элементы LR0,LR1 и т.д., являются выражениями " label_ref ". Тип M определяет, сколько места выделяется каждому адресу; обычно M должен быть " Pmode ".
Представляет таблицу адресов перехода, выраженных как смещения от BASE. Векторные элементы LR0,LR1 и т.д. являются выражениями " label_ref ", и BASE тоже.Режим M определяет, сколько места выделяется каждому адресу.
Четыре специальных кода выражения побочного эффекта появляются как адреса памяти.
Представляет побочный эффект уменьшения X на стандартное число, а также значение, которое X имеет после уменьшения. X должен быть " reg " или " mem ", но большинство машин позволяет только " reg ". М должен быть машинным типом для указателей,используемым на машине. Число, на которое уменьшается X - длина в байтах машинного типа ссылки памяти, для которой это выражение служит адресом. Вот пример использования:
(mem: DF (pre_dec: SI (reg: SI 39)))
Это означает уменьшение псевдорегистра 39 на длину значения
" DFmode " и использование результата для адресации значения " DFmode ".
Аналогично, происходит не уменьшение, а увеличение X.
Представляет тот же самый побочный эффект, что и " pre_dec ", но другое значение. Значение, представляемое здесь - значение X перед уменршением.
Аналогично, происходит не уменьшение, а увеличение X.
Если регистр, используемый как операнд этих выражений, используется для другого адреса в insn, используется первоначальное значение регистра. Использование регистра вне адреса внутри того же самого insn не разрешается, так же, как и использование в выражении с вложенным побочным эффектом, потому что такие insns ведут себя по-разному на разных машинах и, следовательно, должны обрабатываться неоднозначно и запрещаются.
Команду, которая может быть представлена при помощи вложенного побочного эффекта, можно также представить, используя " parallel ", содержащий дополнительный " set ", чтобы описать, как изменяется регистр адреса. Это не сделано, потому что машины, которые вообще позволяют эти операции, обычно позволяют их всюду, где запрашивается адрес памяти. Описание их как дополнительных сохранений " parallel " потребовало бы удвоения числа входов в машинном описании.
RTX код " asm_operands " представляет значение, получившееся из определенной пользователем команды ассемблера. Это используется для представления операторов " asm " с параметрами. Операторы " asm " с одиночным операндом вывода, типа этого:
asm ("foo %1, %2, %0" : "=a" (outputvar): "g" (x + y), "di" (*z));
представляются с использованием одиночного " asm_operands " RTX, который
представляет значение, которое сохранено в " outputvar ":
(set RTX-FOR-OUTPUTVAR
(asm_operands "foo %1, %2, %0" "a" 0
[RTX-FOR-ADDITION-RESULT RTX-FOR-*Z]
[(asm_input: M1 "g")
(asm_input: M2 "di")]))
Здесь операнды " asm_operands " RTX - шаблон ассемблерной
строки, ограничение выходного операнда, индексный номер выходного операнда
среди указанных выходных операндов, вектор входного операнда
RTX и вектор типов и ограничений входного операнда. Режим
M1 - тип суммы " x+y "; M2 - тип для "*z".
Когда оператор " asm " имеет несколько значений для вывода, его insn имеет несколько таких RTX " set " внутри " parallel ". Каждый " set " содержит " asm_operands "; все они совместно используют один и тот же ассемблерный шаблон и векторы, но каждый содержит ограничение для соответствующего операнда вывода. Они также различаются по индексу операнда вывода, который равен 0, 1, ... для последовательных операндов вывода.
RTL представление кода функции - связанная в две стороны цепочка объектов, называемых "insns". Insns - выражения со специальными кодами, которые не используются ни для какой другой цели. Некоторые insns фактически являются командами; другие представляют таблицы управления для операторов " switch "; другие представляют метки перехода или различных видов описаний.
В дополнение к собственным специфическим данным, каждый insn должен иметь уникальный идентифицирующий номер, который отличает его от всех других insns в текущей функции (после отсроченного планирования перехода копии insn с одинаковыми идентифицирующими номерами могут присутствовать в нескольких местах в функции, но эти копии всегда будут идентичны и будут появляться только внутри " sequence "), и указатели на предыдущий и следующий insn для получения цепочки. Эти три поля занимают одну и ту же позицию в каждом insn, независимо от кода выражения insn. Вообще говоря, к ним можно обращаться при помощи " XEXP " и " XINT ", но вместо них всегда используется три специальных макрокоманды:
Обращается к уникальному идентификатору insn I.
Обращается к указателю цепочки на insn, предшествующий I. Если I - первый insn, это - нулевой указатель.
Обращается к указателю цепочки на insn после I. Если I - последний insn, это - нулевой указатель.
NEXT_INSN (PREV_INSN (INSN)) == INSN
всегда справедливо, и если INSN - не последний insn,
PREV_INSN (NEXT_INSN (INSN)) == INSN
всегда справедливо.
После планирования слотов задержки, некоторые из insns в цепочке могут быть выражениями " sequence ", которые содержат вектор insns. Значение " NEXT_INSN " для всех, кроме последнего, из этих insns - следующий insn в вектор; значение " NEXT_INSN " для последнего insn в векторе - такое же, как и значение " NEXT_INSN " для " sequence ", в котором он содержится. Аналогичные правила соблюдаются для " PREV_INSN ".
Это означает, что вышеупомянутые инварианты - не обязательно истина для insns внутри выражений " sequence ". А именно, если INSN - первый insn в " sequence ", " NEXT_INSN (PREV_INSN (INSN)) " - это insn, содержащий выражение " sequence ", а значение " PREV_INSN( NEXT_INSN (INSN)) " - это insn, являющийся последним в выражении " sequence ". Вы можете использовать эти выражения, чтобы найти выражение " sequence ", содержащее данный insn.
Каждый insn имеет один из следующих шести кодов выражения:
Код выражения " insn " используется для команд, которые не делают переходов и обращений к функциям. Выражения " sequence " всегда содержатся в insns с кодом " insn ", даже если один из их insns делает переход или обращение к функции.
Insns с кодом " insn " имеют четыре дополнительных поля после трех обязательных, перечисленных выше. Эти четыре поля описаны ниже в таблице.
Код выражения " jump_insn " используется для команд, которые могут делать переход (или, более общо, могут содержать выражения " label_ref "). Команда возврата из текущей функции регистрируется как " jump_insn ".
" jump_insn " insns имеют те же самые дополнительные поля, что и " insn " insns, обращение к которым производится таким же образом, и, кроме того, содержат поле " JUMP_LABEL ", которое определяется после окончания оптимизации перехода.
Для простого условного и безусловного перехода это поле содержит " code_label ", к которому этот insn будет производить (возможно, условный) переход. В более сложном переходе, в " JUMP_LABEL " записывается одна из меток, к которым insn обращается; единственый путь для того, чтобы найти остальные - просмотреть все тело insn.
insns возврата рассматриваются как переходы, но так как они не обращаются ни к каким меткам, они имеют ноль в поле " JUMP_LABEL ".
Код выражения " call_insn " используется для команд, которые могут делать обращения к функции. Важно отличать эти команды, потому что они подразумевают, что некоторые регистры и области памяти могут непредсказуемо измениться.
" call_insn " insns имеют те же самые дополнительные поля, что и " insn " insns, обращение к которым производится таким же образом, и, кроме того, содержат поле " CALL_INSN_FUNCTION_USAGE ", который содержит список (цепочка выражений " expr_list "), содержащий " use " и " clobber " выражения, которые обозначают аппаратные регистры, используемые или затираемые вызываемой функцией. Регистр, указанный в " clobber " в этом списке, изменяется *после* выполнения " call_insn ", в то время как регистр в " clobber " в теле " call_insn " затирается прежде, чем insn завершает выполнение. " clobber " выражения в этом списке увеличивают регистры, указанные в " CALL_USED_REGISTERS " (* См.: Основные сведения о регистрах::.).
" code_label " insn представляет метку, на которую возможен переход при помощи insn перехода. Он содержит два специальных поля данных в дополнение к трем стандартным. " CODE_LABEL_NUMBER " используется для содержания " label number ", номер, который однозначно идентифицирует эту метку среди всех меток в трансляции (не только в текущей функции). В конечном счете, метка представляется на ассемблерном выводе как метка ассемблера, обычно в форме " LN ", где N - номер метки.
Когда " code_label " появляется в выражении RTL, оно обычно появляется внутри " label_ref ", которое представляет адрес метки как номер.
Поле " LABEL_NUSES " определяется только после завершения фазы оптимизации перехода и содержит количество ссылок на эту метку в текущей функции.
Барьеры помещаются в поток команд, если управление не может передаваться коду после них. Они помещаются после команды безусловного перехода, чтобы указать, что переходы являются безусловными, и после обращений к функциям " volatile ", которые не возвращаются (например, " exit "). Они не содержат никакую информацию, кроме трех стандартных полей.
" note " insns используются для представления дополнительной отладочной и декларативной информации. Они содержат два нестандартных поля, целое число, к которому обращаются макрокомандой " NOTE_LINE_NUMBER " и строку, к которой обращаются " NOTE_SOURCE_FILE ".
Если " NOTE_LINE_NUMBER " положительно, примечание представляет номер исходной строки, а " NOTE_SOURCE_FILE " - имя исходного файла, содержащего эту строку. Эти примечания управляют генерацией номеров строк в ассемблерном выводе.
В противном случае, " NOTE_LINE_NUMBER " не реальный номер строки, а код с одним из следующих значений (а " NOTE_SOURCE_FILE " должен содержать нулевой указатель):
Такие примечания полностью игнорируются. Некоторые проходы транслятора удаляют insns, преобразуя их в примечания этого вида.
Эти типы примечаний указывают позицию начала и конца уровня обзора имен переменных. Они управляют выводом информации об отладке.
Эти типы примечаний указывают позицию начала и конца циклов "while " и " for ". Они позволяют оптимизатору циклов быстро находить циклы.
Появляется в месте цикла, на которое делает переход оператор " continue ".
Это примечание указывает место в цикле, где начинается проверка на выход для тех циклов, в которых проверка на выход продублирована. Эта позиция становится другим виртуальным началом цикла при рассмотрении инвариантов цикла.
Появляется около конца тела функции, непосредственно перед меткой, на которую переходит оператор " return " (на машинах, на которых одиночной команды не достаточно для возврата). Это примечание может быть удалено оптимизацией перехода.
Появляется после каждого обращения к " setjmp " или соответствующей функции.
Вот таблица дополнительных полей " insn ", " jump_insn " и " call_insn " insns:
Этим insn выполняется выражение c побочным эффектом. Это должен быть один из следующих кодов: " set ", " call ", " use ", " clobber ", " return ", " asm_input ", " asm_output ", " addr_vec ", " addr_diff_vec ", " trap_if ", " unspec ", " unspec_volatile ", " parallel " или " sequence ". Если это " parallel ", каждый элемент " parallel " должен быть одним из этих кодов, за исключением того, что " parallel " выражения не могут быть вложены и " addr_vec " и " addr_diff_vec " не разрешаются внутри выражения " parallel ".
Целое число, которое сообщает, какие образцы в машинном описании соответствуют этому insn, или -1, если соответствие еще не устанавливалось.
Такое соответствие никогда не устанавливается и это поле остается -1 для insn, чей образец состоит из одиночного выражения " use ", " clobber ", " asm_input ", " addr_vec " или " addr_diff_vec ".
Соответствие также никогда не устанавливается для insns, которые получаются из операторов " asm ". Они содержат по крайней мере одно выражение " asm_operands ". Функция " asm_noperands " возвращает неотрицательное значение для таких insns.
При отладочном выводе это поле печатается как число с последующим символическим представлением, которое определяет месторасположение образца в " md " файле так некоторое маленькое положительное или отрицательное смещение от указанного образца.
Список (цепочка выражений " insn_list ") предоставляет информацию о зависимостях между командами внутри базисного блока. Между связанным insns не может быть ни перехода, ни метки.
Список (цепочка выражений " expr_list " и " insn_list ") предоставляет различную информацию относительно insn. Часто это информация относительно регистров, используемых в этом insn.
Этот список первоначально устанавливается проходом потокового анализа; до него это нулевой указатель. Потокоый анализ только добавляет связи для тех зависимостей данных, которые могут использоваться для комбинации команд. Для каждого insn проход потокового анализа добавляет связь с insns, которые сохраняют в регистры значения, которые используются впервые в этом insn. проход планирования команд добавляет дополнительные связи так, чтобы каждая зависимость была представлена. Связи представляют зависимости данных, антизависимости и зависимости вывода; машинный тип связи различает эти три типа: антизависимости имеют тип " REG_DEP_ANTI ", зависимости вывода имеют тип " REG_DEP_OUTPUT ", и зависимости данных имеют тип " VOIDmode ".
Поле " REG_NOTES " insn - цепочка, подобная полю " LOG_LINKS ", но оно включает, помимо выражений " insn_list ", выражения " expr_list ". Имеются несколько видов регистровых примечаний, которые различаются машинным типом, который в регистровом примечании действительно понимается как являющийся " enum reg_note ". Первый операнд OP примечания - данные, чья интерпретация зависит от вида примечания.
Макрокоманда " REG_NOTE_KIND (X) " возвращает вид регистрового примечания. Парная к ней макрокоманда " PUT_REG_NOTE_KIND (X, NEWKIND) " устанавливает тип регистрового примечания X в NEWKIND.
Регистровые примечания бывают трех классов: они могут говорить что-либо о вводе в insn, говорить что-либо о выводе insn или создавать связи между двумя insns. Имеется также набор значений, которые используются только в " LOG_LINKS ".
Эти регистровые примечания аннотируют ввод в insn:
Значение в OP умирает в этом insn; то есть изменение значения немедленно после этого insn не воздействовало бы на дальнейшее поведение программы.
Это не обязательно означает, что регистр OP не содержит никакого полезного значения после этого insn, так как это может также быть вывод insn. В таком случае, однако, " REG_DEAD " примечание было бы избыточно и обычно не представляется до окончания прохода перезагрузки, но никакой код не использует этот факт.
Регистр OP увеличивается (или уменьшается; на этом уровне не имеется никакого различия) вложенным побочным эффектом внутри этого insn. Это означает, что он появляется в выражении " post_inc ", " pre_inc ", " post_dec " или " pre_dec ".
Регистр OP имеет неотрицательное значение, когда этот insn достигается. Это используется так, что команды декремента и перехода до нуля, типа m68k dbra, могут быть согласованы.
" REG_NONNEG " примечание добавляется к insns, только если машинное описание имеет образец " decrement_and_branch_until_zero ".
Этот insn не вызывает конфликта между OP и элементом, устанавливаемым этим insn, даже если имеет такую возможность. Другими словами, если регистру-адресату и OP мог бы быть иначе присвоен один и тот же регистр, этот insn не предотвращает этого присваивания.
Insns с этим примечанием - обычно часть блока, который начинается с a " clobber " insn, указывающего псевдорегистр из нескольких слов (который будет выводом блока), группа insns, каждое из которых устанавливает одно слово значения и имеет примечание " REG_NO_CONFLICT ", и заключительное insn, которое копирует вывод к себе с примечанием " REG_EQUAL ", вычисляя выражение. Этот блок инкапсулируется примечаниями " REG_LIBCALL " и " REG_RETVAL " для первого и последнего insns, соответственно.
Этот insn использует OP, " code_label ", но - не " jump_insn ". присутствие этого примечания позволяет оптимизации перехода знать что OP, на самом деле, используется.
Следующие примечания описывают атрибуты выводов insn:
Это примечание имеет силу только для insn, которое устанавливает только один регистр и указывает, что этот регистр будет равен OP во время выполнения; контекст этой эквивалентности различается в зависимости от типа примечаний. Значение, которое insn явно копирует в регистр, может казаться отличным от OP, но они будут равны во время выполнения. Если вывод одиночных " set " является выражением " strict_low_part ", примечание относится к регистру, который содержится в " SUBREG_REG " выражения " subreg ".
Для " REG_EQUIV " регистр эквивалентен OP полностью во всей функции, и все его вхождения можно законно заменить на OP. ("Законно" здесь относится к потоку данных программы; простая замена может делать некоторые insns недопустимыми.) Например, когда константа загружается в регистр, которому больше никогда не присваивается никакое другое значение, используется этот вид примечания.
Когда параметр копируется в псевдорегистр при входе в функцию, примечание этого вида означает, что регистр равен слоту стека, в котором передается параметр. Хотя в этом случае регистр может быть установлен другими insns, по-прежнему возможно заменить регистр слотом стека во время выполнения функции.
В случае " REG_EQUAL ", регистр, который устанавливается этим insn, будет равен OP во время выполнения в конце этого insn, но не обязательно в другом месте в функции. В этом случае OP обычно арифметическое выражение. Например, когда используется последовательность insns типа вызова библиотеки для выполнения арифметической операции, этот вид примечания присоединена к insn, которое производит или копирует значение-результат.
Эти два примечания используются различными способами проходами транслятора. " REG_EQUAL " используется проходами до распределения регистров (такими, как общее удаление подвыражений и оптимизация цикла), чтобы сообщить им, как думать об этом значении. " REG_EQUIV " примечания используются во время распределения регистров, чтобы указать, что имеется доступное выражение замены (или константное или " mem " выражение для расположения параметра на стеке), которое может использоваться вместо регистра, если доступно недостаточное количество регистров.
Кроме расположения параметров в стеке, которое указывается примечанием " REG_EQUIV " и не используется при проходах ранней оптимизации и псевдорегистров, которые являются эквивалентными ячейке памяти в течение всего времени своего существования, которые пока не обнаружены при трансляции, все эквивалентности первоначально обозначаются примечанием " REG_EQUAL ". На ранних стадиях распределения регистров примечание " REG_EQUAL " изменяется на примечание " REG_EQUIV ", если OP - константа, и insn представляет единственый набор его регистров назначения.
Таким образом, проходы транслятора до распределения регистров должны проверять только примечания " REG_EQUAL ", а проходы, следующие после распределения регистров, должны проверять только примечания " REG_EQUIV ".
Регистр OP, устанавливаемый этим insn, не будет использоваться в последующих insn. Это отличается от примечания " REG_DEAD ", которое указывает, что значение во вводе не будет использоваться впоследствии. Эти два примечания независимы и могут оба присутствовать для одного и того же регистра.
Одиночный вывод этого insn, содержащий ноль перед этим insn. OP - insn, устанавливающий его в ноль. Вы можете полагаться на это примечание, если оно присутствует и OP не был удален или превращен в примечание ; его отсутствие не подразумевает ничего.
Этот insn копирует значение последовательности из многих insn (например, вызова библиотеки), и OP - первый insn последовательности (для вызова библиотеки - первый insn, который был сгенерирован для установки параметров вызова библиотеки).
Оптимизация циклов использует это примечание для обработки такой последовательности, как одиночная операция для перемещения кода, а потоковый анализ использует это примечание, чтобы удалить последовательности, результаты которых "мертвы".
Примечание" REG_EQUAL " будет также обычно присоединяться к этому insn для обеспечения выражения, вычисляемого последовательностью.
Это - инверсия " REG_RETVAL ": оно помещается в первый insn последовательности из многих insn и указывает на последний.
На машинах, которые используют " cc0 ", insns, которые устанавливают и используют " cc0 ", установка и использование " cc0 " являются смежными. Однако по окончании заполнения слотов задержки перехода это уже может не быть так. В этом случае примечание " REG_CC_USER " будет помещено в insn, устанавливающий " cc0 ", для указания insn, использующего " cc0 ", а примечание " REG_CC_SETTER " будет помещено в insn, использующий " cc0 ", для указания insn, устанавливающего " cc0 ".
Указывает антизависимость (типа зависимости запись после чтения).
Указывает зависимость вывода (типа зависимости запись после записи).
Единственое различие между кодами выражения " insn_list " и " expr_list " - то, что первый операнд " insn_list " считается insn и печатается в отладочных дампах как уникальный идентификатор insn; первый операнд " expr_list " печатается обычным способом как выражение.
Insns, которые вызывают подпрограммы, имеют код выражения RTL " call_insn ". Эти insns должен удовлетворять специальным правилам, и их тела должны использовать специальный код выражения RTL, " call ".
Выражение " call " имеет два операнда, а именно:
(call (mem: FM ADDR) NBYTES)
NBYTES - операнд, который представляет число байтов
данных параметров, передаваемых подпрограмме, FM - машинный тип
(который должен совпадать с определением макрокоманды " FUNCTION_MODE " в
машинном описании), а ADDR представляет адрес подпрограммы.
Для подпрограммы, которая не возвращает значения, выражение " call ", как показано выше, есть все тело insn, за исключением того, что insn может также содержать выражения " use " или " clobber ".
Для подпрограммы, которая возвращает значение, чей тип - не " BLKmode ", значение возвращается в аппаратном регистре. Если номер этого регистра R, то тело insn вызова выглядит примерно так:
(set (reg: M R)
(call (mem: FM ADDR) NBYTES))
Это выражение RTL поясняет (проходам оптимизатора), что
соответствуюему регистру присваивается полезное значение в этом insn.
Когда подпрограмма возвращает значение " BLKmode ", это обрабатывается путем передачи подпрограмме адреса места, в которое следует записать значение. Так что само insn вызова не " возвращает " никакого значения и имеет тот же самый вид RTL, как и вызов, который не возвращает ничего.
На некоторых машинах команда вызова непосредственно задействует некоторые регистры, например для хранения адреса возврата. " call_insn " insns на этих машинах должны иметь тело, которое является " parallel ", содержащим как выражение " call ", так и выражения " clobber ", которые указывают, значения каких регистров теряются. Аналогично, если команде вызова необходим некоторый регистр, отличный от указателя стека, который не упомянут явно в его RTL, он должен быть упомянут в подвыражении " use ".
Предполагается, что вызываемые функции изменяют все регистры, перечисленные в макрокоманде конфигурации " CALL_USED_REGISTERS " (* См.: Основные сведения о регистрах::.) и, за исключением функций " const " и библиотеки вызовов, изменяют всю память.
Insns, содержащие только выражения " use ", непосредственно предшествуют " call_insn " insn, чтобы указать, какие регистры содержат входные данные для функции. Аналогично, если регистры, отличные от указанных в " CALL_USED_REGISTERS ", затираются вызываемой функцией, insns содержащие одиночный " clobber ", следуют немедленно после вызова, чтобы указать такие регистры.
Транслятор считает, что некоторые виды выражений RTL уникальны; не существует двух различных объектов, представляющих одно и то же значение. В других случаях он делает противоположное предположение: никакой объект RTL выражения определенного вида не появляется более чем в одном месте в объемлющей структуре.
Эти предположения относятся к одиночной функции; кроме RTL объектов, которые описывают глобальные переменные и внешние функции, и нескольких стандартных объектов типа маленьких целочисленных констант, никакие объекты RTL не являются общими для двух функций.
Чтобы читать объект RTL из файла, вызовите " read_rtx ". Ему требуется один параметр, поток стандартного ввода, а возвращает он один объект RTL.
Чтение RTL из файла происходит очень медленно. Это не проблема в настоящее время, поскольку чтение RTL происходит только как часть формирования транслятора.
Люди часто представляют использование RTL, сохраненного как текст в файле, как интерфейс между внешним интерфейсом языка и большей частью GNU CC. Эта идея не выполнима.
GNU CC был разработан, чтобы использовать RTL только внутренне. Корректный RTL для данной программы очень сильно зависит от конкретной целевой машины. И RTL не содержит всей информации о программе.
Соответствующий способ связывать с помощью интерфейса GNU CC на новый внешний интерфейс языка Со структурой данных "дерева". Не имеется никакого руководства для этой структуры данных, но она описана в файлах " tree.h " и " tree.def ".
Машинное описание имеет две части: файл образцов команд ( ".md" файл) и файл заголовка C макроопределений.
".md" файл для целевой машины содержит образец для каждой команды, поддерживаемой целевой машиной (или, по крайней мере, для каждой команда, о которой стоит сообщать транслятору). Он может также содержать комментарии. Часть строки после точки с запятой является комментарием, если точка с запятой не находится внутри строки, ограниченной кавычками.
См. следующую главу для информации о файле заголовка C.
Каждый образец команды содержит незавершенное выражение RTL, с частями, которые будут заполнены позже, ограничениями на операнды, которые говорят,как могут быть заполнены эти части, и образец вывода или C код, чтобы сгенерировать вывод ассемблера, который полностью выполняется в выражении " define_insn ".
" define_insn " является выражением RTL, содержащим четыре или пять операндов:
Вот фактический пример образца команды для 68000/68020.
(define_insn "tstsi"
[(set (cc0)
(Match_operand: SI 0 "general_operand" "rm"))]
""
" *
{ if (TARGET_68020 || ! ADDRESS_REG_P (operands [0]))
return \"tstl %0\";
return \"cmpl *0, %0\"; }")
Это - команда, которая устанавливает условные коды, основанные на
значении общего операнда. Оно не имеет условия, так что любой insn, чье RTL
описание имеет указанную форму, может быть обработан согласно этому
образцу. Имя "tstsi" означает " test a 'SImode' value" и сообщает
проходу генерации RTL, что, когда необходимо проверить такое значение,
insn для того, чтобы сделать это, можно создать, используя этот образец.
Строка управления выводом - C код, который выбирает шаблон вывода для возврата, основываясь на виде операнда и специфическом типе процессора, для которого генерируется код.
` "rm" ' является ограничением операнда. Его значение объясняется ниже.
RTL шаблон используется, чтобы определить, какие insns соответствуют конкретному образцу и как найти их операнды. Для названных образцов, RTL шаблон также показывает, как создать insn из данных операндов.
Конструкция включает замену определенных операндов в копию шаблона. Соответствие включает определение значений, которые служат как операнды в согласовываемом insn. Оба из этих действий управляются специальными типами выражения, которые руководят соответствием и заменой операндов.
Это выражение - placeholder для операнда insn с номером N. При построении insn в этом месте операнд с номером N будет заменяться. При поиске соответствия insn-у, что угодно, появляющееся в этой позиции insn, будет приниматься как операнд номер N; но оно должно удовлетворять PREDICATE, или этот образец команды не будет соответствовать вообще.
Номера операндов должны быть выбраны, последовательно считая от нуля для каждого образца команды. Для каждого номера операнда в образце может иметься только одно выражение `match_operand'. Обычно операнды пронумерованы в порядке появления в выражениях `match_operand'.
PREDICATE - строка, которая является именем С-функции с двумя аргументами: выражение и машинный режим. В течение соответствия, функция будет вызываться с мнимым операндом как параметр выражения, и M как параметр режима (если M не определен, будет использоваться режим 'VOIDmode', который обычно заставляет предикат принимать любой режим). Если возвращается ноль, то эти образцы команды не подходят для соответствия. PREDICATE может быть пустой строкой, это означает, что над операндом не надо выполнять никакого теста, и корректным является любое выражение, стоящее в этой позиции.
Почти всегда PREDICATE отклонит режимы, отличные от M, но не совсем. Например, предикат 'address_operand' использует M как режим памяти, касательно которой адрес должен быть корректен. Многие предикаты принимают 'const_int', даже если их режим - 'VOIDmode' .
CONSTRAINT управляет перезагрузкой и выбором наилучшего класса регистров для хранения значений. ( Подробнее это будет объяснено ниже (см. ограничения::.) ).
Людям часто не ясны различия между ограничениями и предикатами. Предикат помогает решить, соответствует ли данный insn образцу. Ограничения не играют никакой роли в этом решении, но они управляют дальнейшими решениями в случае, когда insn соответствует.
На CISC машинах, наиболее распространенный PREDICATE - это 'general_operand'. Эта функция проверяет является ли мнимый операнд константой, регистром или ячейкой памяти, и корректен ли операнд для режима M.
Для операнда, который должен быть регистром, PREDICATE должен быть 'register_operand'. Возможно так же использование предиката 'general_operand', так как проход перезагрузки копирует любые операнды не-регистры через регистры, но это заставляло бы делать GNU CC дополнительную работу, и предотвращало бы инвариантные операнды (типа константы) от удаления из циклов, и помешало бы регистру allocator выполнять работу наилучшем способом. На RISC машинах, обычно наиболее эффективно позволить PREDICATE пропускать только те объекты, которые позволяют ограничения.
Для операнда, который должен быть константой, Вы должны убедиться, что либо Вы использовали 'immediate_operand' для PREDICATE, либо сделали дополнительное условие образца команды требующее константу, или и то и другое. Одних ограничений может быть недостаточно! Если ограничения разрешают только константы, а предикат позволяет что-то еще, то при возникновении такой ситуации транслятор разрушится.
Это выражение - также placeholder для операнда с номером N и указывает, что операнд должен быть выражением 'scratch' или `reg' .
При соответствии образцов, это эквивалентно
(match_operand:M N "scratch_operand" PRED)
Но, при генерации RTL, это дает выражение ( 'scratch': M ).
Если последние несколько выражения в 'parallel' являются выражениями `clobber', чьи операнды являются либо аппаратным регистром либо 'match_scratch', комбайнер может добавлять или удалять их когда необходимо.
Это выражение - также placeholder для операнда с номером N, оно используется, когда операнд должен появиться в insn больше чем один раз.
При конструировании, 'match_dup' действует точно так же как 'match_operand': в создаваемом insn заменяется операнд. Но в соответствии, 'match_dup' ведет себя по-другому - он принимает, что операнд номер N уже был определен ранее с помощью 'match_operand' в шаблоне распознавания, и он соответствует только идентично выглядящему выражению.
Этот образец - разновидность placeholder для переменного кода выражения RTL.
При построении insn, это заменяется на RTL выражение, чей код выражения взят из такового операнда N, и чьи операнды созданы из образцов OPERANDS.
При поиске соответствия, это соответствует выражению, если функция PREDICATE возвращает не ноль на это выражение *и* образцы OPERANDS соответствуют операндам выражения.
Предположим, что функция 'commutative_operator' определена следующим образом: соответствует любому выражению, чей оператор - один из коммутативных арифметических операторов RTL и чей режим - MODE:
int
commutative_operator (x, mode)
rtx x;
enum machine_mode mode;
{
enum rtx_code code = GET_CODE (x);
if (GET_MODE (x) != mode)
return 0;
return (GET_RTX_CLASS (code) == 'c'
|| code == EQ || code == NE);
}
Тогда следующий образец будет соответствовать любому выражению RTL,
состоящему из коммутативного оператора, примененного к двум общим
операндам:
(match_operator:SI 3 "commutative_operator"
[(match_operand:SI 1 "general_operand" "g")
(match_operand:SI 2 "general_operand" "g")])
Здесь вектор `[OPERANDS...]' содержат два образца, потому что все
выражения, которым нужно найти соответствия, содержат два операнда.
Когда этот образец соответствует, два операнда коммутативного оператора регистрируются как операнды 1 и 2 из insn. (Это выполнено двумя 'match_operand'-ами.) Операнд 3 из insn будет полностью коммутативным выражением: используйте 'GET_CODE (операнды [3]) чтобы видеть, какой коммутативный оператор был использован.
Тип M 'match_operator'-а работает аналогично типу 'match_operand'-а: он передается как второй параметр к функции предиката, и эта функция полностью ответственна за решение, имеет ли выражение, которое будет согласовано, этот тип.
При построении insn, третий параметр gen-функции определит операцию (то есть код выражения) для выражения, которое будет сделано. Это должно быть выражение RTL, чей код выражения скопирован в новое выражение и чьи операнды - параметры 1 и 2 gen-функции. Подвыражения параметра 3 не используются; имеет значение только его код выражения.
Когда 'match_operator' используется в образце для соответствия insn, то обычно лучше всего, если номер операнда 'match_operator' выше чем номера фактических операндов insn. Это улучшает распределение регистров, потому что allocator регистров часто рассматривает операнды 1 и 2 из insns, чтобы узнать, может ли он связать эти регистры.
Не существует способа определить ограничения в 'match_operator' . Операнд insn, который соответствует match_operator' никогда не имеет никаких ограничений, потому что он никогда не перезагружается как целое. Однако, если части его OPERANDS соответствуют 'match_operand' образцам, эти части могут иметь ограничения на них самих.
Подобен 'match_dup', за исключением того, что применяется к операторам вместо операндов. При построении insn, операнд номер N на этом месте будет заменяться. Но в соответствии, 'match_op_dup' ведет себя по-другому. Он принимает, что операнд номер N уже был определен 'match_operator'-ом, появляющимся в шаблоне распознавания ранее, и он соответствует только идентично выглядящему выражению.
Этот образец - placeholder для insn, который состоит из выражения `parallel' с переменным числом элементов. Это выражение может появиться только на верхнем уровне insn образца.
При построении insn, операнд номер N будет заменяться на этом месте. При соответствии insn, это соответствует, если тело insn - выражение `parallel' с по крайней мере таким количеством элементов, как вектор выражений SUBPAT в 'match_parallel' , если каждый SUBPAT соответствует соответствующему элементу 'parallel', *и* функция PREDICATE возвращает не ноль на 'parallel', который является телом insn. За корректность элементов 'parallel', которые не указаны в `match_parallel', несет ответственность предикат.
Обычно `match_parallel' используют, чтобы сравнивать его с многочисленными выражениями чтения и записи, которые могут содержать различное число элементов в 'parallel'. Например:
(define_insn ""
[(match_parallel 0 "load_multiple_operation"
[(set (match_operand:SI 1 "gpc_reg_operand" "=r")
(match_operand:SI 2 "memory_operand" "m"))
(use (reg:SI 179))
(clobber (reg:SI 179))])]
""
"loadm 0,0,%1,%2")
Этот пример взят из 'a29k.md'. Функция 'load_multiple_operations'
определена в 'a29k.c' и проверяет, что последующие элементы в
`parallel' те же, что и `set' в образце, за исключением того, что они
ссылаются на последующие регистры и ячейки памяти.
Insn, который соответствует этому образцу, может выглядеть например так:
(parallel
[(set (reg:SI 20) (mem:SI (reg:SI 100)))
(use (reg:SI 179))
(clobber (reg:SI 179))
(set (reg:SI 21)
(mem:SI (plus:SI (reg:SI 100)
(const_int 4))))
(set (reg:SI 22)
(mem:SI (plus:SI (reg:SI 100)
(const_int 8))))])
Подобно 'match_op_dup', но для 'match_parallel' вместо 'match_operator'.
Этот комплекс выражений - placeholder для операнда номер N в инструкции "загрузки адреса": операнд, который определяет ячейку памяти обычным способом, но для которого фактическое значение операнда есть адрес ячейки, а не ее содержание.
Выражения `address' никогда не появляются в RTL коде, только в машинных описаниях. И они используются только в машинных описаниях, которые не используют особенности ограничения операнда. Когда ограничения операнда используются, символ 'p' в ограничении служит этой цели.
M - тип *адресуемой ячейки памяти*, а не тип адреса. Этот тип всегда один и тот же на данной целевой машине ( 'Pmode' , который обычно является 'SImode'), так что не имеет смысла это упоминать; таким образом, в выражении 'address' не написан никакой тип. Если однажды будет добавлена поддержка машин, в которых адреса объектов различного вида появляются по-разному или используются по-разному (типа PDP-10), различные форматы, возможно, будут нуждаться в различных типах, и эти типы должны быть упомянуты в выражении 'address'.
'Шаблон вывода' - это строка, которая определяет, как выводить ассемблерный код для образца команды. Почти весь шаблон - фиксированная строка, которая выводится буквально. Символ '%' используется, чтобы определить место замены операндом; он может также использоваться, чтобы обозначать места, где различные варианты ассемблера требуют различного синтаксиса.
В самом простом случае, '%', а за ним число N указывает, что надо вывести операнд N в этом месте.
'%' после которого стоит символ и цифра говорит, что надо вывести операнд альтернативным способом. Четыре символа имеют стандартные, встроенные значения, описанные ниже. Машинная макрокоманда описания 'PRINT_OPERAND' может определять дополнительные символы с нестандартными значениями.
'%cDIGIT' может использоваться для замены операнда, который является постоянным значением без синтаксиса, который обычно указывает непосредственный операнд.
'%nDIGIT' тоже, что и '%cDIGIT' , но значение константы перед печатью заменяется на минус ее.
'%aDIGIT ' может использоваться, чтобы заменить операнд, так как если бы это была ссылка на ячейку памяти, фактическим операндом, обрабатываемым как адрес. Это может быть полезно, когда выводится инструкция "загрузить адрес", потому что часто синтаксис ассемблера для такой команды требует, чтобы Вы писали операнд, как будто это была бы ячейка память.
'%lDIGIT ' используется, чтобы заменить ' label_ref ' на команду перехода.
'%=' выводит уникальный номер для каждой команды во всей трансляции. Это полезно для создания локальных меток, которые нужно упомянуть в шаблоне больше чем один раз, генерирующем многократные команды ассемблера.
'%' за которым следует символ пунктуации определяет замену, не использующую операнд. Стандартным является только один случай : ' %% ' - выводит в код ассемблера '%' . Другие, нестандартные случаи могут быть определены в макрокоманде 'PRINT_OPERAND' . Вы также должны определить, какие символы пунктуации корректны, в макрокоманде 'PRINT_OPERAND_PUNCT_VALID_P' .
Шаблон может генерировать несколько команд ассемблера. Пишите текст для таких команд, разделяя их ' \; ' .
Когда RTL содержит два операнда, которые из-за ограничения должны соответствовать друг другу, шаблон вывода должен обратиться только к тому операнду, номер которого меньше. Соответствующие операнды не всегда идентичны, и остальная часть транслятора работает так, чтобы поместить соответствующее выражение RTL для печати в операнд с меньшим номером.
Используя нестандартные символы или пунктуацию после '%', нужно проводить различие между различными языками ассемблеров для той же самой машины; например, синтаксисом Motorola и синтаксисом MIT для 68000. Синтаксис Motorola требует точек в большинстве имен кода операции, в то время как MIT синтаксис не требует этого. Например, код операции 'movel' в MIT синтаксисе - 'move.l' в Motorola синтаксисе. Для обоих видов синтаксиса вывода используется один и тот же файл образцов, но в каждом месте, где Motorola синтаксис хочет точку, используется символьная последовательность '%'. Макрокоманда PRINT_OPERAND для Motorola синтаксиса определяет последовательность, чтобы выводить точку; макрокоманда для MIT синтаксиса определяет, что не надо ничего выводить.
Как специальный случай, шаблон, состоящий из одиночного символа '*' дает инструкцию транслятору, чтобы сначала разбить insn, а затем вывести полученные команды по отдельности. Это помогает устранять избыточность в шаблонах вывода. Если Вы имеете 'define_insn' который должен создать несколько команд ассемблера, и имеется уже определенное соответствие - 'define_split' , то Вы можете просто использовать '*' как шаблон вывода, вместо того, чтобы создавать шаблон вывода, генерящий несколько ассемблерных команд.
Если 'ASSEMBLER_DIALECT' определен, Вы можете использовать в шаблонах конструкции типа '{option0 | option1 | option2} '. Они описывают множество вариантов синтаксиса языка ассемблера. см. Вывод команд
Часто одиночная фиксированная строка шаблона не может производить во всех случаях, подходящих под одиночный образец команды, правильный и эффективный код ассемблера. Например, коды операции могут зависеть от вида операндов; или некоторые неудачные комбинации операндов могут требовать дополнительных машинных команд.
Если строка управления вывода начинается с '@' , то это - ряд шаблонов, каждый на отдельной строке. (Пустые строки, ведущие пробелы и знаки табуляции игнорируются.) Шаблоны соответствуют вариантам ограничения образца (см. Множественные альтернативы). Например, если целевая машина имеет двухадресную команду сложения 'addr' для сложения в регистр и другую 'addm' , чтобы добавить регистр к памяти, то Вы можете использовать этот образец:
(define_insn "addsi3"
[(set (match_operand:SI 0 "general_operand" "=r,m")
(plus:SI (match_operand:SI 1 "general_operand" "0,0")
(match_operand:SI 2 "general_operand" "g,r")))]
""
"@
addr %2,%0
addm %2,%0")
Если строка управления вывода начинается с '*' , то далее идет не шаблон
вывода, а часть программы C, которая должна вычислить шаблон. Она должна
использовать оператор 'return' , чтобы возвратить строку шаблона, которую
Вы хотите. Большинство таких шаблонов использует строчные литералы C,
которые должны быть разграничены символами двойных кавычек. Перед каждым
символом двойных кавычек надо ставить '\' .
Операнды могут быть найдены в массиве 'operands' ,тип данных которого в С- ' rtx [] ' .
Общепринято выбирать различные способы генерирования ассемблерного кода, базирующихся на том, находится ли непосредственный операнд внутри некоторого диапазона. Будьте внимательным при выполнении этого, потому что результат 'INTVAL' на главной машине является целым числом. Если главная машина имеет большее количество битов в 'int' чем целевая машина имеет в типе, в котором константа будет использоваться, то некоторые из битов, которые Вы получаете из 'INTVAL', будут лишними. Для правильных результатов, Вы должны тщательно игнорировать значения этих битов.
Возможно вывести команду ассемблера а затем продолжать выводить или вычислять остальные команды, используя подпрограмму 'output_asm_insn'. Она получает два параметра: строка шаблона и вектор операндов. Вектор может быть 'operands', или это может быть другой массив 'rtx' который Вы объявляете локально и инициализируете самостоятельно.
Когда образец insn имеет несколько вариантов ограничений, часто появление ассемблерного кода определяется в основном тем, какой из вариантов был согласован. Когда это - так, C код может проверять переменную 'which_alternative ', являющуюся порядковым номером варианта, который был согласован первым (0 для первого, 1 для второго варианта, и т.д.).
Например, предположим, что имеются два кода операции для сохранения нуля, 'clrreg ' для регистров и 'clrmem' для ячеек памяти. Ниже приведен пример, как лбразец может использовать 'which_alternative ' для того, чтобы выбрать между ними:
(define_insn ""
[(set (match_operand:SI 0 "general_operand" "=r,m")
(const_int 0))]
""
"*
return (which_alternative == 0
? \"clrreg %0\" : \"clrmem %0\");
")
В вышеприведенном примере ассемблерный код *полностью* определялся
выбранной альтернативой, но он мог быть также определен через
строку управления выводом начинающуюся с '@' следующим образом:
(define_insn ""
[(set (match_operand:SI 0 "general_operand" "=r,m")
(const_int 0))]
""
"@
clrreg %0
clrmem %0")
Каждый 'match_operand' в образце команды может определять ограничение на тип операндов. Ограничения могут указывать, может ли операнд быть в регистре, и в каких видах регистров; может ли операнд быть ячейкой памяти, и каких видов адрес; может ли операнд быть непосредственной константой, и какие возможные значения он может иметь. Ограничения могут также требовать соответствия между двумя операндами.
Самый простой вид ограничения - строка, заполненная символами, каждый из которых описывает один вид разрешенного операнда. Имеются следующие разрешенные символы:
Разрешается операнд памяти с любым видом адреса, который машина вообще поддерживает.
Разрешается операнд памяти только, если адрес - "смещаемый". Это означает, что добавление небольшого целого числа (фактически, ширины операнда в байтах, как определено его типом) может быть добавлено к адресу, и результат - также корректный адрес памяти.
Например, адрес, который является постоянным - смещаемый; поэтому адрес, который является суммой регистра и константы тоже смещаемый (если только небольшое увеличение константы оставляет адрес внутри диапазона, поддерживаемого машиной); но самоувеличивающийся или самоуменьшающийся адрес - не смещаемый. Более сложные косвенные/индексированные адреса могут быть или не быть смещаемыми в зависимости от других способов адресации, которые поддерживает машина.
Обратите внимание на то, что в операнде вывода, который может быть согласован с другим операндом, символ ограничения 'o' корректен только когда сопровождает оба операнда : '<' (если целевая машина имеет увеличение адреса) и '>' (если целевая машина имеет уменьшение адреса).
Не смещаемый операнд памяти. Другими словами, любой операнд, удовлетворяющий 'm' ограничению, но не 'o' ограничению.
Разрешаются операнды памяти с автоматической декрементацией адреса (либо преддекрементацией либо последекрементацией).
Разрешаются операнды памяти с автоматической инкрементацией адреса (либо прединкрементацией либо постинкрементацией).
Разрешается операнд регистра, при условии, что он находится в общем регистре.
Другие символы могут быть определены машинно-зависимым способом вместо конкретных классов регистров. 'D' , 'a' и 'f' определены на 68000/68020, для регистров данных, регистров адреса и регистров с плавающей точкой соответственно.
Разрешается непосредственный целочисленный операнд (с постоянным значением). Сюда так же включаются символьные константы, чьи значения будут известны только во время трансляции.
Разрешается непосредственный целочисленный операнд с известным числовым значением . Большинство систем не поддерживают константы, созданные во время трансляции, для операндов, меньших чем слово. Ограничения для этих операндов должны использовать скорее 'n' чем 'i' .
Другие символы в диапазоне от 'I' до 'P' могут быть определены машинно-зависимым способом для разрешения непосредственных целочисленных операндов с явными целочисленными значениями в определенных диапазонах. Например, на 68000, 'I' определен для диапазона значений от 1 до 8. Это диапазон, разрешенный для размера сдвига в командах сдвига.
Разрешен непосредственный операнд с плавающей точкой (код выражения 'const_double' ), но только, если формат типа с плавающей точкой на целевой машине совпадает с соответствующим форматом на главной машине.
Разрешается непосредственный операнд с плавающей точкой (код выражения 'const_double').
'G' и ' H' могут быть определены машинно-зависимым способом, чтобы разрешать непосредственные вещественные операнды в конкретных диапазонах значений.
Разрешается непосредственный целочисленный операнд, чье значение не является явно заданным целым число.
Это может показаться странным; если insn разрешает постоянный операнд со значением, не известным во времени компиляции, то конечно же он должен позволять и любое известное значение. Так почему используется 's' вместо 'i'. Иногда это позволяет сгенерировать лучший код.
Например, на 68000 в fullword команде возможно использовать непосредственный операнд; но если непосредственное значение - между -128 и 127, лучший код получится, если загрузить значение в регистр и использовать регистр. Это происходит из-за того, что загрузка в регистр может быть выполнена с помощью команды 'moveq'. Мы предусмотрели это, определив, что символ 'K' означает любое целое число вне диапазона от -128 до 127 и тогда записав 'Ks' в ограничения операнда.
Разрешается любой регистр, память или непосредственный целочисленный операнд, кроме регистров, которые не являются общими.
Разрешается любой операнд, даже если он не удовлетворяет 'general_operand'. Обычно это используется в ограничении 'match_scratch ' когда некоторые варианты фактически не будут требовать рабочего регистра.
Разрешается операнд, который соответствует определенному номеру операнда. Если цифра используется вместе с символами внутри того же самого варианта, то цифра должна стоять последней.
Это называется 'соответствие ограничения' и это действительно означает то, что ассемблер имеет только один операнд, который выполняет две роли, рассматриваемые отдельными в RTL insn. Например, insn сложения имеет два входных операнда и один операнд вывода в RTL, но на большинстве CISC машин команда сложения в действительности имеет только два операнда, один из них операнд ввода-вывода:
addl #35,r12
В этих обстоятельствах используется соответствующие ограничения . Более
точно, два операнда, соответствующих друг другу, должны включить один
только входной операнд и один только выходной операнд. Более того,
цифра должна быть меньше, чем номер операнда, который использует ее
в ограничении.
То, что операнды соответствуют друг другу, в конкретном случае означает, что они идентично выглядящие выражения RTL. Но в нескольких специальных случаях разрешаются определенные виды различий. Например, '*x' как входной операнд будет соответствовать '*x++' как операнд вывода. Для правильных результатов в таких случаях, шаблон вывода должен всегда использовать номер операнда вывода при печати операнда.
Разрешается операнд, который является корректным адресом памяти. Это нужно для инструкций "load address" и "push address".
'P' в ограничении должен сопрвождаться 'address_operand' как предикат в 'match_operand'. Этот предикат интерпретирует тип, определенный в 'match_operand' как тип ячейки памяти, для которой адрес был бы корректным.
Символы в диапазоне от 'Q' до 'U' могут быть определены машинно-зависимым способом вместо произвольных типов операнда. Машинной макрокоманде описания 'EXTRA_CONSTRAINT' передается операнд как первый параметр и символ ограничения как второй операнд.
Типичное использование для этого - различение некоторых типы ссылок памяти, которые воздействуют на другие insn операнды.
Не определяйте эти символы ограничения, чтобы принять ссылки регистра ('reg'); проход перезагрузки не ожидает этого и не обработает это правильно.
Сравните два следующих образца:
(define_insn ""
[(set (match_operand:SI 0 "general_operand" "=r")
(plus:SI (match_dup 0)
(match_operand:SI 1 "general_operand" "r")))]
""
"...")
который имеет два операнда, один из которых должен появиться в двух местах, и
(define_insn ""
[(set (match_operand:SI 0 "general_operand" "=r")
(plus:SI (match_operand:SI 1 "general_operand" "0")
(match_operand:SI 2 "general_operand" "r")))]
""
"...")
который имеет три операнда, два из которых по требованию ограничения должны быть идентичны. Если мы рассматриваем insn вида
(insn N PREV NEXT
(set (reg:SI 3)
(plus:SI (reg:SI 6) (reg:SI 109)))
...)
первый образец не применился бы вообще, потому что этот insn не содержит два
идентичных подвыражения в нужном месте. Образец сказал бы "Это не
похоже на команду сложения; попробуйте другие образцы." Второй образец
сказал бы "Да, это команда сложения, но с ней что-то не так." Он направил
бы проход перезагрузки транслятора, чтобы сгенерировать дополнительные insns,
делающие ограничения истинными. Результаты могли бы выглядеть следующим
образом:
(insn N2 PREV N
(set (reg:SI 3) (reg:SI 6))
...)
(insn N N2 NEXT
(set (reg:SI 3)
(plus:SI (reg:SI 3) (reg:SI 109)))
...)
Это для того, чтобы удостовериться что каждый операнд, в каждом образце,
имеет ограничения, которые могут обрабатывать любое выражение RTL, которое
могло бы присутствовать для того операнда. (Когда используются множественные
варианты, каждый образец для каждой возможной комбинации выражений операнда
должен иметь по крайней мере один вариант, который может обрабатывать ту
комбинацию операндов.) Ограничения не должны *позволять* любой возможный
операнд, но они должны по крайней мере указать путь на перезагрузку любого
возможного операнда так, чтобы он удовлетворил ограничениям.
Иногда одиночная команда имеет много альтернативных наборов возможных операндов. Например, на 68000, команда логического or может объединять регистр и непосредственное значение памяти, так же она может объединять операнд любого вида в регистр; но она не может объединять одну ячейку памяти с другой.
Эти ограничения представляются несколькими вариантами. Вариант может быть описан рядом символов для каждого операнда. Полное ограничение для операнда сделано из символов для этого операнда из первого варианта, запятой, символы для этого операнда из варианта второго, запятой, и так далее до последнего варианта. Далее показывается как это делается для логического или с полными словами на 68000:
(define_insn "iorsi3"
[(set (match_operand:SI 0 "general_operand" "=m,d")
(ior:SI (match_operand:SI 1 "general_operand" "%0,0")
(match_operand:SI 2 "general_operand" "dKs,dmKs")))]
...)
Первый вариант имеет 'm' (память) для операнда 0, '0' для операнда 1
(его значение должно соответствовать операнду 0), и 'dKs' для
операнда 2. Другой вариант имеет 'd' (регистр данных) для операнда 0,
'0' для операнда 1, и 'dmKs' для операнда 2. '=' и '%' в ограничениях
обращаются ко всем вариантам; их значение объясняется в следующем разделе
(см. Предпочтения классов).
Если все операнды удовлетворяют любому варианту, команда корректна. Иначе, для каждого варианта, транслятор рассчитывает, сколько команд должны быть добавлены, чтобы скопировать операнды таким образом, чтобы применился этот вариант. Будет выбран вариант, требующий наименьшего копирования. Если двум вариантам требуется одинаковое количество копирования, будет выбран первый. Эти выборы могут быть изменены с помощью символов '?'и '!':
Немного понижает приоритет варианта, в котором появляется. Работает в случае, когда не один из вариантов точно не выбран. Транслятор расценивает такой вариант как более приоритетный.
Понижает приоритет этого варианта до минимума. Транслятор все еще может использовать этот вариант, если он может подойти без перезагрузки. Но если перезагрузка необходима, то обязательно будет выбран другой вариант.
Ограничения операнда служат для других целей: они дают возможность транслятору решить, как лучше всего использовать аппаратные и псевдо регистры. Транслятор исследует ограничения, которые обращаются к insns, использующие псевдо регистр, ища машинно-зависимые символы типа 'd' и 'a' которые определяют классы регистраторов. Псевдо регистр помещен в любой класс становит наиболее голосующим. Символы ограничения 'g' и 'r' также голосуют: они голосуют в пользу общего регистра. В машинном описании говорится, какие регистры являются общими.
Конечно, на некоторых машинах все регистры эквивалентны, и нет никаких классов регистров. И тогда все что описано ниже не нужно.
Далее идут символы модификатора ограничения.
Означает, что этот операнд в этой команде только для чтения: предыдущее значение отбрасывается и заменяется данными результата.
Означает, что этот операнд инструкция может как читать так и писать.
Когда транслятор устанавливает операнды, чтобы удовлетворить ограничению, требуется знать, какие операнды являются вводами к команде а какие являются выводами из нее. '=' идентифицирует вывод; '+' идентифицирует операнд, который является, и вводом и выводом; все другие операнды только входные.
Означает (в отличии от других случаев) что этот операнд записан прежде, чем команда завершена, используя входные операнды. Следовательно, этот операнд не может находиться в регистре, используемом как входной операнд или как часть любого адреса памяти.
'&' применяется только к варианту, в котором это написано. В ограничениях с многократными вариантами, иногда один вариант требует '&' в то время как другие нет. См. например, 'movdf' insn из 68000.
'&' не устраняет потребность писать '=' .
Объявляет, что команда будет коммутативна для этого и следующего операндов. Это означает, что транслятор может обмениваться двумя операндами, если это самый дешевый способ заставить все операнды удовлетворять ограничению. Это часто используется в образцах для команды сложения, которая действительно имеют только два операнда: результат должен войти в один из параметров. Здесь, например, описано как определена инструкция сложения полуслов в 68000:
(define_insn "addhi3"
[(set (match_operand:HI 0 "general_operand" "=m,r")
(plus:HI (match_operand:HI 1 "general_operand" "%0,0")
(match_operand:HI 2 "general_operand" "di,g")))]
...)
Говорит, что весь последующие символы, вплоть до следующей запятой, как ограничение должны игнорироваться. Эти символы значимы только для выбор предпочтительного регистра.
Говорит, что следующий символ при выборе предпочтительного регистра должен игнорироваться. '*' не оказывает никакого эффекта на значение ограничения, перезарядку.
Далее идет пример: 68000 имеет команду для знакового распространения половины слова в регистр данных, и возможно также знаковое распространение с помощью копирования в регистр адреса. В то время как любой вид регистра приемлем, ограничения на адресата регистра адреса менее строги, так что самое лучшее, если распределение регистра заставляет адрес регистрировать цель. Следовательно, '*' используется так, чтобы символ ограничения 'd' (для регистра данных) игнорировался при вычислении предпочтения регистра.
(define_insn "extendhisi2"
[(set (match_operand:SI 0 "general_operand" "=*d,a")
(sign_extend:SI
(match_operand:HI 1 "general_operand" "0,g")))]
...)
По мере возможности, Вы должны пытаться использовать в параметрах 'asm' ограничения общего назначения, т.к. это легче восприниматься другими людьми. Если Вы этого не умеете, используйте символы ограничения, которые имеют очень много разных конкретных значений для разных архитектур. Наиболее часто используются: `m' и `r' (для памяти и регистров общего назначения соответственно; см. Простые ограничения), и `I', обычно символ, указывающий наиболее общий формат уже полуученого числа.
Для каждой архитектуры машины, файл 'config/MACHINE.h' определяет дополнительные ограничения. Эти ограничения используются транслятором непосредственно для генерации команд, также как для asm-операторов; следовательно, некоторые из ограничений не особенно интересны для asm. Ограничения определены через следующие макрокоманды:
Ограничения типа регистра (обычно строчные буквы).
Непосредственные постоянные ограничения, для констант с неплавающей точкой размером слова или меньше (обычно верхний регистр).
Непосредственные постоянные ограничения, для всех констант с плавающей точкой и для констант больших чем точность размера слова (обычно верхний регистр).
Специальные случаи регистров или памяти. Эта макрокоманда не обязательна, и определена только для некоторых машин.
регистр с плавающей точкой
Одна из следующих констант с плавающей точкой - 0.0, 0.5, 1.0, 2.0, 3.0, 4.0, 5.0 или 10.0
Константа с плавающей точкой, которая удовлетворила бы ограничению 'F' если поменять у нее знак
Целое число, которое может использоваться как непосредственный операнд в команде обработки данных. То есть целое число в диапазоне от 0 до 255 с вращаемым множителем 2
Целое число в диапазоне -4095 к 4095
Целое число, которое удовлетворяет ограничение 'I' если изменить знак (одинарное дополнение)
Целое число, которое удовлетворило бы ограничению 'I' если поменять у него знак (двойное дополнение)
Целое число в диапазоне 0 к 32
Ячейка памяти, где точный адрес находится в одном регистре ( ``m'' является предпочтительной для `asm'-операнда )
Элемент constant pool
Символ в текстовом сегменте текущего(актуального) файла
Локальный регистр 0
Регистр указателя байта ('BP')
'Q' регистр
Специальный регистр цели
Первый регистр сумматор
Другой сумматор
регистр с плавающей точкой
Константа большая чем 0, меньшая чем 0x100
Константа большая чем 0, меньшая чем 0x10000
Константа, чьи верхние 24 бита находятся на (1)
16 битная константа, чьи верхние 8 битов находятся на (1)
32 битная константа, чей верхние 16 битов находятся на (1)
32 битная отрицательная константа, которая помещается в 8 бит
Константа 0x80000000 или, на 29050, любые 32 разрядных константа, чей первые 16 битов - 0.
16 битная отрицательная константа, которая помещается в 8 бит.
Константа с плавающей точкой (в asm-операторах, используйте взамен машинно-независимые 'E' или 'F')
Регистр основы Адреса
регистр с плавающей точкой
'MQ' , 'CTR' , или 'LINK' регистр
'MQ' регистр
'CTR' регистр
'LINK' регистр
'CR' регистр номер 0 (регистр условия)
'CR' регистр (регистр условия)
16-битная константа со знаком
Константа, чьи первые 16 бит - 0
Константа, чьи верхние 16 бит - 0
Константа подходящий как операнд маски
Константа больше чем 31
Точная мощность 2
Ноль
Константа, у которой если поменять знак, то получится 16 битная знаковая константа
Константа с плавающей точкой, которая может быть загружена в регистр с помощи одной команды на слово
Операнд Памяти, который является смещением из регистра ( 'm' является предпочтительным для `asm'-операторов )
'a' , 'b' , 'c' , или 'd' регистр
'a' , или 'd' регистр (для ints с 64 битами)
регистр с плавающей точкой
Первый регистр с плавающей точкой (начало стека)
Второй регистр с плавающей точкой
`a' регистр
`b' регистр
`c' регистр
`d' регистр
`di' регистр
`si' регистр
Константа в диапазоне 0 к 31 (для 32 разрядных сдвигов)
Константа в диапазоне 0 к 63 (для 64 разрядных сдвигов)
'0xff'
'0xffff'
0, 1, 2, или 3 (сдвигается c помощью 'lea' команды)
Стандартная 80387 константа с плавающей точкой
регистр с плавающей точкой ( ' fp0 ' к ' fp3 ' )
Локальный регистр ( ' r0 ' к ' r15 ' )
Глобальный регистр ( ' g0 ' к ' g15 ' )
Любой - локальный или глобальный регистр
Целые числа от 0 до 31
0
Целые числа от -31 до 0
вещественный (с плавающей точкой) 0
вещественный (с плавающей точкой) 1
Целочисленный регистр общего назначения
регистр с плавающей точкой (если доступен)
'Hi' регистр
'Lo' регистр
'Hi' или 'Lo' регистр
Целочисленный регистр общего назначения
регистр состояния операций и команд с плавающей точкой
16 разрядная константа со знаком (для арифметических команд)
Ноль
Расширенная нулем 16-битная константа (для логических команд)
Константа у которой нижние 16 бит - 0 (может быть загружена ' lui ' )
32 битная константа, которая требует, две команды для загрузки (константа которая - не `I', `K', или `L' )
Отрицательная 16-битная константа
Точная мощность 2
Положительная 16-битная константа
Вещественный (с плавающей точкой) 0
Ячейка памяти памяти, которая может быть загружена более чем одной командой ( 'm' более предпочтительно для asm-операторов)
Ячейка памяти, которая может быть загружена одной командой ( 'm' более предпочтительно для asm-операторов)
Ячейка памяти во внешнем формате OSF/rose PIC ( 'm' более предпочтительно для asm-операторов)
Регистр Адреса
Регистр Данных
68881 регистр числа с плавающей точкой, если доступен
Sun FPA (вещественный, с плавающей точкой) регистр, если доступен
Первые 16 Sun FPA регистров, ксли доступны
Целое число в диапазоне от 1 до 8
16 битное знаковое число
Знаковое число, чья величина большая чем 0x80
Целое число в диапазоне от -8 до -1
Константа с плавающей точкой, не являющаяся 68881 константой
Константа с плавающей точкой, которая может использоваться Sun FPA
регистр с плавающей точкой
Знаковая 13-битная константа
Ноль
32 битная константа с пустыми нижними 12 битами (константа, которая может быть загружена командой 'sethi')
Вещественный (с плавающей точкой) 0
Знаковая 13 битная константа, знако-распространенная до 32 или 64 бит
Ячейка памяти, которая может быть загружена одной командой ( 'm' более предпочтительно для asm-операторов)
Константа, или адрес памяти
Адрес памяти, выровненный к 8 байтовой границе
Просто регистр
Некоторые машины настолько чисты, что ограничения на операнды просто не нужны. Например, на Vax операнд, корректный в одном контексте, будет так же корректен и в любом другом контексте. На таких машинах каждый операнд должен иметь ограничение `g', исключая, разве что, операнды инструкций загрузки адреса, которые написаны, как будто они обращаются к ячейкам памяти, но фактический они обращаются к адресу ячейки. Они имели бы ограничение 'p'.
Для таких машин, вместо того, чтобы записывать 'g' и 'p' для всех ограничений, Вы можете писать описание с пустыми ограничениями. Тогда Вы пишете `""' для ограничения в каждом 'match_operand' . Операнды Адреса идентифицируются, записыванием выражения `address' рядом с 'match_operand', а не их ограничениями.
Когда машинное описание имеет только пустые ограничения, некоторые части трансляции будут пропущены, что делает транслятор быстрым. Однако, только очень малое число машин фактически не нуждаются в ограничениях; все машинные описания теперь уже включают ограничения использования.
Вот таблица имен команд, которые являются значимыми в проход генерации RTL транслятора. Присваивание одного из этих имен образцу команды сообщает проходу генерации RTL, что он может использовать этот образец для выполнения некоторой задачи.
Здесь M - имя машинного типа из двух символов, строчными буквами. Этот образец команды перемещает данные с этим машинным типом из операнда 1 в операнд 0. Например, " movsi " перемещает данные длиной в слово.
Если операнд 0 - " subreg " с типом M регистра, чей собственный тип более широкий, чем M, эффект этой команды состоит в сохранении указанного значения в части регистра, соответствующей типу M. Эффект на остальной части регистра не определен.
Этот класс образцов выделяется по нескольким причинам. Прежде всего каждое из этих имен *должно* быть определено, потому что нет никакого другого способа скопировать данные из одного места в другое.
Во-вторых, эти образцы используются не только в проходе генерации RTL. Даже проход перезагрузки может генерировать перемещение insns, чтобы копировать значения из слотов стека во временные регистры. Когда он делает это, один из операндов - аппаратный регистр, а другой - операнд, который может потребоваться перезагрузить в регистр.
Следовательно, когда задана такая пара операндов, образец должен генерировать RTL, который не нуждается в перезагрузке и не нуждается во временных регистрах - никаких регистрах, отличных от операндов. Например, если Вы поддерживаете образец с " define_expand ", то в таком случае " define_expand " не должен вызывать " force_reg " или любую другую такую функцию, которая могла бы генерировать новые псевдорегистры.
Это требование существует даже для типов подслова на RISC машине, на которой при выборке этих типов из памяти обычно требуется несколько insns и несколько временные регистров. Посмотрите в " spur.md ", чтобы увидеть как это требование может быть удовлетворено.
В течение перезагрузки ссылка памяти с недопустимым адресом может быть передана как операнд. Такой адрес будет заменен на допустимый адрес позже в проходе перезагрузки. В этом случае с адресом нельзя делать ничего, за исключением использования его так, как это имеет место. Если он копируется, он не заменяется на имеющий силу адрес. Не должно делаться никакой попытки сделать такой адрес допустимым и нельзя вызывать подпрограмму (типа " change_address "), которая будет это делать. Обратите внимание, что " general_operand " потерпит неудачу, если применить его к такому адресу.
Глобальная переменная " reload_in_progress " (которая должна быть явно объявлена, если требуется) может использоваться, чтобы определить, требуется ли такая специальная обработка.
Виды операндов, которые могут перезагружаться, зависят от остальной части машинного описания, но обычно на RISC машинах они могут быть только псевдорегистрами, который не получили аппаратных регистров, в то время как на других машинах явные ссылки памяти иногда могут перезагружаться.
Если рабочий регистр требуется, чтобы переместить объект в память или из памяти, он может быть распределен с использованием " gen_reg_rtx " до перезагрузки. Но это невозможно в течение и после перезагрузки. Если есть случаи, нуждающиеся в рабочих регистрах после перезагрузки, Вы должны определить " SECONDARY_INPUT_RELOAD_CLASs " и, возможно, также " SECONDARY_OUTPUT_RELOAD_CLASs ", чтобы обнаружить их, и предоставить образцы " reload_inM " или " reload_outM ", чтобы обработать их. * См.: Классы Регистров::.
Ограничения на " moveM " должны позволять перемещать любой аппаратный регистр в любой другой аппаратный регистр при условии, что " HARD_REGNO_MODE_OK " позволеят тип M для обоих регистров, а " REGISTER_MOVE_COST ", примененный к их классам, возвращает значение 2.
Обязательно поддерживать команды " moveM " с плавающей точкой внутри и вне любых регистров, которые могут хранить значения с фиксированной точкой, потому что объединения и структуры (которые имеют типы " SImode " или " DImode ") могут быть в этих регистрах, и они могут иметь поля с плавающей точкой.
Может также иметься потребность поддерживать команды " moveM " с фиксированной точкой внутри и вне регистров с плавающей точкой. К сожалению, я забыл, почему это было так, и я не знаю, так ли это до сих пор. Если " HARD_REGNO_MODE_OK " отклоняет значения с фиксированной точкой в регистрах с плавающей точкой, то ограничения на команды " moveM " с фиксированной точкой должны быть предназначены, чтобы избежать попытки перезагрузки в регистр с плавающей точкой.
Подобно " movM ", но используется, когда рабочий регистр требуется, чтобы передвигать между операндом 0 и 1 операндом. Операнд 2 описывает рабочий регистр. См. обсуждение макрокоманды " SECONDARY_RELOAD_CLASs " в * См.: Классы Регистров:: ..
Подобно " movM " за исключением того, что, если операнд 0 - " subreg " с типом M регистра, чей естественный тип более широкий, " movstrictM " команда гарантированно не изменит регистра за исключением части, которая принадлежит типу M.
Загружает несколько последовательных ячеек памяти в последовательные регистры. Операнд 0 - первый из последовательных регистров, операнд 1 - первая ячейка памяти, а операнд 2 - константа: число последовательных регистров.
Определяйте эту команду, только если целевая машина действительно имеет такую команду; не определяйте ее, если наиболее эффективный путь загрузки последовательных регистров из памяти - загружать их по одному.
На некоторых машинах имеются ограничения на то, какая именно последовательность регистров может быть сохранена в память, типа ограничений на начальные или конечные номера регистров или на диапазон допустимых количеств. Для таких машин используйте " define_expand " (* См.: Расширитель определений::.) и делайте сбой образца, если ограничения не выполнены.
Записывайте сгенерированный insn как " parallel " с элементами, являющимися " set " одного регистра из соответствующей ячейки памяти (Вам могут также потребоваться " use " или " clobber " элементы). Используйте " match_parallel ", (* См.: RTL Шаблон::.) чтобы распознать insn. См. " a29k.md " и " rs6000.md " для примеров использования этого образца insn.
Подобно " load_multiple ", но сохраняет несколько последовательных регистров в последовательные ячейки памяти. Операнд 0 - первая из последовательных ячейки памяти, операнд 1 - первый регистр, а операнд 2 - константа: число последовательных регистров.
Добавляет операнд 2 и 1 операнд, сохраняя результат в операнде 0. Все операнды должны иметь тип M. Это может использоваться даже на двухадресных машинах при помощи ограничений, требующих, чтобы операнды 1 и 0 находились в одном и том же месте.
Аналогично, но для других арифметических операций.
Перемножает операнды 1 и 2, которые имеют тип " HImode ", и сохраняет " SImode " результат в операнде 0.
Аналогичные команды умножения с расширением для другой ширины.
Аналогичные команды умножения с расширением, но для беззнакового умножения .
Выполняет знаковое умножение операндов 1 и 2, которые имеют Режим M, и сохраняют старшую половину результата в операнд 0. Младшая половина результата теряется.
Аналогичная команда для беззнакового умножения.
Знаковое деление, дающее и частное, и остаток. Операнд 1 делится на операнд 2, частное сохраняется в операнде 0, а остаток сохраняется в операнде 3.
Для машин с командой, которая выдает и частное, и остаток, сделайте образец для " divmodM4 " но не делайте образцов для " divM3 " и " modM3 ". Это позволяет оптимизацию в относительно общем случае, когда и частное, и остаток вычисляются.
Если команда, которая вычисляет только частное или только остаток, существует и более эффективна, чем команда, которая вычисляет и то, и другое, пишите программу вывода " divmodM4 " для вызова " find_reg_note " и поиска примечания " REG_UNUSED " для частного или остатка и генерации соответствующей команды.
Аналогично, но делает деление без знака.
Арифметический сдвиг операнда 1 влево на число битов, задаваемое операндом 2, с сохранением результата в операнде 0. Здесь M - тип операнда 0 и операнда 1; тип операнда 2 определяется образцом команды, и транслятор преобразует операнд к этому типу перед генерацией команды.
Другие команды сдвига и вращения , аналогичные " ashlM3 ".
Получает число, противоположного операнду 1, и записывает результата в операнд 0.
Записывает абсолютное значение операнда 1 в операнд 0.
Записывает квадратный корень из операнда 1 в операнд 0.
Встроенная функция C " sqrt " всегда использует тип, который соответствует типу данных C " double ".
Записывает в операнд 0 единицу плюс номер самого младшего из установленных в 1 битов 1 операнда. Если операнд 1 - ноль, записывается ноль. M - тип операнда 0; операнда 1 тип определяется образцом команды, и транслятор преобразует операнд к этому типу перед генерацией команды.
Встроенная функция C " ffs " всегда использует тип, который соответствует типу данных C " int ".
Записывает поразрядное дополнение операнда 1 в операнд 0.
Сравнивает операнд 0 и операнд 1 и устанавливает условные коды. RTL образец должен выглядеть следующим образом:
(set (cc0) (compare (match_operand:M 0 ...)
(Match_operand:M 1 ...)))
Сравнивает операнд 0 c нулем и устанавливает условные коды. RTL образец должен выглядеть следующим образом:
(set (cc0) (match_operand:M 0 ...))
Образцы " tstM " не должны определяться для машин, которые не используют
" (cc0) ", поскольку это помешало бы оптимизации, так как перестало бы
быть понятным, какие операции " set " являются сравнениями.
Вместо них должны использоваться образцы " cmpM ".
Команда перемещения блока. Адреса исходной строки и строки-результата - первые два операнда, и они оба имеют тип " Pmode ". Число перемещаемых байтов - третий операнд, в типе M.
Четвертый операнд - известное общее выравнивание исходной строки и строки-результата, в форме " const_int " rtx. Таким образом, если транслятор знает, что обе строки выравниваются на границу слова, он может задавать значение 4 для этого операнда.
Этим образцам не требуется специальное рассмотрение возможности того, что источник и результат могут перекрываться.
Команда сравнения блоков, с пятью операндами. Операнд 0 - результат; он имеет тип M. Остальные четыре операнда соответствуют операндам " movstrM ". Два указанных блока памяти сравниваются побайтно в лексикографическом порядке. Результатом команда является запись значения в операнд 0, знак которого указывает результат сравнения.
Вычисление длины строки, с тремя операндами. Операнд 0 - результат (типа M), операнд 1 - ссылка " mem " на первый символ строки, операнд 2 - символ для поиска (обычно ноль) и операнд 3 - константа, описывающая известное выравнивание начала строки.
Преобразует целочисленный знаковый операнд 1 (допустимый для типа с фиксированной точкой M) к типу с плавающей точкой N и записывает результат в операнд 0 (который имеет тип N).
Преобразует целочисленный беззнаковый операнд 1 (допустимый для типа с фиксированной точкой M) к типу с плавающей точкой N и записывает результат в операнд 0 (который имеет тип N).
Преобразует операнд 1 (допустимый для типа с плавающей точкой M) к типу с фиксированной точкой N как число со знаком и записывает результат в операнд 0 (который имеет тип N). Результат этой команды определен только тогда, когда значение операнда 1 - целое число.
Преобразует операнд 1 (допустимый для типа с плавающей точкой M) к типу с фиксированной точкой N как число без знака и записывает результат в операнд 0 (который имеет тип N). Результат этой команды определен только тогда, когда значение операнда 1 - целое число.
Преобразует операнд 1 (допустимый для типа с плавающей точкой M) к целому числу, по-прежнему представляемому в типе с плавающей точкой M, и записывает результат в операнд 0 (который имеет тип M).
Подобно " fixMN2 ", но преобразует значение с плавающей точкой типа M к целому числу.
Подобно " fixunsMN2 ", но преобразует значение с плавающей точкой типа M к целому числу.
Усекает операнд 1 (допустимый для типа M) к типу N и записывает в операнд 0 (который имеет тип N). Режимы должны быть оба с фиксированной точкой или оба с плавающей точкой.
Расширяет знаком операнд 1 (допустимый для типа M) к типу N и записывает в операнд 0 (который имеет тип N). Режимы должны быть оба с фиксированной точкой или оба с плавающей точкой.
Расширяет нулем операнд 1 (допустимый для типа M) к типу N и записывает в операнд 0 (который имеет тип N). Режимы должны быть оба с фиксированной точкой.
Извлечекает поле битов из операнда 1 (регистра или ячейки памяти), где операнд 2 определяет ширину в битах, а операнд 3 - начальный бит, и записывает его в операнд 0. Операнд 0 должен иметь тип " word_mode ". Операнд 1 может иметь тип " byte_mode " или " word_mode "; часто " word_mode " позволяется только для регистров. Операнды 2 и 3 должны быть допустимы для " word_mode ".
Проход генерации RTL генерирует эту команду только с константами в качестве операндов 2 и 3.
Значение битового поля расширяется знаком до полного целочисленного слова перед записью в операнд 0.
Подобно " extv ", за исключением того, что значение битового поля расширяется нулем.
Записывает операнд 3 (который должен быть допустимым для " word_mode ") в битовое поле в операнде 0, где операнд 1 определяет ширину в битах, а операнд 2 - начальный бит. Операнд 0 может иметь тип " byte_mode " или " word_mode "; часто " word_mode " позволяется только для регистров. Операнды, 1 и 2 должны быть допустимыми для " word_mode ".
Проход генерации RTL генерирует эту команду только с константами в качестве операндов 1 и 2.
Перемещает операнд 2 или операнд 3 в операнд 0 согласно сравнению в операнде 1. Если сравнение истинно, операнд 2 перемещается в операнд 0, иначе перемещается операнд 3.
Режим сравниваемых операндов не обязан быть таким же, как у перемещаемых операнды. Некоторые машины, например sparc64, имеют команды, которые перемещают целочисленное значение в зависимости от сравнения чисел с плавающей точкой и наоборот.
Если машина не имеет условных команд перемещения, не определяйте эти образцы.
Записывает ноль или отличное от нуля число в операнд согласно коду условия. Записываемое значение отлично от нуля, если условие COND истинно. COND - имя кода выражения операции сравнения, такого как " eq ", " lt " или " leu ".
Вы указываете тип, который операнд должен иметь, когда Вы пишете выражение " match_operand ". Транслятор автоматически видит, какой тип Вы использовали и поддерживает операнд этого типа.
Значение, сохраненное для истинного условия, должно иметь 1 в младшем бите или должно быть отрицательно. Иначе команда не подходит и Вы должны исключить ее из машинного описания. Вы описываете транслятору точно, какое значение записывается, определяя макрокоманда " STORE_FLAG_VALUE " (* См.: Разное::.). Если описание не найдено, что может использоваться для всех образцов " sCOND ", Вы должны исключить эти операции из машинного описания.
Эти операции могут не работать, но так должно быть только в относительно нестандартных случаях; если они не будут работать для обычных случаев, включая целочисленные сравнения, лучше всего исключить эти образцы.
Если эти операции исключены, транслятор будет обычно генерировать код, который копирует константу 1 в адресат и делает условный переход вокруг присваивания нуля адресату. Если этот код более эффективен, чем потенциальные команды, используемые для образца " sCOND ", сопровождаемые теми, которые требуются, чтобы преобразовать результат в 1 или ноль в " SImode ", Вы должны исключить " sCOND " операции из машинного описания.
Команда условного перехода. Операнд 0 - " label_ref ", ссылающийся на метку, на которую делается переход. Переход происходит, если коды условия удовлетворяют условию COND.
Некоторые машины не следуют модели, принятой здесь, в которой команда сравнения сопровождается командой условного перехода. В этом случае образцы " cmpM " (и " tstM ") должны просто сохранять куда-нибудь операнды и генерировать все необходимые insns в " define_expand " (* См.: Расширение определений::.) для операций условного перехода(выполняет перехода). Всем обращениям к расширению образцов " bCOND " должны непосредственно предшествовать обращения к расширению образцов " cmpM " или " tstM ".
Машины, которые используют псевдорегистр для значения кода условия, или где тип, используемый для сравнения, зависит от проверяемого условия, должен также использовать вышеупомянутый механизм. * См.: Образцы Переходов::
Вышесказанное применимо также к образцам " movMODEcc " и " sCOND ".
Команда вызова подпрограммы, не возвращающая значения. Операнд 0 - вызываемая функция; операнд 1 - число байтов параметров, помещенных в стек (в типе " SImode ", если это не " const_int "); Операнд 2 - число регистров, используемых как операнды.
На большинстве машин операнд 2 фактически не сохранен в образце RTL. Это делается ради некоторых RISC машин, которые должны поместить эту информацию в код ассемблера; они могут помещать ее в RTL вместо операнда 1.
Операнд 0 должен быть " mem " RTX, чей адрес - адрес функции. Обратите внимание, однако, что этот адрес может быть " symbol_ref " выражением, даже если он не был бы законным адресом памяти на целевой машине. Если это также недопустимый параметр для команды вызова, образцом для этой операции должен быть " define_expand " (* См.: Расширение определений::.), который помещает адрес в регистр и использует этот регистр в команде вызова.
Команда вызова подпрограммы, возвращающая значение. Операнд 0 - аппаратный регистр, в котором значение возвращается. Имеется еще три операнда, такие же, как три операнда команды " call " (но с номерами, увеличенными на один).
Подпрограммы, которые возвращают объекты ` BLKmode ', используют " call " insn.
Аналогичны " call " и " call_value ", за исключением того, что используются, если определены и если " RETURN_POPS_ARGS " отлично от нуля. Они должны сгенерировать " parallel ", который содержит и обращение к функции, и " set ", чтобы указать корректировку, делаемую для указателя кадра.
Для машин, где " RETURN_POPS_ARGS " может быть отлично от нуля, использование этих образцов увеличивает число функций, для которых указатель кадра может быть удален, если это желательно.
Команда вызова подпрограммы, возвращающая значение любого типа. Операнд 0 - вызываемая функция; операнд 1 - ячейка памяти, где должен быть сохранен результат вызова функции; операнд 2 - выражение ` parallel ', где каждый элемент - выражение " set ", которое указывает запись возвращаемого функцией значения в блок результата.
Этот образец команды должен быть определен, чтобы поддерживать " __ builtin_apply " на машинах, где для вызова подпрограммы с произвольными параметрами или сохранения возвращенного значения необходимы специальные команды. Этот образец команды требуется на машинах, имеющих несколько регистров, которые могут содержать возвращаемое значение (то есть " FUNCTION_VALUE_REGNO_P " является истиной для более, чем одного регистра).
Команда возврата из подпрограммы. Это имя образца команды должно быть определено только, если одиночная команда может выполнить всю работу по возврату из функции.
Подобно образцам " movM ", этот образец также используется после фазы генерации RTL. В этом случае он должен поддерживать машины, где для возврата из функции обычно необходимо несколько команд, но некоторый класс функций требует только одну команду, чтобы выполнить возврат. Обычно соответствующие функции - это те, которые не должны сохранять никаких регистров и не должны распределять место в стеке.
Для таких машин, условие, определенное в этом образце должно быть истинным только, когда " reload_completed " отлично от нуля и эпилог функции является одиночной командой. Для машин с окнами регистров подпрограмма " leaf_function_p " может использоваться для определения, требуется ли временное сохранение в окне регистра.
Машины, которые имеют условные команды возврата, должны определить образцы, подобные следующему:
(define_insn ""
[(set (PC)
(if_then_else (match_operator
0 "comparison_operator"
[(cc0) (const_int 0)])
(return)
(pc)))]
"CONDITION"
"...")
Где CONDITION обычно - то же самое условие, что и указанное в
поименованном образце " return ".
Команда возврата из подпрограммы без контроля типов . Этот образец команды должен быть определен для поддержки " __ builtin_return " на машинах, где необходимы специальные команды, чтобы возвратить значение любого типа.
Операнд 0 - ячейка памяти, куда записывается результат вызова функции с " __ builtin_apply "; операнд 1 - выражение ` parallel ', где каждый элемент - выражение ` set ', указывающее восстановление значения, возвращаемого функцией из блока результата.
Пустая команда. Это имя образца команды должно быть всегда определено, чтобы вывести пустую команду в коде ассемблера. " (const_int 0) " будет делать это как образец RTL.
Команда для перехода к адресу, который является нулевым операндом. Это имя образца обязательно на всех машинах.
Команда для перехода через таблицу, включая проверку границ. Эта команда имеет пять операндов:
Команда для перехода к переменному адресу. Это - низкоуровневая возможность, которая может использоваться, чтобы выполнить таблицу переходов, когда нет образца " casesi ".
Этому образцу требуется два операнда: адрес или смещение, и метка, которая должна непосредственно предшествовать таблице перехода. Если макрокоманда " CASE_VECTOR_PC_RELATIVE " определена, то первый операнд является смещением, которое рассчитывается из адреса таблицы; иначе, это - абсолютный адрес перехода. В любом случае первый операнд имеет тип " Pmode ".
" tablejump " insn - всегда последний insn перед таблицей перехода, которую он использует. Код ассемблера обычно не имеет потребности в использовании второго операнда, но Вы должны соединить их в образце RTL так, что оптимизатор перехода не будет удалять таблицу как недостижимый код.
Большинство машин сохраняет и восстанавливает указатель стека, копируя его в или из объекта типа " Pmode ". Не определяйте эти образцы на таких машинах.
Некоторые машины требуют специальной обработки для сохранения и восстановления указателя стека. На этих машинах определяйте образцы соответственно нестандартным случаям, используя " define_expand " (* См.: Расширение Определений::.), который производит требуемый insns. Вот три типа сохранения и восстановления:
Область сохранения - " mem ", который является константным смещении от " virtual_stack_vars_rtx ", когда указатель стека сохраняется для использования нелокальных goto и " reg " в других двух случаях.
Вычитает (или добавляет, если " STACK_GROWS_DOWNWARD " не определено) операнд 0 из указателя стека, чтобы создать пространство для динамически распределяемых данных.
Не определяйт этот образец, если все, что должно выполняться - вычитание. Некоторые машины требуют других операций типа исследования стека или поддержания обратной цепочки. Определите этот образец, чтобы сгенерировать эти операции в дополнение к модифицированию указателя стека.
Иногда insn может соответствовать более чем одному образцу команды. Тогда используется образец, который появляется первым в машинном описании. Следовательно, более специфические образцы (образцы, которые будут соответствовать меньшее количество insns) и более быстрые команды (которые производят лучший код, когда имеет место соответствие им) должны обычно идти сначала в описании.
В некоторых случаях эффект упорядочивания образцов может использоваться, чтобы скрыть образец, когда он не является допустимым. Например, 68000 имеет команду для преобразования слова к плавающей точке и другую для преобразования байта к плавающей точке. Команда, преобразующая целое число к плавающей точке может соответствовать любой из них. Мы помещаем образец преобразования слова сначала, чтобы удостовериться, что он будет использоваться скорее, чем другой. (Иначе большое целое число могло бы быть сгенерировано как несколько одиночных байтов, что не работало бы.) Вместо использования такого упорядочивания образцов можно было бы сделать образец для convert-a-byte достаточно "умный", чтобы правильно обрабатывать любую целочисленную константу.
Каждое машинное описание должно иметь поименованный образец для каждого из имен условных переходов " bCOND ". Шаблон распознавания должен всегда иметь форму
(set (PC)
(if_then_else (COND (cc0) (const_int 0))
(label_ref (match_operand 0 "" ""))
(pc)))
Кроме того, каждое машинное описание должно иметь безымянный образец
для каждой из возможных обратных ветвлений. Их шаблоны
выглядят примерно так:
(set (PC)
(if_then_else (COND (cc0) (const_int 0))
(pc)
(label_ref (match_operand 0 "" ""))))
Они необходимы, потому что оптимизация перехода может превращать прямое
ветвление в обратное.
Часто удобно использовать конструкцию " match_operator ", чтобы уменьшить число образцов, которые должны быть определены для ветвей. Например,
(define_insn ""
[(set (PC)
(if_then_else (match_operator 0 "comparison_operator"
[(cc0) (const_int 0)])
(pc)
(Label_ref (match_operand 1 "" ""))))]
"CONDITION"
"...")
В некоторых случаях машины поддерживают команды, идентичные во всем, кроме
машинного типа одного или более операндов. Например, могут иметься
команды "sign-extend halfword" и "sign-extend byte" с такими образцами:
(set (match_operand:SI 0 ...)
(extend:SI (match_operand:HI 1 ...)))
(set (match_operand:SI 0 ...)
(extend:SI (match_operand:QI 1 ...)))
Целые константы не определяют машинный тип, так что команда расширения
константы может соответствовать любому образцу. Образцом, которому она будет
фактически поставлена в соответствие, будет тот, который появляется первым в
файле. Для правильных результатов это должен быть образец для самого широкого
из возможных типов (здесь - " HImode "). Если бы образец соответствовал
команде " QImode ", результаты могли бы быть неправильными, если константа
фактически не подходит для этого типа.
Такие команды расширения констант редко генерируются, потому что они оптимизируются, но они могут иногда встречаться при неоптимизированной трансляции.
Если ограничение в образце позволяет константу, проход перезагрузки может в некоторых случаях заменять регистр на константу, разрешенную ограничением. Аналогично для ссылок памяти. Из-за этой замены Вы не должны обеспечивать отдельные образцы для команд инкремента и декремента. Вместо этого они будут генерироваться из одного и того же образца, который поддерживает insns сложения из регистра в регистр, при помощи рассмотрения операндов и генерации соответствующей машинной команды.
Для большинства машин GNU CC принимает, что машина имеет условный код. Сравнение insn устанавливает условный код, записывая результат как знакового, так и беззнакового сравнения в заданные операнды. Отдельный insn ветвления проверяет код условия и производит или не производит переход согласно его значению. Среди insns ветвления различают знаковые и беззнаковые. Много часто встречающихся машин, типа Vax, 68000 и 32000, работают этим путем.
Некоторые машины имеют различные команды для знакового и беззнакового сравнения и только один набор команд условного перехода. Самый простой способ обработки этих машин состоит в том, чтобым обрабатывать их точно так же, как и другие, до заключительной стадии, где записывается ассемблерный код. В это время, когда выводится код для команды сравнения, нужно заглянуть вперед в следующий переход, использующий " next_cc0_user (insn) ". (Переменная " insn " ссылается на insn, выводящийся в данный момент, в коде записи вывода коде в образца команды.) Если RTL говорит, что это переход без знака, нужно выводить беззнаковое сравнение; иначе нужно выводить знаковое сравнение. Когда ветвь сама является выводом, Вы можете обрабатывать знаковые и беззнаковые переходы одинаково.
Причина, по которой так можно делать, заключается в том, что GNU CC всегда генерирует пару последовательных RTL insns, возможно отделяемый " note " insns, один, чтобы установить код условия, и один, чтобы проверить его, и хранит эту пару до конца без изменений.
Чтобы так поступить, Вы должны определить макрокоманду машинного описания " NOTICE_UPDATE_CC ", чтобы делать " CC_STATUS_INIT "; другими словами, нет излишних команд сравнения.
Некоторые машины имеют команды одновременного сравнения и перехода и не имеют условного кода. Подобная методика работает для них. Когда наступает время, чтобы "вывести" команду сравнения, запишите ее операнды в двух статических переменных. Когда выводится следующая команда одновременного сравнения и перехода, фактически выводится команды одновременного сравнения и перехода, которая использует записанные операнды.
Этот способ также работает при определении образцов для команды одновременного сравнения и перехода. При оптимизирующей трансляции пара команд сравнения и перехода будет объединена согласно этим образцам. Но этого не происходит, если оптимизация не запрошена. Так что Вы должны использовать одно из решений, указанных выше, в дополнение к любым специальным образцам, которые Вы определяете.
На многих RISC машинах большинство команд не воздействует на код условия и там может даже не быть отдельного регистра кода условия. На этих машинах ограничение, что определение и использование кода условия должно производиться смежными insns, не необходимо и может помешать важным оптимизациям. Например, на IBM RS/6000, имеется задержка для принимаемых ветвей, если регистр кода условия не установлен на три команды раньше условного перехода. Планировщик команд не может выполнять эту оптимизацию, если не разрешается разделите определение и использование регистра кода условия.
На этих машинах не используйте " (cc0) ", а используйте взамен регистр для представления кода условия. Если в машине имеется определенный регистр кода условия, используйте аппаратный регистр. Если код условия или результат сравнения может быть помещен в любой общий регистр, или если имеется несколько регистров условия, используйте псевдорегистр.
На некоторых машинах тип сгенерированной команды перехода может зависеть от способа, которым код условия был произведен; например, на 68k и Sparc установка кода условия непосредственно из команд сложения или вычитания не очищает бит переполнения, в отличие от команды тестирования, так что для некоторых ветвлений должны использоваться различные команды перехода. Для машин, которые используют " (cc0) ", установка и использование кода условия должны быть смежными (разделяясь только " note " insns), позволяя использование флагов в " cc_status ". (* См.: Код Условия::.) Кроме того, сравнение и переход insns может быть найдены друг из друга, при помощи функции " prev_cc0_setter " и " next_cc0_user ".
Однако, это не так на машинах, которые не используют " (cc0) ". На этих машинах нельзя сделать никаких предположений о смежности insns сравнения и перехода, и вышеупомянутые методы не могут использоваться. Вместо этого мы используем машинный тип регистра кода условия, чтобы записать различные форматы регистра кода условия.
Регистры, используемые, чтобы сохранить значение кода условия, должны иметь тип, который находится в классе " MODE_CC ". Обычно это будет " CCmode ". Если требуются дополнительные типы (как для вышеупомянутого примера сложения на Sparc), определите макрокоманду " EXTRA_CC_MODES ", чтобы внести в список дополнительные требуемые типы (* См.: Код Условия::.). Также определите " EXTRA_CC_NAMES ", чтобы внести в список имена этих типов и " SELECT_CC_MODE ", чтобы выбрать тип операнда сравнения.
Если в течение генерации RTL известно, что потребуются различные типы, (например, если машина имеет отдельные команды для знакового и беззнакового сравнений, подобно большинству процессоров IBM), они могут быть определены в это время.
Если случаи, которые требуют различных типов, получаются при комбинировании команд, макрокоманда " SELECT_CC_MODE " определяет, какой машинный тип должен использоваться для результата сравнения. Образцы должны быть написаны с использованием этого типа. Для поддержки случай случая сложения на Sparc, обсуждавшегося выше, мы имеем образец
(define_insn ""
[(set (reg: CC_NOOV 0)
(compare: CC_NOOV
(plus: SI (match_operand:SI 0 "register_operand" "%r")
(Match_operand:SI 1 "arith_operand" "rI"))
(const_int 0)))]
""
"...")
Макрокоманда " SELECT_CC_MODE " на Sparc возвращает " CC_NOOVmode " для
сравнения, чей параметр - " plus ".
Часто встречаются случаи, когда несколько выражений RTL можно представить как операцию, выполняемую одиночной машинной командой. Эта ситуация чаще всего встречается для логических команд, команд перехода и команд умножения с накоплением. В таких случаях транслятор пытается преобразовать эти несколько выражений RTL в одиночную каноническую форму, чтобы уменьшить число требуемых образцов insn.
В дополнение к алгебраическим упрощениям, выполняются следующие канонизации:
(define_insn ""
[(set (match_operand:M 0 ...)
(and:M (not:M (match_operand:M 1 ...))
(match_operand:M 2 ...)))]
"..."
"...")
Аналогично, образец для "NAND" команды должен записываться так:
(define_insn ""
[(set (match_operand:M 0 ...)
(ior: M (not:M (match_operand:M 1 ...))
(not:M (match_operand:M 2 ...))))]
"..."
"...")
В обоих случаях необязательно включать образцы для многих
логически эквивалентных выражений RTL.
(plus:M (plus:M X Y) CONSTANT)
В дополнение к образцам команд " md " файл может содержать определения машинно - специфических peephole оптимизаций. Peephole оптимизация - это оптимизация " просмотром вперед ", т.е. поиск команд, которые можно объединить с данной для ускорения их выполнения.
Комбинатор не обращает внимание на некоторые peephole оптимизации, когда поток данных в программе не предполагает, что он попробует сделать их. Например, иногда два последовательного insns, связанные по цели, могут быть oбъединены, даже если кажется, что второй не использует регистр, вычисленный в первом. Машинно - специфический peephole оптимизатор может обнаружить такие возможности.
Определение выглядит примерно так:
(define_peephole
[INSN-PATTERN-1
INSN-PATTERN-2
...]
"CONDITION"
"TEMPLATE"
" OPTIONAL INSN-ATTRIBUTES ")
Последний строковый операнд может быть опущен, если Вы не используете никакой
машинно-специфической информации в этом машинном описании. Если он имеется,
то он должен подчиняться тем же правилам,что и в " define_insn ".
В этом скелете INSN-PATTERN-1 и так далее - образцы, которые ставятся в соответствие последовательным insns. Оптимизация применяется к последовательности insns, когда INSN-PATTERN-1 соответствует первому, INSN-PATTERN-2 соответствует следующему, и так далее.
Каждый из insns, согласованный по peephole должен также соответствовать " define_insn ". Peepholes проверяются только в последней стадии, непосредственно перед генерацией кода, и только опционально. Следовательно, всякий insn, который соответствовал бы peephole, но не соответствовал бы никакому " define_insn ", вызовет аварию в генерации кода при неоптимизированной трансляции или на различных стадиях оптимизации.
Операнды insns согласованы с " match_operands ", " match_operator " и " match_dup ", как обычно. Необычно то, что количество операндов относится ко всем образцам insn в определении. Так, Вы можете проверять идентичность операндов в двух insns, используя " match_operand " в одном insn и " match_dup " в другом.
Ограничения на операнды, используемые в образцах " match_operand " не имеют прямого эффекта на применимости peephole, но они будет проверены позже, так что удостоверьтесь, что ваши ограничения достаточно общие, чтобы применять их всякий раз для peephole. Если peephole согласовано, но ограничения не выполнены, это вызовет аварию трансляции.
Безопасно опустить ограничения во всех операндах peephole; или Вы можете писать ограничения, которые служат, как двойная проверка на критерии, предварительно проверенные.
Как только последовательность insns соответствует образцам, CONDITION проверяется. Это - выражение C, которое делает окончательное решение, выполнять ли оптимизацию (она выполняется, если выражение отлично от нуля). Если CONDITION опущено (другими словами, строка пуста), то оптимизация применяется к каждой последовательности insns, которая соответствует образцам.
Определенные peephole оптимизации применяются после окончания распределения регистров. Следовательно, peephole определение может проверять, какие операнды заканчиваются в каких видах регистров, только просматривая операнды.
Способ обратиться к операндам CONDITION состоит в том, чтобы писать " operands[I] " для операнда номер I (как согласованному с " (match_operand I...) "). Используйте переменную " insn ", чтобы обратиться к последнему из согласовываемых insns; используйте " prev_active_insn ", чтобы найти предшествующие insns.
При оптимизации вычислений с промежуточными результатами Вы можете использовать CONDITION для создания соответствия только тогда, когда промежуточные результаты не используются нигде в другом месте. Используйте выражение C " dead_or_set_p (INSN, OP) ", где INSN является insn, в котором значение, как Вы считаете, используется в последний раз (из значения " insn ", вместе с использованием " prev_nonnote_insn "), и OP - промежуточное значение (из " operands[I] ").
Применение средств оптимизации означает замену последовательности insns на один новый insn. TEMPLATE управляет окончательным выводом ассемблерного кода для этого объединенного insn. Он работает точно так же, как шаблон " define_insn ". Количества операндов в этом шаблоне - те же, что использовались при установлении соответствия для первоначальной последовательности insns.
Результат определяемого peephole оптимизатора не обязан соответствовать какому-то из образцов insn в машинном описании; он даже не имеет возможности соответствовать им. Определение peephole оптимизатора само служит как образец insn для управления выводом insn.
Определяемые peephole оптимизаторы выполняются во время вывода кода ассемблера, так что insns, который они производят, никогда не объединяются и не переставляются никаким образом.
Вот пример, взятый из машинного описания 68000:
(define_peephole
[(set (reg:SI 15) (plus:SI (reg:SI 15) (const_int 4)))
(set (match_operand:DF 0 "register_operand" "=f")
(match_operand:DF 1 "register_operand" "ad"))]
"FP_REG_P (operands[0]) && ! FP_REG_P (operands[1])"
"*
{
rtx xoperands[2];
xoperands[1] = gen_rtx (REG, SImode, REGNO (operands[1]) + 1);
#ifdef MOTOROLA
output_asm_insn (\"move.l %1,(sp)\", xoperands);
output_asm_insn (\"move.l %1,-(sp)\", operands);
return \"fmove.d (sp)+,%0\";
#else
output_asm_insn (\"movel %1,sp@\", xoperands);
output_asm_insn (\"movel %1,<url url="mailto:sp@-" name="sp@-">\", operands);
return \"fmoved sp@+,%0\";
#endif
}
")
Эффект этой оптимизации заключается в изменении
jbsr _foobar
addql *4,sp
movel d1,<url url="mailto:sp@-" name="sp@-">
movel d0,<url url="mailto:sp@-" name="sp@-">
fmoved sp@+, fp0
на
jbsr _foobar
movel d1,sp@
movel d0,<url url="mailto:sp@-" name="sp@-">
fmoved sp@+,fp0
INSN-PATTERN-1 и так далее выглядят *почти* как второй операнд
" define_insn ". Имеется одно важное различие: второй операнд
" define_insn " состоит из одного или нескольких RTX, заключенных в квадратные
скобки. Обычно, имеется только один: затем то же самое действие может быть
записано как элемент " define_peephole ". Но когда в " define_insn " несколько
действий, они неявно включены в " parallel ". Поэтому Вы должны явно писать
" parallel " и квадратные скобки внутри него в " define_peephole ". Таким
образом, если образец insn выглядит так:
(define_insn "divmodsi4"
[(set (match_operand:SI 0 "general_operand" "=d")
(div:SI (match_operand:SI 1 "general_operand" "0")
(match_operand:SI 2 "general_operand" "dmsK")))
(set (match_operand:SI 3 "general_operand" "=d")
(mod:SI (match_dup 1) (match_dup 2)))]
"TARGET_68020"
"divsl%.l %2,%3:%0")
то способ упомянуть этот insn в peephole таков:
(define_peephole
[...
(parallel
[(set (match_operand:SI 0 "general_operand" "=d")
(div:SI (match_operand:SI 1 "general_operand" "0")
(match_operand:SI 2 "general_operand" "dmsK")))
(set (match_operand:SI 3 "general_operand" "=d")
(mod:SI (match_dup 1) (match_dup 2)))])
...]
...)
На некоторых целевых машинах отдельные стандартные имена образцов для RTL поколения не могут быть обработаны одиночным insn, но их можно представить последовательностью insns. Для этих целевых машин, Вы можете описать 'define_expand', чтобы определить, как генерировать последовательность RTL.
'define_expand' является RTL-выражением, которое работает почти подобно 'define_insn', но, в отличие от последнего, 'define_expand' используется только для RTL поколения и он может произвести больше чем один RTL-insn.
RTX 'define_expand' имеет четыре операнда:
Так же как и операторы управления RTL insns, RTL шаблон описывает операнды, которые должны быть определены, при использовании образца. В частности, это дает предикат для каждого операнда.
Правильный операнд, который должен быть указан при генерации RTL с образца, должен быть описан с помощью 'mathch_operand' в свое первое появления в RTL шаблоне. Это вводит информацию о предикате операнда в таблицы, в которые записываются такие вещи. GNU CC использует эту информацию для предзагрузки операнда в регистр, если это требуется, что бы сделать корректный RTL код. Если на операнд ссылаются более одного раза, то последующие ссылки должны использовать 'mathch_dup'.
RTL-шаблон может также ссылаться на внутренние 'операнды', которые являются временными регистрами или метками, используемыми только в последовательности, сгенерированной 'define_expand'. Внутренние операнды в RTL шаблоне заменяются на 'match_dup', но никогда не на 'match_operand'. Значение внутренних операндов, когда требуется использование этого образца, не передаются транслятором как аргументы. Вместо этого они вычисляются в образце, в операторах подготовки. Эти операторы вычисляют значения и записывают их в соответствующие элементы 'операндов' так, чтобы 'match_dup' мог их найти.
Имеются две специальных макрокоманды, определенные для использования в операторах подготовки: `DONE' and `FAIL'. Если поставить после них ';' то можно использовать их как операторы.
Используйте макрокоманду `DONE', чтобы закончить для образца генерацию RTL. Единственными RTL insn, полученными из образца в этом случае будут те, которые уже сгенерированы явными обращениями к 'emit_insn' в операторах подготовки; RTL шаблон не будет сгенерирован.
Заставляет образец обломиться. Когда образец обламывается, это означает, что образец не был по настоящему доступен. Тогда подпрограммы вызова в трансляторе пробует другие способы для генерации кода, используя другие образцы.
Отказ в настоящее время поддерживается только для бинарных (сложение, умножение, смещение, и т.д.) и битовых (`extv', `extzv', и `insv') операций .
Далее идет пример определения левого сдвига для чипа SPUR:
(define_expand 'ashlsi3'
[(set (match_operand:SI 0 'register_operand' '')
(ashift:SI
(match_operand:SI 1 'register_operand' '')
(match_operand:SI 2 'nonmemory_operand' '')))]
''
'
{
if (GET_CODE (operands[2]) != CONST_INT
|| (unsigned) INTVAL (operands[2]) > 3)
FAIL;
}')
Если транслятор умел бы обрабатывать нетривиальные строки условий в образцах с именами, то было бы возможно использовать в этом случае 'define_insn'. Вот другой случай (нуль-расширение на 68000), который более полно использует мощь 'define_expand':
(define_expand 'zero_extendhisi2'
[(set (match_operand:SI 0 'general_operand' '')
(const_int 0))
(set (strict_low_part
(subreg:HI
(match_dup 0)
0))
(match_operand:HI 1 'general_operand' ''))]
''
'operands[1] = make_safe_from (operands[1], operands[0]);')
Здесь сгенерированы два RTL insn - один что бы очистить весь выходной
операнд, а другой для того, что бы копировать входной операнд в его нижнею
половину. Эта последовательность некорректна если входной операнд ссылается
на выходной операнд (на его старое значение), поэтому операторы подготовки
проверяют, что это не так. Функция 'make_safe_from' копирует операнд
'operands[1]' во временный регистр если он обращается к 'operands[0]'.
Это делается с помощью генерации другого RTL insn.
Наконец, третий пример демонстрирует использование внутреннего операнда Ноль-расширение на SPUR чипах осуществляется с помощью применения 'and' к результату и маски половины слова. Но эта маска не может быть представлена с помощью 'const_int', потому что значение константы слишком велико для его корректного представления на этой машине. Поэтому она должна быть скопирована в регистр с помощью 'force_reg' и тогда этот регистр используется в операции 'and'.
(define_expand 'zero_extendhisi2'
[(set (match_operand:SI 0 'register_operand' '')
(and:SI (subreg:SI
(match_operand:HI 1 'register_operand' '')
0)
(match_dup 2)))]
''
'operands[2]
= force_reg (SImode, gen_rtx (CONST_INT,
VOIDmode, 65535)); ')
*Замечание: Если 'define_expand' используется для того, что бы
обслужить стандартную бинарную или унарную арифметическую операцию, то
последний insn в сгенерированной последовательности не должен быть
'code_label',`barrier' или `note'. Он должен быть `insn', `jump_insn'
или `call_insn'. Если Вам не нужен настоящий insn в конце, то сгенерируйте
insn, который копирует результат операций сам в себя. Такой insn не
генерирует кода, но может предохранить от проблем в трансляторе.
Существует два случая, когда Вы должны определить, как происходит расчленение команды на много insn. На машинах, имеющих команды, нуждающиеся в задержке (см. Слот задержки) или команды, вывод которых не доступен для многократных циклов. Фазы транслятора, которые оптимизируют эти случаи должны быть способна перемещать insn в одно-командный слот задержки. Однако, некоторые insns могут генерировать более одной машинной команды. Эти insn не могут быть помещены в слот задержки.
Часто Вы можете заменить insn на список список insnов каждое из которых соответствует одной машинной команде. Недостаток - медленная трансляция, требующая большого количества памяти. Если возникающий в результате insns слишком сложен, то оптимизация в трансляции уменьшается. Если есть причины предположить, что разбиение insn улучшит команду или планирование слота задержки, то транслятор его выполняет.
Фаза комбинирования insn также разбивает мнимые (putative) insn. Если в сложном выражении, которому не находится соответствующего образца 'define_insn', три insn сливаются в один, то фаза комбинирования пытается разбить сложный образеца в два распознающихся insn. Обычно можно разбить сложный образец на два образца путем разбиения некоторого подвыражения. Тем не менее, в некоторых других случаях, таких как выполнение сложения на RISC машине большой константы в два insn, способ разбиения операции сложения на два insn машинно-зависим.
Определение 'define_split' говорит транслятору как разбивать сложный insn на несколько более простых. Это выглядит примерно так:
(define_split
[INSN-PATTERN]
'CONDITION'
[NEW-INSN-PATTERN-1
NEW-INSN-PATTERN-2
...]
'PREPARATION STATEMENTS')
INSN-PATTERN - образец который должен быть разбит, а CONDITION конечное
условие тестирования, как в 'define_insn'. Когда insn, ответствующий
INSN-PATTERN и удовлетворяющий COONDITION, найден, он заменяется в списке insn
на insn NEW-INSN-PATTERN-1, NEW-INSN-PATTERN-2, и т.д.
PREPARATION STATEMENTS подобны тем операторам, которые, определены для 'define_expand' и выполняются прежде, чем сгенерирован новый RTL, prepare for the generated code or emit some insns whose pattern is not fixed. В отличие от тех выражений `define_expand', эти выражения не должны генерировать никаких новых псевдо регистров. Как только перезагрузка завершена, они также не должны выделять память в странице стека.
Образцы сравниваются с INSN-PATTERN в двух различных случаях. Если insn должен быть разбит для планирования слота задержки или для планирования insn, то уже известно, что insn корректен. Это означает, что ему должен соответствовать некий 'define_insn' и если `reload_completed' не ноль, известно, что он удовлетворяет ограничениям этого 'define_insn'. В этом случае новым insn-образцам так же должны соответствовать неким 'define_insn', и если `reload_completed' не ноль, должны так же удовлетворять ограничениям этих определений.
Как пример этого использования `define_split', рассмотрим следующий пример из `a29k.md', который разбивает `sign_extend' из `HImode' в `SImode' в пару insn сдвига:
(define_split
[(set (match_operand:SI 0 'gen_reg_operand' '')
(sign_extend:SI (match_operand:HI 1 'gen_reg_operand' '')))]
''
[(set (match_dup 0)
(ashift:SI (match_dup 1)
(const_int 16)))
(set (match_dup 0)
(ashiftrt:SI (match_dup 0)
(const_int 16)))]
'
{ operands[1] = gen_lowpart (SImode, operands[1]); }')
Когда фаза комбинирования пытается разбить insn-образец, это всегда
означает, что образцу *не* соответствует никакой `define_insn'.
Проход комбинирования сперва пытается разбить одиночное выражение 'set'
и затем то же выражение 'set' внутри 'parallel', после которого идет
клоббирование псевдо регистра, что бы использовать его как 'scratch' регистр.
В этих случаях комбайнер точно знает, какие два новых insn-образца должны
быть сгенерированы. Он проверит, соответствуют ли эти образцы каким-нибудь
'define_insn'-определениям, поэтому Вам не нужно делать эту проверку в
'define_split' (конечно, бессмысленно писать 'define_split', который
никогда не сгенерирует соответствующих insn).
Далее идет пример такого использования `define_split', взятый из `rs6000.md':
(define_split
[(set (match_operand:SI 0 'gen_reg_operand' '')
(plus:SI (match_operand:SI 1 'gen_reg_operand' '')
(match_operand:SI 2 'non_add_cint_operand' '')))]
''
[(set (match_dup 0) (plus:SI (match_dup 1) (match_dup 3)))
(set (match_dup 0) (plus:SI (match_dup 0) (match_dup 4)))]
'
{
int low = INTVAL (operands[2]) & 0xffff;
int high = (unsigned) INTVAL (operands[2]) >> 16;
if (low & 0x8000)
high++, low |= 0xffff0000;
operands[3] = gen_rtx (CONST_INT, VOIDmode, high << 16);
operands[4] = gen_rtx (CONST_INT, VOIDmode, low);
}')
Здесь предикат 'non_add_cint_operand' соответствует любому ' const_int '
который является *не* корректным операндом insn одиночного сложения.
Сложение с меньшим смещением написано так, чтобы оно могло замениться
на адрес последующей операции.
Пример из того же самого файла, который использует scratch регистр, генерирует сравнение равенства регистра и большой константы:
(define_split
[(set (match_operand:CC 0 'cc_reg_operand' '')
(compare:CC (match_operand:SI 1 'gen_reg_operand' '')
(match_operand:SI 2 'non_short_cint_operand' '')))
(clobber (match_operand:SI 3 'gen_reg_operand' ''))]
'find_single_use (operands[0], insn, 0)
&& (GET_CODE (*find_single_use (operands[0], insn, 0)) == EQ
|| GET_CODE (*find_single_use (operands[0], insn, 0)) == NE)'
[(set (match_dup 3) (xor:SI (match_dup 1) (match_dup 4)))
(set (match_dup 0) (compare:CC (match_dup 3) (match_dup 5)))]
'
{
/*Берет константу С, с которой мы сравниваем и смотрим, на что она
похоже, если ее расширить до 16 бит. Потом посмотрим,
какую константу можно ХОR с С, чтобы получить расширенное знаком
значение. */
int c = INTVAL (operands[2]);
int sextc = (c << 16) >> 16;
int xorv = c ^ sextc;
operands[4] = gen_rtx (CONST_INT, VOIDmode, xorv);
operands[5] = gen_rtx (CONST_INT, VOIDmode, sextc);
}')
Чтобы избежать путаницы, не пишите один 'define_split', принимающий
как insns, соответствующие некоторому 'define_insn ', так и
несоответствующие. Вместо этого надо писать два отдельных
'define_split'-определения, одно для корректных insns, другое для некорректных.
В дополнение к описанию команд, поддерживаемых целевой машиной, файл 'md' также определяет группу 'атрибутов' и набор значений для каждого из них. Каждому сгенерированному insn назначено значение для каждого атрибута. Возможно будет один атрибут, показывающий что insn обманывает (has on) машинный код условия. Этот атрибут 'NOTICE_UPDATE_CC' может затем использоваться для отслеживания кодов условий.
Выражение `define_attr' используется для того, чтобы определить каждый атрибут, требуемый целевой машиной. Это выглядит так:
(define_attr NAME LIST-OF-VALUES DEFAULT)
NAME - строка, определяющая имя определяемого атрибута.
LIST-OF-VALUES является либо строкой, определяющей через запятую список значений, которые могут быть назначены атрибуту, либо пустой строкой, которая указывает, что атрибут берет числовые значения.
DEFAULT - аттрибут-выражение, дающее значение этого атрибута для insns, которым соответствуют образцы, чье определение не включает в себя точного значения для этого атрибута. см. Пример Attr, для более полного описания обработки default. см. Постоянные ограничения, для информации по атрибутам, не зависящим ни от каких конкретных insn.
Для каждого определенного атрибута, ряд областей определения записан в файле 'insn-attr.h'. Для тех случаев, когда для атрибута определен явный набор значений, определено следующее:
(define_attr 'type' 'branch,fp,load,store,arith' ...)
следующие строки будут записаны в файл 'insn-attr.h'.
#define HAVE_ATTR_type
enum attr_type {TYPE_BRANCH, TYPE_FP, TYPE_LOAD,
TYPE_STORE, TYPE_ARITH};
extern enum attr_type get_attr_type ();
Если атрибут берет числовое значение, то 'enum' тип не будет определен,
и функция получающая значение атрибута возвратит 'int'.
Выражения RTL, используемые, чтобы определить атрибуты, используют коды, описанные выше, плюс несколько специфических для областей определения атрибута кодов. Эти выражения будут обсуждены далее. Атрибут-выражения должны иметь одну из следующих форм:
Целое число I определяет значение числового атрибута. I должно быть неотрицателеным.
Значение числового атрибута может быть определено либо с помощью 'const_int' либо как целое число, представляемое строкой в выражениях `const_string', `eq_attr' (см.ниже), и `set_attr'.
Строка VALUE определяет значение атрибутов константы. Если VALUE определено как `'*'', то это означает, что по умолчанию значение атрибута должно использоваться для insn, содержащего это выражение. `'*'' очевидно не может использоваться в DEFAULT-выражении 'define_attr'.
Если атрибут, чье значение определяется - числовой, то VALUE должно быть строка, содержащая неотрицательное целое число (обычно в этом случае используется 'const_int'). Иначе, оно должно содержать одно из корректных значений атрибута.
TEST определяет тест атрибута, чей формат определен ниже. Значение этого выражения - TRUE-VALUE, если ТЕST - истина и FALSE-VALUE если ложь.
Первый операнд этого выражения - массив, содержащий четное число выражений и состоящий из пар выражений TEST и VALUE. Значение выражения `cond' - это то из VALUE, которое соответствует первому истинному выражению TEST. Если все выражения TEST ложны, значение выражения `cond' - то выражение, которое установлено DEFAULT.
Выражения TEST могут иметь одну из следующих форм:
Этот тест истинен, если I отлично от нуля, иначе ложен.
Эти тесты истины, если соответствующая логическая функция истинна.
Этот тест истинен, если N-ый операнд insn, значение атрибута которого определяется, имеет тип M (если M - 'VOIDmode' то эта часть теста игнорируется ) и функция, определенная строкой PRED возвращает не ненулевое значение, в случае если проходит операнд N и режим M (эта часть теста игнорируется, если PRED - пустая строка).
Операнд CONSTRAINTS игнорируется и должен быть пустой строкой.
Эти тесты истины, если соответствующее сравнение из двух арифметических выражений истинно. (Арифметические выражения, сформированные с помощью выражений `plus', `minus', `mult', `div', `mod', `abs', `neg', `and', `ior', `xor', `not', `ashift', `lshiftrt', и `ashiftrt').
`const_int' and `symbol_ref' are always valid terms (см. Длины Insn). `symbol_ref' - строка, означающая выражение на С, которое оставляет 'int', сосчитанный процедурой `get_attr_...'. Обычно она должна быть глобальной переменной.
NAME - строка, определяющая имя атрибута.
VALUE - строка, которая является либо корректным значением для атрибута NAME, либо списком значений через запятую, либо значением, за которым идет '!', либо списком. Если VALUE не начинается с '!', то этот тест истинен, когда значение атрибута NAME текущего insn находится в списке, определенном VALUE. Если ЗНАЧЕНИЕ начинается с '!', то этот тест истинен, когда значение атрибута не в определенном списке.
Например,
(eq_attr 'type' 'load,store')
эквивалентно
(ior (eq_attr 'type' 'load') (eq_attr 'type' 'store'))
Если NAME определяет атрибут `alternative', то он относится к значению
переменной транслятора ' which_alternative '
(* note тверждение Вывода примечания::.) и значения должны быть
небольшими целыми числами.
Если NAME определяет атрибут `alternative', то это ссылка на значение переменной транслятора `which_alternative' (см. Оператор вывода) и значение должно быть маленьким целым числом. Например:
(eq_attr 'alternative' '2,3')
эквивалентно
(ior (eq (symbol_ref 'which_alternative') (const_int 2))
(eq (symbol_ref 'which_alternative') (const_int 3)))
Обратите внимание, что для большинства атрибутов тест `eq_attr'
упрощается в случаях, когда значение проверяемого атрибута известно для
всех insns, соответствующих специфическому образцу. Это намного более
общий случай.
Значение выражения `attr_flag' истинна, если флаг, определенный с помощью NAME - истина для 'insn', который планируется в настоящее время.
NAME - строка, указывающая один из флагов фиксированного набора, для проверки. Проверьте флаги `forward' и `backward' чтобы определить направление условного перехода (conditional branch). Проверите флаги `very_likely', `likely', 'very_unlikely', and `unlikely', что бы определить велика ли вероятность этого перехода .
Если флаг 'very_likely' истинен, то флаг 'likely' также истинен. Аналогично для флагов `very_unlikely' и `unlikely'.
Этот пример описывает слот задержки условного перехода, который может быть аннулирован для прямых (forward) ветвей которые исполняются (annul-true) или для обратных (backward) ветвей, которые не исполняются (annul-false).
(define_delay (eq_attr 'type' 'cbranch')
[(eq_attr 'in_branch_delay' 'true')
(and (eq_attr 'in_branch_delay' 'true')
(attr_flag 'forward'))
(and (eq_attr 'in_branch_delay' 'true')
(attr_flag 'backward'))])
Флаги `forward' и `backward' - ложь, если текущий планируемый 'insn'
не является условным переходом.
Флаги `very_likely' и `likely' истинны, если планируемый 'insn' не является условным переходом. Флаги `very_unlikely' и `unlikely' ложны, если планируемый 'insn' не является условным переходом.
'Attr_flag' используется только в течение планирования слота задержки и не имеет значения для других проходов транслятора.
Значение, присвоенное атрибуту insn, предварительно определено тем, какой из образцов согласован с этим insn (или который `define_peephole' сгенерировал его). Каждый `define_insn' и `define_peephole' может иметь необязательный параметр, определяющий значения атрибутов для соответствующих insn. Атрибуту, не определенному ни в каком insn, устанавливается значение 'по умолчанию', как определено в его `define_attr'. Широкое использование атрибутов 'по умолчанию', дает возможность определять значения только одного-двух атрибутов большинства insn образцов, что видно в примере из следующего раздела.
Последний аргумент `define_insn' и `define_peephole' (его можно не использовать) - это массив выражений, каждое из которых определяет значение единственного атрибута. Наиболее общий способ присвоения значения атрибуту - это использование выражения `set', первый операнд которого - `attr'-выражение, задающее имя устанавливаемого аргумента. Второй операнд `set' - выражение задающее значение атрибута, (см. Выражения).
Когда значение атрибута зависит от атрибута `alternative' (то есть, который является соответствующим вариантом в ограничении insn), может использоваться выражение `set_attr_alternative '. Это позволяет специфицировать один вектора атрибутного выражения для всех вариантов.
Когда не требуется общность произвольных атрибутных выражений, может использоваться более простое выражение `set_attr', которое позволяет определить строку, дающую либо одиночное значение атрибута либо список значений атрибута по одному на каждый вариант.
Ниже показывается форма каждой из вышеупомянутых спецификаций. В каждом случае NAME - строка, определяющая атрибут, который будет установлен.
VALUE-STRING либо строка, дающая требуемое значение атрибута, либо строка, содержащая список через запятую, дающий значения для удачных вариантов. Число элементов должно соответствовать числу вариантов в ограничении образца insn.
Обратите внимание, что может быть полезно определить '*' для некоторого варианта, и в таком случае атрибут примет значение по умолчанию для insns, соответствующего этому варианту.
В зависимости от варианта insn, значение будет одним из определенных значений. This is a shorthand for using a `cond' with tests on the `alternative' attribute.
Первый операнд 'set' должен быть специальным выражением RTL - 'attr', чей единственный операнд - строка, дающая имя устанавливаемому атрибуту. VALUE - значение атрибута.
(set_attr 'type' 'load,store,arith')
(set_attr_alternative 'type'
[(const_string 'load') (const_string 'store')
(const_string 'arith')])
(set (attr 'type')
(cond [(eq_attr 'alternative' '1') (const_string 'load')
(eq_attr 'alternative' '2') (const_string 'store')]
(const_string 'arith')))
Выражение `define_asm_attributes' обеспечивает механизм определения
атрибутов, назначенных insns, который получен из asm-операторов. Оно имеет
следующую форму:
(define_asm_attributes [ATTR-SETS])
где ATTR-SETS определен также как и для обоих выражений 'define_insn' и
`define_peephole '.
Эти значения будут обычно 'худшими' значениями атрибута. Например, они могли бы указывать, что код условия будет уничтожен.
Спецификация для атрибута `length' обрабатывается особенно. Способ вычисления длины 'asm' insn состоит в умножении длины, определенной в выражении 'define_asm_attributes' на число машинных команд, определенных в 'asm' операторе, определяемое с учетом числа точек с запятой и newlins в строке. Следовательно, значение атрибута 'length', определенного в 'define_asm_attributes' должно быть максимальной возможной длиной одиночной машинной команды.
Разумное использование значений по умолчанию важно для эффективного использовании insn атрибутов. Обычно, insns разделены на 'типы' и атрибут, обычно называемый 'type', используемый, для представления это значение. Этот атрибут обычно используется только, чтобы определить значение по умолчанию для других атрибутов. Пример разъяснит это использование.
Предположим, что мы имеем RISC машину с кодом условия и в которой в регистрах выполняются только операции с полным словом. Давайте предположим, что мы можем разделить все insns на загружающие, запоминающие, выполняющие (целые) арифметические операции, операции с плавающей точкой и условные.
Сейчас мы займемся определением действия insn на код условия и ограничим себя следующими возможными эффектами: Код условия может быть установлен непредсказуемо (clobbered), не измениться, быть установленным в зависимости от результатов операций, или изменяться только, если элемент предварительно установленный в коде условия был изменен.
Далее идет часть выборки файла 'md' для такой машины:
(define_attr 'type' 'load,store,arith,fp,branch' (const_string 'arith'))
(define_attr 'cc' 'clobber,unchanged,set,change0'
(cond [(eq_attr 'type' 'load')
(const_string 'change0')
(eq_attr 'type' 'store,branch')
(const_string 'unchanged')
(eq_attr 'type' 'arith')
(if_then_else (match_operand:SI 0 '' '')
(const_string 'set')
(const_string 'clobber'))]
(const_string 'clobber')))
(define_insn ''
[(set (match_operand:SI 0 'general_operand' '=r,r,m')
(match_operand:SI 1 'general_operand' 'r,m,r'))]
''
'@
move %0,%1
load %0,%1
store %0,%1'
[(set_attr 'type' 'arith,load,store')])
Обратите внимание, что мы принимаем в вышеупомянутом примере, что
арифметические операции, выполняемые в количествах меньше чем машинное слово
clobber код условия, так как они установят код условия к значению,
соответствующему полноно-словному результату.
На многих машинах предусмотрены многочисленные типы инструкций ветвления, каждый для своей длины условного смещения. В большинстве случаев, ассемблер выберет правильную инструкцию. Однако, когда ассемблер не может этого сделать, GCC может, если специальный атрибут, атрибут 'length', определен. Этот атрибут должен по определению иметь числовые значения определяемые при помощи записи пустой строки в его `define_attr'.
В случае атрибута 'length', в выражениях теста допускаются две дополнительные формы арифметических условий :
Это выражение обращается к адресу операнда N текущего insn, который должен быть 'label_ref'.
Она ссылается на адрес *текущего* insn. Может было бы лучше сделать ее адресом следующего insn, но это было бы неудобным, потому что длина текущего insn должна быть сосчитана.
Длины измеряются в байтах (наименьших адресуемых блоках).
Следующие макрокоманды могут использоваться, для совершенствования вычисления длины:
Когда используется insn-атрибут 'length', эта макрокоманда определяет значение, которое должно быть назначено адресу первого insn-а в функции. Если не определена, используется 0.
Если определена, то она меняет длину, назначенную для инструкции INSN как функцию от контекста в котором она используется. LENGTH - lvalue, содержащее изначально вычисленную длину insn-а. Это значение следует обновлять, используя правильную длину insn. Если требуется обновление, INSN не должна быть insn меняющей длину (varying-length insn).
Эта макрокоманда обычно не требуется. Случай, когда она требуется - ROMP. На этой машине размер `addr_vec' insn должен быть увеличен на два, чтобы компенсировать тот факт, что может потребоваться выравнивание.
Как пример определения переходов различной длины, рассмотрим IBM 360. Если мы примем соглашение, что в регистре будет установлен начальный адрес функции, то мы можем прыгать на метки в 4-кб от старта, используя 4-байтную инструкцию. В противном случае, мы будем нуждаться в 6-байтной последовательности для загрузки адреса из памяти и выполнения перехода.
На таких машинах образец для инструкции ветвления может быть определен как следующий:
(define_insn 'jump'
[(set (pc)
(label_ref (match_operand 0 '' '')))]
''
'*
{
return (get_attr_length (insn) == 4
? \'b %l0\' : \'l r15,=a(%l0); br r15\');
}'
[(set (attr 'length') (if_then_else (lt (match_dup 0) (const_int 4096))
(const_int 4)
(const_int 6)))])
Специальная форма `define_attr', где выражение для значения по умолчанию является 'постоянным' выражением, указывает атрибут, являющийся константой для данного запуска транслятора. Постоянные атрибуты могут быть использованы для для определения того, какая разновидность используется. Например:
(define_attr 'cpu' 'm88100,m88110,m88000'
(const
(cond [(symbol_ref 'TARGET_88100') (const_string 'm88100')
(symbol_ref 'TARGET_88110') (const_string 'm88110')]
(const_string 'm88000'))))
(define_attr 'memory' 'fast,slow'
(const
(if_then_else (symbol_ref 'TARGET_FAST_MEM')
(const_string 'fast')
(const_string 'slow'))))
Подпрограмма сгенерированная для постоянных атрибутов не имеет параметров,
т.к. она не зависит ни от каких конкретных insn-ов. RTL-выражения,
использующиеся для определения значения постоянного атрибута, могут
использовать форму `symbol_ref', но не могут использовать ни форму
`match_operand' ни форму `eq_attr', включающие insn атрибуты.
Механизм insn атрибутов может быть использован для определения требований к слотам задержки, если на целевой машине такие существуют. Инструкция должна требовать слот задержки, если какие-то инструкции физически расположенные за ней, выполняются так, как если бы были перед ней. Классическими примерами являются инструкции перехода и вызова, которые часто выполняют следующую инструкцию до того, как выполнен переход или вызов.
На некоторых машинах инструкции условного перехода могут дополнительно 'аннулировать' инструкции в слоте задержки. Это означает, что инструкция не будет выполнена для определенных ветвей прихода. Поддерживаются оба типа инструкций: те которые аннулируют, если ветвь - истина, и тех, которые аннулируют, если ложь.
Планирование слота задержки отличается от планирования инструкций тем, что нуждается ли инструкция в слоте задержки или нет, зависит только от типа сгенерированной инструкции и не зависит от данных передаваемых между инструкциями. Смотрите следующий раздел для обсуждения планирования инструкций, зависящего от данных.
Требование insn, нуждающегося в одном или более слотах задержки отображается через выражение `define_delay'. Это имеет следующую форму:
(define_delay TEST
[DELAY-1 ANNUL-TRUE-1 ANNUL-FALSE-1
DELAY-2 ANNUL-TRUE-2 ANNUL-FALSE-2
...])
TEST - проверка атрибутов, которая указывает прилагается ли этот
`define_delay' к конкретному insn. Если прилагается, то число требуемых
слотов задержки определяется длиной вектора, указанного как второй
аргумент. Insn, помещенный в слот задержки N, должен удовлетворять
проверке атрибутов DELAY-N. ANNUL-TRUE-N - тест атрибутов, который
определяет, какие insn-ы могут быть аннулированы, если ветвь - истина.
Аналогично, ANNUL-FALSE-N определяет какие insn-ы в слоте задержки
могут быть аннулированы, если ветвь - ложь. Если аннулирование не
поддерживается этим слотом задержки, то нужно написать `(nil)'.
Например, в часто встречаемом случае, где insn-ы ветвления и вызова требуют один слот задержки, который может содержать любой insn, отличный от insn-ов ветвления и вызова, в `md' файл было бы помещено следующее:
(define_delay (eq_attr 'type' 'branch,call')
[(eq_attr 'type' '!branch,call') (nil) (nil)])
Может быть определено множество выражений `define_delay'. В этом случае
каждое такое выражение определяет различные требования слота задержки
и не должно быть не одного insn-а, для которого верны хотя бы два
из тестов выражений `define_delay'.
Например, если мы имеем машину, требующую один слот задержки для ветвлений и два для вызовов, то никакой слот задержки не может содержать insn ветвления или вызова, и любой корректный insn в слоте задержки для ветвления может быть аннулирован, если ветвь - истина, мы можем представить это следующим образом:
(define_delay (eq_attr 'type' 'branch')
[(eq_attr 'type' '!branch,call')
(eq_attr 'type' '!branch,call')
(nil)])
(define_delay (eq_attr 'type' 'call')
[(eq_attr 'type' '!branch,call') (nil) (nil)
(eq_attr 'type' '!branch,call') (nil) (nil)])
На большинстве RISC машин имеются команды, чьи результаты недоступны для определенного числа циклов. В общем случае, команды загружают данные из памяти. На многих машинах случится pipeline stall, если данные запрошены слишком рано после команды загрузки.
Кроме того, многие более новые микропроцессоры имеют многофункциональные модули - обычно один для целого числа и один для плавающей точки, и часто, когда требуемый результат еще не готов, будет возникать pipeline stall.
Описания в этом разделе позволяют определить, сколько времени должно протечь между выполнением команды и временем, когда используется результат. Они также позволяют определить, когда выполнение команды задержит выполнение подобных команд.
Для целей определения в этом разделе, машина разделена на 'функциональные модули', каждый из которых выполняет специфический класс команд в порядке 'первый-вошел-первый-вышел'. Функциональные модули, которые принимают одну команду за каждый цикл и позволяют результату использоваться в преуспевающей команде (обычно через пересылку) не должны быть определены. Классические RISC микропроцессоры будут обычно иметь одиночный функциональный модуль, который мы можем называть `memory'. Более новые 'superscalar' процессоры будут часто иметь функциональные модули для операций с плавающей точкой, обычно по крайней мере для вещественного сложения и умножения.
Каждое использование функционального модуля классом insn определяется выражением `define_function_unit', которое выглядит приблизительно так:
(define_function_unit NAME MULTIPLICITY SIMULTANEITY
TEST READY-DELAY ISSUE-DELAY
[CONFLICT-LIST])
NAME - строка, дающая имя функционального модуля.
MULTIPLICITY - целое число, определяющее число идентичных модулей в процессоре. Если определен больше чем один модуль, то их планирование будет происходить независимо. Должны быть учтены только по-настоящему независимые модули. (Единственный общий пример машины, которая имеет несколько функциональных модулей для одного класса команды, являющиеся по-настоящему независимыми и не pipelined - два модуля умножения и два модуля сложения в CDC 6600.)
SIMULTANEITY определяет максимальный номер insns, который может выполняться в каждом образце функционального модуля одновременно, или ноль, если модуль - pipelined и не имеет никаких ограничений.
Все определения `define_function_unit', касающиеся функционального модуля NAME, должны иметь те же самые имена и значения для MULTIPLICITY и SIMULTANEITY.
TEST - тест атрибута, который выбирает insns, описываемый в этом определение. Обратите внимание, что insn может использовать более чем один функциональный модуль, а функциональный модуль может быть определен в более чем одном 'define_function_unit'.
READY-DELAY - целое число, которое определяет количество циклов, после которого результат команды может использоваться без всякой задержки.
? ISSUE-DELAY - целое число, которое определяет количество циклов после того, как команда, соответствующая выражению TEST начинает использовать этот модуль, до того как может начаться последующая команда. Цена N указывает задержку цикла номер N-1. Последующая команда может также быть отсрочена, если более ранняя команда имеет большее значение READY-DELAY. Этот эффект блокирования вычислен, используя термины SIMULTANEITY, READY-DELAY, ISSUE-DELAY, и CONFLICT-LIST. Для нормального не-pipelined функционального модуля, в частности SIMULTANEITY работает так, что взятый модуль, блокирует READY-DELAY циклов выполняющейся insn, и меньшее из значений ISSUE-DELAY игнорируется.
CONFLICT-LIST - дополнительный список, дающий уточненные цены конфликта (conflict costs) для этого модуля. Если этот список определен, то это - список выражений теста условии, которые нужно применить к insns, выбранным для выполнения в NAME, после insn который соответствует TEST, уже выполненному в NAME. Для каждого insn в списке, ISSUE-DELAY определяет цену конфликта; для insns, которого нет в списке, цена - ноль. Если этот список не определен, CONFLICT-LIST строится по умолчанию для всех команд, использующих функциональный модуль.
В большинстве случаев этот вектор используется, когда функциональный модуль для поддержки плавающей точки может pipeline-уть операции одинарной или двойной точности, но не обе сразу, или когда модуль памяти может pipeline-ать чтение, но не запись, и т.д. два
Как пример, рассмотрим классическую RISC машину, в которой результат команды загрузки не доступен в течении двух циклов (требуется одиночная команда 'delay') и в которой только одна команда загрузки может быть выполнена одновременно. Это было бы определено как:
(define_function_unit 'memory' 1 1 (eq_attr 'type' 'load') 2 0)
Для случая плавающей точки функциональный модуль, который может pipeline
либо одиночная либо двойная точность, но не обе. Иожет быть
определено следующее:
(define_function_unit
'fp' 1 0 (eq_attr 'type' 'sp_fp') 4 4 [(eq_attr 'type' 'dp_fp')])
(define_function_unit
'fp' 1 0 (eq_attr 'type' 'dp_fp') 4 4 [(eq_attr 'type' 'sp_fp')])
*Замечание*: Планировщик пытается избежать конфликтов функциональных
модулей и использует все определения в выражении `define_function_unit'.
Недавно мы обратили внимание, что эти определения не могут позволять
моделирование некоторых новейших "супер скалярных" процессоров, которые
имеют insn, использующие много pipeline модулей. Эти insn могут служить
причиной потенциального конфликта для второго модуля, используемого в
течение их выполнения, и не существует способа представления этого конфликта.
Мы приветствуем любые примеры того, как происходят конфликты функциональных
модулей в таких процессорах и предположения по их представлению.
В дополнение к файлу 'MACHINE.md', машинное описание включает файл С-заголовка, которому традиционно дано имя 'MACHINE.h'. Этот файл заголовка определяет многочисленные макрокоманды, которые передают информацию относительно целевой машины, не вписывающеюся в схему файла `.md'. Файл 'tm.h' должен быть связан с 'MACHINE.h'. Файл заголовка 'config.h' включает 'tm.h' и большинство исходных файлов транслятора так же включают 'config.h'.
Вы можете управлять драйвером трансляции.
Выражение C, которое определяет, имеет ли опция " -CHAR " параметры. Значение должно быть числом параметров опции, и нулем, если опций несколько.
По умолчанию эта макрокоманда определяется, чтобы правильно обрабатывать стандартные опции. Вы не должны определять ее, если Вы не собираетесь добавлять дополнительные опции, которые имеют параметры.
Выражение C, которое определяет, имеет ли опция " -NAME " параметры. Значение должно быть числом параметров опции, и нулем, если опций несколько. Эта макрокоманда скорее, чем " SWITCH_TAKES_ARG ", используется для многосимвольных имен опции.
По умолчанию, эта макрокоманда определена как " DEFAULT_WORD_SWITCH_TAKES_ARG ", которая правильно обрабатывает стандартные опции. Вы не должны не определять " WORD_SWITCH_TAKES_ARG ", если Вы не собираетесь добавлять дополнительные опции, которые имеют параметры. Всякое переопределение должно вызывать " DEFAULT_WORD_SWITCH_TAKES_ARG " и затем проверять дополнительные опции.
Строковое выражение C, которое является непустым, если компоновщику требуется пробел между опцией " -L " или " -o " и ее параметром.
Если эта макрокоманда не определена, значение по умолчанию - 0.
Строковая константа C, которая сообщает программе драйвера GNU CC опции для передачи CPP. Она может также указывать, как транслировать опции, которые Вы задали GNU CC, в опции GNU CC для передачи CPP.
Не определяйте эту макрокоманду, если не требуется ничего делать.
Если эта макрокоманда определена, препроцессор не будет определять встроенную макрокоманду " __SIZE_TYPE__ ". Макрокоманда " __SIZE_TYPE__ " будет определена вместо этого " CPP_SPEC ".
Она должна быть определена, если " SIZE_TYPE " зависит от машинно-зависимый флагов, которые не доступны для препроцессора. Иначе, она не должна быть определена.
Если эта макрокоманда определена, препроцессор не будет определять встроенную макрокоманду " __PTRDIFF_TYPE__ ". Макрокоманда " __PTRDIFF_TYPE__ " будет определена вместо этого " CPP_SPEC ".
Она должна быть определена, если " PTRDIFF_TYPE " зависит от машинно-зависимый флагов, которые не доступны для препроцессора. Иначе, она не должна быть определена.
Строковая константа C, которая сообщает программе драйвера GNU CC опции для передачи CPP. По умолчанию эта макрокоманда определена, чтобы передать опцию " -D__CHAR_UNSIGNED__ " CPP, если " char " будет обрабатываться " cc1 " как " unsigned char ".
Не определяйте эту макрокоманду, если Вам не нужно перекрывать определение по умолчанию.
Строковая константа C, которая сообщает программе драйвера GNU CC опции для передачи " cc1 ". Она может также определять, как транслировать опции, которые Вы задали GNU CC, в опции для GNU CC для передачи " cc1 ".
Не определяйте эту макрокоманду, если не требуется ничего делать.
Строковая константа C, которая сообщает программе драйвера GNU CC опции для передачи " cc1plus ". Она может также определять, как транслировать опции, которые Вы задали GNU CC, в опции для GNU CC для передачи " cc1plus ".
Не определяйте эту макрокоманду, если не требуется ничего делать.
Строковая константа C, которая сообщает программе драйвера GNU CC опции для передачи ассемблеру. Она может также определять, как транслировать которые Вы задали GNU CC, в опции для GNU CC для передачи ассемблеру. Для примера см. файл " sun3.h ".
Не определяйте эту макрокоманду, если не требуется ничего делать.
Строковая константа C, которая сообщает программе драйвера GNU CC, как выполнять программы, которые производят чистку после нормального ассемблера. Обычно это не является необходимым. Для примера см. файл " mips.h ".
Не определяйте эту макрокоманду, если не требуется ничего делать.
Строковая константа C, которая сообщает программе драйвера GNU CC опции для передачи компоновщику. Она может также определять, как транслировать опции, которые Вы задали GNU CC, в опции для GNU CC для передачи компоновщику.
Не определяйте эту макрокоманду, если не требуется ничего делать.
Другая строковая константа C, используемая подобно " LINK_SPEC ". Различие заключается в том, что " LIB_SPEC " используется в конце команды, задаваемой компоновщику.
Если эта макрокоманда не определена, значение по умолчанию - то, при условии, что загрузки Стандарт C библиотека из обычного места. См. " gcc.c ".
Другая строковая константа C, которая сообщает программе драйвера GNU CC, как и когда помещать ссылку на " libgcc.a " в командную строку компоновщика. Эта константа помещается и до, и после значения " LIB_SPEC ".
Если эта макрокоманда не определена, драйвер GNU CC по умолчанию передает строку " -lgcc " компоновщику, если опция " -shared " не определена.
Другая строковая константа C, используемая подобно " LINK_SPEC ". Различие заключается в том, что " STARTFILE_SPEC " используется в самом начале команды, задаваемой компоновщику.
Если эта макрокоманда не определена, по умолчанию стандартный файл запуска C загружается из обычного места. См. " gcc.c ".
Другая строковая константа C, используемая подобно " LINK_SPEC ". Различие заключается в том, что " ENDFILE_SPEC " используется в самом конце команды, задаваемой компоновщику.
Не определяйте эту макрокоманду, если не требуется ничего делать.
Определите эту макрокоманду, если программа драйвера сама должна искать библиотеку " libgcc.a " и не должна передавать опции " -L " компоновщику. Если Вы не определяете эту макрокоманду, программа драйвера передаст параметр " -lgcc ", чтобы компоновщик произвел поиск и передаст ему опции " -L ".
Определите эту макрокоманду, если программа драйвера сама должна искать библиотеку " libgcc.a ". Если Вы не определяете эту макрокоманду, программа драйвера передаст параметр " -lgcc ", чтобы компоновщик произвел поиск. Эта макрокоманда подобна " LINK_LIBGCC_SPECIAL ", за исключением того, что она не воздействуют на " -L " опции.
Определите эту макрокоманду как выражение C для инициализатора массива строк, чтобы сообщить программе драйвера, какие опции являются значениями по умолчанию в данной ситуации и, таким образом, не нуждаются в специальной обработке при использовании " MULTILIB_OPTIONS ".
Не определяйте эту макрокоманду, если " MULTILIB_OPTIONS " не определен во фрагменте makefile адресата или если ни одна из опций, перечисленных в " MULTILIB_OPTIONS ", не имеет значения по умолчанию. * См.: Фрагмент адресата::.
Определите эту макрокоманду, чтобы сообщить " gcc " что он должен транслировать префикс " -B " в опцию " -L " компоновщика, если префикс указывает абсолютное имя файла.
Определите эту макрокоманду как строковую константу C, если Вы хотите изменить стандартный выбор " /usr/local/lib/gcc-lib/ " как префикс по умолчанию при поиске исполняемых файлов транслятора.
Если определено, эта макрокоманда - дополнительный префикс после " STANDARD_EXEC_PREFIX ". " MD_EXEC_PREFIX " не ищется, если используется опция " -b " или транслятор построен как перекрестный.
Определите эту макрокоманду как строковую константу C, если Вы хотите изменить стандартный выбор " /usr/local/lib/ " как префикс по умолчанию, чтобы при поиске файлов запуска типа " crt0.o ".
Если определена, эта макрокоманда обеспечивает дополнительный префикс после стандартных префиксов. " MD_EXEC_PREFIX " не ищется, если используется опция " -b " или транслятор построен как перекрестный.
Если определена, эта макрокоманда обеспечивает еще один префикс после стандартных префиксов. Она не ищется, если используется опция " -b " или транслятор построен как перекрестный (кросс-транслятор).
Определите эту макрокоманду как строковую константу C, если Вы хотите установить переменные среды для программ, вызываемых драйвером, таких, как ассемблер и загрузчик. Драйвер передает значение этой макрокоманды " putenv ", чтобы инициализировать необходимые переменные среды.
Определите эту макрокоманду как строковую константу C, если Вы хотите изменить стандартный выбор " /usr/local/include " как префикс по умолчанию при поиске локальных файлов заголовка. " LOCAL_INCLUDE_DIR " идет перед " SYSTEM_INCLUDE_DIR " в порядке поиска.
Перекрестные трансляторы не используют эту макрокоманду и не ищут " /usr/local/include " или его замену.
Определите эту макрокоманду как строковую константу C, если Вы хотите указать свой каталог для поиска файлов заголовка перед стандартным каталогом. " SYSTEM_INCLUDE_DIR " идет перед " STANDARD_INCLUDE_DIR " в порядке поиска.
Перекрестные трансляторы не используют эту макрокоманду и не ищут указанный каталог.
Определите эту макрокоманду как строковую константу C, если Вы хотите изменить стандартный выбор " /usr/include " как префикс по умолчанию при поиске файлов заголовка.
Перекрестные трансляторы не используют эту макрокоманду и не ищут " /usr/include " или его замену.
Определите эту макрокоманду, если Вы хотите полностью изменить значение по умолчанию пути поиска включаемых файлов. Заданный по умолчанию путь поиска включает " GCC_INCLUDE_DIR ", " LOCAL_INCLUDE_DIR ", " SYSTEM_INCLUDE_DIR ", " GPLUSPLUS_INCLUDE_DIR ", и " STANDARD_INCLUDE_DIR ". Кроме того, " GPLUSPLUS_INCLUDE_DIR " и " GCC_INCLUDE_DIR " определяются автоматически " Makefile " и указывают частные области поиска для GCC. Каталог " GPLUSPLUS_INCLUDE_DIR " используется только для C++ программ.
Определение должно быть инициализаторос для массива структур. Каждый элемент массива должен иметь два элемента: имя каталога ( строковая константа) и флаг; для C ++ - только каталоги. Массив должен заканчиваться нулевым элементом. Вот, например, определение, используемое для VMS:
#define INCLUDE_DEFAULTS \
{ \
{ "GNU_GXX_INCLUDE:", 1}, \
{ "GNU_CC_INCLUDE:", 0}, \
{ "SYS$SYSROOT:[SYSLIB.]", 0}, \
{ ".", 0}, \
{ 0, 0} \
}
Вот порядок префиксов для исполняемых файлов:
Вот целевые спецификации времени выполнения.
Определите ее строковой константой, содержащей " -D " опции для определения предопределенных макрокоманд, которые идентифицируют эту машину и эту систему. Эти макрокоманды будут предопределенными, если не указана опция " -ansi ".
Кроме того, предопределен параллельный набор макрокоманд, чьи имена получаются добавлением " __ " в начале и в конце. Эти " __ " макрокоманды разрешаются ANSI стандартом, так что они предопределены независимо от того, указано ли " -ansi ".
Например, на Sun можно использовать следующее значение:
" -Dmc68000 -Dsun -Dunix "
Результат должен определять макрокоманды " __ mc68000 __ ", " __ sun __ " и
" __ unix __ " в любом случае, и макрокоманды " mc68000 ", " sun " и
" unix ", если не указано " -ansi ".
Это объявление должно присутствовать.
Этот набор макрокоманд предназначен для того, чтобы позволить параметрам команд транслятора включать или отключать использование опциональных особенностей целевой машины. Например, одно машинное описание служит и для 68000, и для 68020; параметр команды сообщает транслятору, использовать ли ему команды, имеющиеся только на 68020 или нет. Этот параметр команды работает посредством макрокоманды " TARGET_68020 " которая проверяет бит в " target_flags ".
Определите макрокоманду " TARGET_FEATURENAME " для каждой такой опции. Ее определение должно проверять бит в " target_flags "; например:
*define TARGET_68020 (target_flags & 1)
Одним из мест, где используются эти макрокоманды, являются
условные выражения образцов команд. Заметьте, как часто
" TARGET_68020 " появляется в файле машинного описания 68000, " m68k.md ".
Другое место их использования - это определение других макрокоманд в
файле" MACHINE.h ".
Эта макрокоманда определяет имена опций команды, чтобы устанавливать и очищать биты в " target_flags ". Определение - инициализатор с подгруппировкой для каждой опции команды.
Каждая подгруппировка содержит строковую константу, которая определяет имя опции, и число, которое содержит биты для установки в " target_flags ". Отрицательное число указывает на очистку битов; противоположное ему число указывает, какие биты очищать. Фактическое имя опции получается добавлением " -m " к указанному имени.
Одна из подгруппировок должна иметь пустую строку. Число в этой группировке - значение по умолчанию для " target_flags ". Любое действие опций начинается с этим значением.
Вот пример, который определяет " -m68000 " и " -m68020 " с противоположными значениями и выбирает последний как значение по умолчанию:
#define TARGET_SWITCHES \
{ { "68020", 1}, \
{ "68000", -1}, \
{ "", 1}}
Эта макрокоманда аналогична " TARGET_SWITCHES ", но определяет имена опций команды, которые имеют значения. Ее определение - инициализатор с подгруппировкой для каждой опции команды.
Каждая подгруппировка содержит строковую константу, которая определяет фиксированную часть имени опции и адрес переменной. Переменная типа " char * " устанавливается на переменную часть данной опции, если фиксированная часть соответствует. Фактическое имя опции получается добавлением " -m " к указанному имени.
Вот пример, который определяет " -mshort-data-NUMBER ". Если данная опция - " -mshort-data-512 ", переменная " m88k_short_data " будет установлена на строку " "512" ".
extern char *m88k_short_data;
#define TARGET_OPTIONS \
{ { "short-data-", &m88k_short_data } }
Эта макрокоманда - оператор C, выводящий на " stderr " строку, описывающую конкретный выбор машинного описания. Каждое машинное описание должно определять " TARGET_VERSION ". Например:
#ifdef MOTOROLA
#define TARGET_VERSION \
fprintf (stderr, " (68k, Motorola syntax)");
#else
#define TARGET_VERSION \
fprintf (stderr, " (68k, MIT syntax)");
#endif
Иногда некоторые комбинации опций команды не имеют смысла на конкретной целевой машине. Вы можете определить макрокоманду " OVERRIDE_OPTIONS ", чтобы принять это во внимание. Эта макрокоманда, если она определена, выполняется только однажды - сразу после того, как все опции команды будут проанализированы.
Не используйте эту макрокоманду, чтобы включить различные дополнительные оптимизации для " -O ". Для этого есть " OPTIMIZATION_OPTIONS ".
Некоторые машины могут хотеть изменить то, какие оптимизации выполняются для различных уровней оптимизации. Эта макрокоманда, если она определена, выполняется однажды - сразу после того, как уровень оптимизации определен и перед тем, как остаток опций команды проанализируется. Набор значений в этой макрокоманде используется по умолчанию для других опций командной строки.
LEVEL - заданный уровень оптимизации; 2, если указано " -O2 ", 1, если указано " -O " , и 0, если ничего не указано.
Вы не должны использовать эту макрокоманду, для изменения опций, которые не являются машинно-специфическими. Они должны одинаково зависеть от уровня оптимизации на всех поддериваемых машинах. Используйте эту макрокоманду для разрешения машинно-специфических оптимизаций.
* Не используйте " write_symbols " в этой макрокоманде! * Предполагается, что отладочные опции не изменяют сгенерированный код.
Определите эту макрокоманду, если отладка может выполняться даже без указателя кадра. Если эта макрокоманда определена, GNU CC будет включать опцию " -fomit-frame-pointer " всякий раз, когда указано " -O ".
Обратите внимание, что определения макрокоманд в этой таблице, которые являются размерами или выравниваниями, измеряемыми в битах, не обязаны быть постоянными. Они Это могут быть выражения C, который ссылаются на статические переменные, такие как "target_flags ". См.: Адресат времени выполнения::.
Задайте этому макросу значение 1, если старший бит в байте имеет наименьший номер; иначе задайте ему значение 0. Это означает, что побитовые команды отсчитывают биты от старшего. Если машина не имеет побитовых команды, то значение этого макроса не играет роли. Этот макрос не обязан быть константой.
Этот макрос не воздействует на способ упаковки полей структур, байтами или словами; этим управляет " BYTES_BIG_ENDIAN ".
Задайте этому макросу значение 1, если старший байт в слове имеет меньший номер. Этот макрос не обязан быть константой.
Задайте этому макросу значение 1 если в объекте из нескольких слов старшее слово имеет наименьший номер. Это применяется и к ячейкам памяти, и к регистрам; GNU CC всегда считает,что порядок слов в памяти такой же, как и в регистрах. Этот макрос не обязан быть константой.
Определите эту макрокоманду, если WORDS_BIG_ENDIAN - не константа. Это должно быть постоянное значение с тем же самым значением, что и WORDS_BIG_ENDIAN, которое будет использоваться только при компиляции libgcc2.c. Обычно значение устанавливается, основываясь на определениях препроцессора.
Задайте этому макросу значение 1, если числа с плавающей точкой " DFmode ", " XFmode " или " TFmode " сохраняются в памяти со словом, содержащим знаковый разряд по наименьшему адресу; иначе задайте ему значение 0. Этот макрос не обязан быть константой.
Вы не должны определять этот макрос, если упорядочение такое же, как для целых чисел из нескольких слов.
Задайте этому макросу значение, равное числу битов в минимальной адресуемой ячейке памяти (байте); обычно 8.
Число битов в слове; обычно 32.
Максимальное число битов в слове. Если это неопределено, значение по умолчанию - " BITS_PER_WORD ". Иначе, это - константа, равная наибольшему значению, которое может иметь " BITS_PER_WORD " во время выполнения.
Число байтов в слове; обычно 4.
Минимальное число байтов в слове. Если это неопределено, значение по умолчанию - " UNITS_PER_WORD ". Иначе, это - константа, равная наименьшему значению, которое может иметь " UNITS_PER_WORD " во время выполнения.
Длина указателя в битах. Вы не должны указывать значение, большее, чем длина " Pmode ". Если оно не равно ширине " Pmode ", Вы должны определить " POINTERS_EXTEND_UNSIGNED ".
Выражение C, чье значение отлично от нуля, если указатели, которые должны быть расширены от длины " POINTER_SIZE " до длины " Pmode ", следует расширять знаком, и ноль, если их следует расширять нулем.
Вы не должны определять эту макрокоманду, если " POINTER_SIZE " равно длине " Pmode ".
Макрокоманда для модификации M и UNSIGNEDP, когда объект, чей тип - TYPE и который имеет указанный тип и знаковость, должен быть сохранен в регистре. Эта макрокоманда вызывается только тогда, когда TYPE - скалярный тип.
На большинстве RISC машин, которые имеют операции для манипуляции только полными регистрами, определите эту макрокоманду, чтобы установить M в " word_mode ", если M - целочисленный тип, более узкий, чем " BITS_PER_WORD ". В большинстве случаев расширяться должны только целочисленные типы, потому что большая точность широких операций с плавающей точкой обычно дороже, чем для их более узких аналогов.
Для большинства машин макроопределение не изменяет UNSIGNEDP. Однако некоторые машины имеют команды, которые предпочтительно обрабатывают некоторые как знаковые, так и беззнаковые типы. Например, на DEC Alpha 32-битные команды загрузки из памяти и 32-битные команды сложения расширяются знаком до 64 бит. На таких машинах устанавливайте UNSIGNEDP в зависимости от того, какой вид расширения более эффективен.
Не определяйте эту макрокоманду, если она не должна изменять M.
Определите эту макрокоманду, если продвижение, описанное " PROMOTE_MODE ", должно быть также сделано для исходящих параметров функции.
Определите эту макрокоманду, если продвижение, описанное " PROMOTE_MODE ", должно быть также сделано для возвращаемых значений функции.
Если эта макрокоманда определена, " FUNCTION_VALUE " должна выполнить те же самые продвижения, что и сделанные " PROMOTE_MODE ".
Определите эту макрокоманду, если продвижение, описанное " PROMOTE_MODE " должно быть выполнено *только* для исходящих параметров функции или возвращаемых функцией значений, как указано " PROMOTE_FUNCTION_ARGS " и " PROMOTE_FUNCTION_RETURN ", соответственно.
Нормальное выравнивание, требуемое для параметров функции в стеке, в битах. Все параметры стека получают по крайней мере это выравнивание независимо от типа данных. На большинстве машин оно совпадает с размером целого числа.
Определите эту макрокоманду, если Вы хотите сохранить некоторое выравнивание для указателя стека. Определение - выражение C для желаемого выравнивания (измеряемое в битах).
Если " PUSH_ROUNDING " не определено, стек будет всегда выравниваться на указанную границу. Если " PUSH_ROUNDING " определено и определяет менее строгое выравнивание, чем " STACK_BOUNDARY ", выравнивание может быть потеряно на короткое время при записи параметров в стек.
Выравнивание, требуемое для точки входа в функцию, в битах.
Самое большое выравнивание, которое может потребоваться какому-либо типу данных на этой машине, в битах.
Самое большое выравнивание, которое может потребоваться какому-либо полю структуры на этой машине, в битах. Если определено, оно отменяет " BIGGEST_ALIGNMENT " для полей структур.
Самое большое выравнивание, поддерживаемое форматом объектного файла на этой машине. Используйте эту макрокоманду, чтобы ограничить выравнивание, которое может быть определено с использованием конструкции " __ attribute __ ((aligned (N))) ". Если не определено, значением по умолчанию является " BIGGEST_ALIGNMENT ".
Если определено, выражение C, чтобы вычислить выравнивание для статической переменной. TYPE - тип данных, а BASIC-ALIGN - выравнивание, которое объект имел бы без этой макрокоманды. Значение этой макрокоманды используется вместо этого выравнивания для выравнивания объекта.
Если эта макрокоманда не определена, то используется BASIC-ALIGN.
Одно из применений этой макрокоманды заключается в увеличении выравнивания данных среднего размера, чтобы все они поместились на меньшем количестве строк кэша. Другое - выравнивать символьные массивы на границу слова, чтобы вызовы " strcpy ", копирующие константы в символьные массивы, можно было сделать встроенными.
Если определено, выражение C для вычисления выравнивания для константы, которая помещается в память. CONSTANT - константа, а BASIC-ALIGN - выравнивание, которое объект имел бы без этой макрокоманды. Значение этой макрокоманды используется вместо этого выравнивания для выравнивания объекта.
Если эта макрокоманда не определена, то используется BASIC-ALIGN.
Типичным использованием этой макрокоманды является увеличение выравнивание для строковой константы до выравнивания на границу слова, так, чтобы вызовы " strcpy ", копирующие константы в символьные массивы, можно было сделать встроенными.
Выравнивание в битах, задаваемое битовому полю структуры, которое следует за пустым полем, типа " int: 0; ".
Обратите внимание, что " PCC_BITFIELD_TYPE_MATTERS " также воздействует на выравнивание, которое получается после пустого поля.
Число битов, которым должен быть кратным размер любой структуры или объединения. Размер каждой структуры и объединения округляется вверх до его кратного.
Если Вы не определяете эту макрокоманду, значение по умолчанию совпадает с " BITS_PER_UNIT ".
Задайте этому макросу значение 1, если команды не будут работать, в случае если заданные данные не будут иметь номинального выравнивания. Если команды в этом случае просто будут работать медленнее, задайте этому макросу значение 0.
Определите это, если Вы хотите имитировать способ многих других трансляторов C обработки выравнивания битовых полей и структур, которые содержат их.
Поведение состоит в том, что тип, заданный для битового поля (" int ", " short " или другой целочисленный тип) налагает выравнивание для всей структуры, как будто структура действительно содержит обычное поле этого типа. Кроме того, битовое поле помещается внутри структуры так, чтобы это поместилось бы внутри такого поля, не пересекая его границы.
Таким образом, на большинстве машин битовое поле, чей тип описан как " int " не будет пересекать границу четырех байт, и вынудит выравнивание на границу четырех байт для целой структуры. (Используемое выравнивание может быть не четыре байта; этим управляют другие параметры выравнивания.)
Если макрокоманда определена, определение должно быть выражением C; значение выражения, отличное от нуля, допускает такое поведение.
Обратите внимание, что, если эта макрокоманда не определена, или ее значение - ноль, некоторые битовые поля могут пересекать более чем одну границу выравнивания. Транслятор может поддерживать такие ссылки, если имеются insns " insv ", " extv " и " extzv ", которые могут непосредственно ссылаться на память.
Другой известный способ работы с битовыми полями состоит в том, чтобы определить " STRUCTURE_SIZE_BOUNDARY " такого размера, как " BIGGEST_ALIGNMENT ". Тогда к каждой структуре можно будет обращаться полными словами.
Если машина не имеет команд для работы с битовыми полями или если Вы определяете " STRUCTURE_SIZE_BOUNDARY " этим путем, Вы должны задать " PCC_BITFIELD_TYPE_MATTERS " значение, отличное от нуля.
Если ваша цель состоит в том, чтобы заставить GNU CC использовать те же самые соглашения для расположения битовых полей, которые используются другим транслятором, вот как исследовать то, что делает другой транслятор. Скомпилируйте и выполните вот эту программу:
struct foo1
{
char x;
char :0;
char y;
};
struct foo2
{
char x;
int :0;
char y;
};
main ()
{
printf ("Size of foo1 is %d\n",
sizeof (struct foo1));
printf ("Size of foo2 is %d\n",
sizeof (struct foo2));
exit (0);
}
Если она напечатает 2 и 5, то транслятор ведет себя так же, как Вы
получили бы, определив " PCC_BITFIELD_TYPE_MATTERS ".
Подобно PCC_BITFIELD_TYPE_MATTERS, за исключением того, что эффект ограничивается выравниванием битовых полей внутри структуры.
Определите эту макрокоманду как выражение для полного размера структуры (задаваемой STRUCT как узел дерева), если вычисленный размер полей - SIZE, а выравнивание - ALIGN.
Значение по умолчанию - округление SIZE вверх до числа, кратного ALIGN.
Определите эту макрокоманду как выражение для выравнивания структуры (задаваемой STRUCT как узел дерева), если выравнивание, вычисленное обычным путем - COMPUTED, а выравнивание, явно указанное - SPECIFIED.
Значением по умолчанию является SPECIFIED, если оно больше; иначе используется меньшее из COMPUTED и " BIGGEST_ALIGNMENT "
Целочисленное выражение для размера в битах самого большого целого числа машинного типа, который должен фактически использоваться. Все целочисленные машинные типы этого размера или меньше могут использоваться для структур и объединений с соответствующими размерами. Если эта макрокоманда не определена, предполагается " GET_MODE_BITSIZE (DImode) ".
Оператор C для проверки допустимости значения VALUE (типа " double ") для типа MODE. Это означает, что Вы проверяете, входит ли VALUE в диапазон возможных значений для типа MODE на этой целевой машине. Режим MODE - всегда тип класса " MODE_FLOAT ". OVERFLOW отлично от нуля, если значение оказывается вне диапазона.
Если VALUE недопустимо или если OVERFLOW отлично от нуля, Вы должны установить OVERFLOW в 1 и затем присвоить какое-нибудь допустимое значение VALUE. Прохождение недопустимого значения через транслятор может произвести неправильный код ассемблера, который может даже повлечь аварию ассемблеров Unix.
Эта макрокоманда не обязана определяться, если в ней нет потребности.
Код, отличающий формат с плавающей точкой на целевой машине. Имеется три определенных значения:
Этот код указывает формат с плавающей точкой IEEE. Это - значение по умолчанию; нет необходимости определять эту макрокоманду, если формат - IEEE.
Этот код указывает специфический формат, используемый на Vax.
Этот код указывает любой другой формат.
Порядок слов, составляющих значение с плавающей запятой, записанное в памяти, управляется " FLOAT_WORDS_BIG_ENDIAN " для целевой машина и " HOST_FLOAT_WORDS_BIG_ENDIAN " для главной ЭВМ.
Эти макрокоманды определяют размеры и другие характеристики стандартных базисных типов данных, используемых в компилируемых программах. В отличие от макрокоманд предыдущего раздела, они обращаются скорее к специфическим особенностям C и родственных языков, чем к фундаментальным аспектам формата хранения данных.
Выражение C для размера в битах типа " int " на целевой машине. Если Вы не определяете его, значение по умолчанию - одно слово.
Максимальное число для размера в битах типа " int " на целевой машине. Если оно не определено, значение по умолчанию - " INT_TYPE_SIZE ". Иначе, это - постоянное значение, которое является самым большим значением, какое " INT_TYPE_SIZE " может иметь во время выполнения программы. Оно используется в " cpp ".
Выражение C для размера в битах типа " short " на целевой машине. Если Вы не определяете его, значение по умолчанию - половина слова. (Если оно меньше, чем одна адресуемая единица памяти, то оно округляется вверх до ее размера.)
Выражение C для размера в битах типа " long " на целевой машине. Если Вы не определяете его, значение по умолчанию - одно слово.
Максимальное число для размера в битах типа " long " на целевой машине. Если оно не определено, значение по умолчанию - " LONG_TYPE_SIZE ". Иначе, это - постоянное значение, которое является самым большим значением, какое " LONG_TYPE_SIZE " может иметь во время выполнения программы. Оно используется в " cpp ".
Выражение C для размера в битах типа " long long " на целевой машине. Если Вы не определяете его, значение по умолчанию - два слова. Если Вы хотите поддерживать GNU Ada на вашей машине, это значение должно быть по крайней мере 64.
Выражение C для размера в битах типа " char " на целевой машине. Если Вы не определяете его, значение по умолчанию - четверть слова. (Если оно меньше, чем одна адресуемая единица памяти, то оно округляется вверх до ее размера.)
Максимальное число для размера в битах типа " char " на целевой машине. Если оно не определено, значение по умолчанию - " CHAR_TYPE_SIZE ". Иначе, это - постоянное значение, которое является самым большим значением, какое " CHAR_TYPE_SIZE " может иметь во время выполнения программы. Оно используется в " cpp ".
Выражение C для размера в битах типа " float " на целевой машине. Если Вы не определяете его, значение по умолчанию - одно слово.
Выражение C для размера в битах типа " double " на целевой машине. Если Вы не определяете его, значение по умолчанию - два слова.
Выражение C для размера в битах типа " long double " на целевой машине. Если Вы не определяете его, значение по умолчанию - два слова.
Выражение, равное 1 или 0, в зависимости от того, должен тип " char " быть знаковым или беззнаковым по умолчанию. Пользователь всегда может отменить это значение по умолчанию с опциями " -fsigned-char " и " -funsigned-char ".
Выражение C, определяющее, давать ли типу " enum " только столько байтов, сколько требуется, чтобы представить диапазон возможных значений этого типа. Значение, отличное от нуля, означает делать это; значение ноля означает, что все " enum " типы должны распределяться подобно " int ".
Если Вы не определяете макрокоманду, значение по умолчанию - 0.
Выражение C для строки, описывающей имя типа данных, используемого для значений размера. Тип " size_t " определяется с использованием содержимого строки.
Строка может содержать больше одного ключевого слова. Если это так, отделяйте их пробелами, и пишите сначала ключевое слово, указывающее длину, затем " unsigned ", если нужно, и в заключение " int ". Строка должна точно соответствовать одному из имен типа данных, определенных в функции " init_decl_processing " в файле " c-decl.c ". Вы не можете опускать " int " или изменять порядок - это приведет к аварии при запуске транслятора.
Если Вы не определяете эту макрокоманду, значение по умолчанию - " "long unsigned int " ".
Выражение C для строки, описывающей имя типа данных, используемого для значений разности двух указателей. Тип " ptrdiff_t " определяется с использованием содержимого строки. См. " SIZE_TYPE " выше для более подробной информации.
Если Вы не определяете эту макрокоманду, значение по умолчанию - " " long int " ".
Выражение C для строки, описывающей имя типа данных, используемого для длинных символов. Тип " wchar_t " определяется с использованием содержимого строки. См. " SIZE_TYPE " выше для более подробной информации.
Если Вы не определяете эту макрокоманду, значение по умолчанию - " "int" ".
Выражение C для размера в битах типа данных для длинных символов. Это используется в " cpp ", который не может использовать " WCHAR_TYPE ".
Максимальное число для размера в битах типа данных для длинных символов. Если оно не определено, значение по умолчанию - " WCHAR_TYPE_SIZE ". Иными словами, это - константа, которое является самым большим значением, которое " WCHAR_TYPE_SIZE " может иметь во время выполнения программы. Это используется в " cpp ".
Определите эту макрокоманду, если тип селекторов Objective C должен быть " int ".
Если эта макрокоманда не определена, то селекторы должны иметь тип " struct objc_selector * ".
Определите эту макрокоманду, если транслятор может группировать все селекторы вместе в вектор и использовать только одну метку в начале вектора. Иными словами, транслятор должен дать каждому селектору собственную ассемблерную метку.
На некоторых машинах важно иметь отдельную метку для каждого селектора, потому что это дает возможность компоновщику устранить двойные селекторы.
Константное выражение C для целого значения управляющей последовательности " \a ".
Константное выражение C для целых значений управляющих последовательностей " \b ", " \t " и " \n ".
Константное выражение C для целых значений управляющих последовательностей " \v ", " \f " и " \r ".
В этом разделе объясняется, как описывать, какие регистры имеет целевая машина и как (вообще) они могут использоваться.
Описание того, какие регистры могут использовать конкретные команды, сделано с классами регистров; см. *Классы Регистров::. По поводу информации об использовании регистров для обращения к кадру стека, см. *Регистры Кадра::. О передаче значений в регистрах см. *Параметры Регистров::. О возврате значений в регистрах, см. *Возврат скаляров::.
Регистры имеют различные характеристики.
Число аппаратных регистров, известных транслятору. Они получают номера от 0 до " FIRST_PSEUDO_REGISTER-1 "; таким образом, первому псевдорегистру действительно присваивается номер " FIRST_PSEUDO_REGISTER ".
Инициализатор, который говорит, какие регистры используются для фиксированных целей на протяжении всего оттранслированного кода и, следовательно, недоступны для общего распределения. Они могут включать указатель стека, указатель кадра (за исключением машинах, где он может использоваться как общий регистр, если указатель кадра не нужен), программный счетчик на машинах, где он рассматривается как адресуемый регистр, и любой другой пронумерованный регистр со стандартным использованием.
Эта информация выражается как последовательность чисел, разделяемых запятыми и заключенная в фигурные скобки. N-е число равно 1, если регистр N фиксирован, и 0 в противном случае.
Таблица, инициализированная этой макрокомандой, и таблица, инициализированной следующей, могут быть изменены во время выполнения программы как автоматически, под действием макрокоманды " CONDITIONAL_REGISTER_USAGE ", так и пользователем, при помощи опций команды " -ffixed-REG ", " -fcall-used-REG " и " -fcall-saved-REG ".
Подобно " FIXED_REGISTERS ", но имеет 1 для каждого регистра, который затирается (вообще говоря) обращениями к функции так же, как для фиксированных регистров. Эта макрокоманда, следовательно, идентифицирует регистры, которые не доступны для общего распределения значений, которые должны жить во время обращений к функции.
Если регистр имеет 0 в " CALL_USED_REGISTERS ", транслятор автоматически сохраняет его на входе в функцию и восстанавливает его на выходе из функции, если регистр используется внутри функции.
Ноль или более операторов C, которые могут условно изменять две переменных " fixed_regs " и " call_used_regs " (обе - типа " char[] ") после того, как они были инициализированы двумя предыдущими макрокомандами.
Это необходимо в случае, если фиксированные или затиаремые при вызове регистры зависят от целевых флажков.
Не определяйте эту макрокоманду, если не требуется ничего делать.
Если использование всего класса регистров зависит от целевых флагов, Вы можете сообщить об этом GCC, используя эту макрокоманду для установки " fixed_regs " и " call_used_regs " в 1 для каждого из регистров в классах, которые не должны использоваться GCC. Также определите макрокоманду " REG_CLASS_FROM_LETTER " так, чтобы она возвращала " NO_REGS ", если она вызывается с символом для класса, который не должен использоваться.
(Однако, если этот класс не включен в " GENERAL_REGS " и все образцы insn, чей ограничения разрешают этот класс, управляются целевыми переключателями, то GCC будет автоматически избегать использования этих регистров, когда целевые переключатели запрещают это.)
Если эта макрокоманда определена и имеет значение, отличное от нуля, это означает, что " setjmp " и связанные с ней функции не могут сохранить регистров, или что " longjmp " не может восстановить их. В качестве компенсации транслятор избегает помещать переменные в регистры в функциях, использующих " setjmp ".
Определите эту макрокоманду, если целевая машина имеет окна регистров. Это выражение C возвращает номер регистра, который видит вызываемая функция, в зависимости от номера регистра OUT, который видит вызывающая функция. Возвратите OUT, если номер регистра OUT не выходящий (outbound) регистр.
Определите эту макрокоманду, если целевая машина имеет окна регистров. Это выражение C возвращает номер регистра, который видит вызывающая функция, в зависимости от номера регистра IN, который видит вызываемая функция. Возвратите IN, если номер регистра IN не входящий (inbound) регистр.
Регистры распределяются по порядку.
Если определено, инициализатор для вектора целых чисел, содержащих номера аппаратных регистров в порядке, в котором GNU CC предпочтительно должен использовать их (от наиболее прдпочтительных к наименее).
Если эта макрокоманда не определена, самыми первыми используются регистры с самыми маленькими номерами ( все, кроме эквивалентных).
Одно из применений этой макрокоманды - на машинах, где регистры с самыми большими номерами всегда должны сохраняться и команды сохранения нескольких регистров поддерживают только последовательности последовательных регистров. На таких машинах определите " REG_ALLOC_ORDER " как инициализатор, заносящий в список первыми годные для распределения регистры с самыми большими номерами.
Оператор C (без точки с запятой) для выбора порядка распределения аппаратных регистров для псевдорегистров, локальных для базового блока.
Сохраните желательный порядок регистров в массиве " reg_alloc_order ". Элемент 0 должен быть регистр, распределяемым первым; элемент 1 - следующим, и так далее.
Тело макрокоманды не должно делать никаких предположений относительно содержимого " reg_alloc_order " перед выполнением макрокоманды.
На большинстве машин нет необходимости определять эту макрокоманду.
В этом разделе обсуждаются макрокоманды, которые описывают, какие виды значений (конкретно, какие машинные типы) каждый регистр может содержать, и сколько последовательных регистров необходимо для данного типа.
Выражение C для числа последовательных аппаратных регистров, начиная с регистра с номером REGNO, требуемого для хранения значения типа MODE.
Например, на машине, где все регистры - ровно одно слово, эту макрокоманду следует определить так:
#define HARD_REGNO_NREGS(REGNO, MODE) \
((GET_MODE_SIZE (MODE) + UNITS_PER_WORD - 1) \
/ UNITS_PER_WORD))
Выражение C, которое отлично от нуля, если допустимо сохранение значения типа MODE в аппаратном регистре с номером REGNO (или в нескольких регистрах, начиная с него). Для машины, где все регистры одинаковы, определения должно выглядеть так:
#define HARD_REGNO_MODE_OK (REGNO, MODE) 1
Для этой макрокоманды не является необходимой проверка номеров
фиксированных регистров, потому что механизм распределения рассматривает
их как всегда занятые.
На некоторых машинах, значения двойной точности должны храниться в четных/нечетных парах регистров. Способ сделать это заключается в том, чтобы запретить в этой макрокоманде нечетные номера регистров для таких типов.
Минимальное требование для типа, чтобы он подходил для регистра, заключается в том, что образец команды " movMODE " поддерживает перемещение между регистром и любым другим аппаратным регистром, для которого этот тип подходит; и это перемещение значения в регистр и обратно не изменяет его.
Так как та же самая команда, используемая для передвижения " SImode ", будет работать для всех более узких целочисленных типов, для " HARD_REGNO_MODE_OK " не обязательно на любой машине различать эти типы, если Вы определяете образцы " movhi ", и т.д., чтобы воспользоваться преимуществом этого. Это полезно из-за взаимодействия между " HARD_REGNO_MODE_OK " и " MODES_TIEABLE_P "; очень желательно, чтобы все целочисленные типы были связываемы таким образом.
Многие машины имеют специальные регистры для арифметики с плавающей точкой. Часто люди считают, что машинные типы с плавающей точкой позволяются только в регистрах с плавающей точкой. Это не так. Любые регистры, которые могут хранить целые числа, могут безопасно *сохранять* машинный тип с плавающей точкой, независимо от того, может или нет выполняться в этих регистрах плавающая арифметика. Целочисленные команды перемещения могут использоваться и для перемещения этих значений.
На некоторых машинах, однако, верно обратное: машинные типы с фиксированной точкой не могут находиться в плавающих регистрах. Это так, если плавающие регистры нормализуют любое значение, сохраненное в них, потому что сохранение не-плавающего значения там исказило бы его. В этом случае " HARD_REGNO_MODE_OK " должен запретить машинные типы с фиксированной точкой в плавающих регистрах. Но если плавающие регистры не нормализуются автоматически, если Вы можете сохранять любой набор битов в регистр и восстанавливать его без изменений, то любой машинный тип может храниться в плавающем регистре, и Вы можете определять с учетом этого эту макрокоманду.
Основное значение специальных плавающих регистров - это то, что к ним применимы команды арифметики с плавающей точкой. Однако это не имеет никакого отношения к " HARD_REGNO_MODE_OK ". Вы обрабатываете это, записывая соответствующие ограничения для этих команд.
На некоторых машинах доступ к плавающим регистрам особенно медленный, так что лучше хранить значение во кадре стека, чем в таком регистре, если с ним не выполняется команд плавающей арифметики. Поскольку плавающие регистры не содержатся в классе " GENERAL_REGS ", они не будут использоваться, если этого не потребует какое-нибудь ограничение образца.
Выражение C, которое отлично от нуля, если желательно выбирать распределение регистров так, чтобы избегать команд перемещения между a значениями типа MODE1 и значениями типа MODE2.
Если " HARD_REGNO_MODE_OK (R, MODE1) " и " HARD_REGNO_MODE_OK (R, MODE2) " являются различным для любого R, то " MODES_TIEABLE_P (MODE1, MODE2) " должно быть нулем.
На некоторых машинах, leaf-функция (то есть та, которая не производит никаких вызовов) может выполняться более эффективно, если не делает собственного окна регистров. Часто это означает, что она требует, чтобы параметры были в регистрах, в которые их передает вызывающая функция, вместо регистров, через которые они обычно поступают.
Специальная обработка для leaf-функций применяется только когда другие условия выполнены; например, часто они могут использовать только эти же регистры для собственных переменных и временных данных. Мы используем термин "leaf-функция", чтобы обозначить функцию, которая подходит для этой специальной обработки, так что функции без обращений не обязательно - "leaf-функции".
GNU CC назначает номера регистрам прежде чем узнает, является ли функция подходящая для обработки как leaf-функция. Так что ему требуется перенумеровать регистры, чтобы получить leaf-функцию. Следующие макрокоманды выполняют это.
"LEAF_REGISTERS' ("leaf-регистры") Инициализатор C для вектора, индексированного номерами аппаратных регистров, который содержит 1 для регистра, который является кандидатом на обработку для leaf-функции.
Если обработка leaf-функции включает перенумеровку регистров, то регистры, отмеченные выше, должны содержать 1 перед перенумерацией, как GNU CC обычно и распределяет. Регистры, которые будут фактически использоваться в ассемблерном коде, после изменения нумерации, не должны быть отмечены 1 в этом векторе.
Определите эту макрокоманду только если целевая пытается оптимизировать обработку leaf-функций.
"LEAF_REG_REMAP (REGNO)" Выражение C, значение которого - номер регистра, которому должен быть присвоен номер REGNO, когда функция обрабатывается как leaf-функция.
Если REGNO - номер регистра, который не должен появиться в leaf-функции перед изменением нумерации, то выражение должно выдать -1, что заставит транслятор прерваться.
Определите эту макрокоманду только если целевая машина пытается оптимизировать обработку leaf-функций, и чтобы сделать это, регистры должны быть перенумерованы.
Обычно, "FUNCTION_PROLOGUE" и "FUNCTION_EPILOGUE" ("пролог функции" и "эпилог функции") должны обрабатывать leaf-функции особо. Они могут проверить переменную C "leaf_function", которая отлична от нуля для leaf-функций. (Переменная "leaf_function" определена только если "LEAF_REGISTERS" определена.)
На компьютерах, где некоторые из регистров образуют стек (как в 80387 сопроцессоре для 80386), имеются некоторые особенности. Регистры стека обычно записываются, проталкиванием в стек, и пронумерованы относительно вершины стека.
В настоящее время, GNU CC может обрабатывать только одну группу стекоподобных регистров, а они должны быть последовательно пронумерованы.
Определите ее, если машина имеет стекоподобные регистры.
Номер первого стекоподобного регистра. Это - вершина стека.
Номер последнего стекоподобного регистра. Этот - дно стека.
Эти возможности работают не очень хорошо. Они существуют, потому что требуются для генерации правильного кода для 80387 сопроцессора 80386. Они больше не используются в соответствии c машинным описанием и могут быть удалены в более поздней версии транслятора. Не используйте их!
Если определена, то это - выражение C, значение которого отлично от нуля, если аппаратный номер регистра REGNO - перекрывающийся регистр. Это означает аппаратный регистр, который перекрывается c аппаратным регистром с другим номером. (Такое перекрытие нежелательно, но иногда позволяет поддерживаться машине, которая иначе не поддерживалась бы.) Эта макрокоманда должна возвратить значение, отличное от нуля, для *всех* регистров, которые накладываются на друг друга. GNU CC может использовать накладывающийся регистр только в некоторых ограниченных случаях. Они могут использоваться для распределения внутри базисного блока и могут быть spilled для перезагрузки; вот и все.
Если эта макрокоманда не определена, это означает, что ни один из аппаратных регистров не накладывается друг на друга. Это - обычная ситуация.
Если определена, то это - выражение C, значение которого должно быть отлично от нуля, если insn INSN имеет эффект таинственного затирания (clobbering) содержимого аппаратного регистра номер REGNO. "Таинственного" потому, что выражение insn RTL не описывает такого эффекта.
Если эта макрокоманда не определена, это означает, что никакая insn не clobbers регистры. Это - обычная ситуация; при прочих равных условиях, выражению RTL лучше всего показать весь процесс.
Если определена, то это - выражение C, значение которого отлично от нуля, если точные "REG_DEAD" замечания необходимы для номера аппаратного регистра REGNO во время получения ассемблерного кода. Когда это так, некоторые оптимизации, которые происходят после распределения регистров и могли бы свести на нет эти замечания, не выполняются, когда этот регистр включается в процесс.
Вы могли бы принять меры, чтобы предотвратить "смертельную" информацию о регистре, когда некоторый код в машинном описании, который выполняется, чтобы писать ассемблерный код, видит "смертельные" замечания. Это необходимо только, когда фактическая аппаратная возможность, о которой GNU CC думает как о регистре, не является регистром обычного типа. (Это может быть, например, аппаратный стек.)
Если эта макрокоманда не определена, это означает, что никакие "смертельные" примечания не должны сохраняться. Это - обычная ситуация.
На многих машинах пронумерованные регистры - не все эквивалентны. Например, некоторые регистры нельзя использовать для индексной адресации; некоторые регистры нельзя использовать в некоторых командах. Эти машинные ограничения известны транслятору через "классы регистров".
Вы определяете ряд классов регистров, придавая каждому имя и говоря, какие из регистров принадлежат ему. Затем вы можете задать классы регистров, которые разрешены как операнды в конкретных командах.
Вообще, каждый регистр будет принадлежать нескольким классам. Фактически, один класс должен быть назван "ALL_REGS" ("все регистры") и содержать все регистры. Другой класс должен быть назван "NO_REGS" ("никаких регистров") и не содержать никаких регистров. Часто объединение двух классов будет другим классом, однако это необязательно.
Один из классов должен быть назван "GENERAL_REGS" ("регистры общего назначения"). Имя не столь важно, но символы "r" и "g" определяет этот класс. Если "GENERAL_REGS' - то же, что "ALL_REGS", просто определите это как макрокоманду, которая разворачивается до "ALL_REGS".
Упорядочьте классы так, чтобы, если класс X содержится в классе Y то X, имел меньший номер класса чем Y.
Классы, отличные от "GENERAL_REGS", указываются в ограничениях на операнд через машинно-зависимые символы ограничения операнда. Вы можете определять такие символы, чтобы отвечать различным классам, затем использовать их в ограничениях на операнд.
Вы должны определить класс для объединения двух классов всякий раз, когда некоторая команда позволяет использовать оба класса. Например, если команда позволяет использовать как регистр с плавающей точкой (сопроцессорный), так и регистр общего назначения для некоторого операнда, вы должны определить класс "FLOAT_OR_GENERAL_REGS" ("вещественные или общие регистры"), который включает оба из них. Иначе вы получите неоптимальный код.
Вы должны также определить некоторую избыточную информацию относительно классов регистров: для каждого класса : какие классы он содержит и какие содержатся в нем; для каждой пары классов - самый большой класс, содержащийся в их объединении.
Когда значение, занимающее несколько последовательных регистров ожидается в некотором классе, все используемые регистры должны принадлежать этому классу. Следовательно, классы регистров не могут использоваться для усиления требования к регистровой паре, чтобы начаться регистром с четным номером. Способ определять это требование - "HARD_REGNO_MODE_OK".
Классы регистров, используемых как операнды побитового "И" или команд сдвига, имеют специальное требование: каждый такой класс должен иметь для каждого типа с фиксированной точкой, подкласс, регистры которого могут передать этот тип в память или из нее. Например, на некоторых машинах, операции для однобайтовых значений ("QImode") ограничены конкретными регистрами. Когда это так, каждый класс регистров, который используется в побитовом "И" , или командах сдвига, должен иметь подкласс, состоящий из регистров, из которых однобайтовые значения могут быть загружены или сохранены. Так что "PREFERRED_RELOAD_CLASS" всегда имеет значение для возврата.
Перечислимый тип, который должен быть определен всеми именами классов регистров как перечисляемыми значениями. "NO_REGS" должен быть первым. "ALL_REGS" должен быть последним классом регистров, сопровождаемым еще одним значением, "LIM_REG_CLASSES", которое не является классом регистров, но сообщает о количестве классов.
Каждый класс регистров имеет номер, который является значением приведения имени класса, к типу "int". Номер служит индексом во многих таблицах, описанных ниже.
Число различных классов регистров, определенных следующим образом:
#define N_REG_CLASSES (int) LIM_REG_CLASSES
Инициализатор, содержащий имена классов регистров как строковые константы C. Эти имена используются при писании некоторых отладочных дампов.
Инициализатор, содержащий оглавление классов регистров как целые числа, являющиеся битовыми масками. N-ое целое число определяет оглавление класса N. Целочисленная маска MASK интерпретируется так : регистр R находится в классе, если "MASK & (1 << R)" не равно нулю.
Когда машина имеет больше чем 32 регистра, целого числа ("int") не хватает. Тогда целые числа заменяются под-инициализаторами, группами по несколько целых чисел. Каждый под-инициализатор должен подходить как инициализатор для типа "HARD_REG_SET", который определен в "hard-reg-set.h".
Выражение C, значение которого - класс регистров, содержащий REGNO аппаратного регистра. В общем случае имеется более, чем один такой класс; выберите "минимальный" (такой что никакой меньший класс не содержит данный регистр).
Макрокоманда, определение которой - имя класса которому должен принадлежать правильный базовый регистр . Базовый регистр - тот, который используется в адресе, являющемся значением этого регистра плюс смещение.
Макрокоманда, определение которой - имя класса, которому должен принадлежать индексный регистр . Индексный регистр - тот, который используется в адресе, где значение его умножается на масштабирующий коэффициент или прибавляется к другому регистру (или добавляется к смещению).
Выражение C, которое определяет машинно-зависимые символы ограничения операнда для классов регистров. Если CHAR - такой символ, значением должен быть класс регистров, соответствующий ему. Иначе, значение должно быть "NO_REGS". Символ регистра "r", соответствующий классу "GENERAL_REGS", не будет передан этой макрокоманде; вы не должны обрабатывать его.
Выражение C, которое отлично от нуля, если регистр номер NUM подходит для использования как базовый регистр в адресах операндов. Это может быть как подходящий аппаратный регистр, так и псевдорегистр, в котором был распределен аппаратный регистр.
Выражение C, которое отлично от нуля если регистр номер NUM подходит для использования как индексный регистр в адресах операндов. Это может быть как подходящий аппаратный регистр, так и псевдорегистр, в котором был распределен аппаратный регистр.
Различие между индексным регистром и базовым регистром в том, что индексный регистр может масштабироваться. Если адрес включает сумму двух регистров, ни один из них не масштабирован, то любой может быть помечен как "основной", а другой как "индексный"; но какая бы пометка не использовалась, она должна удовлетворять ограничениям машины, регистры которой могут служить только в определенных местах. Транслятор пробует оба способа, ища правильный, и перезагружает один или оба регистра, только если никакой способ пометки не проходит.
Выражение C, которое налагает дополнительные ограничения на класс регистров, если необходимо копировать значение X в регистр класса CLASS. Значение - класс регистров; возможно CLASS, или другой, меньший класс. На многих машинах, безопасно следующее определение :
#define PREFERRED_RELOAD_CLASS (X, CLASS) CLASS
Иногда возвращение более ограниченного класса приводит к лучшему коду.
Например, на 68000, когда X - целочисленная константа, которая находится в
диапазоне для команды "moveq", значение этой макрокоманды - всегда "DATA_REGS",
так как CLASS включает регистры данных. Требование регистра данных гарантирует,
что "moveq" будет использоваться.
Если X - "const_double", возвращая "NO_REGS" вы может превратить X в константу в памяти. Это полезно на некоторых машинах, где непосредственные вещественные значения не могут быть загружены в некоторые типы регистров.
То же, что и "PREFERRED_RELOAD_CLASS", но для перезагрузки вывода вместо перезагрузки ввода. Если Вы не определяете эту макрокоманду, по умолчанию используется CLASS, неизмененный.
Выражение C, которое налагает дополнительные ограничения на класс регистров, чтобы использовать, когда необходимо держать значение типа MODE в перезагружаемом регистре для которого обычно использовался бы класс CLASS.
В отличие от "PREFERRED_RELOAD_CLASS", эта макрокоманда должна использоваться, когда имеются некоторые типы, которые просто не могут входить в некоторые классы перезагрузки.
Значение - класс регистров; возможно CLASS, или другой, меньший класс.
Не определяйте эту макрокоманду, если целевая машина имеет ограничения, которые требуют, чтобы макрокоманда делала нечто нетривиальное.
Многие машины имеют некоторые регистры, которые не могут быть скопированы непосредственно в память или из нее или даже из других типов регистров. Пример - "MQ" регистр, который на большинстве машин может быть скопирован только через регистр общего назначения, но не через память. Некоторые машины позволяют копировать все регистры в память или из нее , но требуют рабочего регистра для памяти (например, с символическим адресом на RT, и с некоторым символическим адресом на Sparc при компиляции PIC). В некоторых случаях требуются и промежуточный, и рабочий регистры.
Вы должны определить эти макрокоманды, чтобы указать для фазы перезагрузки, что может потребоваться распределить по крайней мере один регистр для перезагрузки в дополнение к регистру, содержащему данные. А именно, если при копировании X в регистр класса CLASS типа MODE требуется промежуточный регистр, вы должны определить "SECONDARY_INPUT_RELOAD_CLASS", чтобы возвратить самый большой класс регистров, все регистры которого могут использоваться как промежуточные или рабочие регистры.
Если при копировании регистра класса CLASS типа MODE в X требуется промежуточный или рабочий регистр, "SECONDARY_OUTPUT_RELOAD_CLASS" должна быть определена, чтобы возвратить самый большой требуемый класс регистров. Если требования для перезагрузок ввода и вывода одни и те же, то должна использоваться макрокоманда "SECONDARY_RELOAD_CLASS" вместо того, чтобы определять обе макрокоманды совершенно одинаковыми.
Значения, возвращенные этими макрокомандами - часто "GENERAL_REGS". Возвращается "NO_REGS", если не требуется никакого запасного регистра; то есть, если X может быть непосредственно скопирован в или из регистра класса CLASS типа MODE, не требуя рабочего регистра. Не определяйте эту макрокоманду, если она всегда возвращала бы "NO_REGS".
Если требуется рабочий регистр (с промежуточным регистром или без него), вы должны определить образцы для "reload_inM" или "reload_outM", как требуется (*обратите внимание на Стандартные Имена::.. Эти образцы, которые будут обычно выполняться с "define_expand", должны быть подобны образцам "movM", за исключением того, что операнд 2 - рабочий регистр.
Определите ограничения для регистра перезагрузки и рабочего регистра, которые содержат единственный класс регистров. Если первоначальный регистр перезагрузки (класс которого - CLASS) может встречать ограничение, данное в образце, значение, возвращенное этими макрокомандами используется для класса рабочего регистра. Иначе, требуются два дополнительных регистра перезагрузки. Их классы получены из ограничений в образце insn.
X может быть псевдорегистром или подрегистром псевдорегистра, который может быть в аппаратном регистре или в памяти. Используйте "true_regnum", чтобы выяснить это; она возвратит -1, если псевдорегистр находится в памяти или номер аппаратного регистра, если псевдорегистр находится в регистре.
Эти макрокоманды не должны использоваться в случае, если специфический класс регистров может быть только скопирован в память или в другой класс регистров. В этом случае, вторичные регистры перезагрузки необязательны и не помогают. Вместо этого для выполнения копирования должен использоваться стек, и образец "movM" должен использовать память как место промежуточного хранения. Это часто происходит между регистрами с плавающей точкой и регистрами общего назначения.
Некоторые машины имеют свойство, что некоторые регистры не могут быть скопированы в некоторые другие регистры без использования памяти. Определите эту макрокоманду на этих машинах, чтобы это было выражением C, которое отлично от нуля, если объекты типа M в регистрах CLASS1 могут быть скопированы в регистры класса CLASS2, только сохраняя регистр CLASS1 в память и загружая ячейку памяти в регистр класса CLASS2.
Не определяйте эту макрокоманду, если значение было бы всегда ноль.
Обычно, когда "SECONDARY_MEMORY_NEEDED" определена, транслятор распределяет слот (slot) стека для ячейки памяти, необходимой для копии регистра. Если эта макрокоманда определена, то транслятор вместо этого использует ячейку памяти, определенную этой макрокомандой.
Не определяйте эту макрокоманду, если Вы не определили "SECONDARY_MEMORY_NEEDED".
Когда транслятор нуждается во вторичной ячейке памяти, чтобы копировать один регистр типа MODE в другой, он обычно распределяет достаточное количество памяти, чтобы хранить "BITS_PER_WORD" битов и выполняет операции сохранения/загрузки в типе шириной в много битов, класс которого - MODE.
Это пойдет на большинстве машин, потому что это гарантирует, что все биты регистра скопированы, и предотвращает доступ к регистрам в более узкого (по ширине) типа, что некоторые машины запрещают для регистров с плавающей точкой.
Однако, это заданное по умолчанию поведение неправильно на некоторых машинах, таких как, например, DEC Alpha, которые сохраняют короткие целых числа в регистрах с плавающей точкой не так, как в целочисленных регистрах. На этих машинах, заданное по умолчанию расширение не будет работать правильно, и вы должны определить эту макрокоманду, чтобы подавить это расширение в некоторых случаях. См. подробности в файле "alpha.h".
Не определяйте эту макрокоманду, если Вы не определяете "SECONDARY_MEMORY_NEEDED" или если расширение MODE до типа, который имеет ширину "BITS_PER_WORD" бит, работает правильно на вашей машине.
Обычно транслятор избегает выбирать регистры, которые были явно упомянуты в rtl, как spill-регистры (те, которые используются, для передачи параметров и возвращаемого значения). Однако, некоторые машины имеют слишком мало регистров некоторых классов, что не хватит регистров, чтобы использовать их как spill-регистры, если это было выполнено.
Определите "SMALL_REGISTER_CLASSES" на этих машинах. Когда она определена, транслятор позволяет регистрам, явно используемым в rtl, использоваться как spill-регистры, но предотвращает расширение времени существования этих регистров.
Определять эту макрокоманду всегда безопасно, но если вы без необходимости определяете ее, то в некоторых случаях вы уменьшите возможности оптимизации, которая может выполняться. Если вы не определяете эту макрокоманду, когда это требуется, что транслятор исчерпает все spill-регистры и напечатает сообщение о фатальной ошибке. На большинстве машин, вы не должны определять эту макрокоманду.
Выражение C, значение которого отлично от нуля если псевдорегистры, которые были назначены регистрам класса CLASS, могут быть использованы как spill-регистры, потому что регистры класса CLASS необходимы для spill-регистров.
Значение по умолчанию этой макрокоманды равно 1, если CLASS имеет ровно один регистр, иначе - ноль . На большинстве машин, это значение по умолчанию должно использоваться. Просто определите эту макрокоманду как некоторое другое выражение, если псевдорегистры, распределенные "local-alloc.c", заканчиваются в памяти, потому что их аппаратные регистры были необходимы для spill-регистров. Если эта макрокоманда возвращает не ноль для этих классов, эти псевдорегистры будут распределены "global.c", который знает, как перераспределить псевдорегистр в другой регистр. Если не имелось бы другого регистра для перераспределения, вам не следовало бы изменять определение этой макрокоманды, так как единственный эффект такого определения был бы замедление распределения регистров.
Выражение C для максимального числа последовательных регистров класса CLASS, требуемых для хранения значения типа MODE.
Макрокоманда тесно связана с макрокомандой "HARD_REGNO_NREGS". Фактически, значение макрокоманды "CLASS_MAX_NREGS (CLASS, MODE)" должно быть максимальным значением "HARD_REGNO_NREGS(REGNO,MODE)" по всем значениям REGNO в классе CLASS.
Эти макрокоманды помогают управлять обработкой значений в много слов в процессе перезагрузки.
Если определена, то это выражение C для класса, который содержит регистры, к которым транслятор должен всегда обращаться в типе, размер которого - тот же, что у типа, в котором он загрузил регистр.
Для примера, загрузка 32-битного целого числа или числа с плавающей точкой в регистры с плавающей точкой на Альфе расширяет их до 64 битов. Следовательно, загрузка 64-битного объекта и затем сохранение его как 32-битного не сохраняют младшие 32 бита, как было бы в случае нормального регистра. Так что "alpha.h" определяет эту макрокоманду как "FLOAT_REGS".
Три других специальных макрокоманды описывают, какие операнды пригодны для каких символов ограничения.
Выражение C, которое определяет машинно-зависимые символы ограничения операнда которые определяют специфические диапазоны целочисленных значений. Если C - один из этих символов, выражение должно проверить, что VALUE, целое число, находится в соответствующем диапазоне и возвратить 1 если это так, иначе - 0. Если C - не является одним из этих символов, то значение должно быть 0 независимо от VALUE.
Выражение C, которое определяет машинно-зависимые символы ограничения операнда, которые специфицируют конкретные диапазоны значений "const_double".
Если C - один из этих символов, выражение должно проверить, что VALUE, RTX кода "const_double", находится в соответствующем диапазоне и возвратить 1 если так, иначе - 0. Если C - не является одним из этих символов, значение должно быть 0 независимо от VALUE.
"const_double" используется для всех констант с плавающей точкой и для "DImode" констант с фиксированной точкой. Данный символ может принимать любое или оба вида значений. Он может использовать "GET_MODE " чтобы различить эти виды.
Выражение C, которое определяет опциональные машинно-зависимые символы ограничения, которые могут использоваться, чтобы выделять специфические типы операндов, обычно ссылки в памяти, для целевой машины. Обычно эта макрокоманда не будет определена. Если это требуется для специфической целевой машины, она должна возвратить 1, если VALUE соответствует типу операнда, представленному символом ограничения C. Если C не определен как дополнительное ограничение, возвращенное значение должно быть 0 независимо от VALUE.
Например, на ROMP, команды загрузки не могут иметь вывод в r0, если ссылка в памяти содержит символический адрес. Символ ограничения "Q" определен как представляющий адрес в памяти, который *не* содержит символического адреса. Альтернатива определена как "Q"-ограничение на ввод и "r"-ограничение на вывод. Следующая альтернатива определяет "m" на вводе и класс регистров, который не включает r0 на выводе.
Здесь описываются формат стека и соглашения о вызовах.
Вот основные параметры стека.
Определите эту макрокоманду, если при вталкивании слова в стек указатель стека перемещается на меньший адрес.
Когда мы говорим, "определите эту макрокоманду, если ...", это означает, что транслятор проверяет эту макрокоманду только с "#ifdef", так что точное определение не имеет значения.
Определите эту макрокоманду, если адреса локальных переменных имеют отрицательные смещения относительно указателя кадра.
Определите эту макрокоманду, если последовательные параметры к функции занимают уменьшающиеся адреса в стеке.
Смещение от указателя кадра до первой локальной переменной, которая может быть распределена.
Если "FRAME_GROWS_DOWNWARD", то смещение следующей локальной переменной слота находится вычитанием длины первой локальной переменной из "STARTING_FRAME_OFFSET". Или же прибавлением длины первой локальной переменной к значению "STARTING_FRAME_OFFSET".
Смещение от регистра указателя стека до первого расположения, в которое помещены поступающие параметры. Если не определена, то используется значение по умолчанию - 0. Это - верное значение для большинства машин.
Если "ARGS_GROW_DOWNWARD", то это - смещение к расположению над первым расположением, в которое помещены поступающие параметры.
Смещение регистра-указателя параметров до адреса первого параметра. На некоторых машинах это может зависеть от типа функции.
Если "ARGS_GROW_DOWNWARD", это - смещение расположения над адресом первого параметра.
Смещение от регистра указателя стека до того, что динамически размещено в стеке, например "alloca".
Значение по умолчанию для этой макрокоманды - "STACK_POINTER_OFFSET" плюс длина параметров. Значение по умолчанию правильно для большинства машин. См. подробности в "function.c".
Выражение C, значение которого - RTL-представление адреса в кадре стека, где сохранен указатель на кадр вызывающей функции. Имейте в виду, что FRAMEADDR - RTL-выражение для адреса самого кадра стека.
Если Вы не определяете эту макрокоманду, по умолчанию должно быть возвращено значение FRAMEADDR - то есть адрес кадра стека, или адрес слова стека, которое указывает на предыдущий кадр.
Если определена, то это выражение C, которое производит машинно - специфический код установки стека в такое положение, чтобы можно было обращаться к произвольным кадрам. Например, на Sparc, мы должны сбросить все окна регистров в стек прежде, чем мы можем обращаться к произвольным кадрам. Эту макрокоманду редко надо определять.
Выражение C, значение которого - RTL-представление значения адреса возврата для COUNT кадра, полученное из текущего кадра. FRAMEADDR - указатель COUNT кадра, или указатель на COUNT-1 кадра, если "RETURN_ADDR_IN_PREVIOUS_FRAME" определена.
Определите ее, если к адресу возврата конкретного кадра стека обращаются из указателя предыдущего кадра стека.
Обсуждение регистров, адресующих кадр стека.
Номер регистра указателя стека, который должен также быть фиксированным регистром из "FIXED_REGISTERS". На большинстве машин, аппаратные средства определяют, какой это регистр.
Номер регистра указателя кадра, который используется, чтобы обратиться к автоматическим переменным в кадре стека. На некоторых машинах, аппаратные средства определяют, какой это регистр. На других машинах вы можете выбирать любой регистр, какой пожелаете, для этой цели.
На некоторых машинах смещение между указателем кадра и начальным смещением автоматических переменных неизвестно, пока не выполнено распределение регистров (например, потому что сохраненные регистры - между этими двумя расположениями). На таких машинах определите "FRAME_POINTER_REGNUM" как номер специального, фиксированного регистра, который должен использоваться внутри (internally), пока смещение не станет известным, и определите "HARD_FRAME_POINTER_REGNUM" как фактический номер аппаратного регистра, используемого для указателя кадра.
Вы должны определить эту макрокоманду только в очень редком случае, когда невозможно вычислить смещение между указателем кадра и автоматическими переменными, пока распределение регистров не было завершено. Когда эта макрокоманда определена, вы должны также указать в вашем определении "ELIMINABLE_REGS", как заменить "FRAME_POINTER_REGNUM" на "HARD_FRAME_POINTER_REGNUM" или на "STACK_POINTER_REGNUM".
Не определяйте эту макрокоманду, если она совпадала бы с "FRAME_POINTER_REGNUM".
Номер arg регистра указателя, который используется для обращения к списку параметров функции. На некоторых машинах, это - то же, что и регистр указателя кадра. На некоторых машинах, аппаратные средства определяют, какой это регистр. На других машинах вы можете выбрать любой регистр, который пожелаете, для этой цели. Если это - не тот же самый регистр, что и регистр указателя кадра, то Вы должны отметить его как фиксированный регистр из "FIXED_REGISTERS", или принять меры для устранения его (*обратите внимание на Удаление::.).
Номера регистров, используемые для передачи указателя статической цепи функции. Если используются окна регистров, то это номер регистра, видимый вызываемой функцией - "STATIC_CHAIN_INCOMING_REGNUM", в то время как номер регистра, видимый вызванной функцией - "STATIC_CHAIN_REGNUM". Если эти регистры одни и те же, то "STATIC_CHAIN_INCOMING_REGNUM" не должна быть определена.
Статический регистр цепи не должен быть фиксированным регистром.
Если статическая цепочка передана в память, эти макрокоманды не должны быть определены; вместо этого должны быть определены следующие две макрокоманды.
Если статическая цепочка передана в память, эти макрокоманды обеспечивают rtx данных выражений "mem", которые обозначают, где они сохранены. "STATIC_CHAIN" и "STATIC_CHAIN_INCOMING" делают ячейки видимыми как вызывающим, так и вызываемым функциям, соответственно. Часто первая будет при смещении из указателя стека и последняя при смещении из указателя кадра.
Переменные "stack_pointer_rtx", "frame_pointer_rtx" и "arg_pointer_rtx" будут проинициализированы до использования этих макрокоманд и должны использоваться для обращения к этим структурам.
Если статическая цепочка передана в регистр, две предыдущих макрокоманды должны быть определены вместо этих.
Что касается удаления указателя кадра и указателя аргументов.
Выражение C, которое отлично от нуля, если функция имеет и использует указатель кадра. Это выражение вычисляется в процессе перезагрузки. Если значение отлично от нуля, функция будет иметь указатель кадра.
Это выражение может в принципе исследовать текущую функцию и решить, опираясь на факты, но на большинстве машин, достаточно констант 0 и 1. Используйте 0, когда машина позволяет коду быть сгенерированному без указателя кадра, и это сохраняет немного времени и места. Используйте 1, когда нет преимущества от отсутствия указателя кадра.
В некоторых случаях, транслятор не знает, как произвести правильный код без указателя кадра. Транслятор распознает такие случаи и автоматически делает указатель кадра для функции, независимо от значения "FRAME_POINTER_REQUIRED". Не надо беспокоиться о них.
В функции, которой не требуется указатель кадра, регистр указателя кадра может быть распределен для обычного использования, если Вы не отметили его как фиксированный регистр. Для дополнительной информации об этом ищите "FIXED_REGISTERS".
Оператор C сохранения в переменной DEPTH-VAR разности между указателем кадра и указателем стека сразу после пролога функции. Значение было бы вычислено из информации типа результата "get_frame_size()" и таблиц регистров "regs_ever_live" и "call_used_regs".
Если "ELIMINABLE_REGS" определена, эта макрокоманда не будет использоваться и не должна быть определена. Иначе она должна быть определена, даже если "FRAME_POINTER_REQUIRED" определена как тождественно истинный; в этом случае, вы можете присвоить DEPTH-VAR любое значение.
Если определена, эта макрокоманда определяет таблицу пар регистров, используемую для устранения ненужных регистров, которые указывают на кадр стека. Если не определена, единственное удаление, которое транслятор пытается сделать - замена ссылок на указатель кадра на ссылки на указатель стека.
Определение этой макрокоманды состоит в списке инициализаций структур, каждая из которых определяет оригинальный регистр и регистр замены.
На некоторых машинах позиция указателя параметров неизвестна, пока трансляция не завершена. В таком случае, отдельный аппаратный регистр должен использоваться как указатель параметров. Этот регистр может быть удален путем замены на указатель кадра или на указатель параметров, в зависимости от того, удален или не удален указатель кадра.
В этом случае, вы могли бы определить: #define ELIMINABLE_REGS \ {{ARG_POINTER_REGNUM, STACK_POINTER_REGNUM}, \ {ARG_POINTER_REGNUM, FRAME_POINTER_REGNUM}, \ {FRAME_POINTER_REGNUM, STACK_POINTER_REGNUM}}
Обратите внимание, что удаление указателя параметров с указателем стека определено сначала, так как это удаление предпочтительно.
Выражение C, которое возвращает значение, отличное от нуля, если транслятору позволяется пробовать заменять регистр номер FROM-REG на регистр номер TO-REG. Эта макрокоманда должна быть определена только если определена "ELIMINABLE_REGS", и будет обычно константной 1, так как большинство случаев, предотвращающих удаление регистра - вещи о которых транслятор уже знает.
Эта макрокоманда подобна "INITIAL_FRAME_POINTER_OFFSET". Она определяет начальное различие между парой регистров. Макрокоманда должна быть определена, если "ELIMINABLE_REGS" определена.
Определяйте эту макрокоманду, если функция "longjmp" восстанавливает регистры из кадра стека, а не из сохраненных "setjmp". Некоторые величины не должны сохраняться в регистрах во время обращения к "setjmp" на таких машинах.
Макрокоманды в этом разделе управляют тем, как параметры передаются в стек. См. следующий раздел о других макрокомандах, которые управляют передачей конкретных типов параметров через регистры.
Определяйте эту макрокоманду, если параметр, объявленный в прототипе как целый тип меньший, чем "int", должен фактически быть передан как "int". В дополнение к избежанию ошибок в некоторых случаях несоответствия, это также приводит к лучшему коду на некоторых машинах.
Выражение C, которое является числом байт, фактически переданных через стек, когда команда пытается помещать NPUSHED байт.
Если целевая машина не имеет команды push ("поместить в стек"), не определяйте эту макрокоманду. Это указывает GNU CC использовать альтернативную стратегию: распределить весь блок параметров и затем сохранить параметры в стеке.
На некоторых машинах, определение
#define PUSH_ROUNDING (BYTES) (BYTES)
будет в самый раз. Но на других машинах команды, которые помещают в стек один
байт, фактически помещает два байта, поддерживая выравнивание. Тогда
определение должно быть :
#define PUSH_ROUNDING (BYTES) (((BYTES) + 1) и ~1)
Если определена, то максимальный размер области, требуемой для параметров, будет вычислен и будет помещен в переменную "current_function_outgoing_args_size". Ничего не будет помещаться на стек при каждом вызове; вместо этого пролог функции должен увеличить размер кадра стека на это количество байт.
Нельзя определять "PUSH_ROUNDING" и "ACCUMULATE_OUTGOING_ARGS" одновременно.
Определите эту макрокоманду, если функции рассчитывают, что место в стеке распределено для параметров даже когда их значения переданы в регистрах.
Значение этой макрокоманды - размер в байтах области, зарезервированной для параметров, переданных в регистрах функции, представляемой FNDECL.
Это место может быть распределено вызывающей функцией, или быть частью машинно-зависимого кадра стека: "OUTGOING_REG_PARM_STACK_SPACE" говорит, кто его распределит.
Определите эти макрокоманды в дополнение к описанной выше, если функции могут распределять место в стеке для параметров даже когда их значения переданы через регистры. Они должны использоваться, когда место в стеке, распределенное для параметров в регистрах - не простая константа, независимая от декларации функции.
Значение первой макрокоманды - размер в байтах области, которую мы должны первоначально считать зарезервированной для параметров, переданных в регистрах.
Значение второй макрокоманды - фактический размер в байтах области, которая будет зарезервирована для параметров, переданных в регистрах. У нее два параметра: целое число, представляющее число байт параметров фиксированного размера, и дерево, представляющее число байт параметров переменного размера, переданных в стек.
Когда эти макрокоманды определены, "REG_PARM_STACK_SPACE" будет вызываться только для функций libcall, текущей функции и для функции, вызываемой, когда о ней известно, что такое место в стека должно быть распределено. В любом случае это значение может быть легко вычислено.
При выяснении, нуждается ли вызываемая функция в таком пространстве стека, и сколько надо резервировать, GNU CC использует эти две макрокоманды вместо "REG_PARM_STACK_SPACE".
Определите ее, если вызывающая функция обязана распределить область, зарезервированную для параметров, переданных в регистрах.
Если "ACCUMULATE_OUTGOING_ARGS" определена, эта макрокоманда управляет, не превосходит ли место для параметров значение "current_function_outgoing_args_size".
Определите эту макрокоманду, если "REG_PARM_STACK_SPACE" определена, но стековые параметры не пропускают область, определенную ею.
Обычно, когда параметр не передан в регистрах, он помещен в стек за "REG_PARM_STACK_SPACE" областью. Определение этой макрокоманды подавляет такое поведение и заставляет параметр передаваться в стек на естественное место.
Выражение C, которое должно указать размер в байтах параметров функции, которые она выталкивает при возврате, или 0, если функция не выталкивает параметры, а вызывающая функция должна следовательно вытолкнуть их после возврата из функции.
FUNDECL - переменная C, значение которой - узел дерева, который описывает рассматриваемую функцию. Обычно это - узел типа "FUNCTION_DECL", который описывает декларацию функции. Из нее можно получить DECL_MACHINE_ATTRIBUTES для функции.
FUNTYPE - переменная C, значение которой - узел дерева, который описывает рассматриваемую функцию. Обычно это - узел типа "FUNCTION_TYPE", который описывает тип функции. Из нее можно получить типы значения и параметров (если они есть).
Когда рассматривается обращение к библиотечной функции, FUNTYPE будет содержать идентификатор узла для библиотечной функции. Таким образом, если нужно различить библиотечные функции, вы можете сделать это по их именам. Обратите внимание, что "библиотечная функция" в этом контексте означает арифметическую функцию, имя которой известно только транслятору и не упомянуто в компилируемом C-коде.
STACK-SIZE - число байтов параметров, переданных в стек. Если передано переменное число байт, это - ноль, и выталкивание параметров всегда будет обязанностью вызывающей функции.
На Vax все функции всегда выталкивают свои аргументы, так что определение этой макрокоманды - STACK-SIZE. На 68000, согласно стандартному соглашению о вызовах, никакие функции не выталкивают свои параметры, так что значение макрокоманды - всегда 0 в этом случае. Но альтернативное соглашение о вызовах имеет место, если функции, которые берут фиксированное число параметров, выталкивают их, но другие функции (типа "printf") не выталкивают ничего (вызывающая функция делает это за них). Когда используется это соглашение, исследуется FUNTYPE для определения, берет ли функция фиксированное число аргументов.
Этот раздел описывает макрокоманды, которые позволяют Вам управлять тем, как различные типы параметров передаются в регистрах или как они размещаются в стеке.
Выражение C, которые управлял тем, передается ли параметр функции в регистре, и в каком регистре.
Параметры - CUM, который суммирует все предыдущие параметры; MODE, машинный тип параметра; TYPE, тип данных параметра как узел дерева или 0, если он не известен (как бывает для библиотечных функций поддержки C); и NAMED, который равен 1 для обычного парамета и 0 для безымянных параметров, что соответствет " ... " в прототипе вызываемой функции.
Значение выражения должно быть или " reg " RTX для аппаратного регистра, в котором следует передавать параметр, или ноль для передачи параметра в стеке.
Для машин подобно Vax и 68000, где обычно все параметры передаются в стеке, можно задавать в качестве определения тождественный ноль.
Обычный способ заставить ANSI библиотеку " stdarg.h " работать на машине, на которой некоторые параметры обычно передаются в регистрах, заключается в передаче через стек безымянных параметров. Это достигается возвращением " FUNCTION_ARG " 0 всякий раз, когда NAMED равно 0.
Вы можете использовать макрокоманду " MUST_PASS_IN_STACK (MODE, TYPE) " в определении этой макрокоманды, чтобы определить, имеет ли этот параметр тип, который должен передаваться в стеке. Если " REG_PARM_STACK_SPACE " не определено и " FUNCTION_ARG " возвращает отличное от нуля число для такого параметра, транслятор прервет работу. Если " REG_PARM_STACK_SPACE " определено, параметр будет вычислен в стеке и затем загружен в регистр.
Определите эту макрокоманду, если целевая машина имеет " окна регистра ", то есть регистр, в котором функция видит параметры, не обязательно является тем, в котором вызывающая функция их передала.
Для таких машин " FUNCTION_ARG " вычисляет регистр, в котором вызывающая функция передает значение, а " FUNCTION_INCOMING_ARG " должен определяться подобным способом и сообщать вызываемой функции, где получать параметры.
Если " FUNCTION_INCOMING_ARG " не определено, " FUNCTION_ARG " служит для обеих целей.
Выражение C для числа слов, в начале параметра, которые должны быть помещены в регистры. Значение должно быть нулем для параметров, которые полностью передаются в регистрах или полностью помещаются в стек.
На некоторых машинах определенные параметры должны передаваться частично в регистрах и частично в памяти. На этих машинах обычно первые N слов параметров передаются в регистрах, а остальные - в стеке. Если параметр, состоящий из нескольких слов (" double " или структура), пересекает эту границу, его первые несколько слов должны передаваться в регистрах, а остальные - в стеке. Эта макрокоманда сообщает транслятору, когда это происходит и сколько слов должен идти в регистры.
" FUNCTION_ARG " для этих параметров должна возвращать первый регистр, который должен использоваться вызывающей функцией для этого параметра; аналогично " FUNCTION_INCOMING_ARG " - для вызываемой функции.
Выражение C, которое указывает, когда параметр должен передаваться по ссылке. Если оно отлично от нуля для параметра, в памяти делается копия этого параметра и указатель на параметр передается вместо него самого. Указатель передается любым способом, соответствующий передаче указателя на этот тип.
На машинах, где " REG_PARM_STACK_SPACE " не определено, определения этой макрокоманды может выглядеть так:
#define FUNCTION_ARG_PASS_BY_REFERENCE\
(CUM, MODE, TYPE, NAMED) \
MUST_PASS_IN_STACK (MODE, TYPE)
Если определено, выражение C, которое указывает когда задача создания копий параметров, переданных по невидимой ссылке, возлагается на вызываемую функцию. Обычно вызывающая функция делает копию и передает ее адрес вызываемой подпрограмме. Когда FUNCTION_ARG_CALLEE_COPIES определена и отлична от нуля, вызывающая функция не делает копии. Вместо этого она передает указатель на "настоящее" значение. Вызываемая функция не должна изменять это значение. Если можно определить, будет ли значение изменяться, делать копию не обязательно; иначе копия должна быть сделана.
Тип C для объявления переменной, которая используется как первый параметр " FUNCTION_ARG " и другие связанных значений. Для некоторых целевых машин тип " int " подходит для этой цели и может хранить количество байтов.
Нет необходимости записывать в " CUMULATIVE_ARGS " что-либо о параметрах, которые передаются через стек. Транслятор другие переменные, чтобы следить за этим. Для целевых машин, на которых все параметры передаются через стек, нет необходимости записывать что-либо в " CUMULATIVE_ARGS "; однако, структура данных должна существовать и не должна быть пустой, так что используйте " int ".
Оператор C (без точки с запятой) для инициализации переменной CUM для состояния в начале списка параметров. Переменная имеет тип " CUMULATIVE_ARGS ". Значение FNTYPE - узел дерева для типа данных функции, которая получит параметры, или 0 если аргументы - для библиотечной функции поддержки транслятора.
При обработке обращения к библиотечной функции поддержки транслятора, LIBNAME определяет, к какой именно. Это - " symbol_ref " rtx, который содержит имя функции как строку. LIBNAME равно 0, если обрабатывается обычное обращение к функции C. Таким образом, каждый раз эта макрокоманда вызывается, или LIBNAME, или FNTYPE отличны от нуля, но не оба сразу.
Подобно " INIT_CUMULATIVE_ARGS ", но перекрывает ее для целей нахождения параметров для компилируемой функции. Если это макрокоманда не определена, используется " INIT_CUMULATIVE_ARGS ".
Значение, передаваемое для LIBNAME - всегда 0, потому что библиотечные подпрограммы со специальными соглашениями о вызовах никогда не компилируются GNU CC. Параметр LIBNAME существует для симметрии с " INIT_CUMULATIVE_ARGS ".
Оператор C (без точки с запятой) для продвижения сумматора переменной CUM мимо параметра в списке параметров. Значения MODE, TYPE и NAMED описывают этот параметр. Как только это выполнено, переменная CUM подходит для анализа *следующего* параметра при помощи " FUNCTION_ARG ", и т.д.
Эта макро не должно ничего делать, если рассматриваемый параметр передается в стеке. Транслятор знает, как отслеживать количество свободного места в стеке, используемого для параметров, без специальной помощи.
Если определено, выражение C, которое определяет, добавлять ли, и в каком направлении дополнительное пространство параметру. Значение должно иметь тип " enum direction ": " upward ", чтобы дополнить сверху, " downward ", чтобы дополнить снизу, или " none ", чтобы запретить дополнение.
*Размера* дополнения всегда в точночти достаточно, чтобы достигнуть следующего кратного " FUNCTION_ARG_BOUNDARY "; эта макрокоманда не управляет этим.
Эта макрокоманда имеет заданное по умолчанию определение, которое является правильным для большинства систем. Для little-endian машин значение по умолчанию - вверх. Для big-endian машин - вниз для параметра постоянного размера, короче чем " int ", и вверх в противном случае.
Если определено, выражение C, которое дает границу выравнивания, в битах, параметра с указанными типом и типом. Если оно не определено, для всех параметров используется " PARM_BOUNDARY ".
Выражение C, которое является отличным от нуля если REGNO - номер аппаратного регистра, в котором иногда передаются параметры функций. Это *не включает* неявные параметры типа статической цепочки и адрес значения структуры. На многих машинах никакие регистры не могут использоваться для этой цели, так как все параметры функций передаются через стек.
В этом разделе обсуждаются макрокоманды, которые управляют возвращением скаляров как значений - значений, которые помещаются в регистрах.
Определите эту макрокоманду, если " -traditional " не должно заставлять функции, объявленные возвращающими " float ", преобразовывать значение в " double ".
Выражение C для создания RTX представления места, где a функция возвращает значение типа данных VALTYPE. VALTYPE - узел дерева, представляющий тип данных. Пишите " TYPE_MODE (VALTYPE) ", чтобы получить машинный тип, используемый, чтобы представить этот тип. На многих машинах, уместен только тип. (Фактически, на большинстве машин, скалярные значения возвращаются в одном и том же месте независимо от типа).
Если " PROMOTE_FUNCTION_RETURN " определено, Вы должны применить те же правила поддержки, что и определенные в " PROMOTE_MODE ", если VALTYPE - скалярный тип.
Если точная вызываемая функция известна, FUNC - узел дерева (" FUNCTION_DECL ") для нее; иначе, FUNC - нулевой указатель. Это делает возможным использовать различные соглашения о возвращении значений для отдельных функций, когда известны все обращения к ним.
" FUNCTION_VALUE " не используется для возврата значений составных типов данных, потому что они возвращаются другим способом. См. ниже " STRUCT_VALUE_REGNUM " и связанные с ним макрокоманды.
Определите эту макрокоманду, если целевая машина имеет " окна регистра ", то есть регистр, в котором функция видит параметры, не обязательно является тем, в котором вызывающая функция их передала.
Для таких машин " FUNCTION_VALUE " вычисляет регистр, в котором вызывающая функция получит значение, а " FUNCTION_INCOMING_ARG " должен определяться подобным способом и сообщать функции, куда записать параметры.
Если " FUNCTION_OUTGOING_VALUE " не определена, " FUNCTION_VALUE " служит для обеих целей.
" FUNCTION_OUTGOING_VALUE " не используется для возврата значений составных типов данных, потому что они возвращаются другим способом. См. ниже " STRUCT_VALUE_REGNUM " и связанные с ним макрокоманды.
Выражение C, чтобы создать RTX представление места, где библиотечная функция возвращает значение типа MODE. Если точная вызываемая функция известна, FUNC - узел дерева (" FUNCTION_DECL ") для нее; иначе, FUNC - нулевой указатель. Это делает возможным использовать различные соглашения о возвращении значений для отдельных функций, когда известны все обращения к ним.
Обратите внимание, что "библиотечная функция" в этом контексте означает подпрограмму поддержки транслятора, используемую для выполнения арифметической операции, чье имя специально указано транслятору и не было упомянуто в компилируемом C коде.
Определение " LIBRARY_VALUE " не должно касаться составных типов данных, потому что ни одна из библиотечных функций не возвращает таких типов.
Выражение C, которое является отличным от нуля, если REGNO - номер аппаратного регистра, в котором могут возвращаться значения вызываемой функции.
Регистр, чей использование для возврата значений ограничено употреблением как второго в пары (для значения типа " double ", например), не требуется распознавать этой макрокомандой. Поэтому для большинства машин, достаточно такого определения:
#define FUNCTION_VALUE_REGNO_P(N) ((N) == 0)
Если машина имеет окна регистра, так, чтобы вызывающая и
вызываемая функции использует различные регистры для возврата значения,
эта макрокоманда должна распознать только номера регистров вызывающей
функции.
Определите эту макрокоманду, если " untyped_call " и " untyped_return " требуется больше места, чем подразумевается " FUNCTION_VALUE_REGNO_P ", для сохранения и восстановления произвольного возвращаемого значения.
Когда тип значения функции - " BLKmode " (и в некоторых других случаях), значение не возвращается согласно " FUNCTION_VALUE " (*См.:Возврат скаляров::.). Вместо этого вызывающая функция передает адрес блока памяти, в котором значение должно быть сохранено. Этот адрес называется " структурным адресом значения ".
Этот раздел описывает, как управлять возвратом значений структур в памяти.
Выражение C, которое может запрещать возврат определенных значений функции в регистрах, основываясь на типе значения. Ненулевое значение требует возврата значения функции в памяти, так, как это делается для больших структур. Здесь TYPE будет выражение C типа " tree ", представляя тип данных значения.
Обратите внимание, что значения типа " BLKmode " должны явно обрабатываться этой макрокомандой. Также, опция " -fpcc-struct-return " имеет эффект независимо от этой макрокоманды. На большинстве систем можно оставить макрокоманду неопределенной; тогда используется определение по умолчанию, чье значение - константа 1 для значений ` BLKmode ' и 0 в противном случае.
Не используйте эту макрокоманду, чтобы указать, что структуры и объединения всегда должны возвращаться в памяти. Вы должны использовать " DEFAULT_PCC_STRUCT_RETURN ", чтобы указать это.
Определите эту макрокоманду значением 1, если все возвращаемые значения структур и объединений должны быть в памяти. Так как это приводит к более медленному коду, это должно делаться, только если это необходимо для совместимости с другими трансляторами или с ABI. Если Вы определяете эту макрокоманду значением 0, то соглашения, используемые для возвращаемых значений структур и объединений, определяются макрокомандой " RETURN_IN_MEMORY ".
По умолчанию значение равно 1.
Если адрес значения структуры передается в регистре, то " STRUCT_VALUE_REGNUM " должно быть номером этого регистра.
Если адрес значения структуры не передается в регистре, определите " STRUCT_VALUE " как выражение, возвращающее RTX для места, где адрес передается. Если возвращается 0, адрес передается как "невидимый" первый параметр.
При некоторых архитектурах - место, где вызываемая функция находит адрес значения структуры - не то же самое место, куда его помещает вызывающая. Это может быть из-за регистровых окон или из-за того, что пролог функции перемещает его в другое место.
Если входящее расположение адреса значения структуры находится в регистре, определите эту макрокоманду как номер регистра.
Если входящее расположение - не регистр, то Вы должны определить " STRUCT_VALUE_INCOMING " как выражение для RTX, содержащее место, в котором вызываемая функция должна найти значение. Если она должна найти его в стеке, определите ее как " mem ", которое ссылается на указатель кадра. Определение нулем означает, что адрес передается как "невидимый" первый параметр.
Определите эту макрокоманду, если обычное системное соглашение на целевой машине для возврата структур и объединений заключается в том, что вызываемая функция должна возвращать адрес статической переменной, содержащей значение.
Не определите ее, если обычное системное соглашение системы заключается в том, что вызывающая функция передает адрес подпрограмме.
Эта макрокоманда имеет эффект в типе " -fpcc-struct-return " , но не играет роли, когда Вы используете тип " -freg-struct-return ".
Если Вы разрешаете это, GNU CC может сохранять регистры на время обращений к функции. Это делает возможным использование затираемых регистров для содержания переменных, которые должны существовать и до, и после обращения.
Определите эту макрокоманду, если обращения к функции на целевой машине не сохраняют никаких регистров; другими словами, если " CALL_USED_REGISTERS " имеет 1 для всех регистров. Эта макрокоманда допускает " -fcaller-saves " по умолчанию. В конечном счете эта опция будет установлена по умолчанию на всех машинах и как опция, так и эта макрокоманда будут удалены.
Выражение C, которое определяет, имеет ли смысл рассмотреть размещение псевдорегистра в затираемом аппаратном регистре и сохранять и восстанавливать его при каждом обращении к функции. Выражение должно быть равно 1, если так следует поступать, и 0 - если нет.
Если Вы не определяете эту макрокоманду, используется значение по умолчанию, который является разумным для большинства машин: " 4 * CALLS < REFS ".
Этот раздел описывает макрокоманды, которые выводят код входа функции ("пролог") и выхода ("эпилог").
Составной оператор C, который выводит код ассемблера для входа функции. Пролог ответственен за установку кадра стека, инициализацию регистра указателя кадра, сохранение регистров, которые должны быть сохранены и распределение SIZE дополнительных байтов в памяти для локальных переменных. SIZE - целое число. FILE - stdio поток (поток стандартного ввода-вывода), в который должен выводиться код ассемблера.
Метка для начала функции не должна выводиться этой макрокомандой. Это выполняется при запуске макрокоманды.
Чтобы определить, какие регистры сохранять, макрокоманда могут обратиться к массиву " regs_ever_live ": элемент R отличен от нуля, если аппаратный регистрир R используется где-нибудь внутри функции. Это подразумевает, что пролог функции должен сохранить регистр R, если это - не один из используемых обращением регистры. (" FUNCTION_EPILOGUE " должен аналогично использовать " regs_ever_live ".)
На машинах, которые имеют " окна регистра ", код входа функции не сохраняет в стеке регистры, которые находятся в окнах, даже если предполагается, что они должны сохраняться при обращении к функции; вместо этого требуется соответствующие шаги, чтобы "поместить" в стек регистр, если какие-то регистры, не используемые в вызове, используются в функции.
На машинах, где функции могут иметь или могут не иметь указатели кадра, код входа функции должен изменяться соответственно; он должно устанавливать указатель кадра, если он требуется, и не устанавливать в противном случае. Чтобы определить нужен ли указатель кадра, макрокоманда может обратиться к переменной " frame_pointer_needed ". Значение переменной будет 1 во время выполнения фнукции, которая нуждается в указателе кадра. * См.: Удаление::.
Код входа функции ответственен за распределение любого места в стеке, требуемого для функции. Этот пространство состоит из областей, перечисленных ниже. В большинстве случаев эти области, распределяются в перечисленном порядке, причем названная последней область - самой близкой к вершине стека (наименьший адрес, если " STACK_GROWS_DOWNWARD " определено, и наибольший адрес, если не определено). Вы можете использовать другой порядок для машины, если это будет удобнее или требуется по причинам совместимости. За исключением случаев, когда это требуется стандартом или отладчиком, не имеется никакой причины считать, что распределение стека, используемое GCC, должно согласовываться с используемым другими трансляторами для машины.
Определите эту макрокоманду как выражение C, которое отлично от нуля, если команда возврата или эпилог функции игнорирует значение указателя стека; другими словами, если безопасно удалить команду корректировки указателя стека перед возвратом из функции.
Обратите внимание, что значение этой макрокоманды имеет значение только для функций, которые поддерживают указатели кадра. Не бывает безопасно удалить конечную корректировка стека в функции, которая не имеет указателя кадра, и транслятор знает это независимо от " EXIT_IGNORE_STACK ".
Составной оператор C, который выводит код ассемблера для выхода из функции. Эпилог ответственен за восстановление сохраненных регистров и указателя стека на их значения, когда функция вызывалась, и возвращения управления вызывающей функции. Эта макрокоманда имеет те же параметры, что и макрокоманда " FUNCTION_PROLOGUE ", и регистры, которые нужно восстановить, определяются из " regs_ever_live " и " CALL_USED_REGISTERS " таким же образом.
На некоторых машинах имеется одиночная команда, которая делает всю работу для возврата из функции. На этих машинах, задайте этой команде имя " return " и не определяйте макрокоманду " FUNCTION_EPILOGUE " вообще.
Не определяйте образец по имени " return ", если Вы хотите использовать " FUNCTION_EPILOGUE ". Если Вы хотите, чтобы целевые переключатели управляли тем, используются команды возврата или эпилоги, определите образец " return " с условием проверки правильности, которое соответственно проверяет целевые переключатели. Если условие правильности образца " return " ложно, будут использоваться эпилоги.
На машинах, где функции могут иметь или могут не иметь указатели кадра, код завершения функции должен изменяться соответственно. Иногда код для этих двух случаев полностью различен. Чтобы определить, требуется ли указатель кадра, макрокоманда может обратиться к переменной " frame_pointer_needed ". Значение переменной равно 1, если компилируется функция, которая нуждается в указателе кадра.
Обычно, " FUNCTION_PROLOGUE " и " FUNCTION_EPILOGUE " должен обрабатывать функции листа специальным образом. Переменная C " leaf_function " отлична от нуля для такой функции. * См.: Функции Листа::.
На некоторых машинах некоторые функции восстанавливают из стека их параметры на выходе, в то время как другие оставляют делать это вызывающей функции. Например, 68020, когда задано " -mrtd ", восстанавливает из стека параметры в функциях, которые имеют фиксированное число параметров.
Ваше определение макрокоманды " RETURN_POPS_ARGS " решает, какие функции восстанавливают из стека их собственные параметры. " FUNCTION_EPILOGUE " требуется знать, что было решено. Переменная, которая называется " current_function_pops_args " - число байтов параметров, которые функция должна восстанавливать из стека. * См.: Возвращение Скаляров::.
Определите эту макрокоманду, если эпилог функции содержит слоты задержки, в которые команды из остальной части функции могут "перемещаться". Определение должно быть выражением C, чье значение - целое число, представляющее число слотов задержки.
Выражение C, которое возвращает 1, если INSN может быть помещен в слот задержки номер N эпилога.
Параметр N - целое число, которое идентифицирует рассматриваемый слот задержки (так как различные слоты могут иметь различные правила "подходящести"). Это всегда неотрицателен и всегда меньше, чем количество слотов задержки эпилога (которое возвращает " DELAY_SLOTS_FOR_EPILOGUE "). Если Вы отклоняете данный insn для данного слота задержки, в принципе, это может быть пересмотрено для последующего слота задержки. Также, другой insns могут (по крайней мере, в принципе) рассматриваться для пока незаполненного слота задержки.
Insns, принятые для заполнения слотов задержки эпилога, помещаются в список RTL, сделанный объектами " insn_list ", сохраненными в переменной " current_function_epilogue_delay_list ". Insn для первого слота задержки входит в список первым. Ваше определение макрокоманды " FUNCTION_EPILOGUE " должно заполнять слоты задержки при помощи вывода insns в этом списке, обычно при помощи вызова " final_scan_insn ".
Вам не нужно определять эту макрокоманду, если Вы не определяли " DELAY_SLOTS_FOR_EPILOGUE ".
Эти макрокоманды помогут Вам генерировать код для профилирования.
Оператор C или составной оператор для вывода в FILE некоторого кода ассемблера, вызывающего подпрограмму профилирования " mcount ". Перед вызовом код ассемблера должен загрузить адрес переменной-счетчика в регистр, где " mcount " ожидает адрес. Имя этой переменной " LP " сопровождается номером LABELNO, так что Вам следует генерировать имя, используюя " LP%d " в " fprintf ".
Подробности того, как адрес должен передаваться " mcount ", определяются вашей средой операционной системы, а не GNU CC. Чтобы представить их себе, скомпилируйте маленькую программу для профилирования, используя установленный C транслятор системы и посмотрите не получившийся код ассемблера.
Определите эту макрокоманду, если код для профилирования функции должен идти перед прологом функции. Обычно код профилирования идет после него.
Оператор C или составной оператор для вывода в FILE некоторого кода ассемблера, инициализирующего профилирование базового блока для текущего объектнго модуля. Этот код должен вызывать подпрограмму " __ bb_init_func " по одному разу для каждого объектного модуля, передавая ей к качестве единственного параметра адрес блока, распределенного в объектном модуле.
Имя блока - локальный символ, созданный этим оператором:
ASM_GENERATE_INTERNAL_LABEL (BUFFER, "LPBX", 0);
Конечно, так как Вы записываете определение
" ASM_GENERATE_INTERNAL_LABEL " так же, как для этой макрокоманды, Вы
можете сделать вырезку из определения этой макрокоманды и использовать
имя, которое, как Вы знаете, даст результат.
Первое слово этого блока - флаг, который будет отличный от нуля, если объектный модуль уже был инициализирован. Поэтому проверяйте вначале это слово и не вызывайте " __ bb_init_func ", если флаг отличен от нуля.
Оператор C или составной оператор для увеличения счетчика, связанного с базовым номером блока BLOCKNO. Базовые блоки нумеруются отдельно от нуля внутри каждой трансляции. Счетчик, связанный с номером блока BLOCKNO - это индекс BLOCKNO в векторе слов; имя этого массива - локальный символ, сделанный создаваемый таким оператором:
ASM_GENERATE_INTERNAL_LABEL (BUFFER, "LPBX", 2);
Конечно, так как Вы записываете определение
" ASM_GENERATE_INTERNAL_LABEL " так же, как для этой макрокоманды, Вы
можете сделать вырезку из определения этой макрокоманды и использовать
имя, которое, как Вы знаете, даст результат.
Функция или функции C, которые необходимы в библиотеке для поддержки блока профилирования.
GNU CC имеет встроенную реализацию " varargs.h " и " stdarg.h ", которая работает без изменения на машинах, которые передают параметры через стек. Другие машины требуют собственных реализаций varargs, и два машиннонезависимых файла заголовка должны иметь условные выражения, чтобы включить их.
ANSI " stdarg.h " отличается от традиционного " varargs.h " главным образом соглашением о вызовах для " va_start ". Традиционная реализация имеет только один параметр, который является переменной для сохранения указателя на параметр. ANSI реализация " va_start " имеет дополнительный второй параметр. Предполагается, что пользователь пишет здесь последний именованный параметр функции.
Однако, " va_start " не должна использовать этот параметр. Способ нахождения окончания именованных параметров встроенными функциями описан ниже.
Используйте эту встроенную функцию, чтобы сохранить параметры из регистров в памяти так, чтобы varargs механизм мог обращаться к ним. И ANSI, и традиционная версии " va_start " должны использовать " __ builtin_saveregs ", если Вы не используете вместо этого " SETUP_INCOMING_VARARGS " (см. ниже).
На некоторых машинах " __ builtin_saveregs " открыта закодировано под контролем над макрокомандой " EXPAND_BUILTIN_SAVEREGS ". На других машинах она вызывает подпрограмму, написанную на языке ассемблеров, находящуюся в " libgcc2.c ".
Код, сгенерированный для обращения к " __ builtin_saveregs " появляется в начале функции, в противоположность тому, где обращение к " __ builtin_saveregs " написано, независимо от того, что это за код. Поэтому регистры должны быть сохранены перед тем, как функция начинает их использовать для собственных целей.
Используйте эту встроенную функцию, чтобы найти первые безымянные параметры в регистрах.
Вообще, машина может иметь несколько категорий регистров, используемых для параметров, каждый для специфической категории типов данных. (Например, на некоторых машинах регистры с плавающей запятой используются для параметров с плавающей запятой, в то время как другие параметры передаются в общих регистрах.) Чтобы добиться того, чтобы не-varargs функции использовали соответствующее соглашение о вызовах, Вы должны определить Тип данных " CUMULATIVE_ARGS " для записи того, сколько регистров в каждой категории использовано.
" __ builtin_args_info " обращается к той же самой структуре данных типа " CUMULATIVE_ARGS " после того, как обычное размещение параметра законченный с ним, с CATEGORY, определяющей, к какому слову обращаться. Таким образом, значение указывает первый неиспользуемый регистр в данной категории.
Обычно Вы использовали бы " __ builtin_args_info " в реализации " va_start " для доступа к каждой категории только однажды и сохранения значения в объекте ` va_list '. Поэтому " va_list " должна будет обновлять значения, и нет никакого способа изменить значения, обращаясь при помощи " __ builtin_args_info ".
Это - эквивалент " __ builtin_args_info ", для стековых параметров. Он возвращает адрес первого безымянного стекового параметр, как тип " void * ". Если " ARGS_GROW_DOWNWARD ", он возвращает адрес ячейки выше первого безымянного стекового параметра. Используйте его в " va_start ", чтобы инициализировать указатель для выборки параметров из стека. Также используйте его в " va_start " , чтобы проверить, что второй параметр LASTARG - последний именованный параметр текущей функции.
Так как каждая машина имеет собственные соглашения, какие типы данных могут передаваться в каких видах регистров, ваша реализация " va_arg " должна воплотить эти соглашения. Самый простой способ категоризировать определенный тип данных заключается в использовании " __ builtin_classify_type " вместе с " sizeof " и " __ alignof __ ".
" __ builtin_classify_type " игнорирует значение OBJECT, рассматривая только тип данных. Он возвращает целое число, описывающее, какой это тип - целое число, плавающее, указатель, структура и так далее.
Файл " typeclass.h " определяет перечисление, к которому Вы можете использовать для интерпретации значений " __ builtin_classify_type ".
Эта макрокоманды машинного описания помогают выполнять varargs:
Если определено, является выражением C, которое генерирует машинно-специфический код для обращения к " __ builtin_saveregs ". Этот код будет помещен в самое начало функции, перед тем, как будет получен доступ к какому-либо параметру. Возвращаемое значение этой функции должно быть RTX, которое содержит значение, которое следует использовать как результат " __ builtin_saveregs ".
Параметр ARGS - " tree_list ", содержащий параметры, которые были переданы " __ builtin_saveregs ".
Если эта макрокоманда не определена, транслятор выведет обычный вызов библиотечной функции " __ builtin_saveregs ".
Эта макрокоманда предлагает альтернативный вариант использования " __ builtin_saveregs " и определения макрокоманды " EXPAND_BUILTIN_SAVEREGS ". Используйте его, чтобы сохранить безымянные регистровые параметры в стеке так, как будто все параметры были переданы последовательно в стек. Как только это сделано, Вы можете использовать стандартную реализацию varargs, которая работает на машинах, которые передают все параметры через стек.
Параметр ARGS_SO_FAR - структура данных " CUMULATIVE_ARGS ", содержащая значения, которые получаются после обработки именованных параметров. Параметры MODE и TYPE описывают последний именованный параметр - его машинный тип и тип данных как узел дерева.
Реализация макрокоманды должна делать две вещи: первое, поместить в в стек все регистровые параметры, *не* используемые для именованных параметров, и второе, сохранить размер этих записанных в стек данных, в переменной типа " int ", чье имя поддерживается как параметр PRETEND_ARGS_SIZE. Значение, которое Вы сохраняете, будет служить как дополнительное смещение для установки кадра стека.
Поскольку Вы должны генерировать код, чтобы поместить в стек безымянные параметры во время компиляции, не зная их типов данных, " SETUP_INCOMING_VARARGS " имеет смысл использовать только на машинах, которые имеют только одну категорию регистровых параметров и используют ее одинаково для всех типов данных.
Если параметр SECOND_TIME отличен от нуля, это означает, что параметры функции анализируются второй раз. Так случается для встроенной функции, которая фактически не компилируется до конца исходного файла. Макрокоманда " SETUP_INCOMING_VARARGS " не должна генерировать никаких команд для этого случая.
Определите эту макрокоманду, если место, где передается параметр функции, зависит от того, является ли он именованным параметром.
Эта макрокоманда управляет тем, как устанавливается параметр NAMED к " FUNCTION_ARG " для функций varargs и stdarg. Если эта макрокоманда определена, параметр NAMED - всегда истина для именованных параметров и ложь - для безымянных параметров. Если она не определена, но " SETUP_INCOMING_VARARGS " определена, то все параметры обрабатываются как именованные. В противном случае, все именованные параметры, за исключением последнего, обрабатываются как именованные.
"Trampoline" - маленькая часть кода, которая создается во время выполнения, когда принимается адрес вложенной функции. Она обычно располагается в стеке, во кадре стека содержащей функции. Эти макрокоманды сообщают GNU CC, как генерировать код, чтобы распределять и инициализировать trampoline.
Команды в trampoline должны делать две вещи: загрузка константного адреса в статический цепной регистр, и переход к реальному адресу вложенной функции. На CISC машинах типа m68k это требует двух команд, перемещение и переход. Тогда два адреса присутствуют в trampoline как непосредственные операнды размера word. На RISC машинах часто необходимо загрузить каждый адрес в регистр в двух частях. Тогда части каждого адреса образуют отдельные непосредственные операнды.
Код, сгенерированный, чтобы инициализировать trampoline, должен сохранить переменные части - статическое цепное значение и адрес функции - в непосредственные операнды команд. На CISC машине это просто вопрос копирования каждого адреса к ссылку памяти в соответствующее смещение от начала trampoline. На RISC машине может оказаться необходимо выбирать части адреса и сохранять их отдельно.
Оператор C для вывода в поток FILE кода ассемблера для блока данных, который содержит постоянные части trampoline. Этот код не должен включать метку - о метке позаботятся автоматически.
Имя подпрограммы для включения в раздел, в который должен быть помещен trampoline шаблон (* См.: Разделы::.). Значение по умолчанию - значение " readonly_data_section ", который помещает trampoline в разделе, содержащем данные только для чтения.
Выражение C для размера в байтах trampoline, как целое число.
Выравнивание, требуемое для trampolines, в битах.
Если Вы не определяете эту макрокоманду, для выравнивания trampolines используется значение " BIGGEST_ALIGNMENT ".
Оператор C для инициализации переменных частей trampoline. ADDR - RTX для адреса trampoline; FNADDR - RTX для адреса вложенной функции; STATIC_CHAIN - RTX для статического цепного значения, которое должно быть передано функции, когда она вызывается.
Выражение C для распределения места во время выполнения для trampoline. Значение выражения должно быть RTX, представляющим ссылку памяти на место для trampoline.
Если эта макрокоманда не определена, по умолчанию trampoline распределяется как слот стека. Это значение по умолчанию подходит для большинства машин. Исключения - машины, где невозможно выполнение команд в области стека. На таких машинах Вам, возможно, следует создать отдельный стек, используя эту макрокоманду в сочетании с " FUNCTION_PROLOGUE " и " FUNCTION_EPILOGUE ".
FP указывает на структуру данных, " struct function", которая описывает состояние трансляции непосредственных содержащий функции для функции, которой принадлежит trampoline. Обычно (когда " ALLOCATE_TRAMPOLINE " не определено), слот стека для trampoline находится во кадре стека этой содержащей функции. Другие cтратегии распределения, вероятно, должны делать что-либо аналогичное с этой информацией.
Выполнение trampolines трудно на многих машинах, потому что они имеют раздельные кэши команд и данных. Запись в ячейку стека не может очистить память в кэше команд, так что когда программа переходит к этой ячейке, выполняется старое содержимое.
Имеется два возможных решения. Одно заключается в очистить относящихся к делу частей кэша команд всякий раз, когда trampoline устанавливается. Другой - сделать все trampoline идентичными, сделав в них переходы на стандартную подпрограмму. Вышеупомянутая методика делает выполнение trampoline быстрее; последний способ делает инициализацию быстрее.
Чтобы очистить кэш команд, когда trampoline инициализирован, определите следующие макрокоманды, которые описывают форму кэша.
Полный размер в байтах кэша.
Длина в байтах каждой линии кэша. Кэш разделен на линии кэша, которые являются непересекающимися слотами, каждый из которых содежит часть данных, выбранных из памяти. Каждый раз, когда данные записываются в кэш, вся линия читается целиком. Данные, загруженные в линию кэша, всегда выравниваются на границе, равной размеру линии.
Число альтернативных линий кэша, которые могут содержать любую конкретную ячейку памяти.
Альтернативно, если машина имеет системные вызовы или команды для очистки кэша команды непосредственно, Вы можете определять следующую макрокомандуа.
Если определена, расширяется до выражения C, очищающего *кэш команд* в указанном интервале. Если она не определена, и макрокоманда INSN_CACHE_SIZE определена, генерируется некоторый родовой код для очистки кэша. Определение этой макрокоманды обычно является цепочкой операторов " asm ". BEG и END - выражения-указатели.
Чтобы использовать стандартную подпрограмму, определите следующую макрокоманду. Кроме того, Вы должны удостовериться, что команды в trampoline заполняют всю линию кэша идентичными командами, или же гарантируют, что начало trampoline кода всегда выравнивается по той же самой точке на линии кэша. Смотрите " m68k.h " как руководство.
Определите эту макрокоманду, если trampolines нуждаются в специальной подпрограмме для выполнения их работы. Макрокоманда должна расширяться до ряда " asm " операторов, которые будут компилироваться GNU CC. Они входят в библиотечную функцию под названием " __ transfer_from_trampoline ".
Если Вам нужно избежать выполнения кода обычного пролога cкомпилированной функции C, когда Вы переходите к подпрограмме, Вы можете добиться этого, помещая Вашу собственную специальную метку в коде ассемблера. Использование один оператор " asm ", чтобы сгенерировать метку ассемблера, и другой, чтобы сделать метку глобальной. Тогда trampolines смогут использовать эту метку для перехода непосредственно к вашему специальному коду ассемблера.
Строковая константа C имени функции умножения одного знакового полного слова на другое. Если вы не определяете эту макрокоманду, используется имя, заданное по умолчанию, "__mulsi3" функции, определенной в "libgcc.a".
Строковая константа C имени функции деления одного знакового полного слова на другое. Если вы не определяете эту макрокоманду, используется имя, заданное по умолчанию, "__divsi3" функции, определенной в "libgcc.a".
Строковая константа C имени функции деления одного беззнакового полного слова на другое. Если вы не определяете эту макрокоманду, используется имя, заданное по умолчанию " __udivsi3 " функции, определенной в "libgcc.a".
Строковая константа C имени функции вычисления остатка деления одного знакового полного слова на другое. Если вы не определяете эту макрокоманду, используется имя, заданное по умолчанию " __modsi3 " функции, определенной в "libgcc.a".
Строковая константа C имени функции вычисления остатка деления одного беззнакового полного слова на другое. Если вы не определяете эту макрокоманду, используется имя, заданное по умолчанию "__umodsi3" функции, определенной в "libgcc.a"
Строковая константа C имени функции умножения одного знакового двойного слова на другое. Если вы не определяете эту макрокоманду, используется имя, заданное по умолчанию "__muldi3" функции, определенной в "libgcc.a".
Строковая константа C имени функции деления одного знакового двойного слова на другое. Если вы не определяете эту макрокоманду, используется имя, заданное по умолчанию "__divdi3" функции, определенной в "libgcc.a".
Строковая константа C имени функции деления одного беззнакового полного слова на другое. Если вы не определяете эту макрокоманду, используется имя, заданное по умолчанию "__ divdi3" функции, определенной в "libgcc.a".
Строковая константа C имени функции вычисления остатка деления одного знакового двойного слова на другое. Если вы не определяете эту макрокоманду, используется имя, заданное по умолчанию "__moddi3" функции, определенной в "libgcc.a".
Строковая константа C имени функции вычисления остатка деления одного беззнакового полного слова на другое. Если вы не определяете эту макрокоманду, используется имя, заданное по умолчанию "__umoddi3" функции, определенной в "libgcc.a".
Определите эту макрокоманду как оператор C, который объявляет дополнительные библиотечные подпрограммы и переименовывает существующие. "Init_optabs" вызывает эту макрокоманду после инициализации всех нормальных библиотечных подпрограмм.
Значение "EDOM" на целевой машине в виде целочисленной константы C. Если вы не определяете эту макрокоманду, GNU CC не пытается вносить значение "EDOM" в "errno" непосредственно. Посмотрите в "/usr/include/errno.h" чтобы найти значение "EDOM" для вашей системы.
Если вы не определяете "TARGET_EDOM", то откомпилированный код сообщит об ошибке, заставляя это делать библиотечную функцию. Если математические функции на вашей системе при ошибке используют "matherr", то вы должны оставить "TARGET_EDOM" неопределенным, чтобы "matherr" могла нормально использоваться.
Определите эту макрокоманду как выражение C для создания выражения rtl, которое ссылается на глобальную "переменную" "errno". (На некоторых системах, "errno" может не быть переменной.) Если вы не определяете эту макрокоманду, используется приемлемое значение по умолчанию.
Определите эту макрокоманду, если GNU CC должен генерировать обращения к библиотечным функциям System V (и ANSI C) "memcpy" и "memset", а не к BSD-функциям "bcopy" и "bzero".
Определите эту макрокоманду только если параметры типа "float" не могут быть переданы библиотечным подпрограммам (так что они должны быть преобразованы в "double"). Эта макрокоманда воздействует и на то, как генерируются библиотечные вызовы и как библиотечные подпрограммы в "libgcc1.c" принимают свои параметры. Это полезно на машинах, где параметры с плавающей и фиксированной точкой передаются по-разному, например в i860.
Определите эту макрокоманду, чтобы изменить тип, используемый библиотечными подпрограммами, чтобы передавать параметры типа "float". (По умолчанию, они используют объединение "float" и "int".)
Очевидно выбор должен быть "float", но это не будет работать на традиционных трансляторах C, которые все параметры, объявленные как "float" переделывают в "double". Чтобы избежать такого преобразования, библиотечные подпрограммы запрашивают значение какого-то другого типа, а затем обрабатывают его как "float".
На некоторых системах никакой другой тип не будет так работать. На этих системах вы должны вместо этой использовать "LIBGCC_NEEDS_DOUBLE", заставляя транслятор преобразовывать "double"-значения до того, как они переданы.
Определите эту макрокоманду, чтобы изменить способ, которым библиотечные подпрограммы повторно назначают параметр типа "float" как "float" вместо типа, в качестве которого он был передан. По умолчанию это выражение, которое берет "float"-поле из объединения.
Определите эту макрокоманду, чтобы изменить тип, используемый для возвращения значения библиотечными подпрограммами, которые должны возвращать тип "float". (По умолчанию они используют "int".)
Очевидный выбор был бы "float", но это не будет работать на трансляторе традиционного C, который сам преобразовывает значения, объявленные как "float", в "double".
Определите эту макрокоманду, чтобы изменить способ, каким образом значение, возвращаемое библиотечной подпрограммой, которая должна возвращать тип "float", должно быть упаковано, чтобы возвратить его. Эти функции объявляются как возвращающие тип "FLOAT_VALUE_TYPE" (обычно "int").
Эти значения не могут быть возвращены как тип "float" потому что традиционные C трансляторы сами преобразовывают значение в "double".
Локальная переменная, названная "intify" всегда доступна, когда используется макрокоманда "INTIFY". Она - объединение "float"-поля с именем "f" и поля с именем "i" типа "FLOAT_VALUE_TYPE" или "int".
Если вы не определяете эту макрокоманду, работает заданное по умолчанию определение : копирует значения через это объединение.
Определите эту макрокоманду как имя типа данных, соответствующего "SImode" в собственном C-трансляторе системы.
Вы не должны определять эту макрокоманду, если вышеуказанный тип - "long int", а это обычно он и есть.
Определяйте эту макрокоманду как имя типа данных, соответствующего word_mode в собственном C-трансляторе системы.
Вы не должны определять эту макрокоманду, если вышеуказанный тип - "long int", а это обычно так.
Определите эти макрокоманды, чтобы обеспечить явные операторы C, выполняющие различные арифметические операции от типов "float" и "double" в библиотечных подпрограммах "libgcc1.c". См. в этом файле полный список этих макрокоманд и их параметров.
На большинстве машин вы не должны определять эти макрокоманды, потому что C-транслятор, который приходит с системой, сам заботится об их создании.
Определите эту макрокоманду, чтобы сгенерировать код для посылки сообщений в Objective C , используя соглашения о вызовах системы NeXT. Это соглашение о вызовах включает передачу объекта, селектора и аргументов метода всех сразу к поисковой функции библиотеки методов.
Заданное по умолчанию соглашение о вызовах передает только объект и селектор к функции поиска, которая возвращает указатель на метод.
Здесь содержится информация о способах адресации.
Определите эту макрокоманду, если машина поддерживает постинкрементную адресацию.
Аналогично и для других способов адресации.
Выражение C, которое равно 1, если RTX X - константа, содержащая правильный адрес. На большинстве машин, оно может быть определено как "CONSTANT_P(X)", но на некоторых машинах больше ограничений на поддерживаемые базовые адреса.
неизвестны, такие как "symbol_ref", "label_ref", "high"-выражения и "const"-арифметические выражения в дополнение к выражениям "const_int" и "const_double".
Максимальное число регистров, которые могут появляться в правильном адресе памяти. Обратите внимание, что это вы должны определять значение, равное максимальному числу, которое может принимать "GO_IF_LEGITIMATE_ADDRESS".
Сложный оператор C с условным оператором "goto LABEL;", выполняющимся, если X (RTX) - правильный адрес в памяти на целевой машине для операнда памяти типа MODE.
Обычно лучше определить несколько более простых макрокоманд, служащих подпрограммами для этой. В противном случае эта макрокоманда может оказаться слишком сложной для понимания.
Эта макрокоманда должна существовать в двух вариантах: строгом и нестрогом. Строгий вариант используется в процессе перезагрузки. Она должна быть определена так, чтобы любой псевдорегистр, который не был распределен в аппаратном регистре, считался ячейкой памяти. В контекстах, где требуется некоторый регистр, следует отклонить псевдорегистр, не представленный аппаратным.
Нестрогий вариант используется в других проходах. Она должна быть определена, чтобы принимать все псевдорегистры в каждом контексте, где требуется некоторый регистр.
Исходные файлы транслятора, которые используют строгий вариант этой макрокоманды, определяют макрокоманду "REG_OK_STRICT". Вы должны использовать условную директиву "#ifdef REG_OK_STRICT", чтобы определить строгий вариант в этом случае, иначе - нестрогий вариант.
Подпрограммы для проверки приемлемых регистров для различных целей (одна для базовых регистров, одна для индексных регистров, и так далее) - типичны среди подпрограмм, используемых для определения "GO_IF_LEGITIMATE_ADDRESS". Только эти подпрограммы-макрокоманды должны иметь два варианта; макрокоманды более высоких уровней тоже могут быть строгими или нет.
Обычно, постоянные адреса, которые являются суммой "symbol_ref" и целого числа, располагаются внутри "const" RTX, чтобы отметить их как константы. Следовательно, не надо распознавать такие суммы как правильные адреса. Обычно вы просто распознаете любую "const" как правильную.
Обычно "PRINT_OPERAND_ADDRESS" не подготовлена к обработке константных сумм, которые не отмечены "const". Она принимает, что явный "plus" указывает на индексацию. Если так, то вы должны отбросить такие явные постоянные суммы как неправильные адреса, так чтобы ни одна из них не была передана "PRINT_OPERAND_ADDRESS".
Является ли символический адрес правильным, зависит от раздела, к которому адрес обращается (на некоторых машинах). На таких машинах определите макрокоманду "ENCODE_SECTION_INFO", чтобы сохранить информацию в "symbol_ref", и затем проверите ее там. Когда вы видите "const", вы должны будете заглянуть внутрь нее, чтобы найти "symbol_ref" для определения раздела. *Обратите внимание на Ассемблерный Формат::.
Самый лучший способ изменить строку имени - добавить текст к началу с подходящей пунктуацией, чтобы предотвратить любую неоднозначность. Распределите новое имя в "saveable_obstack". Вы должны будете изменить "ASM_OUTPUT_LABELREF", чтобы удалить и декодировать добавленный текст и вывести имя соответственно, и определить "STRIP_NAME_ENCODING", чтобы обратиться к первоначальной строке имени.
Вы можете проверить информацию, сохраненную в "symbol_ref" в определениях макрокоманд "GO_IF_LEGITIMATE_ADDRESS" и "PRINT_OPERAND_ADDRESS".
Выражение C, которое отлично от нуля если X (считающийся "reg" RTX) подходит для использования в качестве базисного регистра. Для аппаратных регистров оно должно принимать только разрешенные аппаратными возможностями и отклонять остальные. Отклоняет ли макрокоманда псевдорегистры, должен контролироваться "REG_OK_STRICT", как описано выше. Это обычно требует двух различных вариантов определения, причем "REG_OK_STRICT" управляет, какое фактически используется.
Выражение C, которое отлично от нуля если X (считающийся "reg" RTX) годится для использования как индексный регистр.
Различие между индексным регистром и основным регистром в том, что индексный регистр может масштабироваться. Если адрес включает сумму двух регистров, ни один из которых не масштабирован, то любой может быть помечен как "основной", а другой как "индексный"; но какая бы пометка ни использовалась, она должна удовлетворить ограничениям машины, регистры которой могут служить только в определенных местах. Транслятор пробует оба способа, ища правильный, и перезагрузит один или оба регистров только, если никакой способ не сработает.
Сложный оператор C, который пытается заменять X на правильный адрес в памяти для операнда типа MODE. WIN будет меткой оператора в C в другом месте в коде; определение макрокоманды может использовать :
во избежание дальнейшей обработки, если адрес стал правильным.
X будет всегда результатом обращения к "break_out_memory_refs", а OLDX будет операндом, который был передан той функции, чтобы получить X.
Код, сгенерированный этой макрокомандой не должен изменить структуру X. Если он трансформирует X в более правильную форму, он должен назначить X (который будет всегда C переменная) новое значение.
Эта макрокоманда необязательно выдаст правильный адрес. Транслятор имеет стандартные пути выполнения этого всех случаях. Фактически, этой макрокоманде безопасно ничего не делать. Но часто машинно-зависимая стратегия может привести к лучшему коду.
Оператор C или составной оператор с условным "goto LABEL; ", выполняемым, если адрес в памяти X (RTX) может иметь различные значения, в зависимости от машинного типа ячейки памяти, для которой он используется или если адрес правильный для некоторых типов, но не для других.
Автоинкрементные и автодекрементные адреса обычно имеют зависимые от типа эффекты, потому что размер приращения или декремента - размер адресуемого операнда. Некоторые машины имеют другие зависимые от типа адреса. Многие RISC-машины имеют независимые от типа адреса.
Вы можете принять, что ADDR - правильный адрес для данной машины.
Выражение C, которое отлично от нуля, если X - правильная константа для непосредственного операнда на целевой машине. Вы можете принять, что X удовлетворяет "CONSTANT_P", так что вам не надо проверять это. Фактически, "1" является подходящим определением для этой макрокоманды на машинах, где какая-нибудь "CONSTANT_P" правильна.
Описание состояния кода условия.
Файл "conditions.h" определяет переменную "cc_status" для описания того, как был вычислен код условия (в случае, если интерпретация кода условия зависит от команды, которой он был установлен). Эта переменная содержит выражения RTL, на которых основан код условия, и несколько стандартных флажков.
Иногда дополнительные машинно-специфические флаги должны быть определены в заголовочном файле описания машины. Он может также добавлять дополнительную машинно-специфическую информацию, определяя "CC_STATUS_MDEP".
C-код для типа данных, который используется для объявления "mdep" компонент "cc_status". Его значение по умолчанию : "int".
Эта макрокоманда не используется на машинах, которые не используют "cc0".
Выражение C для инициализации поля "mdep" в "empty". Заданное по умолчанию определение не делает ничего, так как большинство машин не использует это поле. Если вы хотите использовать поле, вы должны, вероятно, определить эту макрокоманду, чтобы инициализировать его.
Эта макрокоманда не используется на машинах, которые не используют "cc0".
Составной оператор C для установки компонент "cc_status" соответственно для insn INSN, тело которого - EXP. Эта макрокоманда отвечает за распознавание insn, которые устанавливают код условия как побочный эффект другого действия, такого как установка "(cc0)".
Эта макрокоманда не используется на машинах, которые не используют "cc0".
Если имеются insn, которые не устанавливают код условия, но изменяют другие машинные регистры, эта макрокоманда должна проверить, портят ли они выражения, код условия которых зарегистрирован как отраженный. Например, на 68000, insn, которые сохраняют значения в регистрах адреса, не устанавливают код условия, что означает что обычно "NOTICE_UPDATE_CC" может оставлять "cc_status" неизменным для таких insn. Но предположите, что предыдущий insn установил код условия, основанный на расположении "a4@ (102)", а текущий insn сохраняет новое значение в "a4". Хотя код условия не изменен, он никогда не будет отражать содержимое "a4@ (102)". Следовательно, "NOTICE_UPDATE_CC" должен изменить "cc_status" в этом случае, чтобы сообщить, что ничто не известно относительно значения кода условия.
Определение "NOTICE_UPDATE_CC" должно быть готово иметь дело с результатами peephole-оптимизации: insn, чьи образцы "параллельны" RTX, содержащим различные "reg", "mem" или константы, которые являются только операндами. RTL - структуры этих insn недостаточно, чтобы указать, что insn фактически делают. Что "NOTICE_UPDATE_CC" должен делать, когда видит, что каждый должен только выполнить "CC_STATUS_INIT".
Возможное определение "NOTICE_UPDATE_CC" состоит в вызове функции, которая смотрит на атрибут (*Обратите внимание на Insn Атрибуты::.), например, "cc". Это избавляет от детальной информации относительно образцов в двух местах : в "md" файле и в "NOTICE_UPDATE_CC".
Список имен, которые нужно использовать для дополнительных режимов для значений кода условия в регистрах (*Обратите внимание на Образцы Переходов::.). Эти имена добавлены к "enum machine_mode", и все они имеют класс "MODE_CC". В соответствии c соглашением, они должны начинаться с "CC" и заканчиваться на "mode".
Вы должны определить эту макрокоманду, только, если ваша машина не использует "cc0" и только, если требуются дополнительные типы.
Список C-строк имен для типов, перечисленных в "EXTRA_CC_MODES". Например, Sparc определяет эту макрокоманду и "EXTRA_CC_MODES" так :
#define EXTRA_CC_MODES CC_NOOVmode, CCFPmode, CCFPEmode
#define EXTRA_CC_NAMES "CC_NOOV", "CCFP", "CCFPE"
Эта макрокоманда не требуется, если "EXTRA_CC_MODES" не определена.
Возвращает тип из класса "MODE_CC" для использования, когда код операции сравнения OP применяется к rtx X и Y. Например, на Sparc, "SELECT_CC_MODE" определена, как описано в "Образцы Переходов::.".
#define SELECT_CC_MODE(OP,X,Y) \ (GET_MODE_CLASS (GET_MODE (X)) ==
MODE_FLOAT
\ ? ((OP == EQ || OP == NE) ? CCFPmode : CCFPEmode) \ : ((GET_CODE (X) ==
PLUS || GET_CODE (X) == MINUS \ || GET_CODE (X) == NEG) \ ? CC_NOOVmode :
CCmode))
Вам не нужно определить эту макрокоманду, если "EXTRA_CC_MODES" не
определена.
На некоторых машинах не все возможные сравнения определены, но вы можете получить недопустимое сравнение через допустимые. Например, на Alpha нет "GT"-сравнения, но вы можете использовать вместо него "LT"-сравнение и поменять порядок операндов.
На таких машинах определите эту макрокоманду, как оператор C, делающий любые требуемые преобразования. CODE - начальный код сравнения, OP0 и OP1 - левые и правые операнды сравнения, соответственно. Вы можете изменить CODE, OP0, и OP1, если требуется.
GNU CC не будет считать сравнение, полученное в этой макрокоманде, правильным, но посчитает, если возникающий в результате insn соответствует образцу в "md" файле.
Вам не нужно определять эту макрокоманду, если она никогда не изменяла бы код сравнения или операнды.
Выражение C, значение которого - 1, если всегда можно безопасно обратить сравнение типа MODE. Если "SELECT_CC_MODE" может когда-либо возвращать MODE для неравенства с плавающей точкой, то "REVERSIBLE_CC_MODE (MODE)" должно быть 0.
Вам не нужно определять эту макрокоманду, если она всегда возвращала бы ноль или если формат с плавающей точкой отличается от "IEEE_FLOAT_FORMAT". Например, вот определение, используемое на Sparc, где неравенства с плавающей точкой всегда даны "CCFPEmode":
#define REVERSIBLE_CC_MODE(MODE) ((MODE) != CCFPEmode)
Эти макрокоманды позволяют Вам описывать относительное быстродействие различных операций на целевой машине.
Часть C "switch"-оператора, которая описывает относительные издержки постоянных выражений RTL. Она должна содержать "case"-метки для кодов выражений "const_int", "const", "symbol_ref", "label_ref" и "const_double". Каждый "case" должен в конечном счете достигнуть оператора "return", чтобы возвратить относительную стоимость использования данного вида константы в выражении. Стоимость может зависеть от точного значения константы, которая доступна для исследования в X, и rtx-кода выражения, в котором содержится, и который может быть найден в OUTER_CODE.
CODE - код выражения - избыточный, так как может быть получен, как "GET_CODE(X)".
То же, что "CONST_COSTS", но применяется к неконстантным выражениям RTL. Может использоваться, например, для указания, насколько дорогостоящей является команда умножения. В написании этой макрокоманды, вы можете использовать конструкцию "COSTS_N_INSNS (N)" чтобы определить стоимость, равную N, быстрых команд. OUTER_CODE - код выражения, в котором содержится X.
Эту макрокоманду можно не определять, если заданные по умолчанию предположения стоимости адекватны для целевой машины.
Выражение, дающее стоимость способа адресации, который содержит ADDRESS. Если не определена, то стоимость вычисляется из выражения ADDRESS и значения "CONST_COSTS".
Для большинства CISC машин, заданная по умолчанию стоимость - хорошее приближение истинной стоимости способа адресации. Однако, на RISC машинах, все команды обычно имеют ту же самую длину и время выполнения. Следовательно все адреса будут иметь равные издержки.
В случаях, где известна более, чем одна форма адреса, будет использоваться форма с самой низкой стоимостью. Если многие формы имеют одну и ту же самую низкую стоимость, то будет использоваться та, которая наиболее сложна.
Например, представьте, что адрес, который является суммой регистра и константы, используется дважды в одном базисном блоке. Когда эта макрокоманда не определена, адрес будет вычислен в регистре, и ссылки на память будут косвенными, через этот регистр. На машинах, где стоимость способа адресации, содержащего сумму, не выше чем простой косвенной ссылки, она произведет дополнительную команду и, возможно, потребует дополнительного регистра. Правильная спецификация этой макрокоманды устраняет эту добавку для таких машин.
Подобным образом эта макрокоманда используется при оптимизации циклов.
ADDRESS должен быть правильным, как адрес. В таком случае, стоимость не имеет значения и может быть принята произвольной; недопустимым адресам не должны присваиваться различные стоимости.
На машинах, где адрес, включающий больше, чем один регистр, - такой же дешевый, как адреса, включающий только один регистр, определение "ADDRESS_COST", для отражения этого, может заставить два регистра жить в области кода, где был бы только один, если "ADDRESS_COST" не была бы определена. Этот эффект должен рассматриваться в определении этой макрокоманды. Эквивалентные издержки должны быть приданы, вероятно, только адресам с различными числами регистров на машинах с очень большим количеством регистров.
Эту макрокоманду можно не определять или определять, как константу.
Выражение C стоимости перемещения данных из регистра класса FROM в регистр класса TO. Классы выражены используя порядковые значения "GENERAL_REGS". Значение 4 - значение по умолчанию; другие значения интерпретируются относительно этого.
Не требуется, чтобы стоимость всегда равнялась 2, если FROM = TO; на некоторых машинах дорого перемещать данные между регистрами, если они - не регистры общего назначения.
Если перезагрузка видит insn, состоящий из одиночного "set" между двумя аппаратными регистрами, и если "REGISTER_MOVE_COST" для их классов возвращает значение 2, перезагрузка не проверяет, что ограничения insn выполнены. Установка стоимости на значение, не равное 2, позволяет перезагрузке проверять, что ограничения выполнены. Вы должны делать это, если "movM" ограничения на образец не позволяют такое копирование.
Выражение C стоимости перемещения данных типа M между регистром и памятью. По умолчанию : 2; это стоимость относительно стоимости в "REGISTER_MOVE_COST".
Если копирование между регистрами и памятью дороже, чем между двумя регистрами, вы должны определить эту макрокоманду, чтобы выразить относительную стоимость.
Выражение C стоимости команды перехода (ветвления). По умолчанию : 1; другие значения интерпретируются относительно этого.
Вот дополнительные макрокоманды, которые определяют не точные относительные издержки, а некоторые действия, которые более дороги, чем GNU CC обычно ожидает.
Определите эту макрокоманду как выражение C, которое отлично от нуля, если обращение менее, чем в слову в памяти (то есть к "char" или "short") не быстрее, чем обращение к слову, то есть, если такой доступ требует более одной команды или если нет различия в стоимости загрузки байта и (выровненного) слова.
Когда эта макрокоманда не определена, транслятор обратится к полю, находя самый маленький содержащийся объект; когда определена, будет использоваться загрузка полного слова, если разрешает выравнивание. Если к доступ к байтам не быстрее, чем доступ к словам, использование слов предпочтительно, так как может устранить последующее обращение к памяти, если последующие обращения происходят к другим полям в том же слове из структуры, но к различным байтам.
Определите эту макрокоманду, если расширение нулем (типов "char" или "short" до "int") может быть выполнено быстрее, если адресат - регистр, про который известно, что он - ноль.
Если вы определяете эту макрокоманду, вы должны иметь образцы команды, которые распознают структуры RTL подобно этому:
(set (strict_low_part (subreg:QI (reg:SI ...) 0)) ...)
и аналогично для "HImode".
Определите эту макрокоманду, равной 1, если доступ к невыровненным данным имеет стоимость во много раз большую, чем доступ к выровненным данным, например, если они эмулированы в обработчике ловушки.
Когда эта макрокоманда отлична от нуля, транслятор будет действовать, как будто "STRICT_ALIGNMENT" была отлична от нуля при генерации кода для блочного копирования. Это может заставлять транслятор генерировать гораздо больше инструкций. Следовательно, не устанавливайте эту макрокоманду в отличное от нуля значение, если доступ к невыровненным данным только добавляет цикл или два к времени доступа к памяти.
Если значение этой макрокоманды - всегда ноль, ее не нужно определять.
Определите эту макрокоманду, чтобы запретить уменьшение количества адресов памяти. (На некоторых машинах, такое уменьшение количества делает больше вреда, чем пользы.)
Количество insn, занимающихся скалярным перемещением, которые должны быть сгенерированы вместо insn, реализующего строковое перемещение или вызова библиотечной функции. Увеличение значения будет всегда делать код более быстрым, но в конечном счете сильно увеличивает размер кода.
Если вы не определяете эту макрокоманду, используется приемлемое значение по умолчанию.
Определите эту макрокоманду, если вызвать постоянную функцию не дороже, чем по адресу в регистре.
Определите эту макрокоманду, если функции не дороже вызвать саму себя по явному адресу, чем по адресу в регистре.
Оператор C (без точки с запятой) для модификации целой переменной COST (стоимость) , основанную на связи между INSN, который зависит от DEP_INSN через LINK зависимость. По умолчанию не производится корректировка COST. Это может использоваться например, чтобы указать планировщику, что вывод или анти-зависимость не несет ту же самую стоимость как зависимость данных.
Объектный файл разделен на разделы, содержащие различные типы данных. В наиболее общем случае, имеются три раздела: "текстовый раздел", который содержит команды и данные только для чтения; "раздел данных", который содержит инициализированные перезаписываемые данные; и "раздел bss", который содержит неинициализированные данные. Некоторые системы имеют другие виды разделов.
Транслятор должен сообщить ассемблеру, когда переключать разделы. Эти макрокоманды управляют тем, какие команды вывести, чтобы сообщить об этом ассемблеру. Вы можете также определять дополнительные разделы.
Выражение C, значение которого - строка, содержащая ассемблерную операцию, которая должна предшествовать командам и данным только для чтения. Обычно ".text".
Выражение C, значение которого - строка, содержащая ассемблерную операцию для идентификации следующих данных как перезаписываемые инициализированные данные. Обычно ".data".
Если определена, то это выражение C, значение которого - строка, содержащая ассемблерную операцию для идентификации следующих данных как разделяемых данных. Если не определена, будет использоваться "DATA_SECTION_ASM_OP".
Если определена, это выражение C, значение которого - строка, содержащая ассемблерную операцию для идентификации следующих данных как кода инициализации. Если не определена, GNU CC считает, что такого раздела не существует.
Список имен для разделов, отличных от двух стандартных, которые являются "in_text" и "in_data". Вы не должны определять эту макрокоманду, если на системе нет других разделов (которые GCC должен использовать).
Одна или больше функций, которые определены в "varasm.c". Эти функции должны производить действия, аналогичные функциям из "text_section" и "data_section", но для ваших дополнительных разделов. Не определяйте эту макрокоманду, если вы не определили "EXTRA_SECTIONS".
На большинстве машин переменные только для чтения, константы и таблицы переходов помещены в текстовый раздел. Если на вашей машине это не так, эта макрокоманда должна быть определена именем функции (из "data_section" или определенной в "EXTRA_SECTIONS") которая переключается на соответствующий раздел, который используется для элементов только для чтения.
Если эти элементы были помещены в текстовый раздел, эту макрокоманду не нужно определять.
Оператор(ы) C для переключения на соответствующий раздел для вывода EXP. Вы можете считать, что EXP - или "VAR_DECL" узел, или константа некоторого типа. RELOC указывает, требует ли начальное значение EXP настроек времени компоновки. Выберите раздел, вызывая "text_section" или одну из альтернатив для других разделов.
Не определяйте эту макрокоманду, если вы помещаете все переменные только для чтения и константы в раздел данных только для чтения (обычно текстовый раздел).
Оператор(ы) C для переключения на соответствующий раздел для вывода RTX в типе MODE. Вы можете принять, что RTX - некоторая константа в RTL. Параметр MODE избыточен за исключением случая "const_int" rtx. Выберите раздел, вызывая "text_section" или одну из альтернатив для других разделов.
Не определяйте эту макрокоманду, если вы помещаете все константы в раздел данных только для чтения.
Определите эту макрокоманду, если таблицы перехода (для "tablejump" insns) должны быть выведены в текстовый раздел, наряду с командами ассемблера. Иначе используется раздел данных только для чтения.
Эта макрокоманда не имеет значения, если нет отдельного раздела данных только для чтения.
Определите эту макрокоманду, если ссылки на символ должны обрабатываться по-разному в зависимости от переменной или функции, названной символом (так же как, в каком разделе она находится).
Определение макрокоманды, если есть, выполняется немедленно после того, как rtl для DECL был создан и сохраняется в "DECL_RTL (DECL)". Значение rtl будет "mem", адрес которого - "symbol_ref".
Обычная вещь для этой макрокоманды : записывать флажок в "symbol_ref" (типа "SYMBOL_REF_FLAG") или сохранять измененную строку имени в "symbol_ref" (если одного бита недостаточно для информации).
Декодируйте SYM_NAME, и сохраните реальную часть имени в VAR, без символов, которые кодируют информацию о разделе. Определите эту макрокоманду, если "ENCODE_SECTION_INFO" изменяет строку имени символа.
Этот раздел описывает макрокоманды, которые помогают генерировать позиционно-независимый код. Простое определение этих макрокоманд недостаточно для генерации правильного PIC; вы должны также добавить поддержку макрокоманд "GO_IF_LEGITIMATE_ADDRESS" и "PRINT_OPERAND_ADDRESS", также как "LEGITIMIZE_ADDRESS". Вы должны изменить определение "movsi" так, чтобы она выполняла соответствующее действие, когда исходный операнд содержит символический адрес. Вам может понадобиться также изменение обработки переключающих операторов так, чтобы они использовали относительные адреса.
Номер регистра, используемого для адресации таблицы адресов статических данных в памяти. В некоторых случаях этот регистр определен в "application binary interface" (ABI). Когда эта макрокоманда определена, RTL сгенерирован для этого регистра один раз, как с указателем стека и регистрами указателя кадра. Если эта макрокоманда не определена, машинно-зависимые файлы обязаны распределить такой регистр (в случае необходимости).
Определите эту макрокоманду, если регистр, определенный "PIC_OFFSET_TABLE_REGNUM", затирается (clobbered) обращениями. Не определяйте эту макрокоманду, если "PIC_OFFSET_TABLE_REGNUM" не определена.
Генерируя позиционно-независимый код, когда две различных программы (A и B) совместно используют общую библиотеку (libC.a), текст библиотеки может быть разделен, в зависимости от того, скомпонована ли библиотека к тому же самому адресу к обеим программам. В некоторых из этих сред позиционно-независимый код требует не только использования различных способов адресации, но также специального кода разрешения использования этих способов адресации.
Макрокоманда "FINALIZE_PIC" служит как ловушка, чтобы выдавать эти специальные коды, как только функция компилируется в ассемблерный код, но не раньше. (Это не выполнено раньше, потому что в случае компиляции inline-функции, это вело бы к большому числу прологов PIC, включаемых в функции, которые использовали inline-функции и компилировались в ассемблер.)
Выражение C, которое отлично от нуля если X - правильный непосредственный операнд на целевой машине при генерации позиционно-независимого кода. Вы можете принять, что X удовлетворяет "CONSTANT_P", так что вы не должны проверять этого. Вы можете также принять, что FLAG_PIC истинен, так что вы не должны проверять этого. Вы не должны определять эту макрокоманду, если все константы (включая "SYMBOL_REF") могут быть непосредственными операндами при генерации позиционно-независимого кода.
Этот раздел описывает макрокоманды, принципиальная цель которых состоит в описании того, как писать команды на языке ассемблеров, а не того, что эти команды делают.
Описание полной структуры ассемблерного файла.
Выражение C, которое выводит на stdio STREAM текст, которым должен начинаться ассемблерный файл.
Обычно эта макрокоманда определяется, чтобы вывести строку, содержащую "#NO_APP", которое является комментарием, который не имеет эффекта на большинстве ассемблеров, но сообщает GNU ассемблеру, что он может не тратить время, проверяя некоторые конструкций ассемблера.
На системах, которые используют SDB, необходимо вывести некоторые команды; см. "attasm.h".
Выражение C, которое выводит на stdio STREAM текст, которым должен заканчиваться ассемблерный файл.
Если эта макрокоманда не определена, по умолчанию ничего особенного не должно вывестись в конце файла. Большинство систем не требует никакого определения.
На системах, которые используют SDB, необходимо вывести некоторые команды; см. "attasm.h".
Оператор C вывода команд ассемблера, которые идентифицируют объектный файл как компилированный GNU CC (или другим GNU-транслятором).
Если вы не определяете эту макрокоманду, выводится строка "gcc_compiled.:". Эта строка вычисляется, чтобы определить символ, который на BSD системах, никогда не будет определен по любой другой причине. GDB проверяет присутствие этого символа при чтении таблицы символов выполнимой программы.
На не-BSD системах вы должны установить связь с GDB другим способом. Если GDB не используется на вашей системе, вы можете определить эту макрокоманду с пустым телом.
Строковая константа C, описывающая, как начинать комментарий на целевом ассемблере. Транслятор принимает, что комментарий заканчивается в конце строки.
Строковая константа C для текста, который нужно вывести перед каждым оператором (или последовательной группой) "asm". Обычно это - "#APP", который является комментарием, не имеющим эффекта на большинстве ассемблеров, но сообщающим GNU ассемблеру, что он должно проверить последующие строки на правильность ассемблерных конструкций.
Строковая константа C для текста, который нужно вывести после каждого оператора (или последовательной группы) "asm". Обычно это - "#NO_APP", который говорит GNU ассемблеру экономить время, делая предположения, которые правильны для обычного вывода транслятора.
Оператор C вывода COFF информации или DWARF-отладочной информации, который пишет на stdio поток STREAM, что файл с именем NAME - текущий исходный файл.
Эта макрокоманду не надо определять, если подходит стандартная форма вывода для формата используемого файла.
Оператор C вывода на stdio STREAM DBX или SDB отладочной информации перед кодом для строки номер LINE текущего исходного файла.
Эта макрокоманду не надо определять, если стандартная форма отладочной информации для используемого отладчика, подходящая.
Оператор C вывода чего-то в ассемблерный файл, чтобы обработать "#ident" директиву, содержащую текст STRING. Если эта макрокоманда не определена, ничего не выводится для "#ident" директивы.
Оператор C вывода чего-то в ассемблерный файл, чтобы переключиться на раздел NAME для объекта DECL, который является "FUNCTION_DECL", "VAR_DECL" или "NULL_TREE". Некоторые целевые форматы не поддерживают произвольные разделы. Не определяйте эту макрокоманду в таких случаях.
В настоящее время эта макрокоманда используется только чтобы поддерживать атрибуты раздела. Когда эта макрокоманда не определена, атрибуты раздела запрещены.
Оператор C вывода любых ассемблерных операторов, которые должны предшествовать любым определениям Objective C объектов или посылке сообщений. Оператор выполняется только при компиляции программы на Objective C.
Описание вывода данных.
Операторы C вывода на stdio STREAM ассемблерной команды для трансляции константы с плавающей точкой из "TFmode", "DFmode", "SFmode", "TQFmode", "HFmode", или "QFmode", соответственно, значение которой - VALUE. VALUE - выражение C типа "REAL_VALUE_TYPE". Макрокоманды типа "REAL_VALUE_TO_TARGET_DOUBLE" полезны для написания этих определений.
Оператор C вывода на stdio STREAM ассемблерной команды для трансляции целого числа длиной 16, 8, 4, 2 или 1 байт, соответственно, значение которого - VALUE. Параметр EXP будет выражением RTL, которое представляет постоянное значение. Используйте "output_addr_const(STREAM,EXP)" чтобы вывести это значение как ассемблерное выражение.
Вам не нужно определять эту макрокоманду для размеров больших, чем "UNITS_PER_WORD", если действие макрокоманды было бы многократным вызовом макрокоманды, соответствующей размеру "UNITS_PER_WORD", по одному для каждого слова.
Оператор C вывода на STREAM ассемблерной команды для трансляции одиночного байта, содержащего значение VALUE.
Строковая константа C, дающая псевдооперацию, используемую для последовательности констант в один байт. Если эта макрокоманда не определена, по умолчанию - "byte".
Оператор C вывода на stdio STREAM ассемблерной команды для трансляции строковой константы, содержащей LEN байт в PTR. PTR - выражение C типа "char*", а LEN - выражение C типа "int".
Если ассемблер имеет ".ascii" псевдооперацию, как в Berkeley Unix ассемблере, не определяйте макрокоманду "ASM_OUTPUT_ASCII".
Оператор C вывода ассемблерных команд для определения начала постоянного pool для функции. FUNNAME - строка, дающая имя функции. Если требуется тип возврата функции, он может быть получен через FUNDECL. SIZE - размер в байтах константного pool, который будет написан немедленно после этого обращения.
Если pool-префикс не требуется (обычный случай), то не надо определять эту макрокоманду.
Оператор C (с точкой с запятой или без нее) вывода константы в константный pool, если она требует специальной обработки. (Этой макрокоманде не требуется делать что бы то ни было для выражений RTL, которые могут выводиться обычным образом.)
Параметр FILE - стандартный I/O-поток, для вывода ассемблерного кода. X - выражение RTL для константы, которую надо вывести, и MODE - тип (в случае, если X - "const_int"). ALIGN - требуемое выравнивание для значения X; вы должны вывести ассемблерную директиву, чтобы форсировать это выравнивание.
Параметр LABELNO - номер, используемый во внутренней метке для адреса этого pool. Определение этой макрокоманды ответственно за вывод определения метки на соответствующее место. Вот как это делается :
Когда вы выводите ячейку pool особенным образом, вы должны завершить ее переходом "goto" к метке JUMPTO. Это предотвратит вторичный вывод той же ячейки обычным способом.
Вам не нужно определять эту макрокоманду, если она ничего не делала бы.
Определите эту макрокоманду как выражение C, которое отлично от нуля, если C используется как логический разделитель строк ассемблером.
Если вы не определяете эту макрокоманду, то по умолчанию только символ ";" обрабатывается как логический разделитель строк.
Эти макрокоманды определены как строковые константы C, описывающие синтаксис ассемблера для группировки арифметических выражений. Следующие определения правильны для большинства ассемблеров :
#define ASM_OPEN_PAREN "("
#define ASM_CLOSE_PAREN ")"
Эти макрокоманды обеспечиваются "real.h" для написания определений
"ASM_OUTPUT_DOUBLE" и подобных :
Они транслируют X типа "REAL_VALUE_TYPE" в целевое представление с плавающей точкой, и сохраняют битовый образец в массиве с элементами типа "long int", адрес которого - L. Число элементов в выводимом массиве определено размером желаемого целевого типа данных с плавающей точкой : 32 бита от него входят в каждый "long int" элемент массива. Каждый элемент массива содержит 32 бита результата, даже если "long int" на данной машине шире, чем 32 бита.
Значения элементов массива разработаны так, чтобы вы могли печатать их, используя "fprintf", в порядке, в котором они должны появиться в памяти целевой машины.
Эта макрокоманда преобразует X типа "REAL_VALUE_TYPE" к десятичному числу и сохраняет в виде строки STRING. Вы должны передать в STRING адрес достаточно длинного блока памяти, чтобы содержать результат.
Параметр FORMAT - это "printf"-спецификация, которая служит предложением того, как форматировать строку вывода.
Каждая из макрокоманд в этом разделе используется, чтобы выполнять всю работу по выводу одиночной неинициализированной переменной.
Оператор C (без точки с запятой) для вывода в stdio поток STREAM ассемблерного определения общей метки NAME размером SIZE байт. Переменная ROUNDED - размер, округленный кверху до любого выравнивания которое требуется вызывающей функцией.
Используйте выражение " assemble_name (STREAM, NAME) " для вывода самого имени; до и после которого, выводится дополнительный синтаксис ассемблера для определения имени и переход на новую строку.
Эти макрокоманды контролируют, как выводятся ассемблерные определения неинициализированных глобальные переменные.
Подобно " ASM_OUTPUT_COMMON ", за исключением того, что требует выравнивание как отдельный, явный параметр. Если Вы определяете эту макрокоманду, она используется вместо " ASM_OUTPUT_COMMON ", и дает Вам больше гибкости в обработке требуемого выравнивания переменной. Выравнивание определяется как число битов.
Если определена, то подобна " ASM_OUTPUT_COMMON ", за исключением того, что она используется, если участвует NAME. Если она не определена, будет использоваться " ASM_OUTPUT_COMMON".
Оператор C (без точки с запятой) для вывода в stdio поток STREAM определения ассемблера локальной общей метки NAME размером SIZE байтов. Переменная ROUNDED - это размер, округленный кверху до любого выравнивания, требуемого вызывающей функцией.
Используйте выражение " assemble_name (STREAM, NAME) " для вывода самого имени; до и после него выводите дополнительный синтаксис ассемблера для определения имени и переход на новую строку.
Эти макрокоманды контролируют, как выводятся ассемблерные определения неинициализированных статических переменных.
Подобно " ASM_OUTPUT_LOCAL ", за исключением того, что требует выравнивание как отдельный, явный параметр. Если Вы определяете эту макрокоманду, она используется вместо " ASM_OUTPUT_LOCAL " и дает Вам большую гибкость в обработке требуемого выравнивания переменной. Выравнивание определяется как число битов.
Если определено, подобно " ASM_OUTPUT_LOCAL ", за исключением того, что оно используется, если участвует NAME. Если не определено, будет использоваться " ASM_OUTPUT_LOCAL".
Это относится к выводу меток.
Оператор C (без точки с запятой) для вывода в stdio поток STREAM ассемблерной метки NAME. Используйте выражение " assemble_name (STREAM, NAME) " для вывода имени непосредственно; до и после этого, выводится дополнительный синтаксис ассемблера для определения имени и переход на новую строку.
Оператор C (без точки с запятой) для вывода в stdio поток STREAM любого текста, необходимого для объявления имени NAME определяемой функции. Эта макрокоманда отвечает за вывод определения метки (возможно использование "ASM_OUTPUT_LABEL "). Параметр DECL - это " FUNCTION_DECL " узел дерева, представляющего функцию.
Если эта макрокоманда не определена, то имя функции определяется обычным способом как метка (посредством " ASM_OUTPUT_LABEL ").
Оператор C (без точки с запятой) для вывода в stdio поток STREAM любого текста, необходимого для объявления размера функции, которая определяется. Параметр NAME - имя функции. Параметр DECL - это " FUNCTION_DECL " узел дерева, представляющего функцию.
Если эта макрокоманда не определена, то размер функции не определен.
Оператор C (без точки с запятой) для вывода в stdio поток STREAM любого текста, необходимого для объявления имени NAME инициализированной определяемой переменной. Эта макрокоманда должна выводить определение метки (возможно, используя " ASM_OUTPUT_LABEL "). Параметр DECL - " VAR_DECL " узел дерева, представляющего переменную.
Если эта макрокоманда не определена, то имя переменной определяется обычным способом как метка (посредством " ASM_OUTPUT_LABEL ").
Оператор C (без точки с запятой) для завершения объявления имени переменной, когда компилятор обработал инициализатор полностью и, таким образом, имел возможность определить размер массива, когда он контролировался инициализатором. Используется в системах, где необходимо объявлять что-либо относительно размера объекта.
Если Вы не определяете эту макрокоманду, то это эквивалентно тому, что Вы определяете ее как пустую команду.
Оператор C (без точки с запятой) для вывода в stdio поток STREAM некоторых команд, которые делают метку NAME глобаль- ной, т.е. доступной для ссылки из других файлов. Используйте выражение " аssemble_name (STREAM, NAME) " для вывода самого имени; до и после этого выводится дополнительный синтаксис ассемблера, который делает это имя глобальным и переход на новую строку.
Оператор С (без точки с запятой) для вывода в stdio поток STREAM некоторых команд, которые делают метку NAME "сла- бой", то есть доступной для ссылки из других файлов, но ис- пользуемой только тогда, когда нет других доступных опреде- лений. Используйте выражение " assemble_name (STREAM, NAME) " для вывода самого имени; до и после этого выводится дополнительный синтаксис ассемблера, который делает имя "слабым" и переход на новую строку.
Если Вы не определяете эту макрокоманду, GNU CC не будет поддерживать "слабые" символы и Вы не должны определять макрокоманду " SUPPORTS_WEAK ".
Это выражение C, которое истинно, если поддерживаются "слабые" символы.
Если Вы не определяете эту макрокоманду, " defaults.h " дает определение по умолчанию. Если " ASM_WEAKEN_LABEL " определено, определение по умолчанию " 1 "; иначе - " 0 ". Определите эту макрокоманду, если Вы хотите управлять поддержкой слабых символов с флагом транслятора типа " -melf ".
Оператор C (без точки с запятой) для вывода в stdio поток STREAM любого текста, необходимого для объявления имени внешнего символа NAME, на который ссылаются при компиляции, но который не определен. Значение DECL - узел дерева для объявления.
Эту макрокоманду не обязательно определять, если не требуется ничего выводить.В GNU ассемблере и большинстве Unix ассемблеров ничего не требуется.
Оператор C (без точки с запятой) для вывода в STREAM ассемблерного псевдооператора для объявления внешнего имени библиотечной функции. Имя библиотечной функции задается SYMREF, который имеет тип " rtx " и является " symbol_ref ".
Эту макрокоманду не обязательно определять, если не требуется ничего выводить.В GNU ассемблере и большинстве Unix ассемблеров ничего не требуется.
Оператор C (без точки с запятой) для вывода в stdio поток STREAM ссылки в синтаксисе ассемблера на метку NAME. Это должно добавить " _ " перед именем, если так принято в вашей операционной системе, как в большинстве Berkeley Unix систем. Эта макрокоманда используется в " assemble_name ".
Оператор C для вывода в stdio поток STREAM метку, имя которой состоит из строки PREFIX и номера NUM.
Крайне необходимо, чтобы эти метки были отличны от меток, используемых для функций и переменных на уровне пользователя. Иначе соответствующие программы будут иметь конфликты с внутренними метками.
Желательно исключить внутренние метки из символьной таблицы объектного файла. Большинство ассемблеров имеет соглашение для наименований меток, которые должны быть исключены; во многих системах символ "L" в начале метки имеет этот эффект. Вы должны выяснить, какие соглашения использует ваша система, и следовать этому.
Обычное определение этой макрокоманды следующее:
fprintf (STREAM, "L%s%d:\n", PREFIX, NUM)
Оператор C для сохранения в строке STRING метки, имя которой состоит из строки PREFIX и номера NUM.
Эта строка, когда выводится следом за " assemble_name ", должна генерировать вывод, который " ASM_OUTPUT_INTERNAL_LABEL " сгенерировал бы с теми же PREFIX и NUM.
Если строка начинается со "*", то " assemble_name " выведет остальную часть строки без изменений. Использование "*" таким образом часто удобно для " ASM_GENERATE_INTERNAL_LABEL ". Если строка не начинается со "*", то " ASM_OUTPUT_LABELREF " может изменить строку при выводе. (Конечно, " ASM_OUTPUT_LABELREF " является также частью вашего машинного описания, так что Вы должны знать то, что она делает на вашей машине.)
Оператор C для присваивания OUTVAR (переменной типа " сhar* ") заново распределенной строки, полученной из строки NAME и номера NUMBER, с добавлением некоторой подходящей пунктуации. Используйте " аlloca ", чтобы получить память для строки.
Строка будет использоваться как параметр для " ASM_OUTPUT_LABELREF ", чтобы сделать метку ассемблера для внутренней статической переменной NAME. Следовательно, строка должна быть такой, чтобы дать в результате верный код ассемблера. Параметр NUMBER меняется каждый раз, когда эта макрокоманда выполняется; это предотвращает конфликты между одинаково названными внутренними статическими переменными в различных контекстах.
В идеале, эта строка не должна быть допустимым C идентификатором, чтобы предотвратить любой конфликт с собственными символами пользователя. Большинство ассемблеров допускают знаки "." или "%" в символах ассемблера; помещения по крайней мере одного из этих знаков между именем и номером будет достаточно.
Оператор C для вывода в stdio поток STREAM кода ассемблера, который определяет(присваивает) символу NAME значение VALUE.
Если SET_ASM_OP определен, обеспечивается определение по умолчанию, которое корректно для большинства систем.
Определите эту макрокоманду, чтобы изменить заданные по умолчанию ассемблерные имена, используемые для методов Objective C.
Заданное по умолчанию имя - уникальный номер метода, сопровождаемый именем класса (например, " _1_Foo "). Для методов в категориях имя категории также включается в имя ассемблера (например, " _1_Foo_Bar ").
Эти имена безопасны в большинстве систем, но создают трудности при отладке, так как селектор метода не представлен в имени. Поэтому отдельные системы определяют другие способы вычисления имен.
BUF - выражение типа " char * ", которое дает Вам буфер, в котором хранится имя; его длина равна суммарной длине CLASS_NA- ME, CAT_NAME и SEL_NAME плюс 50 символов.
Параметр IS_INST определяет, является ли метод экземпляром метода или классом метода; CLASS_NAME - имя класса; CAT_NAME - имя категории (или NULL, если метод не содержится в категории); и SEL_NAME - имя селектора.
На системах, где ассемблер может обрабатывать имена в кавычках, Вы можете использовать эту макрокоманду, чтобы обеспечить более читаемые имена.
Оттранслированная программа для некоторых языков включает "конструкторы" (называемые также " подпрограммами инициализации ") - функции для инициализации данных программы, когда она начинает работу. Эти функции должны быть вызваны прежде, чем программа "запускается" - то есть перед вызовом " main "
Компилирование некоторых языков генерирует "деструкторы" (называемые также " подпрограммами завершения "), которые должны вызываться, когда программа завершает работу.
Чтобы заставить работать функции инициализации и завершения, компилятор должен вывести кое-что в коде ассемблера, чтобы эти функции вызывались в соответствующее время. Когда Вы адаптируете транслятор к новой системе, Вы должен указать, как сделать это.
Имеются два основных способа, которыми GCC поддерживает выполнение функций инициализации и завершения. Каждый способ имеет два варианта. Многое из структуры является общим для всех четырех вариантов.
Компоновщик должен формировать два списка из этих функций - список функций инициализации, называемый " __ CTOR_LIST __ ", и список функций завершения, называемый " __ DTOR_LIST __ ".
Каждый список всегда начинается с игнорируемого указателя на функцию (который может содержать 0, -1 или количество указателей на функцию после него, в зависимости от среды). За ним идет последовательность из нуля или более функций - указателей на конструкторы (или деструкторы), заканчивающаяся указателем на функцию, содержащим ноль.
В зависимости от операционной системы и формата исполняемого файла, " crtstuff.c " или " libgcc2.c " просматривает эти списки в момент запуска и выхода. Конструкторы вызваются в порядке, обратном порядку в списке; деструкторы - в прямом порядке.
Самый лучший способ обработки статических конструкторов работает только для форматов объектного файла, которые поддерживают произвольно названные разделы. Разделы определяются отдельно для списка конструкторов и для списка деструкторов.Традиционно они называются ".ctors " и ".dtors ". Каждый объектный файл, который определяет функцию инициализации, также помещает слово в раздел конструктора, чтобы указать на эту функцию. Компоновщик собирает все эти слова в один ".ctors" раздел. Функции завершения обрабатываются аналогично.
Чтобы использовать этот метод, необходимо определить макрокоманды " ASM_OUTPUT_CONSTRUCTOR " и " ASM_OUTPUT_DESTRUCTOR ". Обычно можно получить их, включая " svr4.h ".
Если доступны произвольные разделы, имеется два варианта, в зависимости от того, как вызывается код в " crtstuff.c ". В системах, которые поддерживают "init" раздел, который выполняется при запуске программы, части " crtstuff.c " компилируются в этот раздел. Программа, компонуется " gcc " драйвером примерно так:
ld -o OUTPUT_FILE crtbegin.o ... crtend.o -lgcc
Заголовок функции (" __ do_global_ctors ") появляется в init разделе " crtbegin.o "; остаток функции появляется в init разделе " crtend.o ". Компоновщик соединит две эти части раздела вместе, создавая целую функцию. Если какие-то из пользовательских объектных файлов скомпоновались в середину этого кода, то этот код будет выполняться как часть тела " __ do_global_ctors ".
Чтобы использовать этот вариант, нужно соответственно определить макрокоманду " INIT_SECTION_ASM_OP ".
Если никакой init раздел не доступен, " INIT_SECTION_ASM_OP " не определяется. Затем " __ do_global_ctors" встраивается в текст раздела подобно всем другим функциям и располагается в " libgcc.a ". Когда GCC компилирует произвольную функцию, называемую " main ", он вставляет вызов процедуры " __main " как первый выполнимый код после пролога функции. Функция " __main ", также определенная в " libgcc2.c ", просто вызывает " __ do_global_ctors ".
В форматах файла, которые не поддерживают произвольные разделы, cнова имеется два варианта. В самом простом варианте должны использоваться GNU компоновщик (GNU " ld ") и формат " a.out ". В этом случае " ASM_OUTPUT_CONSTRUCTOR " определяется так, чтобы производить ".stabs" вход типа " N_SETT ", ссылаясь на имя " __CTOR_LIST__ ", и с адресом void функции, содержащей код инициализации как значение. GNU компоновщик распознает это как запрос, чтобы добавить значение к "set"; значения накапливаются и,в конечном счете, помещаются в выполняемый файл как вектор в формате, описанном выше, со счетчиком (игнорируемым) в начале и конечным элементом ноль. " ASM_OUTPUT_DESTRUCTOR " обрабатываеся аналогично. Так как нет доступного init раздела, отсутствие " INIT_SECTION_ASM_OP " заставляет трансляцию " main " вызывать "__ main " как выше, начиная процесс инициализации.
Последний вариант не использует ни произвольные разделы, ни GNU компоновщик. Он предпочтителен, когда требуется динамическая компоновка и когда используются форматы файла, которые GNU компоновщик не поддерживает, типа " ECOFF ". В этом случае, " ASM_OUTPUT_CONSTRUCTOR " не генерирует " N_SETT " символ; функции инициализации и завершения распознаются просто по своим именам. Это требует дополнительной программы на шаге компоновки, которая называется " collect2 ". Эта программа эмулирует компоновщик для использования GNU CC; она работает, запуская обычным компоновщиком, но также упорядочивает включение векторов функций инициализации и завершения. Эти функции вызываются через " __ main ", как описано выше.
Выбор из этих опций конфигурации упрощается набором файлов, зависимых от операционной системы, в каталоге " config ". Эти файлы определяют все существенные параметры. Обычно достаточно включать один из них в файл машинно-зависимой конфигурации. Это следующие файлы:
Для операционных систем, использующих формат ` a.out '.
Для операционных систем, использующих формат ` MachO '.
Для Системы V выпуска 3 и подобных систем, использующих формат ` COFF '.
Для Системы V выпуска 4 и подобных систем, использующих формат ` ELF '.
Для операционной системы VMS.
Вот макрокоманды, управляющие обработкой транслятором функций инициализации и завершения:
Если она определена, это строковая константа C для операции ассемблера, чтобы идентифицировать следующие данные как код инициализации. Если не определена, GNU CC считает, что такого раздела не существует. Когда Вы используете специальные разделы для функций инициализации и завершения, эта макрокоманда также управляет тем, как " crtstuff.c " и " Libgcc2.c " приспосабливаются для запуска функций инициализации.
Если она определена, " main " не будет вызывать " __ main ", как описано выше. Эта макрокоманда должна определяться для систем, которые управляют содержанием init раздела на посимвольной основе, типа OSF/1, и не должна определяться явно для систем ,которые поддерживают " INIT_SECTION_ASM_OP ".
Если определена, это строковая константа С для переключателя, который сообщает компоновщику, что следующий символ - подпрограмма инициализации.
Если определена, это строковая константа С для переключателя, который сообщает компоновщику, что следующий символ - подпрограмма завершения.
Если определено, " main " будет вызывать " __main ", несмотря на присутствие " INIT_SECTION_ASM_OP ". Эта макрокоманда должна быть определена для систем, где init раздел фактически не выполняется автоматически, но полезен для составления списков конструкторов и деструкторов.
Эта макрокоманда определяется как оператор C для вывода в поток STREAM кода ассемблера для приспособления вызова функции NAME во время инициализации.
Предположим, что NAME - имя функции C, сгенерированной автоматически транслятором. Эта функция не имеет параметров. Используйте функцию " assemble_name " для вывода имени NAME; она выполняет любые специфические для системы синтаксические преобразования, такие как добавление подчеркивания.
Если Вы не определяете эту макрокоманду, ничего специального не выводится для упорядочивания вызова функции. Это корректно, когда функция вызывается другим способом - например, посредством программы " collect2 ", которая просматривает таблицу символов, чтобы найти эти функции по их именам.
Похоже на " ASM_OUTPUT_CONSTRUCTOR ", но используется скорее для функций завершения чем функций инициализации.
Если ваша система использует " collect2 " как средство обработки конструкторов, то эта программа обычно использует " nm ", для поиска в объектном файле функций конструктора, которые нужно вызвать. На некоторых видах систем эти макрокоманды могут определяться, чтобы выполнять работу " collect2 " быстрее (и, в некоторых случаях, заставить ее работать вообще):
Определите эту макрокоманду, если система использует формат COFF (Common Object File Format) объектных файлов, чтобы " collect2 " мог распознать этот формат и просматривать объектные файлы непосредственно для поиска динамических функций конструктора/деструктора.
Определите эту макрокоманду, если система использует формат ROSE объектных файлов, чтобы " collect2 " мог распознать этот формат и просматривать объектные файлы непосредственно для поиска динамических функций конструктора/деструктора.
Эти макрокоманды имеют эффект только для "родного" компилятора; " collect2 " как часть кросс-компилятора всегда использует " nm " для целевой машины.
Определите эту макракоманду как строковую константу С, содержащую имя файла, используемого, чтобы выполнить " nm ". По умолчанию ищется путь, обычный для " nm ".
Если система поддерживает общедоступнные библиотеки и имеет программу, чтобы внести в список динамические зависимости данной библиотеки или выполнимой программы, можно определить эти макрокоманды, чтобы разрешить поддержку запуска функций инициализации и завершения в общедоступнных библиотеках:
Эта макрокоманда определяется как строковая константа C, содержащая имя программы, которая вносит в список динамические зависимости, такие как " "ldd" " под SunOS 4.
Эта макрокоманда определяется как C код, который извлекает имена файлов из вывода программы, обозначенной " LDD_SUFFIX ". PTR - переменная типа " char * ", которая указывает на начало строки вывода из " LDD_SUFFIX ". Если строка вносит в список динамическую зависимость, код должен передвинуть PTR к началу имени файла на этой строке. Иначе он должен установить PTR на " NULL ".
Здесь описывается вывод команд ассемблера.
Инициализатор С, содержащий ассемблерные имена для машинных регистров, каждое из которых - строковая константа C. Она транслирует количество регистров в трансляторе в язык ассемблера.
Если определено,то это C инициализатор для массива структур, содержащих имя и номер регистра. Эта макрокоманда определяет дополнительные имена для аппаратных регистров, таким образом разрешая опцию " asm " в объявлениях для ссылки на регистры с использованием альтернативных имен.
Определите эту макрокоманду, если используется нестандартный ассемблер, который требует различные имена для машинных команд.
Определение - оператор или операторы C, которые выводят код операции команды ассемблера в stdio поток STREAM. Операнд PTR - переменная типа " char * ", которая указывает на имя кода операции во "внутренней" форме - форме, которая описана в машинном описании. Это определение должно вывести имя кода операции в STREAM, выполняя любую нужную трансляцию, и увеличить переменную PTR, чтобы она указывала на конец кода операции, чтобы он не выводился дважды.
Фактически,ваше определение макрокоманды может обрабатывать меньше или больше, чем все имя кода операции; но если Вы хотите обработать текст, который включает "%"-последовательности для подстановки операндов, Вы должны позаботиться о подстановке самостоятельно. Вам только надо быть уверенными, что PTR увеличивается для любого текста, который не должен выводиться нормально.
Если надо рассмотреть значения операнда, они могут быть найдены как элементы " recog_operand ".
Если макрокоманда ничего не определяет, команда выводится обычным способом.
Если определено, это оператор C, который будет выполнен прямо перед выводом кода ассемблера для INSN, чтобы изменить извлеченные операнды так, чтобы они выводились по-разному.
Параметром OPVEC является вектор, содержащий операнды, взятые из INSN, и NOPERANDS - число элементов вектора, которые содержат значимые данные для insn. Содержание этого вектора - то, что будет использоваться, для преобразования шаблона insn в код ассемблера, так что можно изменять ассемблерный вывод, изменяя содержание вектора.
Эта макрокоманда полезна, когда разные синтаксисы ассемблера используют один файл образцов инструкций; определяя эту мак- рокоманду иначе, можно заставить большой класс команд выводиться по-разному (например, с переставленными операндами). Конечно, изменения в синтаксисе ассемблера, воздействующие на индивидуальные образцы insn, должны быть обработаны при записи условных программ вывода в этих образцах.
Если эта макрокоманда не определена, она эквивалентна пустому оператору.
Составной операторы С, чтобы вывести в stdio поток STREAM синтаксис ассемблера для операнда команды X. X - выражение RTL.
CODE - значение, которое может использоваться для определения одного из нескольких способов печати операнда. Используется, когда идентичные операнды должны печататься по-разному в зависимости от контекста. CODE исходит из "%" спецификации, которая использовалась, чтобы запросить печать операнда. Если спецификация была только " %DIGIT ", то CODE - 0; Если спецификация была " %LTR DIGIT ", то CODE - ASCII код для LTR.
Если X - регистр, эта макрокоманда напечатает имя регистра. Имена могут быть найдены в массиве " reg_names ", тип которого - "char *[] ". " reg_names " инициализируется из " REGISTER_NAMES ".
Когда машинное описание имеет спецификацию " %PUNCT " (за "%" следует символ пунктуации), эта макрокоманда вызывается с нулевым указателем для X и символом пунктуации для CODE.
Выражение C, которое истинно, если CODE - допустимый символ пунктуации для использования в макрокоманде " PRINT_OPERAND ". Если " PRINT_OPERAND_PUNCT_VALID_P " не определена, это означает, что символы пунктуации (кроме стандартного, "%") не используются таким образом.
Составной оператор C для вывода в stdio поток STREAM синтаксиса ассемблера для операнда команды, который является ссылкой памяти, чей адрес - X. X - выражение RTL.
На некоторых машинах синтаксис для символического адреса зависит от раздел, на который адрес ссылается. На этих машинах определите макрокоманду " ENCODE_SECTION_INFO ", чтобы сохранить информацию в " symbol_ref ", и затем проверяют ее здесь. * См.: Формат Ассемблера::.
Оператор C, который должен быть выполнен после того, как были выведены все инструкции заполнения слотов. В случае необходимости вызовите "dbr_sequence_length ", чтобы определить число слотов, заполненных последовательно (ноль, если в настоящее время не выводится последовательность), чтобы решить, сколько вывести пустых команд.
Не определяйте эту макрокоманду, если ей нечего делать, но она полезна при чтении вывода, если размер последовательности задержек указан явно (например с пропуском).
Обратите внимание, что программы вывода для команд со слотами задержки должны быть подготовлены, чтобы иметь дело не обязательно с частью последовательности (то есть когда проход планирования не запускался, или когда заполнители слотов не были найдены). Переменная " final_sequence " равна нулю, если последовательность не обрабатывается, иначе она содержит выводимую " sequence " rtx.
Если определены, то это строковые выражения С для использования для " %R ", " %L "," %U ", и " %I " опций " asm_fprintf " (см. " final.c "). Они полезны, когда одиночный " md " файл должен поддерживать несколько форматов ассемблера. В этом случае различные " tm.h " файлы могут определять эти макрокоманды по разному.
Если целевая машина поддерживает различные варианты языка ассемблера, (такие, как различные коды операций), определите эту макрокоманду как выражение C, которое дает числовой индекс варианта языка ассемблера для использования, ноль - первый вариант.
Если эта макрокоманда определена, Вы можете использовать конструкции " {option0|option1|option2...} " в шаблонах вывода образцов (*См.: Шаблоны Вывода::.) или в первом параметре " asm_fprintf ". Эта конструкция выводит " option0 ", " option1 " или " оption2 ", и т.д., если значение " ASSEMBLER_DIALECT " равно нулю, один или два, и т.д. Все специальные символы внутри этих строк сохраняют свое обычное значение.
Если Вы не определяете эту макрокоманду, символы " {", " | " и "} " не имеют никакого специального значения, когда они используются в шаблонах или операндах для " asm_fprintf ".
Определите макрокоманды " REGISTER_PREFIX ", " LOCAL_LABEL_PREFIX ", " USER_LABEL_PREFIX " и " IMMEDIATE_PREFIX ", если Вы можете выразить изменения в синтаксисе языка ассемблера этим способом. Определите " ASSEMBLER_DIALECT " и используйте " {option0|option1} " синтаксис, если вариант синтаксиса больше и включает такие вещи, как различные коды операций или порядок операндов.
Выражение C для вывода в STREAM некоторого кода ассемблера, который поместит аппаратный регистр номер REGNO в стек. Код не обязательно должен быть оптимальным, так как эта макрокоманда используется только при профилировании.
Выражение C для вывода в STREAM некоторого кода ассемблера, который восстановит аппаратный регистр номер REGNO из стека. Код не обязательно должен быть оптимальным, так как эта макрокоманда используется только при профилировании.
Это касается таблиц распределения.
Эту макрокоманду нужно определить на машинах, где адреса в таблицах распределения абсолютные.
Определение должно быть оператором C для вывода в stdio поток STREAM псевдоинструкции ассемблера для генерации различия между двумя метками. VALUE и REL - номера двух внутренних меток. Определения этих меток выводятся с использованием " ASM_OUTPUT_INTERNAL_LABEL ", и они должны печататься здесь таким же образом. Например,
fprintf (STREAM, "\t.word L%d-L%d\n",
VALUE, REL)
Эту макрокоманду нужно определить на машинах, где адреса в таблицах распределения абсолютны.
Определение должно быть оператором C для вывода в stdio поток STREAM псевдо-инструкции ассемблера для генерации ссылки на метку. VALUE - номер внутренней метки, определение которой выводится с использованием " ASM_OUTPUT_INTERNAL_LABEL ". Например,
fprintf (STREAM, "\t.word L%d\n", VALUE)
Определите эту макрокоманду, если метка перед таблицей перехода должна выводиться отдельно. Первые три параметра - такие же, как для " ASM_OUTPUT_INTERNAL_LABEL "; четвертый параметр - таблица перехода, которая следует за ними(" jump_insn ", содержащий " addr_vec " или " addr_diff_vec ").
Эта особенность используется на системе V, для вывода оператора " swbeg " для таблицы.
Если эта макрокоманда не определена, эти метки выводятся " ASM_OUTPUT_INTERNAL_LABEL ".
Определите это, если что-нибудь специальное должно выводиться в конце таблицы перехода. Определением должен быть оператор C, который будет выполнен после того, как будет записан код ассемблера для таблицы. Оператор должен писать соответствующий код в stdio поток STREAM. Параметр TABLE является таблицей перехода insn, и NUM - номер предыдущей метки.
Если эта макрокоманда не определена, в конце таблицы перехода ничего специального не выводится.
Здесь описываются команды для выравнивания.
Выражение C для вывода текста, чтобы выровнять текущий счетчик способом, который является желательным в участке кода, который может быть достигнут только при помощи перехода.
Эту макрокоманду не обязательно определять, если в данный момент не нужно никакого специального выравнивания. Большинство машинных описаний машины сейчас не определяет эту макрокоманду.
Выражение C, для вывода текста, чтобы выровнять текущий счетчик, который является желательным в начале цикла.
Эту макрокоманду не обязательно определять, если в данный момент не нужно никакого специального выравнивания. Большинство машинных описаний машины сейчас не определяет эту макрокоманду.
Оператор C для вывода в stdio поток STREAM команды ассемблера, чтобы увеличить расположение счетчика ячеек на NBYTES байт. Эти байты должны равняться нулю при загрузке. NBYTES - выражение C типа " int ".
Определите эту макрокоманду, если " ASM_OUTPUT_SKIP " не будет использоваться в текстовом разделе, потому что она не может поместить нули в байты, которые пропущены. Это так во многих Unix системах, где псевдооператоры пропуска байтов генерируют скорее пустые команды, чем нули, когда они используются в текстовом разделе.
Оператор C, служащий для вывода в stdio поток STREAM команды ассемблера для того, чтобы увеличить счетчик ячеек до кратного 2 в степени POWER байт. POWER должно быть выражением C типа " int ".
Здесь описывается, как определять отладочную информацию.
Эти макрокоманды воздействуют на все отладочные форматы.
Выражение C, которое возвращает номер регистра DBX для номера регистра транслятора REGNO. В простейших случаях значение этого выражения может быть самим REGNO. Но иногда имеются регистры, о которых транслятор знает, а DBX - нет, или наоборот. В таких случаях некоторые регистры должны иметь один номер для транслятора и другой - для DBX.
Если два регистра имеют последовательные номера внутри GNU CC, и они могут использоваться как пара, чтобы содержать значение из нескольких слов, то они *должны* иметь последовательные номера после перенумерации " DBX_REGISTER_NUMBER ". Иначе, отладчики не смогут обратиться к такой паре, потому что они ожидают, что регистровые пары будут последовательными в их собственной схеме нумерации.
Если Вы определяете " DBX_REGISTER_NUMBER " способом, который не сохраняет пары регистров, то Вы должны вместо этого переопределить фактическую схему нумерации регистров.
Выражение C, которое возвращает целочисленное значение смещения для автоматической переменной, имеющей адрес X (выражение RTL). Вычисление по умолчанию предполагает, что X отсчитывается от указателя кадра и дает смещение от указателя кадра. Это требуется для целевых машин, которые производят вывод отладки для DBX или COFF-форматный вывод отладки для SDB и позволяет удалять указатель кадра, когда используются " -g " опции.
Выражение C, которое возвращает целочисленное значение смещения для параметра, имеющего адрес X (выражение RTL). Номинальное смещение - OFFSET.
Выражение C, которое возвращает тип вывода отладки, который GNU CC производит, если пользователь указывает " -g " или " -ggdb ". Определите его, если Вы приспособили GNU CC, чтобы поддерживать более чем один формат отладки вывода. В настоящее время допустимые значения - " DBX_DEBUG "," SDB_DEBUG ", " DWARF_DEBUG " и " XCOFF_DEBUG ".
Значение этой макрокоманды воздействует только на отладочный вывод по умолчанию; пользователь может всегда получать конкретный тип вывода, используя " -gstabs ", " -gcoff ", " -gdwarf ", или " -gxcoff ".
Вот специфические опции для вывода DBX.
Определите эту макрокоманду, если GNU CC произвел вывод отладки для DBX в ответ на опцию ` -g '.
Определите эту макрокоманду, если GNU CC произвел вывод отладки формата XCOFF в ответ на опцию ` -g '. Это - вариант DBX формата.
Определите эту макрокоманду, чтобы контролировать, будет ли GNU CC по умолчанию генерировать расширенную версию GDB об отладочной информации DBX (считая, что отладочная информация DBX-формата вообще разрешена). Если Вы не определяете эту макрокоманду, значение по умолчанию - 1: всегда генерируется расширенную информацию, если для этого имеется возможность.
Определите эту макрокоманду, если все ".stabs " команды должны быть выведены в текстовом разделе.
Строковая константа С, содержащая имя ассемблерного псевдооператора, которое можно использовать вместо ".stabs", чтобы определить обычный символ отладки. Если Вы не определяете эту макрокоманду, используется ".stabs". Эта макрокоманда применяется только для DBX-формата информации об отладке.
Строковая константа С, содержащая имя ассемблерного псевдооператора, которое можно использовать вместо ".stabd", чтобы определить отладочный символ,значением которого является текущее расположение. Если Вы не определяете эту макрокоманду, используется ".stabd". Эта макрокоманда применяется только для DBX-формата информации об отладке.
Строковая константа С, содержащая имя ассемблерного псевдооператора, которое можно использовать вместо ".stabn", чтобы определить безымянный отладочный символ. Если Вы не определяете эту макрокоманду, используется ".stabn". Эта макрокоманда применяется только для DBX-формата информации об отладке.
Определите эту макрокоманду, если DBX на вашей системе не поддерживает конструкцию " xsTAGNAME ". В некоторых системах эта конструкция используется для описания прямой ссылки на структуру, называемую TAGNAME. В других системах, эта конструкция не поддерживается вообще.
Символьное имя в информации об отладке DBX-формата обычно продолжается (расщепляясь на две отдельных ".stabs" директивы), когда оно превышает соответствующую длину (по умолчанию 80 символов). В некоторых операционных системах DBX требует этого расщепления; в других расщепление не должно выполняться. Вы можете запретить расщепление определением этой макрокоманды значением ноль. Вы можете изменить заданную по умолчанию длину расщепления, определяя эту макрокоманду как выражение для длины, которая Вам требуется.
Обычно продолжение определяется добавлением символа "\" к концу ".stabs" строки, когда продолжение следует.Для использования вместо него другого символа, определите эту макрокоманду как символьную константу для символа, который Вы хотите использовать. Не определяйте эту макрокоманду, если наклонная черта влево подходит для вашей системы.
Определите эту макрокоманду, если необходимо перейти к разделу данных перед выведением ".stabs" псевдооператора для неглобальной статической переменной.
Значение для использования в поле "code" директивы ".stabs" для определения типа. Значение по умолчанию - " N_LSYM ".
Значение для использования в поле "code" директивы ".stabs" для статической переменной, размещаемой в текстовом разделе. Формат DBX не обеспечивает никакого "правильный" способа сделать это. Значение по умолчанию - " N_FUN ".
Значение для использования в поле "code" директивы ".stabs" для параметра, передаваемого в регистрах. Формат DBX не обеспечивает никакого "правильного" способа сделать это. Значение по умолчанию - " N_RSYM ".
Буква для использования в символьных данных DBX для идентификации символа как параметра, передаваемого в регистрах. Формат DBX обычно не обеспечивает какого-нибудь способа сделать это. Значение по умолчанию - " "P".
Буква для использования в символьных данных DBX для идентификации символа как параметра стека. Значение по умолчанию - " "p" ".
Определите эту макрокоманду, если DBX информация для функции и ее аргументов должна предшествовать коду ассемблера для этой функции. Обычно, в формате DBX, информация об отладке полностью следует за кодом ассемблера.
Определите эту макрокоманду, если " N_LBRAC " символ для блока должен предшествовать информации об отладке для переменных и функций, определенных в этом блоке. Обычно, в формате DBX, " N_LBRAC " символ идет первым.
Определите эту макрокоманду если значение символа, описывающего область блока (" N_LBRAC " или " N_RBRAC "), должно быть относительно начала вложенной функции. Обычно GNU C использует абсолютный адрес.
Вот ловушки для формата DBX.
Определите эту макрокоманду, чтобы сказать, как выводить в STREAM отладочную информацию для начала области для имен переменных. Параметр NAME - это имя символа ассемблера (для использования с " assemble_name "), значение которого - адрес начала области.
Подобно " DBX_OUTPUT_LBRAC ", но для конца области.
Определите эту макрокоманду, если целевая машина требует специальной обработки для вывода типа перечисления. Это определение должно быть C оператором (без точки с запятой) для вывода соответствующей информации в STREAM для типа TYPE.
Определите эту макрокоманду, если целевая машина требует специального вывода в конце информации об отладке для функции. Определение должно быть оператором C (без точки с запятой) для вывода приспособленной информации в STREAM. FUNCTION - это " FUNCTION_DECL " узел для функции.
Определите эту макрокоманду, если вам нужно контролировать порядок вывода стандартных типов данных в начале компиляции. Параметр SYMS - "дерево", которое является цепочкой всей предопределенных глобальных символов, включая имена типов данных.
Обычно DBX вывод начинается с определений типов для целых чисел и символов, дальше следуют все другие предопределенные типы специфического языка, но не в специфическом порядке.
На некоторых машинах, необходимо сначала вывести различные конкретные типы. Чтобы сделать это, определите " DBX_OUTPUT_STANDARD_TYPES ", чтобы она выводила эти символы в необходимом порядке. Все предопределенные типы, которые Вы явно не выводите, будут выводиться позже без специфического порядка.
Будьте внимательным, чтобы не определить эту макрокоманду так, чтобы она работала только для C. Нет никаких глобальных переменных для доступа к большинству встроенных типов, потому что другой язык может иметь другой набор типов. Способ вывода данного типа состоит в том, чтобы просмотреть SYMS, чтобы увидеть, можете ли Вы его найти. Вот пример:
{
tree decl;
for (decl = syms; decl; decl = TREE_CHAIN (decl))
if (!strcmp (IDENTIFIER_POINTER (DECL_NAME (decl)),
"long int"))
dbxout_symbol (decl);
...
}
Эта программа ничего не делает, если ожидаемый тип не существует.
См. функцию " init_decl_processing " в " c-decl.c ", чтобы найти имена, используемые для всех встроенных типов C.
Вотдругой путь нахождения данного типа:
{
tree decl;
for (decl = syms; decl; decl = TREE_CHAIN (decl))
if (TREE_CODE (decl) == TYPE_DECL
&& (TREE_CODE (TREE_TYPE (decl))
== INTEGER_CST)
&& TYPE_PRECISION (TREE_TYPE (decl)) == 16
&& TYPE_UNSIGNED (TREE_TYPE (decl)))
/* This must be `unsigned short'. */
dbxout_symbol (decl);
...
}
Здесь описываются имена файла в формате DBX.
Определите это, если DBX хочет, чтобы текущий каталог был записан в каждый объектный файл.
Обратите внимание, что рабочий каталог всегда записывается, если включены расширения GDB.
Оператор C для вывода DBX информации об отладке в stdio поток STREAM, который определяет, что файл NAME - основной файл источника - этот файл указывается как входной файл для компиляции. Эта макрокоманда вызывается только однажды, в начале трансляции.
Эта макрокоманда не нуждается в определении, если стандартная форма вывода для DBX отладочной информации является подходящей.
Оператор C для выводя DBX информации об отладке в stdio поток STREAM, который указывает, что текущий каталог в течение трансляции называется NAME.
Эта макрокоманда не нуждается в определении, если стандартная форма вывода для DBX отладочной информации является подходящей.
Оператор C для вывода DBX информации об отладке в конец трансляции основного файла источника NAME.
Если Вы не определяете эту макрокоманду, ничего специального не выводится в конце трансляции, что является правильным для большинства машин.
Оператор C для вывода DBX информации об отладке в stdio поток STREAM, который определяет, что файла NAME - текущий файл источника. Этот вывод генерируется каждый раз, когда ввод перемещается на другой исходный файл в результате " #include ", конца включенного файла или команды " #line ".
Эта макрокоманда не нуждается в определении, если стандартная форма вывода для DBX отладочной информации является подходящей.
Вот макрокоманды для вывода DWARF и SDB.
Определите эту макрокоманду, если GNU CC должен вывести вывод отладки в coff-формате для SDB в ответ на опцию ` -g '.
Определите эту макрокоманду, если GNU CC должен вывести вывод отладки в DWARF формате в ответ на опцию ` -g '.
Определите эти макрокоманды, чтобы изменить синтаксис ассемблера для специальных SDB директив ассемблера. См. " sdbout.c " для списка этих макрокоманд и их параметров. Если используетя стандартный синтаксис, Вам не нужно определять их самостоятельно.
Некоторые ассемблеры не поддерживают точку с запятой как разделитель, даже между SDB директивами ассемблера. В этом случае определите эту макрокоманду как используемый разделитель (обычно " \n "). Не обязательно определять новый набор " PUT_SDB_OP " макрокоманд, если это - единственое требуемое изменение.
Определите эту макрокоманду, чтобы изменить обычный метод построения dummy имени для анонимной структуры и типов объединения. См. " sdbout.c " для большей информации.
Определите эту макрокоманду, чтобы разрешить выделение ссылок на структуры, объединения и перечисления, которые еще не встечались. Стандарт COFF не позволяет обработку неизвестных ссылок, а MIPS ECOFF поддерживает их.
Определите эту макрокоманду, чтобы разрешить обработку ссылок на структуры, объединения и перечисления, которые еще не встечались. Некоторые ассемблеры не поддерживают забегания вперед, в то время как некоторые требуют его.
В то время как все современные машины используют одинаковое представление для целых чисел, существует множество представлений чисел с плавающей точкой. Это значит, что при перекрестной трансляции представление чисел с плавающей точкой (вещественных чисел) в компилируемой программе может быть отлично от представления на машине, на которой происходит трансляция.
Т.к. различные системы представлений могут использовать числа с разными размерами и разной точность, то перекрестная компиляция не может использовать вещественную арифметику главной машины. Следовательно, вещественные константы должны представляться в формате целевой машины. Это означает, что в фазе перекрестной компиляций нельзя использовать `atof' для анализирования вещественных констант. Вместо этого должна использоваться специальная подпрограмма. Свертка констант так же должна эмулировать арифметику целевой машины (или свертка констант не должна производиться вообще).
Макрокоманды из следующей таблицы должны быть определены только если Вы производите перекрестную компиляцию между машинами с различными форматами чисел с плавающей точкой.
Иначе, не определяйте их совсем. В этом случае будут установлены значения по умолчанию, использующие тип данных `double' и `==' для проверки равенства, и т.д.
Вам не нужно беспокоиться, как много раз Вы используете операнд любой из этих макрокоманд. Транслятор никогда не использует операнды которые имеют побочный эффект.
Макрокоманда для типа данных C, который нужно использовать, чтобы держать вещественное (с плавающей точкой) значение в формате целевой машины. Обычно этот тип должен быть `struct', содержащая массив `int'.
Макрокоманда для выражения на C, которое проверяет равенство двух значения, X и Y, оба типа `REAL_VALUE_TYPE'.
Макрокоманда для выражения на С, которое проверяет является ли X меньше чем Y, оба значения типа `REAL_VALUE_TYPE' и интерпретируются как числа с плавающей точкой в формате целевой машины.
Макрокоманда для выражения на C, которое выполняет стандартную библиотечную функцию `ldexp', но использует представление плавающей точки в формате целевой машины. Как X, так и значение выражения имеют тип `REAL_VALUE_TYPE'. Второй параметр, SCALE - целое число.
Макрокоманда, которая определяется, как выражение на С, преобразующее значение Х в вещественном формате целевой машины к целому знаковому числу. Х имеет тип `REAL_VALUE_TYPE'.
Макрокоманда, которая определяется, как выражение на С, преобразующее значение Х в вещественном формате целевой машины к целому беззнаковому числу. Х имеет тип `REAL_VALUE_TYPE'.
Макрокоманда, которая определяется, как выражение на С, округляющее значение Х в вещественном формате целевой машины в сторону нуля к целому числу (но при этом тип остается вещественным). Х имеет тип `REAL_VALUE_TYPE'.
Макрокоманда, которая определяется, как выражение на С, округляющее значение Х в вещественном формате целевой машины в сторону нуля к целому беззнаковому числу (но при этом тип остается вещественным). Х имеет тип `REAL_VALUE_TYPE'.
Макрокоманда, для выражения на С, которое преобразует выражение типа char* - STRING в вещественное число в формате целевой машины, представленное типом MODE. Х имеет тип `REAL_VALUE_TYPE'.
Определите эту макрокоманду, если возможно бесконечное вещественно значение. В таком случае деление на ноль является корректной операцией.
Макрокоманда, для выражения на С, которое определяет является ли вещественное число Х бесконечностью. Значение имеет тип `int'. По умолчанию она вызывает `isinf'.
Макрокоманда, для выражения на С, которое определяет является ли вещественное число "nan" (not-a-number [не число]). Значение имеет тип `int'. По умолчанию, это определено, чтобы вызвать `isnan'.
Макрокоманда, для выражения на С, которое вычисляет результат арифметической операции над над двумя значениями с плавающей точкой. X и Y типа `REAL_VALUE_TYPE`, представленного в формате целевой машины. Результат будет иметь тот же тип и такое же представление типа. Результат сохраняется в OUTPUT (OUTPUT должен быть переменной).
Операция, которую нужно выполнить определяется CODE - кодом, который всегда один из следующих: `PLUS_EXPR', `MINUS_EXPR', `MULT_EXPR', `RDIV_EXPR', `MAX_EXPR' или `MIN_EXPR'.
Расширение этой макрокоманды ответственно за проверку переполнения. Если случается переполнение, макрорасширение должно выполнить оператор `return 0;', который указывает на неспособность выполнить запрошенную арифметическую операцию.
Макрокоманда, для выражения на С, которое возвращает вещественное значение Х с измененным знаком. Как Х, так и значение выражения имеют тип `REAL_VALUE_TYPE' и представлены в формате целевой машины.
В этой макрокоманде не предусмотрен механизм сообщения о переполнение, т.к. переполнение невозможно.
Макрокоманда, для выражения на С, которое преобразовывает вещественное значение Х в тип MODE.
Как Х, так и значение выражения представлены в формате целевой машины и имеют тип `REAL_VALUE_TYPE'. Тем не менее, значение должно иметь соответствующий битовый образец, чтобы его можно было корректно выводить как плавающую константу, чей тип в точности согласуется с типом MODE.
В этой макрокоманде не предусмотрен механизм сообщения о переполнение.
Макрокоманда, для выражения на С, которое преобразовывает вещественное число Х в целое число двойной точности, которое затем сохраняется в двух переменных типа INT - LOW и HIGH.
Макрокоманда, для выражения на С, которое преобразовывает целое число двойной точности, расположенное в двух переменных типа INT - LOW и HIGH, в вещественное число, которое затем записывается в Х.
Здесь представлено несколько смешанных параметров.
Определите его, если Вы предварительно определили специальные предикаты в файле `MACHINE.c'. Эта макрокоманда вызывается в инициализаторе массива структур. Первое поле в структуре - имя предиката, второе - массив кодов RTL. Для каждого предиката существует список всех кодов RTL, которые могут встречаться в выражениях, соответствующих предикату. Элементы этого списка должны разделяться запятыми. Вот пример двух списков типичных для RISC машины:
#define PREDICATE_CODES \
{"gen_reg_rtx_operand", {SUBREG, REG}}, \
{"reg_or_short_cint_operand", {SUBREG, REG, CONST_INT}},
Определение этой макрокоманды не повлияет на сгенерированный код
(тем не менее, некорректные определения, в которых пропущен
ЫЫЫ код, которому может быть поставлен в соответствие предикат,
могут привести к ошибке транслятора). Вместо этого оно сделает
таблицу, построенную с помощью `genrecog', более компактной
и эффективной. И это ускорит транслятор. Важнее всего включить в список,
определяемый этой макрокомандой, предикаты, используемые в большинстве
insn.
Псевдоним для имени типа. Это тип, который должны иметь элементы таблицы переходов.
Определите эту макрокоманду, если таблицы переходов содержат относительные адреса.
Определите эту макрокоманду, если выход значения указателя за разрешенные пределы приводит к потере управления над 'case' insn. Это означает, что определенная по умолчанию метка в действительности игнорируется 'case' insn-ом.
Определите эту макрокоманду, как наименьшее число, при котором лучше использовать таблицу переходов, чем дерево условных ветвей. По умолчанию она равна четырем для машин с `casesi' инструкциями, и пять для всех остальных. Это самое лучшее для большинства машин значение.
Определите эту макрокоманду, чтобы операции между регистрами с интегральным режимом (типом) размера меньше, чем размер слова, всегда выполнялись на всем регистре. Большинство RISC машин имеют такую возможность, а большинство CISC машин нет.
Определите эту макрокоманду, как выражение на C, указывающее, когда insns, читающие из памяти тип MODE - интегральный тип уже чем слово, делают либо знаковое расширение, либо расширение нулем, устанавливая биты вне MODE. Для тех типов MODE, которые надо расширять нулем макрокоманда должна возвратить `ZERO_EXTEND', для типов знакового расширения - `SIGN_EXTEND', и `NIL' для остальных.
Эта макрокоманда не вызывается если MODE не интегральный тип, или если размер MODE больше или равен, чем `BITS_PER_WORD', поэтому в таких случаях Ваша макрокоманда может возвращать что угодно. Не определяйте эту макрокоманду если она всегда будет возвращать 'NIL'. На машинах, на которых эта макрокоманда определена, Вы обычно будете определять ее как константу `SIGN_EXTEND', либо как константу `ZERO_EXTEND'.
Псевдоним для tree кода, который следует использовать по умолчанию для преобразования вещественных значений в значения с фиксированной точкой. Обычно используется `FIX_ROUND_EXPR'.
Определите эту макрокоманду, если те же самые команды, которые преобразовывают вещественное число в число с плавающей точкой, так же правильно преобразовывают в беззнаковое.
Псевдоним для tree кода, который в общем случае является наиболее простым видом деления для компиляции кода. Он может быть `TRUNC_DIV_EXPR', `FLOOR_DIV_EXPR', `CEIL_DIV_EXPR' или `ROUND_DIV_EXPR'. Эти четыре оператора деления различаются тем, как они округляют результаты до целого. `EASY_DIV_EXPR' используется, когда разрешимо использовать любой из этих операторов и выбор должен быть сделан исходя из их сравнительной эффективности.
Максимальное число байтов, которые одна команда может быстро переместить из памяти в память.
Максимальное число байтов, которые одна команда может быстро переместить из памяти в память. Если она не определена, то по умолчанию берется `MOVE_MAX'. Иначе, это - постоянное значение, которое является самым большим из значений, которые принимает 'MOVE_MAX'.
Выражение на C, которое не равно нулю, если на этой машине число битов, фактически используемых для счета операции сдвига, равно числу битов, которое требуется для представления перемещаемого объекта.
Когда эта макрокоманда не ноль, транслятор исходит из предположения, что безопаснее опустить знако-расширяющие, нуль-расширяющие и некоторые выполняющие побитовое "и" инструкции, которые усекают размер сдвига. На машинах, имеющих инструкции, которые действуют на битовые поля в различных позициях, которые могут включать в себя инструкции `bit test', ненулевой `SHIFT_COUNT_TRUNCATED' также осуществляет уничтожение усеканий значений, которые служат аргументами для инструкций битовых полей.
Если оба типа инструкций усекают размер (сдвигов) и позицию (для операций битовых полей), или если не существует инструкций битовых полей с переменной позицией, Вам следует определить эту макрокоманду.
Тем не менее, на некоторых машинах, таких как 80386 и 680x0, усечение работает только с операциями сдвига и не работает с (реальными или симулируемыми) операциями битовых полей. Определите для таких машин значение `SHIFT_COUNT_TRUNCATED' равным нулю. Вместо этого добавьте образцы в файл `md', который включает подразумеваемые усечения инструкций сдвигов.
Вы можете не определять эту макрокоманду если она всегда будет иметь значение ноль.
Выражение на С, которое не является нулем, если на этой машине безопасно "преобразовывать" целое число размером INPREC бит в целое размером OUTPREC (где OUTPREC меньше чем INPREC) простым обращением с ним, как если бы оно имело только OUTPREC биты.
На многих машинах, это выражение может быть 1.
Когда `TRULY_NOOP_TRUNCATION' возвращает 1 для пары размеров типов, для которых `MODES_TIEABLE_P' равен 0, может быть сгенерирован неоптимальный код. В таком случае назначение `TRULY_NOOP_TRUNCATION' нулём для таких ситуаций может улучшить положение.
Выражение на C, которое описывает значение, возвращенное оператором сравнения с интегральным типом и сохраненное командой сохранения флага (`sCOND') когда условие истинно. Это описание должно прилагаться ко *всем* `sCOND' образцам, и ко всем операторам сравнения, чьи результаты имеют тип `MODE_INT'.
Значение 1 или -1 означает, что инструкция, содержащая сравнение, возвращает соответственно 1 или -1, когда сравнение - истина и 0, когда сравнение - ложь. Другое значение указывает какие биты результата гарантированно равны 1, когда сравнение - истина. Это значение интерпретируется в типе операции сравнения, который определяется типом первого операнда в `sCOND' образце. Будет установлен либо нижний, либо знаковый бит `STORE_FLAG_VALUE'. Транслятором используются только эти биты.
Если `STORE_FLAG_VALUE' ни 1 ни -1, то транслятор сгенерирует код, зависящий только от определенного бита. Он так же может заменить операторы сравнения на эквивалентные операции, даже если они действуют только на эти особенные биты и оставляют другие биты неопределенными. Например, на машинах, чьи операторы сравнения возвращают значение типа `SImode' и где `STORE_FLAG_VALUE' определен как `0x80000000', т.е. только знаковый бит имеет значение, выражение:
(ne:SI (and:SI X (const_int POWER-OF-2)) (const_int 0))
может быть преобразовано к
(ashift:SI X (const_int N))
где N подходящий размер операции сдвига для перемещения проверяемого
бита в знаковый бит.
Не существует способа описать машину, которая всегда устанавливает бит младшего разряда для значения истина, но не гарантирует значения никаких других битов, но мы не знаем таких машин. Если Вы пытаетесь установить GNU CC на такой машине, включите инструкцию, выполняющую логическое "и" с 1 в образце для операторов сравнения и дайте нам знать (см. Как вывести сообщение об ошибке).
Часто машина будет иметь много инструкций, которые получают значения от сравнений (или кодов условия). Вот правила для выбора значения для `STORE_FLAG_VALUE', и следовательно инструкций, которые нужно использовать:
(set A (neg:M (ne:M B C)))
Некоторые машины могут так же выполнять операции `and' или `plus'
над значениями кода условия и с меньшим количеством инструкций, чем
соответствующий insn `sCOND', сопровождаемый `and' или `plus'.
На этих машинах Вам следует определить нужные образцы. Используйте имена
`incscc' и `decscc' соответственно, для образцов, которые выполняют
операции `plus' или `minus' над значениями кода условия. Для примеров
смотрите `rs6000.md'. Вы можете использовать GNU Superoptizer, что бы
найти такие последовательности инструкций на других машинах.
Вам не нужно определять `STORE_FLAG_VALUE', если машина не имеет инструкций сохранения флага.
Выражение на C, которое дает ненулевое вещественное значение, возвращаемое, когда операция сравнения с вещественным результатом истина. Определите эту макрокоманду на машине, если она имеет операции сравнения, возвращающие значение с плавающей точкой. Если же таких команд нет, то определять эту макрокоманду не надо.
Псевдоним для машинного режима указателей. На большинстве машин, эта макрокоманда определяется как целочисленным режимом, соответствующий ширине аппаратного указателя; `SImode' на 32-битных машинах и `DImode' на 64-битных. На некоторых машинах эта макрокоманда должна быть одним из частичных целых типов, таких как `PSImode'.
Ширина `Pmode' должна быть по крайней мере такого же размера, как значение `POINTER_SIZE'. Если она не равна, то Вы должны определить макрокоманду `POINTERS_EXTEND_UNSIGNED' чтобы определить, как расширить указатель до `Pmode'.
Псевдоним для типа, используемого для ссылок на функции, вызываемые в RTL выражениях вызова. На большинстве машин этот тип должен быть `QImode'.
Выражение на С для максимального числа инструкций, для которых функцию DECL можно сделать inline. DECL есть узел `FUNCTION_DECL'.
Значение этой макрокоманды по умолчанию равно 64 плюс число аргументов, которое понимает функция, умноженное на 8. Некоторые люди полагают, что на RISC машинах следует использовать большее пороговое значение.
Определите ее, если препроцессору следует игнорировать директивы `#sccs', и не выдавать сообщения об ошибках.
Определите эту макрокоманду, если системные файлы описания поддерживают С++ так же, как и С. Эта макрокоманда отключает обычный метод использования системных файлов описания, симулирующий, что содержимое файлов заключено в `extern "C" {...}'.
Определите эту макрокоманду, если Вы хотите вставлять какие-нибудь прагмы. Если она определена, то выражение, выполняющееся, когда замечена `#pragma', должно быть выражением на С. Аргумент STREAM есть входной поток stdio из которого читается текст источника.
Идея использования новых `#pragma' как правило плохая идея. Единственная причина определить эту макрокоманду - для совместимости с другими трансляторами, поддерживающими `#pragma' ради уже существующих программ юзера, которые ее используют.
Если определен, то это выражение на С, чье значение не ноль, если IDENTIFIER с аргументами ARGS есть специфичный корректный машинный атрибут для DECL. Атрибуты в ATTRIBUTES были предварительно назначены для DECL.
Если определен, то это выражение на С, чье значение не ноль, если IDENTIFIER с аргументами ARGS есть специфичный корректный машинный атрибут для TYPE. Атрибуты в ATTRIBUTES были предварительно назначены для TYPE.
Если определен, то это выражение на С, чье значение ноль, если атрибуты на TYPE1 и TYPE2 несовместимы, один если совместимы, и два если они почти совместимы (в этом случае выдастся warning).
Если определена, утверждение C, которое назначает заданные по умолчанию атрибуты к недавно определенному ТИПУ.
Определите эту макрокоманду, что бы контролировать использование символа '$' в именах идентификатора. Значение должно быть 0, 1 или 2. 0 значит, что по умолчанию '$' не позволен; 1 значит, что позволен, если используется `-traditional'; 2 значит, что позволен, если `-ansi' не используется. По умолчанию 1. В этом случае нет надобности определят эту макрокоманду.
Определите эту макрокоманду, если ассемблер не принимает меткам с именами, содержащими символ '$'. По умолчанию в именах конструкторов и деструкторов в G ++ содержится символ '$'. Если эта макрокоманда определена, то вместо '$' используется `.'.
Определите эту макрокоманду, если ассемблер не принимает меткам с именами, содержащими символ '.'. По умолчанию в именах конструкторов и деструкторов в G ++ содержится символ '.'. Если эта макрокоманда определена, то вместо имена переделываются, что бы избежать этого символа.
Определите эту макрокоманду, если целевая система считает, что функция `main' каждой программы по умолчанию возвратит стандартное значение "успеха" (если никакое другое значение явно не возвращено).
Определение должно быть оператором на С (с ';'), генерирующем соответствующие rtl команды. Оно используется только при компилировании конца `main'.
Определите ее, если целевая система поддерживает функцию `atexit' из ANSI C стандарт. Если она не определена, и не определен `INIT_SECTION_ASM_OP', то `exit' функция, заданная по умолчанию, будет поддерживать C ++.
Определите ее, если ваша `exit' функция должна делать что-нибудь кроме вызова внешней функции `_cleanup' перед завершением с `_exit'. Макрокоманда `EXIT_BODY' необходим только, если не определены ни 'HAVE_ATEXIT' ни 'INIT_SECTION_ASM_OP'.
Определите эту макрокоманду как выражение на C, которое отлично от нуля, если планировщик слота задержки может безопасно, поместить команды в слот задержки INSN, даже если их появление устанавливает или уничтожпет ресурсы в INSN. INSN - всегда или 'jump_insn' или 'insn'; GNU CC знает, что каждый 'call_insn' ведет себя так. На машинах, на которых некоторые 'insn' или 'jump_insn' действительно являются вызовами функции и следовательно имеют такое поведение, Вы должны определить эту макрокоманду.
Вам не надо определять эту макрокоманду если она всегда будет возвращать ноль.
Определите эту макрокоманду как выражение на C, которое отлично от нуля, если планировщик слота задержки может безопасно, поместить команды в слот задержки INSN, даже если их появление устанавливает или уничтожает ресурсы в INSN. INSN - всегда или 'jump_insn' или 'insn'. На некоторых машинах, на которых `insn' или `jump_insn' есть настояшие вызовы функции и их операнды - регистры, которые фактический используют в вызвающей подпрограмме, Вы должны определить эту макрокоманду. Такое выполнение позволяет планировщику слота задержки перемещать команды, копирующие параметры в регистры аргументов в слоте задержки INSN.
Вы были не должны определять эту макрокоманду, если она всегда возвращает ноль.
В редких случаях(ящиках), корректная генерация объектного кода требует дополнительной машинно-зависимо обработки между вторым проходом оптимизации переходов и отсроченным планированием перехода. На таких машинах, определите эту макрокоманду как оператор на C, чтобы действовать на код, начинающийся в INSN.
Файл конфигурации `xm-MACHINE.h' содержит макроопределения, описывающие машину и систему, на которых производится трансляция, в отличии от определений в `MACHINE.h', которые описывают целевую машину. Большинство значений в `xm-MACHINE.h' в действительности одинаковы для всех машин, на которых работает GNU CC, поэтому все файлы конфигурации имеют большие одинаковые части. Но существуют макрокоманды, которые отличаются:
Определите эту макрокоманду, если главная система - System V.
Определите эту макрокоманду, если главная система - VMS.
Выражение на C для кода состояния, который будет возвращен, при выходе транслятора после серьезных ошибок.
Выражение на C для кода состояния, который будет возвращен, когда транслятор выходит без серьезных ошибок.
Определите эту макрокоманду, если на главной машине слова в составном слове идут в обратном порядке. (GNU CC не зависит от упорядочения байтов внутри слова на главной машине.)
Определите эту макрокоманду, которая должна быть 1 если на главной машине при сохранение вещественных чисел типов `DFmode', `XFmode' или `TFmode' бит знака записывается в самый маленький адрес. В противном случае она должна быть ноль.
Если упорядочивание такое же как и упорядочивание целых чисел в составном слове (тип из нескольких слов).
Числовой код, отличающий вещественной формат главной машины. См. `TARGET_FLOAT_FORMAT' в для различных возможных вариантов и значения по умолчанию.
Выражение на C для числа битов в `char' на главной машине.
Выражение на C для числа битов в `short' на главной машине. .
Выражение на C для числа битов в `int' на главной машине.
Выражение на C для числа битов в `long' на главной машине.
Определите эту макрокоманду, чтобы указать, что главный транслятор поддерживает битовые поля только для 'int', но не для других целых типов, включая `enum', как то делают большинство компиляторов С.
Выражение на C для размера обычных obstack кусков. Если Вы не определяете, его по умолчанию используется разумное обычное значение.
Функция, используемая, чтобы распределить obstack куски. Если Вы не ее, то будет использоваться `xmalloc'.
Функция, используемая, чтобы освободить obstack куски. Если Вы не ее, то будет использоваться `free'.
Определите эту макрокоманду, чтобы указать, что транслятор работает с 'alloca', выполненной на C. Эта версия 'alloca' может быть найдена в файле 'alloca.c'; чтобы использовать ее, Вы должны также измениться переменную 'Makefile'-а - 'ALLOCA'. (Для систем, для которых мы знаем, что это необходимо, это выполнено автоматически)
Если Вы определяете эту макрокоманду, Вы должны вероятно сделать это следующим образом:
#ifndef __GNUC__
#define USE_C_ALLOCA
#else
#define alloca __builtin_alloca
#endif
так, чтобы, когда транслятор компилировался с GNU CC, он использовал
более эффективную встроенную функцию `alloca'.
Определите эту макрокоманду, чтобы указать, что главный транслятор не правильно обрабатывает преобразование функционального значения к указатель-в-функцию, когда это используется в выражении.
Определите ее, если библиотечная функция `vprintf' является доступной на вашей системе.
Определите эту макрокоманду, чтобы допустить поддержку для символов мультибайта во вводе GNU CC. Это требует, когда главная система поддерживала ANSI C библиотечными функциями для преобразования символов мультибайта к широким символам.
Определите ее, если библиотечная функция `putenv' является доступной на вашей системе.
Определите ее, если ваша система - POSIX.1 совместима.
Определите ее, если ваша система *не* поддерживает переменную `sys_siglist'.
Определите ее, если ваша система имеет переменную `sys_siglist', и она уже объявлена в системных файлах заголовков.
Определите эту макрокоманду 1-ой, если Вы знаете, что главный транслятор поддерживает прототипы, даже если это не определяет __STDC__, или определите ее 0, если Вы не хотите, что бы в GNU CC использовались какие то ни было прототипы. Если `USE_PROTOTYPES' не определена, то это буде определяться автоматический с помощью проверки определено ли `__STDC__'.
Определите ее, если Вы же, что бы было подавление прототипов, сгенерированных их файла описания машины, но использовать другие прототипы внутри GNU CC. Если 'USE_PROTOTYPES' определен 0-ем, или главный транслятор не поддерживает прототипы, эта макрокоманда не будет иметь никакого эффекта.
Определите ее, если Вы желаете генерировать прототипы для функции 'gen_call' или `gen_call_value', сгенерированных из файла описания машины. Если 'USE_PROTOTYPES' определен 0-ем, или главный транслятор не поддерживает прототипы, или определен 'NO_MD_PROTOTYPES', то эта макрокоманда не воспринимается. Как только все машинные описания изменяются, чтобы иметь соответствующее число параметров, эта макрокоманда будет удалена.
В некоторые системах есть соответствующая переменная, но она может иметь разные имена, типа '_sys_siglist'. На этих системах, Вы можете определять 'sys_siglist' как макрокоманде, которая расширяется в фактическое переменной.
Определите ее, если ваша система не имеет инклюд файла 'stab.h'. Если 'USG' определен, то 'NO_STAB_H' определен.
Эта макрокоманда должна быть определена символом, который используется для разделения в путях. По умолчанию используется символ двоеточия.
Если Ваша система использует символ, отличный от слэша для разделения имен директорий в указании файла, то определите его в эту макрокоманду. Когда GNU CC отображает имя файла будет использоваться определенный символ. GNU CC проверит и слыш и вами определенный символ при разборе имени файла.
Определите эту макрокоманду, как расширение объектных файлов на вашей машине. По умолчанию используется `.o'.
Определите эту макрокоманду, как расширение исполняемых файлов на вашей машине. По умолчанию используется пустая строка.
Если определено, `collect2' просмотрит индивидуальные объектные файлы, определенные в командной строке и создаст экспортный список для линкера. Определите эту макрокоманду для систем подобных AIX, где линкер отбрасывает объектные файлы, не вызванные из 'main' или пользовательского export-списка.
Когда Вы конфигурируете GNU CC используя сценарий `configure' (см. Инсталяция) из файла шаблона `Makefile.in' создастся файл `Makefile'. При этом включается файлы фрагментов '-TARGET' и `x-HOST' из директории `config'. Если эти файлы не существуют, то это означает, что к главной и целевой машине ничего не надо добавлять.
Фрагменты Makefil `t-TARGET', отвечающие целевой машине определяют специальные переменные, зависящие от этой машины:
Правило, использующие, чтобы сформировать 'libgcc1.a'. Если Ваша целевая машина не должна использовать функции из 'libgcc1.a', установите его пустым. см. Интерфэйс.
Правило, использующие, чтобы сформировать 'libgcc1.a при формировании кросс-компилятора. Если Ваша целевая машина не должна использовать функции из 'libgcc1.a', установите его пустым.
Трансляторный флаг для использование во время компилирования `libgcc2.c'.
Список исходных файлов, которые должны быть скомпилированы или скомпилированы ассемблером, а потом вставлены в into `libgcc.a'.
Специальный флаг, использующийся во время компилирования `crtstuff.c'. см. Инициализация.
Для некоторых целевых машин, вызывая GNU CC различными способами будут произведены объекты, которые не могут быть слинкованы вместе. Например, для некоторых целевых машин GNU CC производит оба, и большой и маленький конечный код. Для таких целевых машин, Вы должны принять меры для многократного компилирования 'libgcc.a', по одному разу для каждого набора несовместимых опций. Когда GNU CC вызывает компоновщик, то он предлагает правильные версии `libgcc.a', основываясь на используемых опциях командной строки.
Макрокоманда 'MULTILIB_OPTIONS' вносит в список набор опций, для которых должны быть сформированы специальные версии 'libgcc.a'. Опции, которые являются взаимно несовместимыми, пишите рядом, через слэш. Опции, которые могут использоваться вместе, пишите через пробелом. Формирующаяся процедура сформирует все комбинации совместимых опций.
Например, если Вы устанавливаете 'MULTILIB_OPTIONS' на `m68000/m68020 msoft-float', 'Makefile' будет формировать специальные версии из ' libgcc.a ' используя опций '-m68000', '-m68020', '-msoft-float', '-m68000 -msoft-float', и '-m68020 -msoft-float'.
Если используется 'MULTILIB_OPTIONS', то эта переменная определяет имена директории, которые должны использоваться, для содержания различных библиотек. Пишите один элемент в 'MULTILIB_DIRNAMES' для каждого элемента в 'MULTILIB_OPTIONS'. Если 'MULTILIB_DIRNAMES' не используется, значение по умолчанию будет 'MULTILIB_OPTIONS', со всеми слешами, обрабатываемыми как пробелы.
Например, если 'MULTILIB_OPTIONS' - `m68000/m68020 msoft-float', то значение по умолчанию 'MULTILIB_DIRNAMES' будет `m68000 m68020 msoft-float'. Вы можете определить другое значение, если Вы желаете получить другой набора имен каталогов.
Иногда та же самая опция может быть написана двумя различными способами. Если опция перечислена в 'MULTILIB_OPTIONS', GNU CC знать асе ее синонимы. В этом случае, установите 'MULTILIB_MATCHES' в списке элементов формы 'option=option', чтобы описать все уместные синонимы. Например, 'm68000=mc68000 m68020=mc68020 '.
Фрагмент makefile главной машины, `x-HOST', определяет специальные, зависимые от главной машины переменные и цели, используемые в `Makefile':
Транслятор выполняет, когда строит первую страницу.
Что бы прилинковываться к библиотеками главной машины.
Для использования транслятором, при формировании `libgcc1.a' для местной трансляции.
Версия `ar' для использования, когда строится `libgcc1.a' для местной трансляции.
Программа инсталяции.