Практикум «Оптимизирующие компиляторы» (на примере GCC) (1157417), страница 12
Текст из файла (страница 12)
рисунок 20). Все они находятся в каталогеgcc/config/tm, где tm – это мнемоническое имя для целевогопроцессора или семейства процессоров, например i386,sparc,vax.ОписываемоенамисемействоAVRalpha,находитсяводноимённом каталоге avr. Таким образом, в этом разделе мы рассмотримнекоторые примеры описаний из файлов avr.h, avr.c, avr.md.Файл tm.hОписание процессора и ABI (Application Binary Interface) производится спомощью макросов в файле tm.h. Этими макросами описываютсякатегории, которые перечислены ниже.Практикум «оптимизирующие компиляторы»• Окружение компилятора.
На пример, синтаксис ассемблера, каталог,где искать заголовочные файлы и системные библиотеки.• Основные свойства машины (Fundamental machine properties), такиекак, порядок байт (прямой или обратный), адресуемое пространствопамяти, количество и тип регистров, а так же режимы адресации.• ABI. Описываются способы вызова функций.Поддержка описания машины – дополнительные средства, которыенепосредственно используются в md-файле или при работе с внутреннимпредставлением.Теперь приведём несколько примеров из перечисленных категорий. Нижерассмотрены лишь некоторые макросы; полное описание можно найти вфайле avr.h.FIXED_REGISTERSМакрос описывает регистры, за которыми закреплена определённаяфункциональность, т.е. такие регистры не доступны для обычногоиспользования.
Например, типичными регистрами такого рода являются:указатель на стек (stack pointer), указатель на кадр стека, счетчик команд ит.п.Описание представляет собой последовательность чисел, разделенныхзапятыми, заключенная в фигурные скобки (это инициализатор дляобычногомассивасоответствующемуязыкарегистру.C).КаждыйЕслиэтотэлементэлементотноситсяравен1,соответствующий регистр специальный, иначе – общего назначения.#define FIXED_REGISTERS {\1,1,/* r0 r1 */\0,0,/* r2 r3 */\0,0,/* r4 r5 */\0,0,/* r6 r7 */\ктоПрактикум «оптимизирующие компиляторы»0,0,/* r8 r9 */\0,0,/* r10 r11 */\0,0,/* r12 r13 */\0,0,/* r14 r15 */\0,0,/* r16 r17 */\0,0,/* r18 r19 */\0,0,/* r20 r21 */\0,0,/* r22 r23 */\0,0,/* r24 r25 */\0,0,/* r26 r27 */\0,0,/* r28 r29 */\0,0,/* r30 r31 */\1,1,/* вершина и кадр стека */ \1,1/* указатели на аргументы */}В этом примере объявлены следующие фиксированные регистры: r0,r1, указатели стека, указатели на аргументы.CALL_USED_REGISTERSУказывает регистры, которые могут терять своё значение при вызовефункций.
Другими словами, указываются регистры, значения которыхнужносохранитьпривызовефункции.Описаниеаналогичнопредыдущему. Если для регистра соответствующий элемент равен 0, токомпилятор автоматически сохранит его значение в теле функции, ивосстановит его значение перед выходом из неё, если значение регистраизменилось.#define CALL_USED_REGISTERS {\1,1,/* r0 r1 */\0,0,/* r2 r3 */\0,0,/* r4 r5 */\0,0,/* r6 r7 */\0,0,/* r8 r9 */\0,0,/* r10 r11 */\0,0,/* r12 r13 */\0,0,/* r14 r15 */\0,0,/* r16 r17 */\1,1,/* r18 r19 */\1,1,/* r20 r21 */\Практикум «оптимизирующие компиляторы»1,1,/* r22 r23 */\1,1,/* r24 r25 */\1,1,/* r26 r27 */\0,0,/* r28 r29 */\1,1,/* r30 r31 */\1,1,/*\1,1/* arg pointer */STACK */}Регистры с r18 по r27 и r30, r31 не будут сохранены при вызовахфункций.REG_CLASS_CONTENTSЭтотмакросописываетклассырегистров.Длякаждогоклассауказываются регистры входящие в него.
Описание, так же как и впредыдущих случаях, представляет собой инициализатор обычного Cмассива: каждый элемент соответствует классу регистров.Принадлежность регистра с номером R классу K, определяется изистинности условия REG_CLASS_CONTENTS[K] & (1 << R) == 1,где REG_CLASS_CONTENTS[K] – элемент описания с номером K,который представляется как битовая маска.1: #define REG_X 262: #define REG_Y 283: #define REG_Z 304: #define REG_W 245: #define REG_CLASS_CONTENTS {\6:{0x00000000,0x00000000},/* NO_REGS */\7:{0x00000001,0x00000000},/* R0_REG */\8:{3 << REG_X,0x00000000},/* POINTER_X_REGS, r26 - r27 */\9:{3 << REG_Y,0x00000000},/* POINTER_Y_REGS, r28 - r29 */\10: {3 << REG_Z,0x00000000},/* POINTER_Z_REGS, r30 - r31 */\11: {0x00000000,0x00000003},/* STACK_REG, STACK */\12: {(3 << REG_Y) | (3 << REG_Z),0x00000000},\/* BASE_POINTER_REGS, r28 - r31 */13: {(3 << REG_X) | (3 << REG_Y) | (3 << REG_Z),0x00000000},/* POINTER_REGS, r26 - r31 */14: {(3 << REG_X) | (3 << REG_Y) | (3 << REG_Z) | (3 << REG_W),\\\\Практикум «оптимизирующие компиляторы»0x00000000},/* ADDW_REGS, r24 - r31 */15: {0x00ff0000,0x00000000},\/* SIMPLE_LD_REGS r16 - r23 */\16: {(3 << REG_X)|(3 << REG_Y)|(3 << REG_Z)|(3 << REG_W)|(0xff << 16),0x00000000},\/* LD_REGS, r16 - r31 */\17: {0x0000ffff,0x00000000},/* NO_LD_REGSr0 - r15 */\18: {0xffffffff,0x00000000},/* GENERAL_REGS, r0 - r31 */\19: {0xffffffff,0x00000003}/* ALL_REGS */\20:}В примере определяются следующие классы регистров: пустой класс (6),класс, состоящий из 0-го регистра (7), класс, состоящий из 26 и 27регистров (8), и т.д.
Заметим, что у AVR более 32 регистров, поэтомукаждый из элементов в примере состоит не из одного числа-маски, а издвух.INDEX_REG_CLASSМакрос определяет имя класса, которому принадлежат все индексныерегистры. Индексный регистр – это регистр, использующийся в адресныхвыражениях. В этих выражениях происходит его умножение на число исложение с базовым адресом памяти.#define INDEX_REG_CLASS NO_REGSПример показывает, что в AVR нет индексных регистров.REGNO_OK_FOR_BASE_PЭтот макрос принимает в качестве своего аргумента номер регистра.
Еслирегистр может использоваться как базовый регистр при адресацииоперандов, то возвращается ненулевое значение. Аргумент может быть какаппаратным регистром, так и псевдорегистром.#define REGNO_OK_FOR_BASE_P(r) (((r) < FIRST_PSEUDO_REGISTER&& ((r) == REG_X\\|| (r) == REG_Y\|| (r) == REG_Z\|| (r) == ARG_POINTER_REGNUM))\|| (reg_renumber&& (reg_renumber[r] == REG_X\\Практикум «оптимизирующие компиляторы»|| reg_renumber[r] == REG_Y\|| reg_renumber[r] == REG_Z\|| (reg_renumber[r]\== ARG_POINTER_REGNUM))))Впримерепоказано,чтовкачествебазовогорегистрамогутиспользоваться аппаратные регистры: REG_X, REG_Y, REG_Z илиARG_POINTER_REGNUM и псевдорегистры, которые были распределеныкак эти аппаратные регистры.Определение типов данныхДля определения длин типов данных используются несколько макросов.Размеры типов указываются в битах.#define INT_TYPE_SIZE (TARGET_INT8 ? 8 : 16)#define SHORT_TYPE_SIZE (INT_TYPE_SIZE == 8 ? INT_TYPE_SIZE : 16)#define LONG_TYPE_SIZE (INT_TYPE_SIZE == 8 ? 16 : 32)#define MAX_LONG_TYPE_SIZE 32#define LONG_LONG_TYPE_SIZE 64#define FLOAT_TYPE_SIZE 32#define DOUBLE_TYPE_SIZE 32#define LONG_DOUBLE_TYPE_SIZE 32В примере устанавливаются длины основных типов данных.Файл tm.сМногие макросы имеют достаточно сложную реализацию, которая состоитне из одной инструкции и при его подстановке получается длинная строкакода.
Реализация таких макросов походит на реализацию нетривиальнойфункции, код которой не имеет смысла вставлять в место использованиямакроса. Вместо того, что бы записывать весь код такого макроса в видеего непосредственной подстановки, делают функцию, в вызов которой иразворачивается данный макрос. Это упрощает отладку и уменьшаетвлияниеконтекстаиспользованиямакросанареализациюегофункциональности. Функция имеет то же имя, что и макрос, но написанноестрочными буквами.Практикум «оптимизирующие компиляторы»В файле tm.c содержатся реализации таких функций, а также функции,которые служат поддержкой описаний в tm.md.Рассмотрим описание макроса такого рода.REG_CLASS_FROM_LETTERВозвращает класс регистра по его символьному обозначению.
В avr.h этотмакрос реализован следующим образом:#define REG_CLASS_FROM_LETTER(C) avr_reg_class_from_letter(C)а в файле avr.c представлена реализация функцииavr_reg_class_from_letter:enum reg_classavr_reg_class_from_letter(c)int c;{switch (c){case 't' : return R0_REG;case 'b' : return BASE_POINTER_REGS;case 'e' : return POINTER_REGS;case 'w' : return ADDW_REGS;case 'd' : return LD_REGS;case 'l' : return NO_LD_REGS;case 'a' : return SIMPLE_LD_REGS;case 'x' : return POINTER_X_REGS;case 'y' : return POINTER_Y_REGS;case 'z' : return POINTER_Z_REGS;case 'q' : return STACK_REG;default: break;}return NO_REGS;}Файл tm.mdЭтот файл содержит описание машины, а именно:• описание инструкций;• описание атрибутов, которые используются в других описаниях;Практикум «оптимизирующие компиляторы»• описаниеспособовразделениясложныхинструкцийнапоследовательность простых;• описание peephole-оптимизаций.Все описания выполнены в формате RTL.
Здесь мы рассмотрим лишьописание инструкций.Синтаксис описания:(define-тип-описания “(необязательно) имя-описания”[(set (результат-инструкции)(операнд))необязательные дополнительные set-выражения]“необязательное условие-применимости-описания”“шаблон выхода”(необязательно: [атрибуты]))имя-описания – имя шаблона. Имена должны быть уникальны.Возможно наличие анонимных шаблонов, т.е. без имени.тип-описания – тип шаблона, различают два типа:• define_insn – определение оператора, прямо соответствующегоинструкции процессора;• define_expand – определение оператора, которому соответствуетнесколько инструкций процессора.операнд – любая комбинация операций. Такая комбинация, очевидно,является суперпозицией и имеет вид дерева. Листьями этого дереваявляются непосредственные операнды.
Здесь мы опишем лишь один частоиспользуемый формат для этих операндов, а именно:(match_operand : M номер-операнда "предикат" "ограничение")где,• M – режим (см. главу RTL);Практикум «оптимизирующие компиляторы»• “предикат” – указывает на класс операндов, которые можноприменять; перечислим несколько предопределённый классов:o register_operand – регистровый операнд;o address_operand – операнд, являющийся адресом;o immediate_operand – константный операнд (может бытьконстантным адресом);o const_int_operand–целочисленныйконстантныйоперанд;o const_double_operand–константныйоперанд,являющийся числом с плавающей точкой;o nonimmediate_operand – операнды, которые не входят вкласс immediate_operand;o memory_operand – операнд в памяти;o general_operand – любой допустимый операнд: регистр,константа, память;• “ограничение” – указывает разрешённые комбинации операндовидополнительныеограничения.Представляетсобойстрокусимволов, возможно с запятыми, которые отделяют различныеварианты(альтернативы)использованияданногооперанда.Перечислим некоторые элементы ограничений (символы):o ‘0’ .