4

How would I add 1 or 2 to the register xmm0 (double)?

I can do it like this, but sure there must be an easier way:

movsd xmm0, [ecx]

xor eax, eax
inc eax
cvtsi2sd xmm1, eax
addsd xmm0, xmm1

movsd [ecx], xmm0

Also would it be possible to do this with the floating point x87 instructions?

This doesn't work for me:

fld dword ptr [ecx]
fld1
faddp
fstp dword ptr [ecx]
Jens Björnhager
  • 5,632
  • 3
  • 27
  • 47
Tyilo
  • 28,998
  • 40
  • 113
  • 198

2 Answers2

9

You can keep a constant in memory or in another register:

_1      dq      1.0

and

addsd   xmm1,[_1]

or

movsd   xmm0,[_1]
addsd   xmm1,xmm0

If you are on x64, you can do this:

mov     rax,1.0
movq    xmm0,rax
addsd   xmm1,xmm0  

or use the stack if the type mismatch bothers you:

mov     rax,1.0
push    rax
movsd   xmm0,[rsp]
pop     rax
addsd   xmm1,xmm0 

As for the x87 code, doubles are qwords, not dwords.

Jens Björnhager
  • 5,632
  • 3
  • 27
  • 47
  • `movsd xmm0,[esp]` or `movsd xmm0,[rsp]`? – Michael Petch Jul 10 '16 at 17:59
  • 1
    The suggestion to use the stack is terrible anyway, and doesn't avoid the surprising use of a `double` constant as an operand to `mov r64, imm64`. If you want to avoid that, suggest `mov eax, 1` / `cvtsi2sd xmm0, eax` – Peter Cordes Jul 11 '16 at 07:10
  • 1
    You can also generate `1.0` in an xmm register with only a 3 instructions, IIRC (starting with `pcmpeqw` to generate all-ones). Agner Fog's [Optimizing Assembly](http://agner.org/optimize) – Peter Cordes Jul 11 '16 at 07:13
  • See [Use of NASM's \_\_?float?\_\_ macros](https://stackoverflow.com/q/66476230) for `mov rax, __?float64?__(1.0)`. YASM accepts `mov rax, 1.0` but NASM doesn't. – Peter Cordes Dec 16 '22 at 07:56
0
vpcmpeqq  xmm1,xmm1,xmm1          ; xmm1 = [ -1 | -1 | -1 | -1 ] as ints
vmovsd    xmm0,dword ptr [ecx]    ; xmm0 = VALUE as int
vsubsd    xmm0,xmm0,xmm1          ; xmm0 = VALUE - (-1) = VALUE + 1

The above should be

vpcmpeqq  xmm1,xmm1,xmm1          ; xmm1 = [ -1 | -1 | -1 | -1 ] as ints
vmovd     xmm0,dword ptr [ecx]    ; xmm0 = VALUE as int
vpsubd    xmm0,xmm0,xmm1          ; xmm0 = VALUE - (-1) = VALUE + 1

for integer increment by 1 and

vpcmpeqq  xmm1,xmm1,xmm1          ; xmm1 = [ -1 | -1 ] as quads
vmovsd    xmm0,dword ptr [ecx]    ; xmm0 = VALUE as double
vcvtdq2pd xmm1,xmm1               ; xmm1 = [ -1.0 | -1.0 ] as doubles
vsubsd    xmm0,xmm0,xmm1          ; xmm0 = VALUE - (-1.0) = VALUE + 1.0

for double increment by 1.0

Igor Fujs
  • 11
  • 3
  • Could you specify what CPU extensions are needed for these AVX/SIMD instructions? – Anton Krug Apr 10 '21 at 14:16
  • 2
    This doesn't seem like it'll work. You're going to subtract the double-precision float with bit pattern `0xffffffffffffffff` and that's a NaN, not -1. – Nate Eldredge Apr 10 '21 at 15:01
  • 1
    You're missing a `vcvtdq2pd xmm1,xmm1` int -> FP conversion to get double `-1.0`. Or probably a single left shift of the `-1ULL` could create the right bit-pattern, with contiguous bits set at the top. – Peter Cordes Apr 10 '21 at 17:09
  • Please don't post only code as answer, but also provide an explanation what your code does and how it solves the problem of the question. Answers with an explanation are usually more helpful and of better quality, and are more likely to attract upvotes. – Mark Rotteveel Apr 12 '21 at 10:08
  • Thank you all for pointing out my mistakes. I corrected them so I hope It is ok now. All instructions are AVX. – Igor Fujs Apr 12 '21 at 10:43