2016-10-19 13 views
5

Возможно, это касается даже не микро-, а нанооптимизации, но предмет меня интересует, и я хотел бы знать, есть ли какие-либо штрафы при использовании неродного размера регистра в длинном режиме?Могут ли быть какие-либо штрафы при использовании 64/32-разрядных регистров в длинном режиме?

Я узнал из различных источников, что частичные обновления регистра (например, ax вместо eax) могут привести к тому, что eflags остановится и ухудшит производительность. Но я не уверен в длинном режиме. Какой размер регистра считается родным для этого режима работы процессора? x86-64 все еще являются расширениями для архитектуры x86, поэтому я считаю, что 32 бита по-прежнему являются родными. Или я ошибаюсь?

Например, инструкции, как

sub eax, r14d 

или

sub rax, r14 

имеют одинаковый размер, но может ли быть какие-либо штрафные санкции при использовании любого из них? Могут ли быть какие-либо штрафы при смешивании размеров регистра в последовательных инструкциях, как показано ниже? (При условии высокой DWORD равен нулю во всех случаях)

sub ecx, eax 
sub r14, rax 
+0

Имеются штрафы за 16-разрядные обращения. Использование 32-разрядных регистров и исключение r8-r15 в порядке и фактически часто приводит к меньшему размеру кода. –

+4

Запись в 32-битный регистр автоматически очищает верхние 32 бита, поэтому избегает проблемы частичного обновления. – Jester

+0

Регистр EFLAGS сильно виртуализирован в современных процессорах. Как и все регистры. Обязательно так, слишком много инструкций модифицируют его, и это большой заслон над суперскалярным исполнением. В коде отсутствует код, который фактически использует * регистр. Таким образом, нет никакой веской причины, по которой процессор блокирует его и останавливает отправленный вами код. Никогда не задумывайтесь над тем, как это должно/работать. Единственная точка написания ассемблерного кода - сделать его быстрее, чем компилятор C. Мера. –

ответ

8

Может ли какие-либо штрафы при смешивании 32 и 64-битовых регистров размеров в последовательных инструкций?

No, writing to a 32-bit register always zero-extends to the full register, поэтому x86-64 избегает любых штрафов за частичный регистратор для 32-разрядной и 64-разрядной инструкции.

Таким образом, я считаю, что 32 бита по-прежнему являются родными.

Да, размер операнда по умолчанию для большинства инструкций составляет 32 бит (other than PUSH/POP). Для 64-битного кода требуется префикс REX с бит W, установленным в 1. Предпочитают 32-битные причины для кода. Вот почему компиляторы используют mov r32, imm32 для адресов статических данных (поскольку по умолчанию для кодовой модели требуется, чтобы кодовые и статические адреса данных находились в низком виртуальном адресном пространстве 2 Гбит).

Это был дизайнерский выбор от AMD. Они могли выбрать другой путь и потребовали префикс, чтобы получить размер 32-битного операнда. Поскольку длительный режим - это отдельный режим, машинный код x86-64 может отличаться от машинного кода x86-32, но он хочет. AMD решила минимизировать различия, чтобы они могли делиться как можно большим количеством транзисторов в декодерах. Ваш вывод верен, но ваши рассуждения полностью фиктивные.


частичные обновления регистра (например, топор вместо EAX) может вызвать срыв EFLAGS и привести к снижению производительности.

Партии с отдельным флагом отделены от парковых столов с частными регистрами. Они обрабатываются аналогично внутренне (отдельно переименованные части EFLAGS должны быть объединены так же, как модифицированный AX должен быть объединен с немодифицированными верхними байтами EAX). Но один не вызывает другого.

# partial-reg stall 
setcc al   # leaves the upper 3 (or 7) bytes unmodified 
add  edx, eax  # reads full EAX. Older CPUs stall while merging 

Zeroing EAX ahead of the flag-setting and setcc with xor eax,eax avoids the partial-register penalty entirely. (Core2/Nehalem останавливается на меньшее количество циклов, чем предыдущие процессоры, но все равно останавливается на 2 или 3c при вставке слияния uop.Sandybridge вообще не останавливается при вставке слияния uop).

(Другое резюме штрафов за частичный регистратор на разных ЦП: Why doesn't GCC use partial registers?, говоря в основном то же самое).

AMD не страдает от неполных регистров при чтении полного регистра позже, но вместо этого частичная регистрация записей и чтения имеет ложную зависимость от полного регистра. (Процессоры AMD не переименовывать субрегистры отдельно в первую очередь. Intel P4 и посадки Silvermont/Рыцарский являются таким же образом.)

Intel Хасуэлл/Skylake (и, возможно, Ivybridge) не переименовывать al отдельно от rax вообще, поэтому им никогда не нужно объединять регистры low8/low16. Но setcc al имеет ложную зависимость от старого значения. Они все еще переименовывают и объединяют ah. (Details on HSW/SKL partial-reg performance.)


# partial flag stall when reading a flag that didn't come from 
# the last instruction to write any flags. 
clc 
# edi and esi = one-past-the-end of dst and src 
# ecx = -count 
bigInt_add: 
    mov eax, [esi+ecx*4] 
    adc [edi+ecx*4], eax # reads CF, partial flag stall on 2nd and later iterations 
    inc ecx    # writes all flags except CF 
    jl bitInt_add   # loop upwards towards zero 

См this Q&A для более детального обсуждения вопросов о частичных флагов на Intel предварительной SandyBridge против SandyBridge.


Смотрите также Agner Fog's microarch pdf и другие ссылки в тегов вики для получения более подробной информации обо всем этом.

+0

Большое спасибо –

 Смежные вопросы

  • Нет связанных вопросов^_^