Использование макросов NASM __?float?__

avatar
mediocrevegetable1
4 марта 2021 в 13:39
157
1
2

Руководство NASM говорит об этих макросах, но, насколько я понимаю, не объясняет, как их использовать. Раздел 3.4.6 гласит:

Плавающие точечные константы приемлемы только в качестве аргументов DB, DW, DW, DQ, DT, и DO или в качестве аргументов специальных операторов __?float8?__ __?float16?__>, __?bfloat16?__, __?float32?__, __?float64?__, __?float80m?__, __?float80e?__, __?float128l?__ и __?float128l?__ и <4908037042015><260420153

Сначала я подумал, что это связано с использованием констант с плавающей запятой вне раздела данных. Но когда я попробовал mov xmm0, __?float32?__(1.23), я получил ошибку «Неверная комбинация кода операции и операндов». В конце концов я увидел, что foo: dd __?float32?__(1.23) работает. Хотя мне это кажется странным; если вы можете сделать dd 1.23 напрямую, какой смысл в этих макросах? Одна из возможностей может заключаться в том, что вам нужно определить, например, число с плавающей запятой одинарной точности в четверном слове. Это действительно единственное применение этих макросов, или я использую их неправильно?

Источник

Ответы (1)

avatar
Peter Cordes
4 марта 2021 в 13:46
3

Эти макросы не меняют того факта, что x86 не имеет инструкций с непосредственным источником и назначением XMM или x87. Помните, что NASM — это ассемблер, а не компилятор.

Случаи использования включают редкий случай, когда вы хотите немедленно переместить битовый шаблон FP в целочисленный регистр, например mov eax, __?float32?__(1.23). После чего вы можете ввести movd xmm0, eax или даже AVX-512 vpbroadcastd xmm0, eax.

Обычно компиляторы загружают данные FP в регистры из констант в памяти (и это обычно хороший вариант), но это не единственный способ сделать это.

(AVX-512 делает немедленные операции более привлекательными из-за эффективной трансляции, но вы также можете транслировать из памяти только с AVX1 или SSE3 movddup для двойного числа. Компиляторы по-прежнему используют константы памяти для скалярного числа с плавающей запятой, и это все еще то, что Я бы порекомендовал, если только профилирование не показывает много промахов кэша данных, и не так много промахов I-кэша в вашей программе в целом.)

Или для чего-то вроде if (x) *fp_ptr = 1.0; вы можете захотеть немедленно переместить в память, например mov dword [rdi], __?float32?__(1.0).

Еще один вариант использования может быть в директиве NASM %if условной сборки или в каком-либо другом случае, когда вам нужен битовый шаблон FP в виде целочисленного значения, которое не и dd. Хотя ничего толкового в голову не приходит.

Или как часть выражения типа __?float32?__(1.0) >> 23, чтобы получить показатель степени (и бит знака) константы с плавающей запятой, которую вы хотите использовать для чего-то.


Для протокола:

mov eax, __?float32?__(1.23)
mov eax, __?float32?__(1.0) >> 23
mov dword [rdi], __?float32?__(1.0)

в сборе с nasm -felf64 foo.asm и в разобранном виде с objdump -drwC -Mintel foo.o

   0:   b8 a4 70 9d 3f          mov    eax,0x3f9d70a4
   5:   b8 7f 00 00 00          mov    eax,0x7f
   a:   c7 07 00 00 80 3f       mov    DWORD PTR [rdi],0x3f800000
mediocrevegetable1
4 марта 2021 в 13:53
1

Ах да, я только что попробовал это с eax, и это сработало. Довольно глупо с моей стороны не попробовать это задним числом ... Я не знал, что вы вообще не можете помещать литералы в регистры xmm (я пытаюсь изучить векторы и SIMD). В любом случае, вы дали мне ответ, который я искал.

Peter Cordes
4 марта 2021 в 13:56
2

@mediocrevegetable1: Также имейте в виду, что mov может никогда не иметь назначения XMM (felixcloutier.com/x86/mov), так что это еще одна вещь, которую нужно проверить в следующий раз, когда инструкция не соберется. Инструкции, которые могут записывать регистр XMM, включают movd xmm, r/m32, movdqu xmm, xmm/mem, vbroadcastss xmm, xmm/mem.

mediocrevegetable1
4 марта 2021 в 13:58
0

Ок, я этого не понял. Инструкцию поищу, спасибо за ссылку.

Peter Cordes
4 марта 2021 в 14:06
2

@mediocrevegetable1: Обновил мой ответ другим правдоподобным и, может быть, интересным вариантом использования: mov-немедленно в память или дальнейшие математические вычисления с константным выражением для битового шаблона float32.

mediocrevegetable1
4 марта 2021 в 14:10
0

Спасибо за обновления. Я не думал об их использовании для этого, особенно с битовым сдвигом. Интересный.