Registriert seit: 13. Aug 2003
1.111 Beiträge
|
asm MulDiv64 C übersetzung stürzt ab ...
19. Feb 2008, 06:21
beim Übersetzen eines C Quelltextes tritt noch ein GleitkommadivisionsFehler auf...
Wissen die Assembler Profis mehr?
Vielen Dank schonmal !!
Delphi-Quellcode:
type Var128 = packed record
DW : array[0..3] of DWORD;
end;
function xMulDiv64(operant, multiplier, divider : int64) : int64; stdcall;
var
quotient : Var128;
// // Declare 128bit storage
// struct{
// unsigned long DW[4];
// }var128, quotient;
// // Change semantics for intermediate results for Full Div
// // by renaming the vars
// #define REMAINDER quotient
// #define QUOTIENT edi
begin
asm
mov eax, dword ptr[operant+4]
xor eax, dword ptr[multiplier+4]
xor eax, dword ptr[divider+4]
pushfd
end;
// Take absolute values because algorithm is for unsigned only
operant := ABS(operant);
multiplier := ABS(multiplier);
divider := ABS(divider);
asm
// First check divider for 0
mov eax, dword ptr[divider+4]
or eax, dword ptr[divider]
jnz @@dividerOK
div eax
@@dividerOK:
lea edi,[var128] // edi = &var128
// Check multiplier for 1 or 0
xor eax, eax
cmp eax, dword ptr[multiplier+4]
jnz @@startMUL
cmp eax, dword ptr[multiplier]
jnz @@multiNotNUL
xor edx, edx
popfd // cleanup stack
jmp @@done
@@multiNotNUL:
// Set result HI part to 0
xor eax,eax
mov dword ptr[edi+12], eax
mov dword ptr[edi+8], eax
mov eax, 1
cmp eax, dword ptr[multiplier]
jnz @@smallMUL
// Multiplier is 1 so just copy operant to result
mov eax, dword ptr[operant+4]
mov dword ptr[edi+4], eax
mov eax, dword ptr[operant]
mov dword ptr[edi], eax
jmp @@startDIV
@@smallMUL:
// Test for 32/32 bit multiplication
xor eax, eax
mov ecx, dword ptr[operant+4]
or ecx, eax //;test for both hiwords zero.
jnz @@startMUL
// Do 32/32 bit multiplication
mov ecx, dword ptr[multiplier]
mov eax, dword ptr[operant]
mul ecx
mov dword ptr[edi+4], edx
mov dword ptr[edi], eax
jmp @@startDIV
@@startMUL:
// Check signs
// Multiply: var128 = operant * multiplier
mov eax, dword ptr[multiplier] // eax = LO(multiplier)
mul dword ptr[operant] // edx:eax = eax * LO(operant)
mov dword ptr[edi], eax // var128.DW0 = eax
mov ecx, edx // ecx = edx
mov eax, dword ptr[multiplier] // eax = LO(multiplier)
mul dword ptr[operant+4] // edx:eax = eax * HI(operant)
add eax, ecx // eax = eax + ecx
adc edx, 0 // edx = edx + 0 + carry
mov ebx, eax
mov ecx, edx
mov eax, dword ptr[multiplier+4]
mul dword ptr[operant]
add eax, ebx
mov dword ptr[edi+4], eax
adc ecx, edx
pushfd
mov eax, dword ptr[multiplier+4]
mul dword ptr[operant+4]
popfd
adc eax, ecx
adc edx, 0
mov dword ptr[edi+8], eax
mov dword ptr[edi+12], edx
@@startDIV:
// Divide: var128 = var128 / divider
//
// Test divider = 32bit value
mov eax, dword ptr[divider+4]
cmp eax, 0
jnz @@fullDIV
mov ecx, dword ptr[divider]
cmp ecx, 1
jz @@applySign
// Start 128/32 bit division
mov eax, dword ptr[edi+12]
xor edx, edx
div ecx
mov dword ptr[quotient+12], eax
mov eax, dword ptr[edi+8]
div ecx
mov dword ptr[quotient+8], eax
mov eax, dword ptr[edi+4]
div ecx
mov dword ptr[quotient+4], eax
mov eax, dword ptr[edi]
div ecx
mov dword ptr[quotient], eax
// Copy the quotient to the result storage (var128)
mov eax, dword ptr[quotient+12]
mov dword ptr[edi+12], eax
mov eax, dword ptr[quotient+8]
mov dword ptr[edi+8], eax
mov eax, dword ptr[quotient+4]
mov dword ptr[edi+4], eax
mov eax, dword ptr[quotient]
mov dword ptr[edi], eax
// To sign correction and return
jmp @@applySign
@@fullDIV:
// Full 128/64 bit division
xor eax, eax
mov dword ptr[quotient+12], eax
mov dword ptr[quotient+8], eax
mov dword ptr[quotient+4], eax
mov dword ptr[quotient], eax
mov ecx, 128
@@loop1:
// Compute REMAINDER:QUOTIENT = REMAINDER:QUOTIENT shl 1
shl dword ptr[edi], 1
rcl dword ptr[edi+4], 1
rcl dword ptr[edi+8], 1
rcl dword ptr[edi+12], 1
rcl dword ptr[quotient], 1
rcl dword ptr[quotient+4], 1
rcl dword ptr[quotient+8], 1
rcl dword ptr[quotient+12], 1
// Test (REMAINDER >= Divider)
xor eax, eax
cmp dword ptr[quotient+12], eax
ja @@iftrue
jb @@iffalse
cmp dword ptr[quotient+8], eax
ja @@iftrue
jb @@iffalse
mov eax, dword ptr[quotient+4]
cmp eax, dword ptr[divider+4]
ja @@iftrue
jb @@iffalse
mov eax, dword ptr[quotient]
cmp eax, dword ptr[divider]
jb @@iffalse
@@iftrue:
// Remainder = remainder - divider
mov eax, dword ptr[divider]
sub dword ptr[quotient], eax
mov eax, dword ptr[divider+4]
sbb dword ptr[quotient+4], eax
xor eax, eax
sbb dword ptr[quotient+8], eax
sbb dword ptr[quotient+12], eax
// Quotient = quotient +1
add dword ptr[edi], 1
adc dword ptr[edi+4], 0
adc dword ptr[edi+8], 0
adc dword ptr[edi+12], 0
@@iffalse:
// Loop size = 101 bytes, is less than 127 so loop is possible
loop @@loop1
@@applySign:
// Correct the sign of the result based on the stored combined sign
popfd
jns @@storeRes
not dword ptr[edi+12]
not dword ptr[edi+ 8]
not dword ptr[edi+ 4]
not dword ptr[edi]
add dword ptr[edi], 1
adc dword ptr[edi+ 4], 0
adc dword ptr[edi+ 8], 0
adc dword ptr[edi+12], 0
@@storeRES:
// Get low order qword from var128
mov edx, dword ptr[edi+4]
mov eax, dword ptr[edi]
@@done:
// result is returned in edx:eax
END;
end;
Delphi-Quellcode:
/*
* Source file: MulDiv64.cpp
* Author: Richard van der Wal
* Contact: [email]R.vdWal@xs4all.nl[/email]
*
* Description:
* Implementation for MulDiv64 and MulShr64
*
* $Log: $
*/
/*
* MulDiv64
* Multiplies an operant by a multiplier and divides the result by a divider
* Used for scaling 64 bit integer values
* Xscaled = Xstart * Multiplier / Divider
* Uses 128 bit intermediate result
*/
#define ABS64(num) (num >=0 ? num : -num)
//
__int64 _stdcall MulDiv64(__int64 operant, __int64 multiplier, __int64 divider)
{
// Declare 128bit storage
struct{
unsigned long DW[4];
}var128, quotient;
// Change semantics for intermediate results for Full Div
// by renaming the vars
#define REMAINDER quotient
#define QUOTIENT edi
// Save combined sign on stack
_asm{
mov eax, dword ptr[operant+4]
xor eax, dword ptr[multiplier+4]
xor eax, dword ptr[divider+4]
pushfd
}
// Take absolute values because algorithm is for unsigned only
operant = ABS64(operant);
multiplier = ABS64(multiplier);
divider = ABS64(divider);
_asm{
// First check divider for 0
mov eax, dword ptr[divider+4]
or eax, dword ptr[divider]
jnz dividerOK
div eax
dividerOK:
lea edi,[var128] // edi = &var128
// Check multiplier for 1 or 0
xor eax, eax
cmp eax, dword ptr[multiplier+4]
jnz startMUL
cmp eax, dword ptr[multiplier]
jnz multiNotNUL
xor edx, edx
popfd // cleanup stack
jmp done
multiNotNUL:
// Set result HI part to 0
xor eax,eax
mov dword ptr[edi+12], eax
mov dword ptr[edi+8], eax
mov eax, 1
cmp eax, dword ptr[multiplier]
jnz smallMUL
// Multiplier is 1 so just copy operant to result
mov eax, dword ptr[operant+4]
mov dword ptr[edi+4], eax
mov eax, dword ptr[operant]
mov dword ptr[edi], eax
jmp startDIV
smallMUL:
// Test for 32/32 bit multiplication
xor eax, eax
mov ecx, dword ptr[operant+4]
or ecx, eax ;test for both hiwords zero.
jnz startMUL
// Do 32/32 bit multiplication
mov ecx, dword ptr[multiplier]
mov eax, dword ptr[operant]
mul ecx
mov dword ptr[edi+4], edx
mov dword ptr[edi], eax
jmp startDIV
startMUL:
// Check signs
// Multiply: var128 = operant * multiplier
mov eax, dword ptr[multiplier] // eax = LO(multiplier)
mul dword ptr[operant] // edx:eax = eax * LO(operant)
mov dword ptr[edi], eax // var128.DW0 = eax
mov ecx, edx // ecx = edx
mov eax, dword ptr[multiplier] // eax = LO(multiplier)
mul dword ptr[operant+4] // edx:eax = eax * HI(operant)
add eax, ecx // eax = eax + ecx
adc edx, 0 // edx = edx + 0 + carry
mov ebx, eax
mov ecx, edx
mov eax, dword ptr[multiplier+4]
mul dword ptr[operant]
add eax, ebx
mov dword ptr[edi+4], eax
adc ecx, edx
pushfd
mov eax, dword ptr[multiplier+4]
mul dword ptr[operant+4]
popfd
adc eax, ecx
adc edx, 0
mov dword ptr[edi+8], eax
mov dword ptr[edi+12], edx
startDIV:
// Divide: var128 = var128 / divider
//
// Test divider = 32bit value
mov eax, dword ptr[divider+4]
cmp eax, 0
jnz fullDIV
mov ecx, dword ptr[divider]
cmp ecx, 1
jz applySign
// Start 128/32 bit division
mov eax, dword ptr[edi+12]
xor edx, edx
div ecx
mov dword ptr[quotient+12], eax
mov eax, dword ptr[edi+8]
div ecx
mov dword ptr[quotient+8], eax
mov eax, dword ptr[edi+4]
div ecx
mov dword ptr[quotient+4], eax
mov eax, dword ptr[edi]
div ecx
mov dword ptr[quotient], eax
// Copy the quotient to the result storage (var128)
mov eax, dword ptr[quotient+12]
mov dword ptr[edi+12], eax
mov eax, dword ptr[quotient+8]
mov dword ptr[edi+8], eax
mov eax, dword ptr[quotient+4]
mov dword ptr[edi+4], eax
mov eax, dword ptr[quotient]
mov dword ptr[edi], eax
// To sign correction and return
jmp applySign
fullDIV:
// Full 128/64 bit division
xor eax, eax
mov dword ptr[REMAINDER+12], eax
mov dword ptr[REMAINDER+8], eax
mov dword ptr[REMAINDER+4], eax
mov dword ptr[REMAINDER], eax
mov ecx, 128
loop1:
// Compute REMAINDER:QUOTIENT = REMAINDER:QUOTIENT shl 1
shl dword ptr[QUOTIENT], 1
rcl dword ptr[QUOTIENT+4], 1
rcl dword ptr[QUOTIENT+8], 1
rcl dword ptr[QUOTIENT+12], 1
rcl dword ptr[REMAINDER], 1
rcl dword ptr[REMAINDER+4], 1
rcl dword ptr[REMAINDER+8], 1
rcl dword ptr[REMAINDER+12], 1
// Test (REMAINDER >= Divider)
xor eax, eax
cmp dword ptr[REMAINDER+12], eax
ja iftrue
jb iffalse
cmp dword ptr[REMAINDER+8], eax
ja iftrue
jb iffalse
mov eax, dword ptr[REMAINDER+4]
cmp eax, dword ptr[divider+4]
ja iftrue
jb iffalse
mov eax, dword ptr[REMAINDER]
cmp eax, dword ptr[divider]
jb iffalse
iftrue:
// Remainder = remainder - divider
mov eax, dword ptr[divider]
sub dword ptr[REMAINDER], eax
mov eax, dword ptr[divider+4]
sbb dword ptr[REMAINDER+4], eax
xor eax, eax
sbb dword ptr[REMAINDER+8], eax
sbb dword ptr[REMAINDER+12], eax
// Quotient = quotient +1
add dword ptr[QUOTIENT], 1
adc dword ptr[QUOTIENT+4], 0
adc dword ptr[QUOTIENT+8], 0
adc dword ptr[QUOTIENT+12], 0
iffalse:
// Loop size = 101 bytes, is less than 127 so loop is possible
loop loop1
applySign:
// Correct the sign of the result based on the stored combined sign
popfd
jns storeRes
not dword ptr[edi+12]
not dword ptr[edi+ 8]
not dword ptr[edi+ 4]
not dword ptr[edi]
add dword ptr[edi], 1
adc dword ptr[edi+ 4], 0
adc dword ptr[edi+ 8], 0
adc dword ptr[edi+12], 0
storeRES:
// Get low order qword from var128
mov edx, dword ptr[edi+4]
mov eax, dword ptr[edi]
done:
}
// result is returned in edx:eax
}
Phantasie ist etwas, was sich manche Leute gar nicht vorstellen können.
|