News:

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

MODx and DIVx macros

Started by ecube, May 11, 2007, 06:21:34 AM

Previous topic - Next topic

Ian_B

You could also add handling for the special (trivial) case of DIV by 1:


DIVx MACRO num1:REQ,num2:REQ
mov ecx, num2
xor edx, edx
mov eax, ecx
sub edx, ecx        ; sets ZF if divide by zero
jz div_exit2
cmp ecx, 1
je div_by_1

and eax, edx
xor edx, edx
cmp ecx, eax
mov eax, num1       ; doesn't change flags
je power2div

div ecx
jmp div_exit

div_by_1:
mov edx, num1       ; result = input
jmp div_exit

power2div:
bsf ecx, ecx        ; get power of 2 in CL
mov edx, eax
shr edx, cl

div_exit:
test ecx, ecx       ; must unset ZF
div_exit2:
endm                ; result in EDX, ZF is set to show divide by zero error to the calling code


ecube

this macro divides a qword by a dword then returns the value in a dword(eax) I wrote this when I was playing with GetFreeDiskSpaceEx

   
DivQbyD MACRO num1:REQ,num2:REQ
xor edx,edx
mov eax,dword ptr num1+0
IF num2
mov ecx,num2
div ecx
ENDIF
endm



example

include \masm32\include\masm32rt.inc

     CTEXT MACRO text:VARARG
            local TxtName
              .data
               TxtName BYTE text,0
              .code
            EXITM <ADDR TxtName>
     ENDM
     
DIVx MACRO num1:REQ,num2:REQ
xor edx,edx
mov eax,num1
IF num2
mov ecx,num2
div ecx
ENDIF
endm

DivQbD MACRO num1:REQ,num2:REQ
xor edx,edx
mov eax,dword ptr num1+0
IF num2
mov ecx,num2
div ecx
ENDIF
endm     
     
.data
FreeBytes         dq 0
TotalBytes        dq 0
TotalFreeBytes  dq 0
kilobytes           dd 0
megabytes        dd 0

.data?
buff db 1024 dup(?)
     
.code
start:
invoke GetDiskFreeSpaceEx,CTEXT("c:\"),addr FreeBytes,addr TotalBytes,addr TotalFreeBytes

;FreeBytes is a qword
DivQbD FreeBytes,1024

;results in a dword
mov kilobytes,eax

;lets divide once more to get megabytes
DIVx eax,1024
mov megabytes,eax

invoke wsprintf, addr buff,CTEXT("free disk space: megabytes:%i ,kilobytes:%i "),megabytes,kilobytes
invoke MessageBox,0,addr buff,NULL,MB_ICONINFORMATION
invoke ExitProcess,0
end start


also thanks for your guess optimized versions of these macros, I really hope hutch puts these or macros similiar to these in masm32 to make life easier for those just trying to do some simple math.

Tedd

Quote from: E^cube on May 31, 2007, 10:15:55 PM
this macro divides a qword by a dword then returns the value in a dword(eax) I wrote this when I was playing with GetFreeDiskSpaceEx

   
DivQbyD MACRO num1:REQ,num2:REQ
xor edx,edx
mov eax,dword ptr num1+0
IF num2
mov ecx,num2
div ecx
ENDIF
endm

I must be missing something.. but how is it a qword when you set edx (the high dword component) to zero?
(Technically any such division is "qword DIV dword", but if edx is zero then it's no different to "dword DIV dword")
No snowflake in an avalanche feels responsible.

fearless

I was looking at the DivQbyD macro for use with the GetDriveSpaceEx function, after having tried a number of other code examples. Unfortunately this one doesnt seem to work either.

Does anyone have a simple function to divide a 64 bit number (QWORD) by a dword? I want to be able to break the 64bit number down to a value that can be utilized with a progress bar - PBM_SETRANGE32 and had hoped to divide the qword down to a dword value at most for this reason.
Ć’earless

Tedd


div64 proc dividend_hi:DWORD,dividend_lo:DWORD,divisor:DWORD
    ;;divides 64-bit dividend by 32-bit divisor
    ;(dividend_hi is the top 32-bits, dividend_lo the lower 32-bits)
    mov eax,dividend_lo
    mov edx,dividend_hi
    mov ecx,divisor
    div ecx
    ;returns with eax as the quotient
    ;    and edx as the remainder
    ret
div64 endp

But you may as well just do the division yourself (without calling a separate function) - the DIV instruction is intended to be used for dividing a 64-bit value.
Use IDIV if you require negative values.
No snowflake in an avalanche feels responsible.

fearless

Thanks Tedd,

I must have spent a good whole day trying everything i could think of and using loads of snippets of code in an attempt to resolve my impass. The solution appears so easy - i suppose it always does, with hindsight  :bg

Appreciate your help though. Saved me from another day of frustration and ive been able to use that function to show the progress bar for the amount of space being processed vs total amount as obtained by the GetDiskFreeSpaceEx function.  :U

Cheers
Ć’earless

Rockoon

Quote from: Ian_B on May 12, 2007, 08:27:44 PM
Actually, I was a little surprised by BSF. According to the Opcodes help file that comes with MASM, for 486 BSF is VERY slow, at 6-42 clocks depending on the number of bits it has to search before first match. But according to Agner's Pentium optimisation guide, it is really quite fast, with only a 4-clock latency compared to the 50 or so for a DIV. So for newer processors, including the jump and 6 clocks for the SHR reg CL the special case optimisation isn't that bad, about five times as fast.

But how often are you likely to get a power of 2 to DIV by that you can't identify in advance and write specific code for instead of always using a less efficient do-it-all macro? Hence my extreme antipathy towards them generally.


Bitscan Forward and Reverse

Pentium 4 
4 cycle latency

Amd64 
8..10 cycle latency

Core2
2 cycle latency


..so even on the Core2 it is wise to have other work available (more than 1 dependency chain)


If I was to create some sort of "smart division" macro the only real division I would do is 2^32 / divisor (the 32-bit fixed point reciprocal of the divisor)

As long as the divisor is the same as last time, you can use a much cheaper fixed point multiplication strategy at the cost of a compare and conditional (and its potential branch misprediction)


When C++ compilers can be coerced to emit rcl and rcr, I *might* consider using one.