ASMMultU64ByU32DivByU32.asm revision e64031e20c39650a7bc902a3e1aba613b9415dee
; $Id$
;; @file
; IPRT - Assembly Functions, ASMMultU64ByU32DivByU32.
;
;
; Copyright (C) 2006-2007 Oracle Corporation
;
; This file is part of VirtualBox Open Source Edition (OSE), as
; available from http://www.virtualbox.org. This file is free software;
; you can redistribute it and/or modify it under the terms of the GNU
; General Public License (GPL) as published by the Free Software
; Foundation, in version 2 as it comes in the "COPYING" file of the
; VirtualBox OSE distribution. VirtualBox OSE is distributed in the
; hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
;
; The contents of this file may alternatively be used under the terms
; of the Common Development and Distribution License Version 1.0
; (CDDL) only, as it comes in the "COPYING.CDDL" file of the
; VirtualBox OSE distribution, in which case the provisions of the
; CDDL are applicable instead of those of the GPL.
;
; You may elect to license modified versions of this file under the
; terms and conditions of either the GPL or the CDDL or both.
;
%include "iprt/asmdefs.mac"
;;
; Multiple a 64-bit by a 32-bit integer and divide the result by a 32-bit integer
; using a 96 bit intermediate result.
;
; @returns (u64A * u32B) / u32C.
; @param u64A/rcx/rdi The 64-bit value.
; @param u32B/edx/esi The 32-bit value to multiple by A.
; @param u32C/r8d/edx The 32-bit value to divide A*B by.
;
; @cproto DECLASM(uint64_t) ASMMultU64ByU32DivByU32(uint64_t u64A, uint32_t u32B, uint32_t u32C);
;
BEGINPROC_EXPORTED ASMMultU64ByU32DivByU32
%ifdef RT_ARCH_AMD64
%ifdef ASM_CALL64_MSC
mov rax, rcx ; rax = u64A
mov r9d, edx ; should check the specs wrt to the high bits one day...
mov r8d, r8d ; be paranoid for the time being.
%else
mov rax, rdi ; rax = u64A
mov r9d, esi ; r9d = u32B
mov r8d, edx ; r8d = u32C
%endif
mul r9
div r8
%else ; X86
;
; This implementation is convered from the GCC inline
; version of the code. Nothing additional has been done
; performance wise.
;
push esi
push edi
%define u64A_Lo [esp + 04h + 08h]
%define u64A_Hi [esp + 08h + 08h]
%define u32B [esp + 0ch + 08h]
%define u32C [esp + 10h + 08h]
; Load parameters into registers.
mov eax, u64A_Lo
mov esi, u64A_Hi
mov ecx, u32B
mov edi, u32C
; The body, just like the in
mul ecx ; eax = u64Lo.lo = (u64A.lo * u32B).lo
; edx = u64Lo.hi = (u64A.lo * u32B).hi
xchg eax, esi ; esi = u64Lo.lo
; eax = u64A.hi
xchg edx, edi ; edi = u64Low.hi
; edx = u32C
xchg edx, ecx ; ecx = u32C
; edx = u32B
mul edx ; eax = u64Hi.lo = (u64A.hi * u32B).lo
; edx = u64Hi.hi = (u64A.hi * u32B).hi
add eax, edi ; u64Hi.lo += u64Lo.hi
adc edx, 0 ; u64Hi.hi += carry
div ecx ; eax = u64Hi / u32C
; edx = u64Hi % u32C
mov edi, eax ; edi = u64Result.hi = u64Hi / u32C
mov eax, esi ; eax = u64Lo.lo
div ecx ; u64Result.lo
mov edx, edi ; u64Result.hi
; epilogue
pop edi
pop esi
%endif
ret
ENDPROC ASMMultU64ByU32DivByU32