The MASM Forum Archive 2004 to 2012

General Forums => The Campus => Topic started by: Ficko on August 07, 2009, 07:52:48 PM

Title: CMOV Macro ?
Post by: Ficko on August 07, 2009, 07:52:48 PM
Do somebody knows where can I find some kind of "CMOV" macro.
- I am to lazy to write one if allready exists - :toothy

Should be something like:

CMOV (eax == ebx)


cmp eax, ebx
cmove eax, ebx


of curse that's the easy part it should be able to handle this:

CMOV (sdword ptr eax > ebx)
as well. :bg

Thanks,
Ficko
Title: Re: CMOV Macro ?
Post by: Jimg on August 07, 2009, 10:08:17 PM
It's going to be pretty tough since < and > are macro variable delimiters.
Title: Re: CMOV Macro ?
Post by: hutch-- on August 08, 2009, 12:42:58 AM
Arrrrgh, whats wrong with CMOV ?
Title: Re: CMOV Macro ?
Post by: GregL on August 08, 2009, 12:49:23 AM
QuoteArrrrgh, whats wrong with CMOV ?

:lol  That's exactly what I was going to say.  Why not just use CMOV?


Title: Re: CMOV Macro ?
Post by: donkey on August 08, 2009, 03:47:13 AM
I have a great macro:

MOV(mem32,reg32) MACRO
    push reg32
    pop eax
    push offset mem32
    pop edi
    stosd
ENDMACRO
Title: Re: CMOV Macro ?
Post by: dedndave on August 08, 2009, 10:44:25 AM
very nice Edgar   :U
how about ...

  push reg32
  pop  mem32

i have been poking around - reading about cmov's
one of the articles i read said you may be better off to use the traditional cmp/branch code
according to the article, the branch will be predicted and run faster, overall
the cmov cannot be predicted, and thus, may take longer
the article did say, that in cases where the outcome of the conditional is completely random, cmov may have a slight advantage due to size
they said that on a P4, the branch will typically be better
on newer cpu's, the difference will be more or less negligible
Title: Re: CMOV Macro ?
Post by: jj2007 on August 08, 2009, 11:06:24 AM
Quote from: dedndave on August 08, 2009, 10:44:25 AM
very nice Edgar   :U
how about ...

  push reg32
  pop  mem32


How good to have a long-time macro hater finally on our side! But Edgar trashes edi :naughty:

Quote
i have been poking around - reading about cmov's
one of the articles i read said you may be better off to use the traditional cmp/branch code
according to the article, the branch will be predicted and run faster, overall
the cmov cannot be predicted, and thus, may take longer
the article did say, that in cases where the outcome of the conditional is completely random, cmov may have a slight advantage due to size
they said that on a P4, the branch will typically be better
on newer cpu's, the difference will be more or less negligible

The Mozilla guys say cmov is a winner (https://mail.mozilla.org/pipermail/tamarin-devel/2008-April/000455.html), sometimes.

P.S.: Since this is the Campus: attention, the MOV macro is an insider joke... :wink
Title: Re: CMOV Macro ?
Post by: Vortex on August 08, 2009, 11:26:56 AM
Quote from: Greg on August 08, 2009, 12:49:23 AM
QuoteArrrrgh, whats wrong with CMOV ?

:lol  That's exactly what I was going to say.  Why not just use CMOV?

Possibly, he could have an old processor not supporting the CMOV instruction.
Title: Re: CMOV Macro ?
Post by: dedndave on August 08, 2009, 12:41:27 PM
with regard to designing code around the P4, i would say, there are a lot of P4's out there
of course, intel and amd want you to buy a newer one, so they'll account for smaller target percentages over time
as Erol said, the cmp/branch code works on more older processors
i am guessing the random/non-random thing leans toward the non-random
most branching is somewhat predictable
it's harder to predict the future - cpu architecture is likely to improve to the point that there is little difference
in days of old, if you could eliminate a cmp/branch with 4 fast lines (mov reg,reg etc), it was probably better not to branch
i am a little surprised to see just how fast conditional branches are, nowdays
an extreme example of the same thing is all the kinks we use to multiply and divide - lol
at some point intel and amd are going to figure out that a static gate array can do most of the work
then, div and mul will be under 10 clock cycles and we'll have all this code that has long shl/add sequences - lol
Title: Re: CMOV Macro ?
Post by: jj2007 on August 08, 2009, 01:58:14 PM
cmov seems faster for "alternating" tests:

mov ecx, 1000
.Repeat
test ecx, 1
cmove eax, ecx
dec ecx
.Until Zero?


For a test ecx, ecx, it is slower:
2621    cycles for cmove, test ecx, 1
4016    cycles for je, test ecx, 1

2624    cycles for cmove, test ecx, ecx
2036    cycles for je, test ecx, ecx


Full code below.
.nolist
include \masm32\include\masm32rt.inc
.686
include \masm32\macros\timers.asm
buffersize = 10000 ; don't go higher than 100000, ml.exe would slow down
LOOP_COUNT = buffersize ; in this case; otherwise, 1000000 would be a typical value

.data?
dummy db 8 dup(?)
buffer dd buffersize dup(?)

.code
start:
REPEAT 2
counter_begin LOOP_COUNT, HIGH_PRIORITY_CLASS
mov ecx, 1000
.Repeat
test ecx, 1
cmove eax, ecx
dec ecx
.Until Zero?
counter_end
print str$(eax), 9, "cycles for cmove, test ecx, 1", 13, 10

counter_begin LOOP_COUNT, HIGH_PRIORITY_CLASS
mov ecx, 1000
.Repeat
test ecx, 1
jne @F
mov eax, ecx
@@:
dec ecx
.Until Zero?
counter_end
print str$(eax), 9, "cycles for je, test ecx, 1", 13, 10, 10

counter_begin LOOP_COUNT, HIGH_PRIORITY_CLASS
mov ecx, 1000
.Repeat
test ecx, ecx
cmove eax, ecx
dec ecx
.Until Zero?
counter_end
print str$(eax), 9, "cycles for cmove, test ecx, ecx", 13, 10

counter_begin LOOP_COUNT, HIGH_PRIORITY_CLASS
mov ecx, 1000
.Repeat
test ecx, ecx
jne @F
mov eax, ecx
@@:
dec ecx
.Until Zero?
counter_end
print str$(eax), 9, "cycles for je, test ecx, ecx", 13, 10, 10, 10
ENDM

inkey chr$(13, 10, "--- ok ---", 13)
exit
end start
Title: Re: CMOV Macro ?
Post by: dedndave on August 08, 2009, 02:04:32 PM
that is a strange result   :red
it's almost as though test ecx,immed is the bad guy - lol
on the last 2 tests, the mov never happens
Title: Re: CMOV Macro ?
Post by: jj2007 on August 08, 2009, 03:34:45 PM
Quote from: dedndave on August 08, 2009, 02:04:32 PM
that is a strange result   :red
it's almost as though test ecx,immed is the bad guy - lol

In a way, yes. Test xxx, 1 is a test for odd or even, and apparently the branch prediction algos are not clever enough to realise that every second iteration is odd. Very odd ::)

Quote
on the last 2 tests, the mov never happens

That was intended. If it happens, timings for branch and cmove are identical.
Title: Re: CMOV Macro ?
Post by: Ficko on August 08, 2009, 03:41:08 PM
Hi guys!

Sorry I didn't express myself clearly I was almost sleeping. :P

I am using a lots recently this guy "cmov" mainly to determine the Min/Max of two signed or not signed number and thought since MASM has
"IF (SDWORD PTR EAX > EBX)" may somebody did a macro for "CMOV" allready so you not have to strugle with "LE","GE","L" etc..

I did come up with a pseudo macro - dosn't work jet because I have difficulty to pass "<=" as an argument :'( so if anybody could have a guess to fix that would be appreciated or any suggestion
I am not a macro master- :bg

The macro would have as parameters:

CMOV DWORD/SDWORD,Reg1,"Operator",Reg2,OPTIONAL Reg3,OPTIONAL Reg4

It would cmovX Reg1, Reg2 if Reg3 = nothing
otherwise it would cmovX Reg3, Reg4



.686p
.model flat, stdcall
; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
CMOV MACRO Sign:REQ,Reg1:REQ,Comp:REQ,Reg2:REQ,Reg3,Reg4
cmp Reg1, Reg2
IF @SizeStr(Reg3)
m1 TEXTEQU <Reg3>
m2 TEXTEQU <Reg4>
ELSE
m1 TEXTEQU <Reg1>
m2 TEXTEQU <Reg2>
ENDIF
IF Sign EQ dword
IF Comp EQ ">"
cmova m1, m2
ELSEIF Comp EQ "<"
cmovb m1, m2
ELSEIF Comp EQ "="
cmove m1, m2
ELSEIF Comp EQ ">=" OR Comp EQ "=>"
cmovae
ELSEIF Comp EQ "<=" OR Comp EQ "=<"
cmovbe
ELSE
echo The Comp operator is not valid  
ENDIF
ELSEIF Sign EQ sdword
IF Comp EQ ">"
cmovge m1, m2
ELSEIF Comp EQ "<"
cmovle m1, m2
ELSEIF Comp EQ "="
cmove m1, m2
ELSEIF Comp EQ ">=" OR Comp EQ "=>"
cmovg
ELSEIF Comp EQ "<=" OR Comp EQ "=<"
cmovl
ELSE
echo The Comp operator is not valid  
ENDIF
ENDIF
ENDM
.code
; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
start:
call Pilot
Pilot proc
int 3
CMOV DWORD,eax,"=",ebx,ecx,edx
ret
Pilot endp
end start

Title: Re: CMOV Macro ?
Post by: dedndave on August 08, 2009, 03:57:31 PM
ahhhh - lol
it's not hard to remember, really
once you have been programming a while, you will have them memorized (unless you use a macro - lol)
(Jcc has pretty much the same mnemonics as CMOVcc and SETcc)

i'd be more inclined to try to write a macro that randomly selects CMOVcc or Jcc/MOV
that way, half the time, you'll have the fastest code
Title: Re: CMOV Macro ?
Post by: Ficko on August 08, 2009, 04:01:29 PM
If I am tired I not even remember my own name. :lol

And by experience using macros the prg is not that error prone since you use well tested pieces of codes. :U
Quote
i'd be more inclined to try to write a macro that randomly selects CMOVcc or Jcc/MOV

Great idea! :wink

But at first I would be happy to get my first try to work. :bg
Title: Re: CMOV Macro ?
Post by: jj2007 on August 08, 2009, 04:24:24 PM
If it's for min/max, you might try this one. I am was *) a bit confused by the inverted logic (jb/jl seems to correspond to cmovl/cmovb) but according to some rough testing it seems to work just fine:

eax=333, ecx=-1
sMin eax, ecx, -123, +123: -123
uMin eax, ecx, -123, +123: 123
sMax eax, ecx, -123, +123: 333
uMax eax, ecx, -123, +123: 4294967295


.nolist
include \masm32\include\masm32rt.inc
.686

sMin MACRO dest, src:VARARG
  FOR s1, <src>
cmp dest, s1
CMX cmovB, dest, s1
  ENDM
ENDM

uMin MACRO dest, src:VARARG
  FOR s1, <src>
cmp dest, s1
CMX cmovL, dest, s1
  ENDM
ENDM

sMax MACRO dest, src:VARARG
  FOR s1, <src>
cmp dest, s1
CMX cmovA, dest, s1
  ENDM
ENDM

uMax MACRO dest, src:VARARG
  FOR s1, <src>
cmp dest, s1
CMX cmovG, dest, s1
  ENDM
ENDM

CMX MACRO cmType, cmDest, cmArg
LOCAL oa, CMX_FAST
  CMX_FAST = 0 ;; 0=short and slow for imm8 sources, 1=long and fast
  oa = (opattr(cmArg)) AND 127 ;; 36=immediate
  if oa eq 36
ifidn <cmovB>, <cmType>
jl @F
elseifidn <cmovL>, <cmType>
jb @F
elseifidn <cmovA>, <cmType>
jg @F
elseifidn <cmovG>, <cmType>
ja @F
endif
if cmArg gt 127 or cmArg lt -128 or CMX_FAST
mov cmDest, cmArg
else
push cmArg
pop cmDest
endif
  @@:
  else
cmType cmDest, cmArg
  endif
ENDM

.code
start:
print "eax=333, ecx=-1", 13, 10
print "sMin eax, ecx, -123, +456: "
mov eax, 333
mov ecx, -1
; int 3 ; activate to see in Olly what the macro does
sMin eax, ecx, -123, 456
nop
print str$(eax), 13, 10

print "uMin eax, ecx, -123, +456: "
mov eax, 333
mov ecx, -1
; int 3
uMin eax, ecx, -123, 456
nop
print ustr$(eax), 13, 10

print "sMax eax, ecx, -123, +456: "
mov eax, 333
mov ecx, -1
; int 3
sMax eax, ecx, -123, 456
nop
print str$(eax), 13, 10

print "uMax eax, ecx, -123, +456: "
mov eax, 333
mov ecx, -1
; int 3
uMax eax, ecx, -123, 456
nop
print ustr$(eax), 13, 10

exit

end start


* EDIT: The inverted logic is needed because cmov works if the condition is fulfilled, while the jxx will be taken if the condition is not fulfilled.
Title: Re: CMOV Macro ?
Post by: dedndave on August 08, 2009, 04:52:14 PM
jb isn't the same as jl
jb is the same as jc, of course
jl is jump if overflow is not equal to sign
Title: Re: CMOV Macro ?
Post by: Ficko on August 08, 2009, 05:07:01 PM
Thanks jj..

Quote
If it's for min/max..

Yes it would do for Min/Max but since I think I am so close with my macro and if it would work it would cover much more than that would be great to get that one fixed. :bg

If I am using "!<=" like the manul says:

Quote
he <text> is any name, number, or expression.
It can contain commas, spaces, tabs, or semicolons.
The exclamation point (!) is an escape character that allows you to include special characters such as the semicolon, ampersand, and quotation marks.

MASM takes it without error but doesn't seem to work like an escape character it goes to the macro as "!<="
If I put

ELSEIF Comp EQ "!<="

in the macro I get error. :dazzled:

I tryed using "{="  like a replacement but no luck jet.

Any guess?!?
Title: Re: CMOV Macro ?
Post by: qWord on August 08, 2009, 05:39:59 PM
Quote from: Ficko on August 08, 2009, 05:07:01 PM

ELSEIF Comp EQ "!<="

in the macro I get error. :dazzled:

You have to use IFIDN\ELSEIFIDN or IFDIF\ELSEIFDIF for comparing literals. In this case, i recommend you to desing your macro like this:


cmov macro dest, cond, ....
   
    cm_cond TEXTEQU @CatStr(cond)   ; avoid problems with angle brackets
                                    ; and exclamation marks
    ...
   
    IFIDN cm_cond,<"!>=">
        ...
    ENDIF
endm
...
cmov xyz,"!=", ...
cmov xyz,">=", ...



Title: Re: CMOV Macro ?
Post by: jj2007 on August 08, 2009, 06:05:03 PM
Quote from: dedndave on August 08, 2009, 04:52:14 PM
jb isn't the same as jl
jb is the same as jc, of course
jl is jump if overflow is not equal to sign

Thanks, Dave. The source of my confusion was that cmovxx performs for "condition fulfilled", while the jxx (needed only for immediate src operands) is needed if the condition is not fulfilled (i.e., do not move, jump). The code above is corrected accordingly, a lot shorter, and allows for an unlimited number of source arguments, e.g. sMin eax, ecx, 123, edx, 456, 789, -1 will do just fine.

I also added a CMX_FAST switch. In case of 8-bit immediate operands (-128...+127), for CMX_FAST=0 the m2m option will be chosen.
Title: Re: CMOV Macro ?
Post by: Ficko on August 08, 2009, 06:07:54 PM
Thanks qWord very much!

That's really helped! :U

Here is it so far:


.686p
.model flat, stdcall
; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
CMOV MACRO Sign:REQ,Reg1:REQ,Cond:REQ,Reg2:REQ,Reg3,Reg4
cmp Reg1, Reg2
L_Cond TEXTEQU @CatStr(Cond)
IF @SizeStr(Reg3)
m1 TEXTEQU <Reg3>
m2 TEXTEQU <Reg4>
ELSE
m1 TEXTEQU <Reg1>
m2 TEXTEQU <Reg2>
ENDIF
IF Sign EQ dword
IFIDN L_Cond,<"!>">
cmova m1, m2
ELSEIFIDN L_Cond,<"!<">
cmovb m1, m2
ELSEIFIDN L_Cond,<"=">
cmove m1, m2
ELSEIFIDN L_Cond,<"!>="> OR L_Cond,<"=!>">
cmovae m1, m2
ELSEIFIDN L_Cond,<"!<="> OR L_Cond,<"=!<">
cmovbe m1, m2
ELSE
echo The Cond operator is not valid
ENDIF
ELSEIF Sign EQ sdword
IFIDN L_Cond,<"!>">
cmovge m1, m2
ELSEIFIDN L_Cond,<"!<">
cmovle m1, m2
ELSEIFIDN L_Cond,<"=">
cmove m1, m2
ELSEIFIDN L_Cond,<"!>="> OR L_Cond,<"=!>">
cmovg m1, m2
ELSEIFIDN L_Cond,<"!<="> OR L_Cond,<"=!<">
cmovl m1, m2
ELSE
echo The Cond operator is not valid  
ENDIF
ENDIF
ENDM
.code
; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
start:
call Pilot
Pilot proc
int 3
CMOV SDWORD,eax,"<",ebx,ecx,edx
ret
Pilot endp
end start


it works with "=", ">" and "<" but it gives me an error on "<=" and simile.

I don't know why?? :eek
Title: Re: CMOV Macro ?
Post by: qWord on August 08, 2009, 06:36:35 PM
IFIDN\IFDIF has only two parameters: IFIDN <a>,<b>. OR,AND... are not allowed. 
Title: Re: CMOV Macro ?
Post by: Ficko on August 08, 2009, 06:46:25 PM
Thanks !

Now it seems to work :U


; ---------------------------------------------------------------
; CMOV SDWORD/DWORD,Arg1,"Operator",Arg2,opt Arg3,opt Arg4
; Syntax:
; CMOV DWORD,eax,"!=",ebx                    'cmp eax, ebx:cmovne eax, ebx
; CMOV DWORD,eax,"<>",ebx,edx                'cmp eax, ebx:cmovne eax, edx
; CMOV DWORD,eax,"!=",ebx,edx,ecx            'cmp eax, ebx:cmovne edx, ecx
; ---------------------------------------------------------------
CMOV MACRO Sign:REQ,Arg1:REQ,Operator:REQ,Arg2:REQ,Arg3,Arg4
cmp Arg1, Arg2
L_Operator TEXTEQU @CatStr(Operator)
IF @SizeStr(Arg4)
m1 TEXTEQU <Arg3>
m2 TEXTEQU <Arg4>
ELSEIF @SizeStr(Arg3)
m1 TEXTEQU <Arg1>
m2 TEXTEQU <Arg3>
ELSE
m1 TEXTEQU <Arg1>
m2 TEXTEQU <Arg2>
ENDIF
IF Sign EQ dword
IFIDN L_Operator,<"!>">
cmova m1, m2
ELSEIFIDN L_Operator,<"!<">
cmovb m1, m2
ELSEIFIDN L_Operator,<"=">
cmove m1, m2
ELSEIFIDN L_Operator,<"!<!>">
cmovne m1, m2
ELSEIFIDN L_Operator,<"!!=">
cmovne m1, m2
ELSEIFIDN L_Operator,<"!>=">
cmovae m1, m2
ELSEIFIDN L_Operator,<"=!>">
cmovae m1, m2
ELSEIFIDN L_Operator,<"!<=">
cmovbe m1, m2
ELSEIFIDN L_Operator,<"=!<">
cmovbe m1, m2
ELSE
echo The Operator operator is not valid
ENDIF
ELSEIF Sign EQ sdword
IFIDN L_Operator,<"!>">
cmovg m1, m2
ELSEIFIDN L_Operator,<"!<">
cmovl m1, m2
ELSEIFIDN L_Operator,<"=">
cmove m1, m2
ELSEIFIDN L_Operator,<"!<!>">
cmovne m1, m2
ELSEIFIDN L_Operator,<"!!=">
cmovne m1, m2
ELSEIFIDN L_Operator,<"!>="> 
cmovge m1, m2
ELSEIFIDN L_Operator,<"=!>"> 
cmovge m1, m2
ELSEIFIDN L_Operator,<"!<=">
cmovle m1, m2
ELSEIFIDN L_Operator,<"=!<">
cmovle m1, m2
ELSE
echo The Operator operator is not valid  
ENDIF
ELSE
echo The first parameter have to be "DWORD" or "SDWORD" !
ENDIF
ENDM
Title: Re: CMOV Macro ?
Post by: GregL on August 08, 2009, 08:17:08 PM
Quote from: VortexPossibly, he could have an old processor not supporting the CMOV instruction.

Yes, I thought of that about two seconds after I posted.

Title: Re: CMOV Macro ?
Post by: Ficko on August 09, 2009, 01:57:48 PM
I fixed some bugs in the macro above and extended to 3 arguments interpretation.

And just for fun there are the 64-bit Min/Max with cmovs: :bg
The procs are taking 2 quadwords as input and in edx:eax the return value.


; =============== S U B R O U T I N E =======================================
MinU64 proc near public
mov ecx, [esp+16]
pop [esp+12]
pop eax
pop edx
CMOV DWORD,edx,">",ecx
pop ecx
ja @F
jb Exit
cmp eax, ecx
@@:             cmova eax, ecx
Exit:           retn
MinU64 endp
; =============== S U B R O U T I N E =======================================
MaxU64 proc near public
mov ecx, [esp+16]
pop [esp+12]
pop eax
pop edx
CMOV DWORD,edx,"<",ecx
pop ecx
jb @F
ja Exit
cmp eax, ecx
@@:             cmovb eax, ecx
Exit:           retn
MaxU64 endp
; =============== S U B R O U T I N E =======================================
MinS64 proc near public
mov ecx, [esp+16]
pop [esp+12]
pop eax
pop edx
CMOV SDWORD,edx,">",ecx
pop ecx
jg @F
jb Exit
cmp eax, ecx
@@:             cmovg eax, ecx
Exit:           retn
MinS64 endp
; =============== S U B R O U T I N E =======================================
MaxS64 proc near public
mov ecx, [esp+16]
pop [esp+12]
pop eax
pop edx
CMOV SDWORD,edx,"<",ecx
pop ecx
jl @F
jg Exit
cmp eax, ecx
@@:             cmovl eax, ecx
Exit:           retn
MaxS64 endp