News:

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

Simple multiply algorithm.

Started by hutch--, November 04, 2008, 01:09:12 PM

Previous topic - Next topic

hutch--

I had a look at the postigs, Dave was right, no need to XOR edx. Here is a test piece with 4 macros, 2 for mnemonic format and 2 as functions.


; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
    include \masm32\include\masm32rt.inc
; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤

comment * -----------------------------------------------------
                        Build this  template with
                       "CONSOLE ASSEMBLE AND LINK"
        ----------------------------------------------------- *

  ; -------------
  ; mnemonic form
  ; -------------
    umul MACRO num, mult
      mov eax, num
      mov ecx, mult
      mul ecx
    ENDM

    smul MACRO num, mult
      mov eax, num
      mov ecx, mult
      imul ecx
    ENDM

  ; -------------
  ; function form
  ; -------------
    fnumul MACRO num, mult
      mov eax, num
      mov ecx, mult
      mul ecx
      EXITM <eax>
    ENDM

    fnsmul MACRO num, mult
      mov eax, num
      mov ecx, mult
      imul ecx
      EXITM <eax>
    ENDM

    .code

start:
   
; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤

    call main
    inkey
    exit

; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤

main proc

    numb equ <2000000000>
    mulb equ <2>

    smul numb, mulb
    print sdword$(eax),13,10

    umul numb, mulb
    print udword$(eax),13,10

    print sdword$(fnsmul(numb,mulb)),13,10
    print udword$(fnumul(numb,mulb)),13,10

    ret

main endp

; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤

end start
Download site for MASM32      New MASM Forum
https://masm32.com          https://masm32.com/board/index.php

drizz

The truth cannot be learned ... it can only be recognized.

jj2007

Quote from: hutch-- on November 05, 2008, 12:53:34 AM
    fnumul MACRO num, mult
      mov eax, num
      mov ecx, mult
      mul ecx
      EXITM <eax>
    ENDM

    fnsmul MACRO num, mult
      mov eax, num
      mov ecx, mult
      imul ecx
      EXITM <eax>
    ENDM


You might check for redundant mov eax, eax, and avoid using ecx:

fnsmul MACRO accu:REQ, mult:REQ
  ifdifi <accu>, <eax>
mov eax, accu
  endif
  imul eax, mult
  EXITM <eax>
ENDM

fnumul MACRO accu:REQ, mult:REQ
  ifdifi <accu>, <eax>
mov eax, accu
  endif
  ifdifi <mult>, <edx>
mov edx, mult
  endif
  mul edx
  EXITM <eax>
ENDM


raymond

I would definitely avoid using an instruction in a macro such as:

imul eax, mult

regardless if it is used for a signed or unsigned multiplication.

If the user knows what he's doing, he probably doesn't need a macro anyway. For a "newby", if the result should exceed 32 bits, it may throw an exception and possibly crash the program.
jj2007's latest proposed macro for a signed multiplication should thus be:

fnsmul MACRO accu:REQ, mult:REQ
  ifdifi <accu>, <eax>
mov eax, accu
  endif
  ifdifi <mult>, <edx>
mov edx, mult
  endif
  imul edx
  EXITM <eax>
ENDM


The user of these multiplication macros should then be advised that the multiplication result, whether signed or unsigned, will always be returned as a 64-bit value in the EDX:EAX pair (the imul eax,mult instruction would only return a 32-bit result in the EAX register while the mul edx instruction would return 64 bits).
When you assume something, you risk being wrong half the time
http://www.ray.masmcode.com

hutch--

Spot the difference or the instruction count using the macro I posted and JJs "improvement". By my count 4 instructions is 4 instructions.

This,


    nop
    mov edx, fnumuljj(numb, mulb)
    nop
    mov edx, fnumul(numb,mulb)
    nop
    mov edx, fnumuljj(esi, mulb)
    nop
    mov edx, fnumul(esi,mulb)
    nop
    mov edx, fnumuljj(esi, mem)
    nop
    mov edx, fnumul(esi, mem)
    nop
    mov edx, fnumuljj(esi, edi)
    nop
    mov edx, fnumul(esi, edi)
    nop
    mov edx, fnumuljj(mem, edi)
    nop
    mov edx, fnumul(mem, edi)
    nop


Produces,


0040103E 90                     nop
0040103F B800943577             mov     eax,77359400h
00401044 BA02000000             mov     edx,2
00401049 F7E2                   mul     edx
0040104B 8BD0                   mov     edx,eax
0040104D 90                     nop
0040104E B800943577             mov     eax,77359400h
00401053 B902000000             mov     ecx,2
00401058 F7E1                   mul     ecx
0040105A 8BD0                   mov     edx,eax
0040105C 90                     nop
0040105D 8BC6                   mov     eax,esi
0040105F BA02000000             mov     edx,2
00401064 F7E2                   mul     edx
00401066 8BD0                   mov     edx,eax
00401068 90                     nop
00401069 8BC6                   mov     eax,esi
0040106B B902000000             mov     ecx,2
00401070 F7E1                   mul     ecx
00401072 8BD0                   mov     edx,eax
00401074 90                     nop
00401075 8BC6                   mov     eax,esi
00401077 8B55FC                 mov     edx,[ebp-4]
0040107A F7E2                   mul     edx
0040107C 8BD0                   mov     edx,eax
0040107E 90                     nop
0040107F 8BC6                   mov     eax,esi
00401081 8B4DFC                 mov     ecx,[ebp-4]
00401084 F7E1                   mul     ecx
00401086 8BD0                   mov     edx,eax
00401088 90                     nop
00401089 8BC6                   mov     eax,esi
0040108B 8BD7                   mov     edx,edi
0040108D F7E2                   mul     edx
0040108F 8BD0                   mov     edx,eax
00401091 90                     nop
00401092 8BC6                   mov     eax,esi
00401094 8BCF                   mov     ecx,edi
00401096 F7E1                   mul     ecx
00401098 8BD0                   mov     edx,eax
0040109A 90                     nop
0040109B 8B45FC                 mov     eax,[ebp-4]
0040109E 8BD7                   mov     edx,edi
004010A0 F7E2                   mul     edx
004010A2 8BD0                   mov     edx,eax
004010A4 90                     nop
004010A5 8B45FC                 mov     eax,[ebp-4]
004010A8 8BCF                   mov     ecx,edi
004010AA F7E1                   mul     ecx
004010AC 8BD0                   mov     edx,eax
004010AE 90                     nop
Download site for MASM32      New MASM Forum
https://masm32.com          https://masm32.com/board/index.php

jj2007

Quote from: hutch-- on November 05, 2008, 04:26:43 AM
Spot the difference or the instruction count using the macro I posted and JJs "improvement". By my count 4 instructions is 4 instructions.

Odd or Even? I prefer Odd :bg

JJ macro:
ecx contained 12345, now its value is 12345
Result=500000
Codesize=5

Hutch macro:
ecx contained 12345, now its value is 500
Result=500000
Codesize=8

include \masm32\include\masm32rt.inc

; **** CONSOLE assembly ****

fnsmul MACRO accu:REQ, mult:REQ
  ifdifi <accu>, <eax>
mov eax, accu
  endif
  imul eax, mult
  EXITM <eax>
ENDM

fnumul MACRO accu:REQ, mult:REQ
  ifdifi <accu>, <eax>
mov eax, accu
  endif
  ifdifi <mult>, <edx>
mov edx, mult
  endif
  mul edx
  EXITM <eax>
ENDM

fnumulHutch MACRO num, mult
      mov eax, num
      mov ecx, mult
      mul ecx
      EXITM <eax>
ENDM

fnsmulHutch MACRO num, mult
      mov eax, num
      mov ecx, mult
      imul ecx
      EXITM <eax>
ENDM

.code
start:
print chr$(13, 10, "ecx contained 12345, now its value is ")
mov ecx, 12345
mov eax, 1000
mov edx, 500
mov esi, esi ; marker for Olly - jj macro starts
inJJ:
mov edi, fnsmul(eax, edx)
outJJ:
mov esi, esi ; marker for Olly - jj macro ends
print str$(ecx)
print chr$(13, 10, "Result=")
print str$(edi)
print chr$(13, 10, "Codesize=")
print str$(offset outJJ-inJJ), 13, 10

print chr$(13, 10, "ecx contained 12345, now its value is ")
mov ecx, 12345
mov eax, 1000
mov edx, 500
mov ah, ah ; marker for Olly - Hutch macro starts
inHutch:
mov edi, fnsmulHutch(eax, edx)
outHutch:
mov ah, ah ; marker for Olly - Hutch macro starts
print str$(ecx)
print chr$(13, 10, "Result=")
print str$(edi)
print chr$(13, 10, "Codesize=")
print str$(offset outHutch-inHutch), 13, 10, 10

inkey "Hit any key to get outta here"
exit

end start

jj2007

Quote from: raymond on November 05, 2008, 03:15:26 AM
For a "newby", if the result should exceed 32 bits, it may throw an exception and possibly crash the program.

Raymond, what you write is technically absolutely correct. However, if any of my code produces an integer that exceeds 32 bit, I would love to see it crash - at least, it would force me to insert an int 3 and launch Olly to see what's wrong with the code. I guess newbies would also appreciate that kind of behaviour.

But of course, there are people who work with 64 bit integers. As you rightly say, these people probably don't need a macro anyway.

EDIT: By the way, under which conditions does imul eax, mult crash? I have tested it with a global variable and two high 32 bits values, but it won't do me the favour to crash... :eek

hutch--

JJ,

I cheat, I look in the second column of the disasembly I posted as that tells you the byte count of each instruction. Add up ech digit in hex and Bingo, you have the byte size.

Ray,

What do you see as the problem, overflow is handled in EDX in the normal manner. With a macro of this type, this would need to be in the documentation but then this is already the case with the macros that MASM32 uses. Here is the example of an overflow result and it just shows this result in EDX.


; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
    include \masm32\include\masm32rt.inc
; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤

comment * -----------------------------------------------------
                        Build this  template with
                       "CONSOLE ASSEMBLE AND LINK"
        ----------------------------------------------------- *

    .code

start:
   
; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤

    call main
    inkey
    exit

; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤

main proc

    LOCAL var1  :DWORD
    LOCAL var2  :DWORD

    mov var1, 4000000000
    mov var2, 2

    mov eax, var1
    mov ecx, var2
    mul ecx

    push edx
    print ustr$(eax),13,10
    pop edx
    print ustr$(edx),13,10

    ret

main endp

; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤

end start
Download site for MASM32      New MASM Forum
https://masm32.com          https://masm32.com/board/index.php

jj2007

Quote from: hutch-- on November 05, 2008, 09:32:15 AM
JJ,
I cheat, I look in the second column of the disasembly I posted as that tells you the byte count of each instruction. Add up ech digit in hex and Bingo, you have the byte size.
Hey, is cheating allowed by the forum rules?? ::)
And what about recklessly destroying the contents of ecx without any need??

mov edi, fnumul(eax, edx)
0040101A   |. 8BF6             mov esi, esi <-marker start
0040101C   |. F7E2             mul edx
0040101E   |. 8BF8             mov edi, eax
00401020   |. 8BF6             mov esi, esi <-marker end


mov edi, fnumulHutch(eax, edx)
0040109A   |. 8AE4             mov ah, ah <-marker start
0040109C   |. 8BC0             mov eax, eax
0040109E   |. 8BCA             mov ecx, edx
004010A0   |. F7E1             mul ecx
004010A2   |. 8BF8             mov edi, eax
004010A4   |. 8AE4             mov ah, ah <-marker end

:bg

hutch--

JJ,

> And what about recklessly destroying the contents of ecx without any need??

Who cares, the register convention allows ECX to be overwritten.  :bg
Download site for MASM32      New MASM Forum
https://masm32.com          https://masm32.com/board/index.php

raymond

QuoteWhat do you see as the problem, overflow is handled in EDX in the normal manner.

You did not read what I wrote. I will repeat it once more.
QuoteI would definitely avoid using an instruction in a macro such as:

imul eax, mult

If the result of such an instruction exceeds 32 bits, it DOES NOT overflow into the EDX register. Your "test" was based on the regular mul instruction with a single parameter which obviously returns the result in the EDX:EAX registers.

jj
QuoteBy the way, under which conditions does imul eax, mult crash?

I had not verified if an overflow would throw an exception, that's why I mentioned "it may throw ...". I have now verified it and it does NOT throw any exception nor does it crash the program. An overflow simply leaves in EAX the same result as if the regular mul instruction would have, any overflow being discarded. With overflow, the result in EAX would thus be erroneous.
When you assume something, you risk being wrong half the time
http://www.ray.masmcode.com

hutch--

Ray,

Tolerate me here for the moment, I did not undersand your complaint.


; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
    include \masm32\include\masm32rt.inc
; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤

comment * -----------------------------------------------------
                        Build this  template with
                       "CONSOLE ASSEMBLE AND LINK"
        ----------------------------------------------------- *

    .code

start:
   
; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤

    call main
    inkey
    exit

; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤

main proc

    LOCAL var1  :DWORD
    LOCAL var2  :DWORD

  ; ------------
  ; within range
  ; ------------
    mov var1, 1000000000
    mov var2, 2

    mov eax, var1
    mov ecx, var2
    imul ecx

    push edx
    print sstr$(eax),13,10
    pop edx
    print sstr$(edx),13,10

  ; --------
  ; overflow
  ; --------
    mov var1, 4000000000
    mov var2, 2

    mov eax, var1
    mov ecx, var2
    imul ecx

    push edx
    print sstr$(eax),13,10
    pop edx
    print sstr$(edx),13,10

    ret

main endp

; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤

end start



2000000000
0
-589934592
-1
Press any key to continue ...


On both forms I tested EDX and its result shows if the result exceeds the size of 32 bit.
Download site for MASM32      New MASM Forum
https://masm32.com          https://masm32.com/board/index.php

KeepingRealBusy

Hutch and Raymond,

If you multiply two 32 bit numbers, each containing 040000000h (a 1 bit followed by 31 zero bits), the result will only be 63 bits. Do the math in binary, looks just like doing decimal. You will end up with a 1 bit followed by 2*31 zeros. Only if BOTH numbers start with "11" will the result end up with 64 bits.

Dave.

raymond

Hutch,

When you use mul (for unsigned multiplication) or imul (for signed multiplication) with a single parameter, the result is returned as 64 bits in the EDX:EAX pair. One of the multiplicands is expected to be in the EAX register and the other is the single parameter which can be a register or a memory operand. An immediate operand is not allowed as the single parameter.

When you use imul with more than one parameter, only the lower 32 bits of the result is returned strictly in the 32-bit destination, any overflow gets discarded. None of the multiplicands needs to be in the EAX register. They can be almost anywhere according to the parameters (Ex.: imul  ebx,esi). An immediate operand is also allowed as one of the multiplicands in this format.

That is why I'm opposed to the use of an instruction such as
imul eax, mult (notice the two parameters)
in a macro, or whatever, to be used by "newbies" who may not know the difference.

When you assume something, you risk being wrong half the time
http://www.ray.masmcode.com