The MASM Forum Archive 2004 to 2012

General Forums => The Workshop => Topic started by: savage on June 13, 2006, 03:08:37 PM

Title: Sorry if this is a common question
Post by: savage on June 13, 2006, 03:08:37 PM
what's the easiest way to get an absolute value of an sse register?
I'm thinking I could use AND 07FFFFFFFFF..... or something, but is there a better way?
Title: Re: Sorry if this is a common question
Post by: dsouza123 on June 14, 2006, 01:41:34 AM
Signed integers use twos complement encoding.
For switching signs
not reg  ; xor reg, -1
add 1

For example using a signed byte:
00000010 == 2
00000001 == 1
00000000 == 0
11111111 == -1
11111110 == -2

If you knew it was negative then the equivalent of this

xor reg, -1
add reg, 1

would give the positive version.


SSE code equivalent to this would do it no matter the sign of the integer.

mov reg, reg0
and reg,10000000  ; for byte sized signed integer
cmp reg, 0
je past
xor reg0, -1
add reg0, 1
past:
Title: Re: Sorry if this is a common question
Post by: redskull on June 14, 2006, 01:53:07 AM
i don't know about SSE registers, but maybe something like this could be converted?  (for eax)

CDQ
XOR EAX, EDX
SUB EAX, EDX
Title: Re: Sorry if this is a common question
Post by: savage on June 14, 2006, 03:03:41 PM
wow, yeah, guys, im asking about SSE =P

for regular registers i can just do

AND eax, 07FFF FFFFh

The problem is you can't use immediate values for sse instructions, so I was trying to avoid using a weird looking constant, it's not a big deal, I was just making sure there's not a faster way
Title: Re: Sorry if this is a common question
Post by: dsouza123 on June 14, 2006, 04:42:38 PM
AND eax, 07FFF FFFF wont give the correct absolute value.

The -1 will turn into 2147483647, surely not what you expected.

Redskull's code works correctly.

This code with tweaks may work, but it isn't tested .

.data
  number dq somenum, somenum
  minusone dq -1, -1
  zero dq 0, 0
  justhi dq  10..0b, 10..0b

.code
  movaps xmm1, minusone
  movaps xmm2, number
  movaps xmm3, xmm2
  andps xmm3, justhi
  comisd xmm3, justhi
  je past
  movaps xmm1, zero
past:
  xorps  xmm2, xmm1
  psubq  xmm2, xmm1
Title: Re: Sorry if this is a common question
Post by: Ossa on June 14, 2006, 04:47:23 PM
dsouza123 is right, take a look at this: http://ossa.the-wot.co.uk/tutorial_asm1_tex.htm#1_6

It is something that I wrote a while back to explain 2's complement. Your code will only work for signed magnitude values, but Intel processors use 2's complement.

Ossa
Title: Re: Sorry if this is a common question
Post by: redskull on June 14, 2006, 06:39:08 PM
Quote from: dsouza123 on June 14, 2006, 04:42:38 PM
Redskull's code works correctly.

Just for the record, i'm totally not claiming to have thought that code up; the original was a 16-bit version using CWD, taken from a book i can't remember long ago.  Again, sorry I can't help with SSE registers :'(

alan
Title: Re: Sorry if this is a common question
Post by: savage on June 15, 2006, 03:04:05 PM
Quote from: Ossa on June 14, 2006, 04:47:23 PM
dsouza123 is right, take a look at this: http://ossa.the-wot.co.uk/tutorial_asm1_tex.htm#1_6

It is something that I wrote a while back to explain 2's complement. Your code will only work for signed magnitude values, but Intel processors use 2's complement.

Ossa

I feel stupid now, DUHHHHHHHHHHHHHHHHHHHHHH. 
Sorry guys, my neurons aren't exactly working this week.  :green2
Title: Re: Sorry if this is a common question
Post by: savage on June 15, 2006, 03:23:11 PM
What about

   mov edx, eax
   sub eax, edx
   sub eax, edx

and

   movaps xmm1, xmm0
   subps xmm0, xmm1
   subps xmm0, xmm1
Title: Re: Sorry if this is a common question
Post by: Ossa on June 15, 2006, 03:25:51 PM
Quote from: savage on June 15, 2006, 03:23:11 PM
   mov edx, eax
   sub eax, edx
   sub eax, edx

Therefore:

mov edx, eax    ; edx = eax = val
sub eax, edx    ; eax = 0, edx = val
sub eax, edx    ; eax = 0 - val = -val


I don't think that that's what you want to do.

Ossa
Title: Re: Sorry if this is a common question
Post by: savage on June 15, 2006, 03:29:16 PM
I never said that.
You liar!   :cheekygreen:

I have a huge headache.  I think my brain is falling out of my ear. 

Why is it so hard to get the absolute value.  Arrrg
Title: Re: Sorry if this is a common question
Post by: Ossa on June 15, 2006, 03:50:51 PM
This probably won't assemble (I haven't had time to check) but should work... there MUST be a better way though... I don't use MMX/SSE much, so I'm not the one to ask though:

mask1 dd  10000000h,  10000000h,  10000000h,  10000000h

movdqa   xmm2, xmm1
pand     xmm1, mask1
pcmpeqd  xmm1, mask1 ; xmm1 has all 1s for any dword that is negative

pxor     xmm3, xmm3
psubd    xmm3, xmm2 ; xmm3 = -xmm2

pand     xmm3, xmm1
pandn    xmm1, xmm2
por      xmm1, xmm3


[edit] Now that I finally looked at redskull's code, try this - I don't know of any sign extension instructions for SSE but I'll go have a look now:

mask1 dd  10000000h,  10000000h,  10000000h,  10000000h

movdqa   xmm2, xmm1
pand     xmm2, mask1
pcmpeqd  xmm2, mask1 ; xmm1 has all 1s for any dword that is negative

pxor     xmm1, xmm2
psubd    xmm1, xmm2


(for non-dowrd things, you just change the mask and the psubd instruction)

[/edit]

Ossa
Title: Re: Sorry if this is a common question
Post by: savage on June 15, 2006, 04:14:19 PM
how does this look:

   movaps xmm1, xmm0
   cmpnltps xmm1, 0  ; obviously this shouldnt be immediate, but just an example
   andps xmm1, xmm0
   subps xmm0, xmm1
   subps xmm0, xmm1

Title: Re: Sorry if this is a common question
Post by: Ossa on June 15, 2006, 04:17:44 PM
Wait - you're using FLOATS ??? well then, you first method WILL work and it is much the best.

[edit] The code that has been discussed so far is for integers, but you are using float SSE instructions there... which are you using? [/edit]

Ossa
Title: Re: Sorry if this is a common question
Post by: savage on June 15, 2006, 04:19:23 PM
Well I'd like to have the best method for both.
Title: Re: Sorry if this is a common question
Post by: asmfan on June 15, 2006, 04:22:41 PM
I think the Ossa's code should contain mask = 80000000h to work correct... on sign bit
Title: Re: Sorry if this is a common question
Post by: Ossa on June 15, 2006, 04:25:24 PM
For floats, definately just do the and.

For integers, the code you just posted won't work as it is for floating point values (a quick glance says that the code will work for floats, but it will be much slower than the and you posted about right at the start).

Quote from: asmfan on June 15, 2006, 04:22:41 PM
I think the Ossa's code should contain mask = 80000000h to work correct... on sign bit

Exactly right asmfan:

mask1 OWORD  80000000800000008000000080000000h

movaps   xmm2, xmm1
pand     xmm2, mask1
pcmpeqd  xmm2, mask1 ; xmm1 has all 1s for any dword that is negative

pxor     xmm1, xmm2
psubd    xmm1, xmm2


Thanks for spotting that.

[edit] Just edited it to get it assemble under MASM... also used MOVAPS instead of MOVDQA (SSE instead of SSE2) [/edit]

Ossa
Title: Re: Sorry if this is a common question
Post by: savage on August 18, 2006, 04:35:38 PM
I just thought of this method for eax registers:


bt eax, 31
adc eax, 0





mov ecx, 45 ; << number to be absoluted

xor eax, eax
bt ecx, 31
adc eax, 0
adc ecx, 0
neg eax
sbb ecx,0
xor ecx, eax


Well at least that works, it's obviously not optimised
just a weird idea