News:

MASM32 SDK Description, downloads and other helpful links
MASM32.com New Forum Link
masmforum WebSite

Compare QWORDS

Started by Ghirai, December 13, 2005, 10:37:33 PM

Previous topic - Next topic

Ghirai

Hey,

I have:

VAR1 qword ?
VAR2 qword ?

In my code i modify them, and then need to compare them.

What would be a quick way to see if VAR1>VAR2?

Thanks.
MASM32 Project/RadASM mirror - http://ghirai.com/hutch/mmi.html

Human

easiest method is 64bit cpu
mov rax,[var1]
cmp rax,[var2]

but if we dont own one, first compare high dwords if higher so its higher,if equal then you need to compare lower dwords if its higher, additionally you can use mmx pcmpgtd and pmovmskb but also it compares just dword as separate things.
for all set of 8086 till sse2 instructions get nasm documentation from sourceforge.net there is explain and list of instruction combination
600kb of pure power

another thing is if you want to compare signed or unsigned qwords
thats other story

MichaelW

This macro should have the same effect on the CPU flags as the CMP instruction. A .686 processor directive is required. The indeterminate result (see Simply FPU tutorial) should never occur with integer operands (?).

qwcmp MACRO arg1, arg2
  fild  arg2
  fild  arg1
  fcomip st(0),st(1)
  fwait
ENDM


eschew obfuscation

zooba

mov eax, DWORD PTR VAR1[4]    ; need to use [4] because is stored in little-endian
cmp eax, DWORD PTR VAR2[4]
jg IsGreater     ; ja IsAbove   for unsigned comparison
jl IsLess        ; jb IsBelow   for unsigned comparison
mov eax, DWORD PTR VAR1
cmp eax, DWORD PTR VAR2
jg IsGreater     ; ja IsAbove   for unsigned comparison


IsLess:
...

IsGreater:
...


Slightly longer code but much more efficient than using the FPU. Doesn't translate nicely into a macro either unfortunately.

Ratch

Human,
     Your method for 32-bit ALU instructions only works for unsigned QWORDs.  I think you know that.

zooba,
     Your method will work for unsigned QWORDs, but you need to add some code to take of the equals situation.  The code will fail for signed QWORDs because you do a signed comparision on the lower QWORD.  Since a legitimate positive number can have the MSB set on the lower QWORD, that instruction will cause your code to fail.  You cannot do a unsigned comparision either, because a larger/smaller QWORD means a smaller/larger number for a negative word and larger/smaller number for a positive word.  So now you have to know if the number is positive/negative and select your code accordingly.  The code below for two signed numbers, subtracts the number while propagating the carry, and then does all the testing at the end.  Ratch


MOV EAX,VAR1 ;use any convenient registers
SUB  EAX,VAR2 ;subtract the lower QWORD first

MOV ECX,EAX   :store result for testing later
MOV EAX,VAR1+DWORD
SBB EAX,VAR2+DWORD ;now the upper QWORD

JL LESS
OR EAX,ECX
JE EQUAL
                   ;greater code here



EQUAL:
                   ;equal code here


LESS:
                  ;less code here



Human

well point was greater so we just need to know if greater if less or equal its not what we want so it will not jump where it should be. so for unsigned it should work due lower words consider as jg or jle

zooba

Damn, that was silly (re: signed comparison on lower DWORD  :dazzled:  ::) :P)

Here's a version that should work for signed greater than comparisons:


  mov eax, VAR1[4]
  cmp eax, VAR2[4]
  jg  IsGreater
  jl  IsNotGreater

  or  eax, eax
  mov eax, VAR1[0]
  js  Test2
  cmp eax, VAR2[0]
  ja  IsGreater
  jmp IsNotGreater

Test2:
  cmp eax, VAR2[0]
  jb  IsGreater

IsNotGreater:
...

IsGreater:
...


Again, its unfortunate to have the extra jump in there but as newer Intel processors (and AMD?) have neglected a range of instructions including SBB, it will probably work out faster. Especially since there are short-circuits for some cases (ie. if the high DWORD is greater than the low DWORD, only one comparison and one jump)

MichaelW

Quote from: zooba on December 14, 2005, 02:52:25 AM
Slightly longer code but much more efficient than using the FPU.

Yes, much more efficient. Faster by a factor of 70 on a P3: 209 cycles for the FPU macro, 3 cycles for Ratch's code (selected for timing because it has no embedded jumps).



[attachment deleted by admin]
eschew obfuscation

Ghirai

MASM32 Project/RadASM mirror - http://ghirai.com/hutch/mmi.html

Ratch

zooba,
    How does this code handle equal numbers?  Don't you think it is starting to look like spaghetti?  Ratch
   


 mov eax, VAR1[4]
 cmp eax, VAR2[4]
 jg  IsGreater
 jl  IsNotGreater                 ;IsNotGreater does NOT mean JL, IsNotGreater means JLE

 or  eax, eax                     ;OR here is redundant, CMP already done above
 mov eax, VAR1[0]
 js  Test2
 cmp eax, VAR2[0]
 ja  IsGreater
 jmp IsNotGreater

Test2:
 cmp eax, VAR2[0]
 jb  IsGreater                    ;what about equal?

IsNotGreater:
...

IsGreater:                        ;what about equal?
...

zooba

Quote from: Ratch on December 14, 2005, 11:40:20 AM
How does this code handle equal numbers?  Don't you think it is starting to look like spaghetti?

With all due respect, I don't believe you're reading the code properly.

jl  IsNotGreater                 ;IsNotGreater does NOT mean JL, IsNotGreater means JLE

Your comment is based entirely on this one line and not the entire snippet. At this point we only know if the high-order DWORD of VAR1 is greater, equal or less than the same of VAR2. If it is greater, we know that the entire number must be greater than. If it is less, we know that the entire number is less. If they are equal, we have to check the rest of the number. However, if we already know that VAR1 is less than VAR2, we don't need to check the lower order DWORD, so we can skip to the end of the snippet. Note that we are only testing for greater or not-greater (ie. less or equal).

or  eax, eax                     ;OR here is redundant, CMP already done above

The CMP above compared eax (VAR1[4]) with VAR2[4]. Since we would have jumped elsewhere if VAR1[4] was greater or less than VAR2[4], we know that they are equal. The purpose of the 'or' was to check the sign bit of VAR1 or VAR2 (since the sign bits will be equal).

I've just tried to prove my point and figured out that this part is wrong  :( Since the signs of the two numbers are the same a simple unsigned comparison of the lower DWORD will suffice:

11111111b (-1d) > 11111110b (-2d)
11111111b (255d) > 11111110b (254d)

Here, once more, is my revised version... perhaps I should test it before I post it...  ::)

(The original question didn't require an equals case which is why it was not included. I'll include an equals case in this one)


mov eax, VAR1[4]
cmp eax, VAR2[4]
jg  IsGreater
jl  IsLessThan

mov eax, VAR1[0]
cmp eax, VAR2[0]
ja  IsGreater
jb  IsLessThan
;je  IsEqual               ; this is a redundant jump

IsEqual:
...

IsLessThan:
...

IsGreater:
...

Ratch

#11
zooba,
     Your latest code looks good now.  I cannot find any logical anomalies.  The equals condition must be handled somehow unless the numbers are guaranteed to be different.  Ratch

zooba

Quote from: Ratch on December 14, 2005, 05:07:18 PM
The equals condition must be handled somehow unless the numbers are guaranteed to be different

It can be handled by simply allowing it to fall through to the 'IsNotGreater' case, which is what I had in the first place.

EduardoS

Another one with the same efect in flags as cmp eax, ecx but with jump (not very efective) but starting from higer dword,
cmp edx:eax, ebx:ecx

cmp edx, ebx
jne @F
cmp eax, ecx
@@: