Почему eax содержит количество векторных параметров?
Почему все содержит количество векторных параметров в сборке?
Почему векторные параметры отличаются от нормальных параметров для вызываемого?
1 ответ
Значение используется для оптимизации, как указано в документе ABI
Пролог должен использовать
%rax
чтобы избежать ненужного сохранения регистров XMM. Это особенно важно для целочисленных программ, чтобы предотвратить инициализацию модуля XMM.https://software.intel.com/sites/default/files/article/402129/mpx-linux64-abi.pdf
Когда вы звоните va_start
он сохранит все параметры, переданные в регистрах, в область сохранения регистров
Для начала, любая известная функция
va_start
требуется в начале функции сохранить все регистры, которые могли использоваться для передачи аргументов в стек, в "область сохранения регистров" для последующего доступаva_start
а такжеva_arg
, Это очевидный шаг, и я считаю, что это довольно стандартно для любой платформы с соглашением о вызовах регистра. Регистры сохраняются как целочисленные регистры, за которыми следуют регистры с плавающей запятой...
Но сохранение всех 8 векторных регистров может быть медленным, поэтому компилятор может оптимизировать его, используя значение, переданное в al
... В качестве оптимизации во время вызова функции
%rax
требуется хранить количество регистров SSE, используемых для хранения аргументов, чтобы позволить вызывающему varargs вообще не касаться FPU, если нет аргументов с плавающей запятой.
Поскольку вы хотите сохранить хотя бы использованные регистры, значение может быть больше, чем действительное количество используемых регистров. Вот почему эта линия в ABI
Содержание
%al
не обязательно должны точно соответствовать количеству регистров, но должны быть верхней границей количества используемых векторных регистров и находятся в диапазоне 0–8 включительно.
Вы можете увидеть эффект от пролога ICC
sub rsp, 216 #5.1
mov QWORD PTR [8+rsp], rsi #5.1
mov QWORD PTR [16+rsp], rdx #5.1
mov QWORD PTR [24+rsp], rcx #5.1
mov QWORD PTR [32+rsp], r8 #5.1
mov QWORD PTR [40+rsp], r9 #5.1
movzx r11d, al #5.1
lea rax, QWORD PTR [r11*4] #5.1
lea r11, QWORD PTR ..___tag_value_varstrings(int, ...).6[rip] #5.1
sub r11, rax #5.1
lea rax, QWORD PTR [175+rsp] #5.1
jmp r11 #5.1
movaps XMMWORD PTR [-15+rax], xmm7 #5.1
movaps XMMWORD PTR [-31+rax], xmm6 #5.1
movaps XMMWORD PTR [-47+rax], xmm5 #5.1
movaps XMMWORD PTR [-63+rax], xmm4 #5.1
movaps XMMWORD PTR [-79+rax], xmm3 #5.1
movaps XMMWORD PTR [-95+rax], xmm2 #5.1
movaps XMMWORD PTR [-111+rax], xmm1 #5.1
movaps XMMWORD PTR [-127+rax], xmm0 #5.1
..___tag_value_varstrings(int, ...).6:
По сути, это устройство Даффа. r11
регистр загружается с адресом после инструкции по сохранению xmm, а затем al*4
вычитается из результата (так как movaps XMMWORD PTR [rax-X], xmmX
длиной 4 байта), чтобы перейти к movaps
инструкция, что мы должны запустить
Как я вижу, другие компиляторы всегда сохраняют все векторные регистры или не сохраняют их вообще, поэтому им все равно al
значение и просто проверьте, равен ли он нулю
Регистры общего назначения всегда сохраняются, возможно потому, что дешевле просто перенести 6 регистров в память вместо того, чтобы тратить время на проверку условий, вычисление адресов и переход. В результате вам не нужен параметр для того, сколько целых чисел было передано в регистрах.
Вот вопрос, похожий на ваш. Вы можете найти больше информации в ссылках ниже