64-разрядные соглашения о вызовах функции PowerPC

Когда функции (подпрограммы) вызывают другие функции (подпрограммы), они, возможно, должны передать параметры им. Эти подпрограммы получают доступ к тем параметрам как к параметрам. С другой стороны некоторые функции передают результат или возвращаемое значение к их вызывающим сторонам. И параметры и результаты могут быть переданы с помощью 64-разрядных регистров архитектуры PowerPC или стека этапа выполнения, в зависимости от типа данных включенных значений. Для успешной и эффективной передачи значений между подпрограммами и подпрограммами, GCC соблюдает строгие правила, когда это генерирует объектный код программы.

Эта статья описывает типы данных, которые могут использоваться для управления параметрами и результатами вызовов функции, как подпрограммы передают параметры подпрограммам, которые они вызывают, и как функции передают результаты своим вызывающим сторонам. Это также перечисляет регистры, доступные в 64-разрядной архитектуре PowerPC и сохраняется ли их значение после вызова функции.

Типы данных и выравнивание данных

Используя правильные типы данных для Ваших переменных и установки надлежащего выравнивания данных для Ваших данных может максимизировать производительность и мобильность Ваших программ. Выравнивание данных указывает, как данные размечаются в памяти.

Таблица 1 перечисляет ANSI C скалярные типы данных и их размеры и естественное выравнивание в этой среде.

Табличный 1  Размер и естественное выравнивание скалярных типов данных

Тип данных

Размер и естественное выравнивание (в байтах)

_Bool, bool

1

unsigned char

1

char, signed char

1

unsigned short

2

signed short

2

unsigned int

4

signed int

4

unsigned long

8

signed long

8

unsigned long long

8

signed long long

8

float

4

double

8

long double

16

указатель

8

Это некоторые важные подробные данные о 64-разрядной среде PowerPC:

Это поддержка сред многократные режимы выравнивания данных. Выравнивание типов данных попадает в две категории:

Например, выравнивание unsigned short переменная на штабеле может отличаться от того из unsigned short элемент данных встраивается в структуру данных.

Выравнивание встраивания для структур данных варьируется в зависимости от выбранного режима выравнивания. Обычно можно установить режим выравнивания с помощью параметров компилятора или #pragma операторы. Необходимо считать совместимость и проблемы производительности описанными позже в этом разделе при выборе определенного режима выравнивания.

Это режимы выравнивания встраивания, доступные в 64-разрядной среде PowerPC:

Таблица 2 перечисляет выравнивание для полей структуры основополагающих типов данных и составных типов данных в поддерживаемых режимах выравнивания.

Табличное 2  Выравнивание для полей структуры

Тип данных

Естественное выравнивание

Выравнивание питания

Упакованное выравнивание

_Bool, bool

1

1

1

char

1

1

1

short

2

2

1

int

4

4

1

long

8

4

1

long long

8

4

1

float

4

4

1

double

8

4 или 8

1

long double

8

8

1

vector

16

16

1

Составной объект (структура данных или массив)

1, 2, 4, 8, или 16

4, 8, или 16

1

С GCC можно управлять выравниванием структуры данных путем добавления #pragma операторы к Вашему исходному коду или при помощи параметров командной строки. Если Вы не указываете иначе, режим выравнивания питания используется.

Для установки режима выравнивания используйте gcc флаги -malign-power и -malign-natural. Для использования определенного режима выравнивания в структуре данных добавьте этот оператор как раз перед объявлением структуры данных:

#pragma option align=<mode>

Замена <mode> с power, natural, или packed. Для восстановления предыдущего режима выравнивания использовать reset как режим выравнивания в a #pragma оператор:

#pragma option align=reset

Вызовы функции

Этот раздел детализирует процесс вызова подпрограммы и передающих параметров ей, и как возвращаемые значения функций к их вызывающим сторонам.

Структура штабеля

Эта среда использует штабель, становящийся нисходящим и содержащий информацию о связи, локальные переменные и информацию о параметре подпрограммы, как показано на рисунке 1. (Чтобы помочь предотвратить выполнение вредоносного кода на штабеле, GCC защищает штабель от выполнения.)

  Расположение Штабеля рисунка 1

Указатель вершины стека (SP) указывает на нижнюю часть штабеля. Штабель имеет фиксированный тип телосложения, который известен во время компиляции.

Стековый фрейм вызывающей подпрограммы включает область параметра и некоторую информацию о связи. Область параметра имеет параметры, которые вызывающая сторона передает вызванной подпрограмме или пространству для них, в зависимости от типа каждого параметра и доступности регистров (см. Передающие Параметры за подробные данные). Так как вызывающая подпрограмма может вызвать несколько подпрограмм, область параметра должна быть достаточно большой для размещения самого большого списка аргументов всех подпрограмм вызовы вызывающей стороны. Это - ответственность вызывающей подпрограммы установить область параметра перед каждым вызовом функции. Вызванная функция ответственна за доступ к параметрам, помещенным в область параметра.

Байты 48 - 112 из области параметра соответствуют регистрам общего назначения GPR3 через GPR10. Когда данные помещены в регистр общего назначения и не дублированы в области параметра, соответствующий раздел в области параметра резервируется в случае, если вызванная подпрограмма должна скопировать значение в регистре к штабелю. Таблица 3 показывает корреспонденцию расположений области параметра к регистрам общего назначения, которые могут использоваться для передачи параметров.

  Область Table 3 Parameter к отображению регистра общего назначения

Расположение стекового фрейма

Регистр

SP+48

GPR3

SP+56

GPR4

SP+64

GPR5

SP+72

GPR6

SP+80

GPR7

SP+88

GPR8

SP+96

GPR9

SP+104

GPR10

Когда площадь выделена для параметра в области параметра, выделенная площадь может быть больше, чем тип параметра. В этом случае параметр «способствуется» большему типу данных. Адрес каждого параметра является адресом предыдущего параметра плюс размер продвинутого типа предыдущего параметра.

Когда параметры помещаются в область параметра или в регистры общего назначения, это правила продвижения и выравнивания, соблюденные:

  1. Целые числа продвинуты на long. Например, short элементы расширяются до знака на 64 бита, и unsigned int элементы дополняются нулем слева к 64 битам.

  2. Элементы с плавающей точкой продвинуты на double.

  3. Составные параметры (массивы и структуры) обрабатываются этот путь:

    1. Выровненный размер вычислен путем добавления необходимого дополнения для создания его кратным числом выравнивания.

    2. Если выровненный размер равняется 1, 2 или 4, параметру предшествуют путем дополнения к 4 байтам.

    3. Иначе, параметр сопровождается путем дополнения для создания его размера кратным числом 4 байтов с дополнительными байтами, являющимися неопределенным. (GCC дополняет 0.

  4. Параметры с 16-байтовым естественным выравниванием (например, векторы или структуры, содержащие вектор), выровненных 16 байтов.

Например, примите функцию foo объявляется как это:

int foo(int i, float f, long l, vector int v,
        double d, void* p, char c, short s);

Расположение области параметра было бы как показано в Таблице 4.

  Расположение области Table 4 Parameter для foo вызвать

Параметр

Заявленный тип

Продвинутый тип

Расположение

i

int

long

SP+48: Запустите области параметра.

f

float

double

SP+56: 56 = 48 + sizeof(long)

l

long

long

SP+64: 64 = 56 + sizeof(double)

v

vector

vector

SP+80: 80 = align16(64 + sizeof(long))

d

double

double

SP+96: 96 = 80 + sizeof(vector)

p

void*

void*

SP+104: 104 = 96 + sizeof(double)

c

char

long

SP+112: 112 = 104 + sizeof(void*)

s

short

long

SP+120: 120 = 112 + sizeof(long)

Область связи вызывающей подпрограммы содержит много значений, некоторые из которых сохраняются вызывающей подпрограммой и некоторыми вызванной подпрограммой. Элементы в области связи:

  • Регистр ссылки (LR). Это - значение, сохраняется в 16(SP) вызванной функцией, если это принимает решение сделать так. Регистр ссылки содержит обратный адрес инструкции, следующей за ответвлением и инструкцией ссылки.

  • Регистр условия (CR). Это - значение, может быть сохранен в 8(SP) вызванной функцией. Регистр условия содержит результаты операций сравнения. Как с регистром ссылки, вызванная подпрограмма не требуется, чтобы сохранять это значение. Поскольку регистр условия является 32-разрядным регистром, байты, 12 - 15 из стекового фрейма не использованы, но зарезервированы.

  • Указатель вершины стека (SP). Это - значение, может быть сохранен в 0(SP) вызванной функцией как часть ее стекового фрейма. Листовые подпрограммы не требуются, чтобы сохранять указатель вершины стека. Листовая функция является подпрограммой, не вызывающей никакую другую функцию.

Область связи наверху стекового фрейма, смежного с указателем вершины стека. Это расположение необходимо, таким образом, вызывающая подпрограмма может найти и восстановить значения, сохраненные там, и также позволить вызванной подпрограмме находить область параметра вызывающей стороны. Это размещение означает, что подпрограмма не может продвинуть и вытолкать параметры от штабеля, как только устанавливается стековый фрейм.

Стековый фрейм также включает пространство для локальных переменных вызванной функции. Однако некоторые регистры доступны для использования вызванной функцией; посмотрите Сохранение Регистра для подробных данных. Если бы подпрограмма содержит больше локальных переменных, чем поместился бы в регистры, она использует дополнительное пространство на штабеле. Размер области локальной переменной определяется во время компиляции. Как только стековый фрейм выделяется, размер области локальной переменной не может измениться.

Прожурналы и эпилоги

Вызванная функция ответственна за выделение ее собственного стекового фрейма, удостоверяясь сохранять 16-байтовое выравнивание в штабеле. Эта работа выполняется разделом кода, названного Прологом, который компилятор помещает перед организацией подпрограммы. После организации подпрограммы компилятор помещает эпилог для восстановления процессора к состоянию, которым это было до вызова подпрограммы.

Сгенерированный компилятором код Пролога делает следующее:

  1. Постепенно уменьшает указатель вершины стека для учета нового стекового фрейма и пишет предыдущее значение указателя вершины стека в его собственную область связи, гарантирующую, что штабель может быть восстановлен его исходному состоянию после возврата из вызова.

    Важно, чтобы декремент и задачи обновления произошли атомарно (например, с stwu, stwux, stdu, или stdux) так, чтобы указатель вершины стека и обратный канал были в непротиворечивом состоянии. Иначе, асинхронные сигналы или прерывания могли повредить штабель.

  2. Сохраняет все энергонезависимые регистры с плавающей точкой и общего назначения в область сохраненных регистров. Обратите внимание на то, что, если вызванная функция не изменяет определенный энергонезависимый регистр, она не сохраняет его.

  3. Сохраняет регистр ссылки и значения регистра условия в области связи вызывающей стороны, в случае необходимости.

Перечисление 1 показывает пример стандартного Пролога. Заметьте, что порядок этих действий отличается от порядка, ранее описанного.

  Пролог перечисления 1 В качестве примера

linkageArea = 48                                           ; size in 64-bit PowerPC ABI
params = 64                                                ; callee parameter area
localVars = 0                                              ; callee local variables
numGPRs = 0                                                ; volatile GPRs used by callee
numFPRs = 0                                                ; volatile FPRs used by callee
 
spaceToSave = linkageArea + params + localVars + 8*numGPRs + 8*numFPRs
spaceToSaveAligned = ((spaceToSave+15) & (-16))            ; 16-byte-aligned stack
 
_functionName:                                             ; PROLOG
    mflr        r0                                         ; extract return address
    std         r0, 16(SP)                                 ; save the return address
    stdu        SP, -spaceToSaveAligned(SP)                ; skip over caller save area

В конце функции сгенерированный компилятором эпилог делает следующее:

  1. Восстанавливает энергонезависимые регистры с плавающей точкой и общего назначения, сохраненные в стековом фрейме.

    Энергонезависимые регистры сохраняются в новом стековом фрейме, прежде чем указатель вершины стека будет обновлен только, когда они соответствуют в пространстве ниже указателя вершины стека, где новый стековый фрейм обычно выделялся бы, также известен как красная зона. Красная зона является по определению достаточно большой для содержания всех энергонезависимых регистров с плавающей точкой и общего назначения, но не энергонезависимых векторных регистров. Посмотрите Красную Зону для подробных данных.

  2. Восстанавливает регистр условия и значения регистра ссылки, которые были сохранены в области связи.

  3. Восстанавливает указатель вершины стека к его предыдущему значению.

  4. Возвраты управляют к вызывающей подпрограмме с помощью адреса, сохраненного в регистре ссылки.

Перечисление 2 показывает эпилог в качестве примера.

  Эпилог перечисления 2 В качестве примера

                                                    ; EPILOG
ld             r0, spaceToSaveAligned + 16(SP)      ; get the return address
mtlr           r0                                   ;    into the link register
addi           SP, SP, spaceToSaveAligned           ; restore stack pointer
blr                                                 ; and branch to the return address

Регистр VRSAVE используется для указания, какие векторные регистры должны быть сохранены во время контекстного переключения процесса или потока. Перечисление 3 показывает Пролог в качестве примера, устанавливающий VRSAVE так, чтобы вектор зарегистрировался, V0 через V2 сохраняются. Перечисление 3 также включает эпилог, восстанавливающий VRSAVE к его предыдущему состоянию.

  Использование перечисления 3 В качестве примера регистра VRSAVE

#define VRSAVE 256                           //  VRSAVE IS SPR# 256
 
    _functionName:
        mfspr    r2, VRSAVE                  ; get vector of live VRs
        oris         r0, r2, 0xE000          ; set bits 0-2 since we use V0..V2
        mtspr    VRSAVE, r0                  ; update live VR vector before using any VRs
 
        ; Now, V0..V2 can be safely used.
        ; Function body goes here.
 
        mtspr    VRSAVE, r2                  ; restore VRSAVE
        blr                                  ; return to caller

Красная зона

Пространство ниже указателя вершины стека, где новый стековый фрейм обычно выделялся бы подпрограммой, вызывают красной зоной. Красную зону, показанную на рисунке 2, считают частью самого верхнего (текущего) стекового фрейма. Эта область не изменяется асинхронными нажатиями, такими как сигналы или обработчики прерываний. Поэтому красная зона может использоваться в любой цели, пока новый стековый фрейм не должен быть добавлен к штабелю. Однако содержание красной зоны, как предполагается, уничтожается любым синхронным вызовом.

Рисунок 2  красная зона

Например, потому что листовая функция не вызывает никакие другие функции — и, поэтому, не выделяет область параметра на штабеле — это может использовать красную зону. Кроме того, такая функция не должна использовать штабель для хранения локальных переменных; это должно сохранить только энергонезависимые регистры, которые это использует для локальных переменных. Так как по определению не больше, чем одна листовая функция активна в любое время в потоке, нет никакой возможности многократных листовых функций, конкурирующих за то же красное зональное пространство.

Листовая функция может или может не выделить стековый фрейм и постепенно уменьшить указатель вершины стека. Когда это не выделяет стековый фрейм, листовая функция хранит регистр ссылки и значения регистра условия в области связи подпрограммы, вызывающей его (если необходимый), и хранит значения любых энергонезависимых регистров, которые это использует в красной зоне. Эта оптимизация означает, что листовой Пролог функции и эпилог выполняют минимальную работу; они не должны устанавливать и приводить в нерабочее состояние стековый фрейм.

Размер красной зоны составляет 288 байтов, который является достаточным количеством пространства для хранения значений девятнадцати 64-разрядных регистров общего назначения и восемнадцати 64-разрядных регистров с плавающей точкой, окруженных к самой близкой 16-байтовой границе. Если бы красное зональное использование функции листа превысило бы красный зональный размер, оно должно установить стековый фрейм, как функции, вызывающие другие функции, делают.

Передача параметров

На языке C функции могут объявить свои параметры с помощью одного из трех соглашений:

  • Типы всех параметров указаны в прототипе функции. Например:

    int foo(int, short);

    В этом случае тип параметров всей функции известен во время компиляции.

  • Прототип функции объявляет некоторые фиксированные параметры и некоторые нефиксированные параметры. Группу нефиксированных параметров также вызывают списком аргумента переменной. Например:

    int foo(int, ...);

    В этом случае, тип одного из параметров функции в известном во время компиляции. Тип нефиксированных параметров не известен.

  • Функция не имеет никакого прототипа или использует предANSI C объявление. Например:

    int foo();

    В этом случае тип параметров всей функции неизвестен во время компиляции.

Когда компилятор генерирует Пролог к вызову функции, это использует информацию от объявления функции, чтобы решить, как передать параметры функции. Когда компилятор знает тип параметра, это передает его самым эффективным возможным способом. Но когда тип неизвестен, он передает параметр с помощью самого безопасного подхода, который может вовлечь помещающие данные и в регистры и в область параметра. Для вызванных функций для доступа к их параметрам правильно важно, чтобы они знали, когда параметры передаются в штабеле или в регистрах.

Параметры передаются в штабеле или в регистрах в зависимости от их типов и доступности регистров. Существует три типа регистров: общая цель, плавающая точка и вектор. Регистры общего назначения (GPRs) являются 64-разрядными регистрами, которые могут управлять интегральными значениями и указателями. Регистры с плавающей точкой (FPRs) являются 64-разрядными регистрами, которые могут управлять одинарной точностью и двойной точностью значения с плавающей точкой. Векторные регистры являются 128-разрядными регистрами, которые могут управлять 4 - 16 блоками данных параллельно.

Регистры, которые могут использоваться для передачи параметров вызванным функциям, являются регистрами общего назначения GPR3 через GPR10, регистры с плавающей точкой FPR1 через FPR13, и вектор регистрирует V2 через V13 (см. Сохранение Регистра для подробных данных). Эти регистры также известны как регистры параметра.

Компилятор использует соблюдающие правила когда передающие параметры подпрограммам:

  • Параметры, продвинутый тип которых известен во время компиляции, обрабатываются с помощью этих правил (см. Структуру Штабеля для подробных данных о продвинутом типе параметра):

    1. Вызывающая сторона помещает элементы с плавающей точкой (кроме long double элементы) в регистрах с плавающей точкой FPR1 через FPR13. Поскольку каждый регистр с плавающей точкой используется, вызывающая сторона пропускает следующий доступный регистр общего назначения. Когда регистры с плавающей точкой исчерпываются, вызывающая сторона помещает эти элементы в область параметра.

    2. Места вызывающей стороны long double элементы — которые используют пару float элементы — в двух регистрах с плавающей точкой. Поскольку каждая пара регистров с плавающей точкой используется, вызывающая сторона пропускает следующие два доступных регистра общего назначения. Когда регистры с плавающей точкой исчерпываются, вызывающая сторона помещает эти элементы в область параметра.

    3. Места вызывающей стороны vector элементы в векторных регистрах V2 через V13. Использование векторного регистра не влияет на доступность регистров общего назначения. Т.е. никакие регистры общего назначения не пропускаются в результате использования векторного регистра. Когда векторные регистры исчерпываются, вызывающая сторона помещает эти элементы в область параметра.

    4. Вызывающая сторона помещает элементы всех других типов данных — включая complex (определенный в complex.h) — в регистрах общего назначения GPR3 через GPR10, когда доступно. Когда регистры общего назначения исчерпываются, вызывающая сторона помещает эти элементы в область параметра.

      Структуры, которые составляют 16 байтов в размере, обрабатываются, как будто они были парой 64-разрядных целых чисел. Поэтому они размещаются в два регистра общего назначения. Примеры структур, удовлетворяющих этот критерий, включают структуру, содержащую четыре float поля и структура, содержащая два double поля. Структуры, содержащие три float поля, например, быть обработанными с помощью правила 5.

    5. Вызывающая сторона рекурсивно обрабатывает элементы структур, переданных значением и содержащий объединения:

      • Поля с плавающей точкой обрабатываются с помощью правила 1 или правила 2, в зависимости от их типа.

      • Векторные поля обрабатываются с помощью правила 3.

      • Поля всех других типов — включая массивы — обрабатываются с помощью правила 4.

  • Параметры предANSI функция C–declared обрабатываются следующим образом:

    1. Вызывающая сторона помещает элементы с плавающей точкой в регистры с плавающей точкой и регистры общего назначения, когда доступно. Иначе, вызывающая сторона размещает их в область параметра.

    2. Места вызывающей стороны vector элементы в векторных регистрах и регистрах общего назначения, когда доступно. Иначе, вызывающая сторона размещает их в область параметра.

    3. Вызывающая сторона помещает элементы всех других типов в регистрах общего назначения, когда доступно. Иначе, вызывающая сторона размещает их в область параметра.

  • Параметры, которые являются частью списка аргумента переменной, помещаются в регистры общего назначения, когда доступно. Иначе, вызывающая сторона размещает их в область параметра.

Используя ANSI C прототипы

Когда типы всех параметров подпрограммы известны во время компиляции, размещение параметров в регистры является прямым.

Например, предположите, что подпрограмма вызывает функцию foo_ansi заявленный как это:

int foo_ansi(int i, float f, long l, vector int v,
             double d, void* p, char c, short s);

Вызывающая сторона помещает параметры функции как показано в Таблице 5.

  Параметры Table 5 Passing функции, объявляющей все типы ее параметров

Параметр

Ввести

Помещенный в

Причина

я

int

GPR3

Не или векторный элемент с плавающей точкой.

f

float

FPR1

Сначала элемент с плавающей точкой, таким образом, это входит в первый регистр с плавающей точкой. GPR4 пропускается.

l

long

GPR5

Не или векторный элемент с плавающей точкой.

v

vector int

V2

Первый векторный элемент, таким образом, это входит в первый векторный регистр. Никакой регистр общего назначения не пропускается.

d

double

FPR2

Второй элемент с плавающей точкой, таким образом, это входит в следующий доступный регистр с плавающей точкой. GPR6 пропускается.

p

void*

GPR7

Не или векторный элемент с плавающей точкой.

c

char

GPR8

Не или векторный элемент с плавающей точкой.

s

short

GPR9

Не или векторный элемент с плавающей точкой.

Рисунок 3 иллюстрирует размещение параметров в регистрах и области параметра.

  Присвоение Параметра рисунка 3, когда известны все типы параметра

Используя структуры

Примите структуру data и функция bar объявляются как это:

struct data {
    float f;
    int i;
    double d;
    vector float v;
};
int bar(int a, struct data b, void* c);

Когда подпрограмма вызывает, таблица 6 показывает присвоение регистра bar.

  Параметры Table 6 Passing функции с a struct параметр

Параметр

Ввести

Помещенный в

Причина

a

int

GPR3

Не или векторный элемент с плавающей точкой.

b.f

float

FPR1

Сначала элемент с плавающей точкой, таким образом, это входит в первый регистр с плавающей точкой. GPR4 пропускается. Поскольку b структура содержит a vector, все struct выравнивание 16 байтов потребностей в области параметра.

b.i

int

GPR5 (низкая половина)

Не или векторный элемент с плавающей точкой.

b.d

double

FPR2

Второй элемент с плавающей точкой, таким образом, это входит в следующий доступный регистр с плавающей точкой.

b.v

vector float

V2

Первый векторный элемент, таким образом, это входит в первый векторный регистр.

c

void*

GPR9

Не или векторный элемент с плавающей точкой.

Используя списки аргумента переменной

Примите структуру numbers и функция var объявляются как это:

struct numbers {
    float f;
    int i;
};
extern void var(int a, float b, vector float c, struct numbers n, ...);

Также предположите, что подпрограмма содержит следующий код:

int i1, i2;
float f1, f2;
vector float v1, v2;
struct numbers n1, n2;
...
var(i1, f1, v1, n1, i2, f2, v2, n2);

Вызывающая сторона присваивает параметры var как показано в Таблице 7.

  Параметры Table 7 Passing функции со списком аргумента переменной

Параметр

Ввести

Помещенный в

Причина

i1

int

GPR3

Не или векторный элемент с плавающей точкой.

f1

float

FPR1

Сначала элемент с плавающей точкой, таким образом, это входит в первый регистр с плавающей точкой.

v1

vector float

V2

Первый векторный элемент, таким образом, это входит в первый векторный регистр.

n1.f

float

FPR2

Второй элемент с плавающей точкой, таким образом, это входит в следующий доступный регистр с плавающей точкой.

n1.i

int

GPR7 (низкая половина)

Не или векторный элемент с плавающей точкой.

i2

int (неизвестный во время компиляции)

GPR8

Элемент списка аргумента переменной.

f2

float (неизвестный во время компиляции)

GPR9

Элемент списка аргумента переменной.

v2

vector float (неизвестный во время компиляции)

SP+112 (16 байтов)

Элемент списка аргумента переменной и вектор. Должны быть выровненных 16 байтов; не может использовать GPR10.

n2.f

float (неизвестный во время компиляции)

SP+128 (4 байта)

Элемент списка аргумента переменной. Никакие доступные регистры общего назначения.

n2.i

int (неизвестный во время компиляции)

SP+132 (4 байта)

Элемент списка аргумента переменной. Никакие доступные регистры общего назначения.

Используя предANSI C Прототипы

Примите структуру numbers и функция foo_pre_ansi объявляются как это:

struct numbers {
    float f;
    int i;
};
void foo_pre_ansi();

Также предположите, что подпрограмма содержит следующий код:

...
int i;
float f;
vector float v;
struct numbers n;
...
foo_pre_ansi(i, f, v, n);

Вызывающая сторона присваивает параметры foo_pre_ansi как показано в Таблице 8.

  Параметры Table 8 Passing функции с предANSI C прототип

Параметр

Ввести

Помещенный в

Причина

i

int (неизвестный во время компиляции)

GPR3

Не или векторный элемент с плавающей точкой.

f

float (неизвестный во время компиляции)

FPR1, GPR4

Сначала элемент с плавающей точкой, таким образом, это входит в первый регистр с плавающей точкой и следующий доступный регистр общего назначения.

v

vector float (неизвестный во время компиляции)

V2, GPR5–GPR6

Первый векторный элемент, таким образом, это входит в первый векторный регистр и следующие два доступные регистра общего назначения.

n.f

float (неизвестный во время компиляции)

FPR2, GPR7 (высокая половина)

Второй элемент с плавающей точкой, таким образом, это входит в следующий доступный регистр с плавающей точкой и следующий доступный регистр общего назначения.

n.i

int (неизвестный во время компиляции)

GPR7 (низкая половина)

Не или векторный элемент с плавающей точкой, таким образом, это входит в следующий доступный регистр общего назначения.

Возврат результатов

Функциональный результат может быть возвращен в регистрах или в памяти, в зависимости от типа данных возвращаемого значения функции. Когда возвращаемое значение вызванной функции было бы передано в регистрах, если бы это было передано в качестве параметра в вызове функции, вызванная функция помещает свое возвращаемое значение в те же регистры. Иначе, функция помещает свой результат в расположении, на которое указывает GPR3. Посмотрите Передающие Параметры для получения дополнительной информации.

Таблица 9 перечисляет некоторые примеры того, как возвращаемые значения могут быть переданы вызывающей подпрограмме.

Табличные 9  Примеры передачи результатов к вызывающим сторонам

Возвратите тип

Возвращенный в

int

GPR3 (расширенный знак).

unsigned short

GPR3 (заполненный нуль).

long

GPR3.

long long

GPR3.

float

FPR1.

double

FPR1.

long double

FPR1–FPR2.

struct { float, float }

FPR1, FPR2.

struct { double, double }

FPR1, FPR2.

struct { long, long }

GPR3, GPR4.

struct { long[8] }

GPR3, GPR4... GPR10.

struct { long[10] }

Ячейка памяти, на которую указывает GPR3, составленный из 80 байтов хранения.

vector float

V2.

complex float

FPR1 (вещественное число), FPR2 (мнимое число).

complex double

FPR1 (вещественное число), FPR2 (мнимое число).

complex long double

FPR1–FPR2 (вещественное число), FPR3–FPR4 (мнимое число).

Сохранение регистра

Таблица 10 перечисляет 64-разрядные регистры архитектуры PowerPC, используемые в этой среде и их энергозависимости в вызовах подпрограммы. Регистры, которые должны сохранить их значение после вызова функции, вызывают энергонезависимые.

Табличный 10  Процессор регистрируется в 64-разрядной архитектуре PowerPC

Ввести

Имя

Сохраненный

Примечания

Регистр общего назначения

GPR0

Нет

GPR1

Да

Используемый в качестве указателя вершины стека для хранения параметров и других временных элементов данных.

GPR2

Нет

Доступный для общего использования.

GPR3

Нет

Вызывающая сторона передает параметры вызванной подпрограмме в GPR3 через GPR10. Вызывающая сторона может также передать адрес хранению, куда вызываемый помещает его возвращаемое значение в этот регистр.

GPR4–GPR10

Нет

Используемый вызывающими сторонами для передачи параметров вызванной подпрограмме (см. примечания для GPR3).

GPR11

Да во вложенных функциях. Нет в листовых функциях.

Во вложенных функциях вызывающая сторона передает свой стековый фрейм вложенной функции в этом регистре. В листовых подпрограммах регистр доступен. Для получения дополнительной информации на вложенных функциях, см. документацию GCC. Этот регистр также используется ленивыми тупиками в динамической генерации кода для указания на ленивый указатель.

GPR12

Нет

Набор к адресу цели ответвления перед непрямым вызовом динамической генерации кода. Этот регистр не установлен для подпрограммы, которую вызвали непосредственно, таким образом, подпрограммы, которые можно вызвать непосредственно, не должны зависеть от этого регистра, устанавливаемого правильно. Посмотрите Мужественные Темы Программирования для получения дополнительной информации.

GPR13

Да

Зарезервированный для специфичного для потока хранения.

GPR14–GPR31

Да

Регистр с плавающей точкой

FPR0

Нет

FPR1–FPR13

Нет

Используемый вызывающими сторонами для передачи параметров с плавающей точкой вызванной подпрограмме. Результаты с плавающей точкой передаются в FPR1.

FPR14–FPR31

Да

Векторный регистр

V0–V19

Нет

Вызывающие стороны используют V2 через V13 для передачи аргументов вектора вызванной подпрограмме. Векторные результаты передаются в V2.

V20–V31

Да

Векторный регистр специального назначения

VRSAVE

Да

32-разрядный регистр специального назначения. Каждый бит в этом регистре указывает, должен ли соответствующий векторный регистр быть сохранен во время контекстного переключения процесса или потока.

Регистр ссылки

LR

Нет

Хранит обратный адрес вызывающей подпрограммы который названный текущей подпрограммой.

Регистр количества

CTR

Нет

Регистр исключения фиксированной точки

XER

Нет

Поля регистра условия

CR0, CR1

Нет

CR2–CR4

Да

CR5–CR7

Нет