News:

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

CMOV Macro ?

Started by Ficko, August 07, 2009, 07:52:48 PM

Previous topic - Next topic

jj2007

#15
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.

dedndave

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

Ficko

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?!?

qWord

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,">=", ...



FPU in a trice: SmplMath
It's that simple!

jj2007

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.

Ficko

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

qWord

IFIDN\IFDIF has only two parameters: IFIDN <a>,<b>. OR,AND... are not allowed. 
FPU in a trice: SmplMath
It's that simple!

Ficko

#22
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

GregL

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.


Ficko

#24
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