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
It's going to be pretty tough since < and > are macro variable delimiters.
Arrrrgh, whats wrong with CMOV ?
QuoteArrrrgh, whats wrong with CMOV ?
:lol That's exactly what I was going to say. Why not just use CMOV?
I have a great macro:
MOV(mem32,reg32) MACRO
push reg32
pop eax
push offset mem32
pop edi
stosd
ENDMACRO
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
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
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.
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
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
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
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.
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
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
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
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.
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 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?!?
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,">=", ...
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.
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
IFIDN\IFDIF has only two parameters: IFIDN <a>,<b>. OR,AND... are not allowed.
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
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.
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