64-разрядные соглашения о вызовах функции PowerPC
Когда функции (подпрограммы) вызывают другие функции (подпрограммы), они, возможно, должны передать параметры им. Эти подпрограммы получают доступ к тем параметрам как к параметрам. С другой стороны некоторые функции передают результат или возвращаемое значение к их вызывающим сторонам. И параметры и результаты могут быть переданы с помощью 64-разрядных регистров архитектуры PowerPC или стека этапа выполнения, в зависимости от типа данных включенных значений. Для успешной и эффективной передачи значений между подпрограммами и подпрограммами, GCC соблюдает строгие правила, когда это генерирует объектный код программы.
Эта статья описывает типы данных, которые могут использоваться для управления параметрами и результатами вызовов функции, как подпрограммы передают параметры подпрограммам, которые они вызывают, и как функции передают результаты своим вызывающим сторонам. Это также перечисляет регистры, доступные в 64-разрядной архитектуре PowerPC и сохраняется ли их значение после вызова функции.
Типы данных и выравнивание данных
Используя правильные типы данных для Ваших переменных и установки надлежащего выравнивания данных для Ваших данных может максимизировать производительность и мобильность Ваших программ. Выравнивание данных указывает, как данные размечаются в памяти.
Таблица 1 перечисляет ANSI C скалярные типы данных и их размеры и естественное выравнивание в этой среде.
Тип данных | Размер и естественное выравнивание (в байтах) |
---|---|
| 1 |
| 1 |
| 1 |
| 2 |
| 2 |
| 4 |
| 4 |
| 8 |
| 8 |
| 8 |
| 8 |
| 4 |
| 8 |
| 16 |
указатель | 8 |
Это некоторые важные подробные данные о 64-разрядной среде PowerPC:
Эта среда использует схему порядка байтов с обратным порядком байтов сохранить числовой и типы данных указателя. Т.е. старшие значащие байты идут сначала, сопровождаемые младшими значащими байтами.
Эта среда использует two's-дополнительное двоичное представление для типов данных целого числа со знаком.
float
иdouble
типы данных соответствуют представлению стандарта IEEE 754. Для диапазона значений и точного формата типов данных с плавающей точкой, посмотрите Численные данные PowerPC в Документации Производительности.
Это поддержка сред многократные режимы выравнивания данных. Выравнивание типов данных попадает в две категории:
Естественное выравнивание. Выравнивание типа данных, когда выделено в памяти или присвоенный адрес памяти.
Естественное выравнивание типа данных является своим размером. Таблица 1 показывает естественное выравнивание каждого типа данных, поддерживаемого этой средой.
Встраивание выравнивания. Выравнивание типа данных в составной структуре данных.
Например, выравнивание unsigned short
переменная на штабеле может отличаться от того из unsigned short
элемент данных встраивается в структуру данных.
Выравнивание встраивания для структур данных варьируется в зависимости от выбранного режима выравнивания. Обычно можно установить режим выравнивания с помощью параметров компилятора или #pragma
операторы. Необходимо считать совместимость и проблемы производительности описанными позже в этом разделе при выборе определенного режима выравнивания.
Это режимы выравнивания встраивания, доступные в 64-разрядной среде PowerPC:
Режим выравнивания питания получен на основании правил выравнивания, используемых IBM компилятор XLC для операционной системы ЭКС-АН-ПРОВАНСА. Это - режим выравнивания по умолчанию для версии архитектуры PowerPC GCC, используемого на ЭКС-АН-ПРОВАНСЕ и OS X. Поскольку этот режим, наиболее вероятно, будет совместим между компиляторами архитектуры PowerPC от различных поставщиков, он обычно используется со структурами данных, совместно использующимися различными программами.
Правила для выравнивания питания:
Выравнивание встраивания первого элемента в структуре данных равно естественному выравниванию элемента.
Для последующих элементов с естественным выравниванием меньше чем 4 байта выравнивание встраивания каждого элемента равно его естественному выравниванию.
Для последующих элементов, имеющих естественное выравнивание, больше, чем 4 байта, выравнивание встраивания равняется 4, если элемент не является a
vector
.Выравнивание встраивания для
vector
элементы всегда - 16 байтов.Выравнивание встраивания составного типа данных (структура массива или структура данных) определяется самым большим выравниванием встраивания его элементов.
Общий размер составного типа окружен к кратному числу его выравнивания встраивания и дополняется нулевыми байтами.
Поскольку естественное выравнивание
double
иlong long
типы данных больше, чем 4 байта, они могут не быть соответственно выровненные в режиме выравнивания питания. Когда к таким элементам данных получают доступ, любое неточное совмещение повреждает производительность. При использовании этих типов данных для любого элемента после того, как первый элемент, компилятор дополнит структуру для выравнивания элементов к их естественному выравниванию.Естественный режим выравнивания использует естественное выравнивание каждого типа данных как его выравнивание встраивания. Используйте этот режим выравнивания для получения самой высокой производительности при использовании
double
,long
,long long
, иlong double
типы данных.Упакованный режим выравнивания не содержит дополнения выравнивания между элементами (выравнивание для всех типов данных составляет 1 байт). Используйте этот режим выравнивания при необходимости в структуре данных для использования как можно меньше памяти. Отметьте, однако, что упакованное выравнивание может значительно ниже производительность Вашего приложения.
Таблица 2 перечисляет выравнивание для полей структуры основополагающих типов данных и составных типов данных в поддерживаемых режимах выравнивания.
Тип данных | Естественное выравнивание | Выравнивание питания | Упакованное выравнивание |
---|---|---|---|
| 1 | 1 | 1 |
| 1 | 1 | 1 |
| 2 | 2 | 1 |
| 4 | 4 | 1 |
| 8 | 4 | 1 |
| 8 | 4 | 1 |
| 4 | 4 | 1 |
| 8 | 4 или 8 | 1 |
| 8 | 8 | 1 |
| 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 защищает штабель от выполнения.)
Указатель вершины стека (SP) указывает на нижнюю часть штабеля. Штабель имеет фиксированный тип телосложения, который известен во время компиляции.
Стековый фрейм вызывающей подпрограммы включает область параметра и некоторую информацию о связи. Область параметра имеет параметры, которые вызывающая сторона передает вызванной подпрограмме или пространству для них, в зависимости от типа каждого параметра и доступности регистров (см. Передающие Параметры за подробные данные). Так как вызывающая подпрограмма может вызвать несколько подпрограмм, область параметра должна быть достаточно большой для размещения самого большого списка аргументов всех подпрограмм вызовы вызывающей стороны. Это - ответственность вызывающей подпрограммы установить область параметра перед каждым вызовом функции. Вызванная функция ответственна за доступ к параметрам, помещенным в область параметра.
Байты 48 - 112 из области параметра соответствуют регистрам общего назначения GPR3 через GPR10. Когда данные помещены в регистр общего назначения и не дублированы в области параметра, соответствующий раздел в области параметра резервируется в случае, если вызванная подпрограмма должна скопировать значение в регистре к штабелю. Таблица 3 показывает корреспонденцию расположений области параметра к регистрам общего назначения, которые могут использоваться для передачи параметров.
Расположение стекового фрейма | Регистр |
---|---|
| GPR3 |
| GPR4 |
| GPR5 |
| GPR6 |
| GPR7 |
| GPR8 |
| GPR9 |
| GPR10 |
Когда площадь выделена для параметра в области параметра, выделенная площадь может быть больше, чем тип параметра. В этом случае параметр «способствуется» большему типу данных. Адрес каждого параметра является адресом предыдущего параметра плюс размер продвинутого типа предыдущего параметра.
Когда параметры помещаются в область параметра или в регистры общего назначения, это правила продвижения и выравнивания, соблюденные:
Целые числа продвинуты на
long
. Например,short
элементы расширяются до знака на 64 бита, иunsigned int
элементы дополняются нулем слева к 64 битам.Составные параметры (массивы и структуры) обрабатываются этот путь:
Выровненный размер вычислен путем добавления необходимого дополнения для создания его кратным числом выравнивания.
Если выровненный размер равняется 1, 2 или 4, параметру предшествуют путем дополнения к 4 байтам.
Иначе, параметр сопровождается путем дополнения для создания его размера кратным числом 4 байтов с дополнительными байтами, являющимися неопределенным. (GCC дополняет
0
.
Параметры с 16-байтовым естественным выравниванием (например, векторы или структуры, содержащие вектор), выровненных 16 байтов.
Например, примите функцию foo
объявляется как это:
int foo(int i, float f, long l, vector int v, |
double d, void* p, char c, short s); |
Расположение области параметра было бы как показано в Таблице 4.
Параметр | Заявленный тип | Продвинутый тип | Расположение |
---|---|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Область связи вызывающей подпрограммы содержит много значений, некоторые из которых сохраняются вызывающей подпрограммой и некоторыми вызванной подпрограммой. Элементы в области связи:
Регистр ссылки (LR). Это - значение, сохраняется в
16(SP)
вызванной функцией, если это принимает решение сделать так. Регистр ссылки содержит обратный адрес инструкции, следующей за ответвлением и инструкцией ссылки.Регистр условия (CR). Это - значение, может быть сохранен в
8(SP)
вызванной функцией. Регистр условия содержит результаты операций сравнения. Как с регистром ссылки, вызванная подпрограмма не требуется, чтобы сохранять это значение. Поскольку регистр условия является 32-разрядным регистром, байты, 12 - 15 из стекового фрейма не использованы, но зарезервированы.Указатель вершины стека (SP). Это - значение, может быть сохранен в
0(SP)
вызванной функцией как часть ее стекового фрейма. Листовые подпрограммы не требуются, чтобы сохранять указатель вершины стека. Листовая функция является подпрограммой, не вызывающей никакую другую функцию.
Область связи наверху стекового фрейма, смежного с указателем вершины стека. Это расположение необходимо, таким образом, вызывающая подпрограмма может найти и восстановить значения, сохраненные там, и также позволить вызванной подпрограмме находить область параметра вызывающей стороны. Это размещение означает, что подпрограмма не может продвинуть и вытолкать параметры от штабеля, как только устанавливается стековый фрейм.
Стековый фрейм также включает пространство для локальных переменных вызванной функции. Однако некоторые регистры доступны для использования вызванной функцией; посмотрите Сохранение Регистра для подробных данных. Если бы подпрограмма содержит больше локальных переменных, чем поместился бы в регистры, она использует дополнительное пространство на штабеле. Размер области локальной переменной определяется во время компиляции. Как только стековый фрейм выделяется, размер области локальной переменной не может измениться.
Прожурналы и эпилоги
Вызванная функция ответственна за выделение ее собственного стекового фрейма, удостоверяясь сохранять 16-байтовое выравнивание в штабеле. Эта работа выполняется разделом кода, названного Прологом, который компилятор помещает перед организацией подпрограммы. После организации подпрограммы компилятор помещает эпилог для восстановления процессора к состоянию, которым это было до вызова подпрограммы.
Сгенерированный компилятором код Пролога делает следующее:
Постепенно уменьшает указатель вершины стека для учета нового стекового фрейма и пишет предыдущее значение указателя вершины стека в его собственную область связи, гарантирующую, что штабель может быть восстановлен его исходному состоянию после возврата из вызова.
Важно, чтобы декремент и задачи обновления произошли атомарно (например, с
stwu
,stwux
,stdu
, илиstdux
) так, чтобы указатель вершины стека и обратный канал были в непротиворечивом состоянии. Иначе, асинхронные сигналы или прерывания могли повредить штабель.Сохраняет все энергонезависимые регистры с плавающей точкой и общего назначения в область сохраненных регистров. Обратите внимание на то, что, если вызванная функция не изменяет определенный энергонезависимый регистр, она не сохраняет его.
Сохраняет регистр ссылки и значения регистра условия в области связи вызывающей стороны, в случае необходимости.
Перечисление 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 |
В конце функции сгенерированный компилятором эпилог делает следующее:
Восстанавливает энергонезависимые регистры с плавающей точкой и общего назначения, сохраненные в стековом фрейме.
Энергонезависимые регистры сохраняются в новом стековом фрейме, прежде чем указатель вершины стека будет обновлен только, когда они соответствуют в пространстве ниже указателя вершины стека, где новый стековый фрейм обычно выделялся бы, также известен как красная зона. Красная зона является по определению достаточно большой для содержания всех энергонезависимых регистров с плавающей точкой и общего назначения, но не энергонезависимых векторных регистров. Посмотрите Красную Зону для подробных данных.
Восстанавливает регистр условия и значения регистра ссылки, которые были сохранены в области связи.
Восстанавливает указатель вершины стека к его предыдущему значению.
Возвраты управляют к вызывающей подпрограмме с помощью адреса, сохраненного в регистре ссылки.
Перечисление 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, считают частью самого верхнего (текущего) стекового фрейма. Эта область не изменяется асинхронными нажатиями, такими как сигналы или обработчики прерываний. Поэтому красная зона может использоваться в любой цели, пока новый стековый фрейм не должен быть добавлен к штабелю. Однако содержание красной зоны, как предполагается, уничтожается любым синхронным вызовом.
Например, потому что листовая функция не вызывает никакие другие функции — и, поэтому, не выделяет область параметра на штабеле — это может использовать красную зону. Кроме того, такая функция не должна использовать штабель для хранения локальных переменных; это должно сохранить только энергонезависимые регистры, которые это использует для локальных переменных. Так как по определению не больше, чем одна листовая функция активна в любое время в потоке, нет никакой возможности многократных листовых функций, конкурирующих за то же красное зональное пространство.
Листовая функция может или может не выделить стековый фрейм и постепенно уменьшить указатель вершины стека. Когда это не выделяет стековый фрейм, листовая функция хранит регистр ссылки и значения регистра условия в области связи подпрограммы, вызывающей его (если необходимый), и хранит значения любых энергонезависимых регистров, которые это использует в красной зоне. Эта оптимизация означает, что листовой Пролог функции и эпилог выполняют минимальную работу; они не должны устанавливать и приводить в нерабочее состояние стековый фрейм.
Размер красной зоны составляет 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 (см. Сохранение Регистра для подробных данных). Эти регистры также известны как регистры параметра.
Компилятор использует соблюдающие правила когда передающие параметры подпрограммам:
Параметры, продвинутый тип которых известен во время компиляции, обрабатываются с помощью этих правил (см. Структуру Штабеля для подробных данных о продвинутом типе параметра):
Вызывающая сторона помещает элементы с плавающей точкой (кроме
long double
элементы) в регистрах с плавающей точкой FPR1 через FPR13. Поскольку каждый регистр с плавающей точкой используется, вызывающая сторона пропускает следующий доступный регистр общего назначения. Когда регистры с плавающей точкой исчерпываются, вызывающая сторона помещает эти элементы в область параметра.Места вызывающей стороны
long double
элементы — которые используют паруfloat
элементы — в двух регистрах с плавающей точкой. Поскольку каждая пара регистров с плавающей точкой используется, вызывающая сторона пропускает следующие два доступных регистра общего назначения. Когда регистры с плавающей точкой исчерпываются, вызывающая сторона помещает эти элементы в область параметра.Места вызывающей стороны
vector
элементы в векторных регистрах V2 через V13. Использование векторного регистра не влияет на доступность регистров общего назначения. Т.е. никакие регистры общего назначения не пропускаются в результате использования векторного регистра. Когда векторные регистры исчерпываются, вызывающая сторона помещает эти элементы в область параметра.Вызывающая сторона помещает элементы всех других типов данных — включая
complex
(определенный вcomplex.h
) — в регистрах общего назначения GPR3 через GPR10, когда доступно. Когда регистры общего назначения исчерпываются, вызывающая сторона помещает эти элементы в область параметра.Структуры, которые составляют 16 байтов в размере, обрабатываются, как будто они были парой 64-разрядных целых чисел. Поэтому они размещаются в два регистра общего назначения. Примеры структур, удовлетворяющих этот критерий, включают структуру, содержащую четыре
float
поля и структура, содержащая дваdouble
поля. Структуры, содержащие триfloat
поля, например, быть обработанными с помощью правила 5.Вызывающая сторона рекурсивно обрабатывает элементы структур, переданных значением и содержащий объединения:
Поля с плавающей точкой обрабатываются с помощью правила 1 или правила 2, в зависимости от их типа.
Векторные поля обрабатываются с помощью правила 3.
Поля всех других типов — включая массивы — обрабатываются с помощью правила 4.
Параметры предANSI функция C–declared обрабатываются следующим образом:
Вызывающая сторона помещает элементы с плавающей точкой в регистры с плавающей точкой и регистры общего назначения, когда доступно. Иначе, вызывающая сторона размещает их в область параметра.
Места вызывающей стороны
vector
элементы в векторных регистрах и регистрах общего назначения, когда доступно. Иначе, вызывающая сторона размещает их в область параметра.Вызывающая сторона помещает элементы всех других типов в регистрах общего назначения, когда доступно. Иначе, вызывающая сторона размещает их в область параметра.
Параметры, которые являются частью списка аргумента переменной, помещаются в регистры общего назначения, когда доступно. Иначе, вызывающая сторона размещает их в область параметра.
Используя 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.
Параметр | Ввести | Помещенный в | Причина |
---|---|---|---|
я |
| GPR3 | Не или векторный элемент с плавающей точкой. |
f |
| FPR1 | Сначала элемент с плавающей точкой, таким образом, это входит в первый регистр с плавающей точкой. GPR4 пропускается. |
l |
| GPR5 | Не или векторный элемент с плавающей точкой. |
v |
| V2 | Первый векторный элемент, таким образом, это входит в первый векторный регистр. Никакой регистр общего назначения не пропускается. |
d |
| FPR2 | Второй элемент с плавающей точкой, таким образом, это входит в следующий доступный регистр с плавающей точкой. GPR6 пропускается. |
p |
| GPR7 | Не или векторный элемент с плавающей точкой. |
c |
| GPR8 | Не или векторный элемент с плавающей точкой. |
s |
| GPR9 | Не или векторный элемент с плавающей точкой. |
Рисунок 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
.
Параметр | Ввести | Помещенный в | Причина |
---|---|---|---|
|
| GPR3 | Не или векторный элемент с плавающей точкой. |
|
| FPR1 | Сначала элемент с плавающей точкой, таким образом, это входит в первый регистр с плавающей точкой. GPR4 пропускается. Поскольку |
|
| GPR5 (низкая половина) | Не или векторный элемент с плавающей точкой. |
|
| FPR2 | Второй элемент с плавающей точкой, таким образом, это входит в следующий доступный регистр с плавающей точкой. |
|
| V2 | Первый векторный элемент, таким образом, это входит в первый векторный регистр. |
|
| 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.
Параметр | Ввести | Помещенный в | Причина |
---|---|---|---|
|
| GPR3 | Не или векторный элемент с плавающей точкой. |
|
| FPR1 | Сначала элемент с плавающей точкой, таким образом, это входит в первый регистр с плавающей точкой. |
|
| V2 | Первый векторный элемент, таким образом, это входит в первый векторный регистр. |
|
| FPR2 | Второй элемент с плавающей точкой, таким образом, это входит в следующий доступный регистр с плавающей точкой. |
|
| GPR7 (низкая половина) | Не или векторный элемент с плавающей точкой. |
|
| GPR8 | Элемент списка аргумента переменной. |
|
| GPR9 | Элемент списка аргумента переменной. |
|
|
| Элемент списка аргумента переменной и вектор. Должны быть выровненных 16 байтов; не может использовать GPR10. |
|
|
| Элемент списка аргумента переменной. Никакие доступные регистры общего назначения. |
|
|
| Элемент списка аргумента переменной. Никакие доступные регистры общего назначения. |
Используя пред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.
Параметр | Ввести | Помещенный в | Причина |
---|---|---|---|
|
| GPR3 | Не или векторный элемент с плавающей точкой. |
|
| FPR1, GPR4 | Сначала элемент с плавающей точкой, таким образом, это входит в первый регистр с плавающей точкой и следующий доступный регистр общего назначения. |
|
| V2, GPR5–GPR6 | Первый векторный элемент, таким образом, это входит в первый векторный регистр и следующие два доступные регистра общего назначения. |
|
| FPR2, GPR7 (высокая половина) | Второй элемент с плавающей точкой, таким образом, это входит в следующий доступный регистр с плавающей точкой и следующий доступный регистр общего назначения. |
|
| GPR7 (низкая половина) | Не или векторный элемент с плавающей точкой, таким образом, это входит в следующий доступный регистр общего назначения. |
Возврат результатов
Функциональный результат может быть возвращен в регистрах или в памяти, в зависимости от типа данных возвращаемого значения функции. Когда возвращаемое значение вызванной функции было бы передано в регистрах, если бы это было передано в качестве параметра в вызове функции, вызванная функция помещает свое возвращаемое значение в те же регистры. Иначе, функция помещает свой результат в расположении, на которое указывает GPR3. Посмотрите Передающие Параметры для получения дополнительной информации.
Таблица 9 перечисляет некоторые примеры того, как возвращаемые значения могут быть переданы вызывающей подпрограмме.
Возвратите тип | Возвращенный в |
---|---|
| GPR3 (расширенный знак). |
| GPR3 (заполненный нуль). |
| GPR3. |
| GPR3. |
| FPR1. |
| FPR1. |
| FPR1–FPR2. |
| FPR1, FPR2. |
| FPR1, FPR2. |
| GPR3, GPR4. |
| GPR3, GPR4... GPR10. |
| Ячейка памяти, на которую указывает GPR3, составленный из 80 байтов хранения. |
| V2. |
| FPR1 (вещественное число), FPR2 (мнимое число). |
| FPR1 (вещественное число), FPR2 (мнимое число). |
| FPR1–FPR2 (вещественное число), FPR3–FPR4 (мнимое число). |
Сохранение регистра
Таблица 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 | Нет |