These macros don't change the fact that x86 has no instructions with an immediate source and an XMM or x87 destination. Remember, NASM is an assembler, not a compiler.
The use-cases include the rare case where you want to mov-immediate an FP bit-pattern into an integer register, like mov eax, __?float32?__(1.23)
. After which you might do movd xmm0, eax
, or even AVX-512 vpbroadcastd xmm0, eax
.
Normally compilers load FP data into registers from constants in memory (and that's usually a good option), but it's not the only way to go about it.
(AVX-512 makes immediates more attractive because of efficient broadcast, but you can broadcast from memory too with only AVX1, or SSE3 movddup
for a double. Compilers still use memory constants for scalar float, and that's still generally what I'd recommend unless profiling shows lots of data cache misses on that, and not a lot of I-cache misses in your program in general.)
Or for something like if (x) *fp_ptr = 1.0;
, you might want to mov-immediate to memory like mov dword [rdi], __?float32?__(1.0)
.
Another use-case could possibly be in a NASM %if
conditional assembly directive, or some other case where you want an FP bit-pattern as an integer value that isn't a dd
. Although nothing sensible comes to mind.
Or as part of an expression like __?float32?__(1.0) >> 23
to get the exponent (and sign bit) of a float constant you want to use for something.
For the record:
mov eax, __?float32?__(1.23)
mov eax, __?float32?__(1.0) >> 23
mov dword [rdi], __?float32?__(1.0)
assembled with nasm -felf64 foo.asm
and disassembled with 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
Related:
Older NASM documented __float32__(1.23)
; that still assembles, but the NASM manual currently only documents the form with ?
used in this answer. I think that makes it not a valid NASM preprocessor macro/token, in case that's relevant. And not a valid symbol name.