TL: DR: у вас есть 2 отдельных вопроса. 1 о C размерах шрифта, а другой о том, как машинный код x86-64 кодирует 32, а не 64-битный размер операнда. Выбор кодировки довольно произвольный и мог бы быть сделан другим. Но int
является 32-битным, потому что именно это и выбрали разработчики компилятора, ничего общего с машинным кодом.
int
- 32-битный, потому что это все еще полезный размер для использования. Он использует половину пропускной способности памяти / кэш-памяти int64_t
. Большинство C реализаций для 64-битных ISA имеют 32-битные int
, включая оба основных ABI для x86-64 (x86-64 System V и Windows). В Windows даже long
является 32-разрядным типом, предположительно для совместимости исходного кода с кодом, написанным для 32-разрядных, в котором делались предположения о размерах шрифта.
Кроме того, целочисленный множитель AMD в то время был несколько быстрее для 32-битных, чем для 64-битных, и так было до Ryzen. (Кремний AMD64 первого поколения был микроархитектурой AMD K8; см. https://agner.org/optimize/ для таблиц инструкций.)
Преимущества использования 32-битных регистров / инструкций в x86-64
x86-64 был разработан AMD в 2000 году как AMD64. Intel была привержена Itanium и не участвовала; все проектные решения для x86-64 были приняты архитекторами AMD.
AMD64 разработан с неявным расширением нуля при записи 32-битного регистра, поэтому 32-битный размер операнда может использоваться эффективно при отсутствии ни одного из махинаций с частичным регистром, которые вы получаете с 8- и 16-битным режимами .
TL: DR: ЦПУ имеют веские причины хотеть сделать доступным 32-битный размер операнда каким-то образом и для систем типа C иметь легко доступный 32-битный тип. Использование int
для этого вполне естественно.
Если вы хотите 64-битный операнд Размер, используйте его. (А затем опишите его для C компилятора как long long
или [u]int64_t
, если вы пишете объявления C для ваших глобальных переменных asm или прототипов функций). Ничто не мешает вам (за исключением несколько большего размера кода, когда вам не нужны префиксы REX, которых у вас раньше не было).
Все это совершенно отдельный вопрос о том, как кодируется машинный код x86-64 32-битный размер операнда.
AMD решила сделать 32-битный размер по умолчанию, а для 64-битного размера операнда требуется префикс REX.
Они могли бы пойти другим путем и сделал размер по умолчанию 64-битным операндом, требуя REX.W = 0, чтобы установить его на 32, или 0x66
размер операнда, чтобы установить его на 16. Это могло привести к меньшему машинному коду для кода, который в основном манипулирует вещами в любом случае они должны быть 64-битными (обычно указатели), если для этого не требуется r8..r15.
Префикс REX также необходим для использования r8..r15 вообще (даже как часть режим адресации), поэтому код, который требует большого количества регистров, в любом случае часто использует префикс REX для большинства инструкций, даже при использовании размера операнда по умолчанию.
В большом количестве кода для многих используется int
вещи, так что 32-битный операнд Размер не редкость. И, как отмечено выше, это иногда быстрее. Так что имеет смысл сделать самые быстрые инструкции максимально компактными (если вы избегаете r8d..r15d).
Возможно, аппаратное обеспечение декодера будет проще, если один и тот же код операции декодирует аналогичным образом без префиксов в 32- и 64-битном режиме. Я думаю, что это была реальная мотивация AMD для этого выбора дизайна. Они, конечно, могли бы убрать много бородавок x86, но предпочли не делать этого, возможно, продолжать декодирование, более похожее на 32-битный режим.
Было бы интересно посмотреть, сохраните ли вы общий размер кода для версия x86-64 с размером операнда по умолчанию 64-битным. например, настроить компилятор и скомпилировать некоторые существующие кодовые базы. Однако вы бы хотели научить его оптимизатор отдавать предпочтение устаревшим регистрам RAX..RDI для 64-битных операндов вместо 32-битных, чтобы попытаться минимизировать количество инструкций, которым требуются префиксы REX.
(Многие инструкции, такие как add
или imul reg,reg
, могут безопасно использоваться с размером 64-битных операндов, даже если вы заботитесь только о младших 32, хотя высокий мусор повлияет на результат FLAGS.)
Re: дезинформация в комментариях: сравнение с 32-битным машинным кодом не имеет к этому никакого отношения. 64-битный режим не двоично совместим с существующим 32-битным машинным кодом; Вот почему в x86-64 введен новый режим . 64-разрядные ядра запускают 32-разрядные двоичные файлы в режиме сжатия, где декодирование работает точно так же, как в 32-разрядном защищенном режиме.
https://en.wikipedia.org/wiki/X86-64#OPMODES имеет полезную таблицу режимов, включая длинный режим ( и 64-битные и 32-битные и 16-битные режимы сжатия) и устаревший режим (если вы загружаете ядро, которое не поддерживает x86-64).
В 64-битном режиме некоторые коды операций отличаются, и операнд -размер по умолчанию 64-битный для push
/ pop
и других кодов команд стека.
32-битный машинный код будет некорректно декодироваться в этом режиме. Например, 0x40
- это inc eax
в режиме Compat, но префикс REX в 64-битном режиме. См. x86-32 / x86-64 фрагмент машинного кода полиглота, который обнаруживает 64-битный режим во время выполнения? для примера.
Также
* Декодирование в 1096 * 64-битном режиме в основном аналогичным образом - это вопрос совместного использования транзисторов в декодерах, а не двоичной совместимости. Предположительно, для декодеров проще иметь только 2 зависимых от режима размера операнда по умолчанию (16 или 32-бит) для коды операций, такие как 03 add r, r/m
, а не 3. Только специальный корпус для кодов операций, таких как push
/ pop
, которые гарантируют это. (Также обратите внимание, что REX.W = 0 делает не , позволяющим вам кодировать push r32
; размер операнда остается на 64-битном.)
Решения AMD по дизайну Похоже, что основное внимание было уделено обмену транзисторами декодера в максимально возможной степени, возможно, в случае, если AMD64 не завоевала популярность, и они застряли, поддерживая его без людей, использующих его.
Они могли бы сделать много тонких вещей, которые убрали досадные причуды x86, например, сделали setcc
32-битной инструкцией размера операнда в 64-битном режиме, чтобы избежать необходимости сначала обнуления xor. Или CIS C раздражения, такие как флаги, оставшиеся неизменными после сдвигов с нулевым счетом (хотя процессоры AMD обрабатывают это более эффективно, чем Intel, поэтому, возможно, они намеренно оставили это в силе.)
Или, возможно, они думали, что тонкие изменения могут повредить портирование исходного кода в asm, или в краткосрочной перспективе усложнит работу бэкэндов компилятора для поддержки 64-битного кода.