x86-64 Система V использует использование AL для функций с переменным числом: вызывающий передает число аргументов FP в регистрах XMM.
(Это толькооптимизация, позволяющая вызываемому объекту не сбрасывать все векторные регистры в массив; разрешается, чтобы число в AL превышало количество аргументов FP. На практике код ggen для функций variadic просто проверяет, является ли оно ненулевым, ивыводит либо none, либо все 8 из xmm0..7. Я думаю, что ABI гарантирует, что безопасно всегда передавать al=8
, даже если на самом деле нет никаких аргументов FP, и что вы не можете передавать аргументы FP в стеке.вместо этого, установив al=0
)
Но почему бы не использовать r9b
для этого и использовать RAX для 6-го аргумента?Или RAX для некоторого более раннего аргумента?
Поскольку RAX имеет так много неявных применений в x86 , и эксперименты при разработке соглашения о вызовах (http://web.archive.org/web/20140414124645/http://www.x86-64.org/pipermail/discuss/2000-November/001257.html) обнаружили, что использование RAX обычно требуетдополнительные инструкции в вызывающем или вызываемом объекте, например, потому что RAX часто требовался как часть вычисления других аргументов в вызывающем объекте, или был необходим при выполнении чего-либо с одним из других аргументов, прежде чем код сможет использовать аргумент, переданный в RAX.
RAX используется для rep stos
(который gcc использовал более агрессивно для встроенного memset) и для div
и расширения (с одним операндом) mul
/ imul
, чтоgcc использует для деления на константу времени компиляции. ( Почему GCC использует умножение на странное число при реализации целочисленного деления? ).
Большинство других специальных применений RAX просто корочекодировки вещей, которые вы также можете делать с другими регистрами, например cdqe
против movsxd rax, eax
(или между любыми другими регистрами) или add eax,imm32
(без ModRM) против add r/m32, imm32
(или большинстводругие инструкции ALU).Смотрите один из моих ответов на Советы по игре в гольф в машинном коде x86 / x64 .В оригинальном 8086 отсутствовали многие более длинные альтернативы без AX, но между 8086 и 386 были добавлены такие вещи, как imul r32,r32
и movsx
/ movzx
.Другие инструкции только для RAX не стоит использовать при оптимизации скорости (например, xlatb
, lodsd
) или устарели из-за расширений P6 / AMD64 (lahf
, поскольку часть FP сравнивает устаревшие fucomi
и использует SSE/ SSE2 ucomisd
для математики FP), или являются специализированными инструкциями, такими как cmpxchg
или cpuid
, которые слишком редки, чтобы оказать влияние на разработку соглашения о вызовах.В любом случае, компиляторы не использовали инструкции BCD, такие как aaa
, а AMD64 удалила их.
Разработчики соглашения о вызовах System V для x86-64 (в первую очередь Ян Хубичка для целочисленного регистра передачи аргументов arg)дизайн), как правило, направлен на то, чтобы избежать регистров со многими / распространенными неявными применениями.rdx
предшествует rcx
в порядке прохождения аргументов, потому что cl
требуется для переменного числа сдвигов (без BMI2).Возможно, они встречаются чаще, чем mul
и div
, поскольку 2-операнд imul reg,reg
допускает нормальное умножение без расширения без дробления RDX: RAX.
На выбор rdi
и rsi
в качествепервые 2 аргумента были, по-видимому, мотивированы включением memset
или memcpy
как rep movs
(что gcc сделал в 2000 году, хотя на самом деле это не был хороший выбор во многих случаях, когда gcc делал это).Несмотря на то, что rep
-строковые инструкции используют RCX в качестве счетчика, они все же нашли в среднем сохраненные инструкции для передачи 3-го аргумента в RDX вместо RCX, поэтому соглашение о вызовах не вполне работает, чтобы memcpy
было rep stosb
/ ret
.
Ян Хубичка (Jan Hubička) оценил многочисленные варианты регистров передачи аргументов путем компиляции SpecInt с текущей версией x86-64 gcc.См. Мой ответ по Почему Windows64 использует соглашение о вызовах, отличное от всех других операционных систем на x86-64? , чтобы узнать больше подробностей и ссылок.
Один из вычисленных им порядков регистра arg былRAX, RDX, RCX, RBX, RSI, RDI
, но он нашел это менее удачным, чем другие варианты.(См. Сообщение в списке рассылки, указанное выше).
Соглашения о вызовах RISC довольно часто передают первый аргумент в первый регистр возвращаемого значения.ARM делает это (r0
), и я думаю, что делает PowerPC.Другие (например, MIPS) этого не делают.Но во всех этих архитектурах нет неявного использования большинства целочисленных регистров, часто это просто регистр ссылок и, возможно, указатель стека.
x86-64 SysV и Windows делают это для аргументов FP: xmm0 для передачи и возврата.