0

I need to divide an unsigned 128-Bit number on a 64-Bit Processor at the Register rdx:rax with a 64-Bit divisor in rdi. The lower Bits are in raxand the higher ones in rdx. However the DIV-Instruction only supports 64/64 Bit divisions.

My approach was to save rax, the lower Bits of the number, in another Register and left-shift the Bits from the rdx-Register bitwise into rax to perform a long division with rdi. And save the computational steps in another Register to build up the solution Step-by-Step.

But I think there has to be a more efficient approach. Are there instruction which support this kind of calculations between several Registers?

HeapUnderStop
  • 378
  • 1
  • 9
  • 4
    @MooingDuck: x86-64 `div` does 128-bit/64-bit => 64-bit quotient narrowing division in hardware. The usual algorithm is `div` of high-half / divisor, leaving the remainder in RDX as the high half of the dividend for the second division. With RAX = the low half of the original dividend. (The 64-bit remainder is obtained directly as shown in [Why should EDX be 0 before using the DIV instruction?](https://stackoverflow.com/q/38416593) for the general n-limb/1-limb case; the 128-bit quotient is I think computed from both partial quotients.) – Peter Cordes Apr 19 '23 at 23:30
  • I realized I'd misread the question and am *way* out of my depth – Mooing Duck Apr 19 '23 at 23:33
  • 3
    First divide the high 64 bit using `div`. Remember what you got, it's the high 64 bit of the quotient. Keep the reminder in `rdx` and move the low 64 bit to `rax`. Then another `div` to get the low 64 bit of the quotient and the remainder. – fuz Apr 19 '23 at 23:52

1 Answers1

2

Dividing the unsigned 128-bit number held in RDX:RAX by the 64-bit number held in RDI

On x86-64 a cascade of 2 divisions is needed to divide the 128-bit value in RDX:RAX by a 64-bit value.
The 1st division divides the high dividend (extended with 0) yielding a high quotient. The 2nd division divides the low dividend (extended with the remainder from the 1st division) yielding the low quotient. It's the remainder from the 2nd division that we return in RCX.

; IN (RDX:RAX,RDI) OUT (RDX:RAX,RCX)
    mov     rcx, rax       ; Temporarily store LowDividend in RCX
    mov     rax, rdx       ; First divide the HighDividend
    xor     edx, edx       ; Setup for division RDX:RAX / RDI
    div     rdi            ; -> RAX is HighQuotient, Remainder is re-used
    xchg    rax, rcx       ; Temporarily move HighQuotient to RCX restoring LowDividend to RAX
    div     rdi            ; -> RAX is LowQuotient, Remainder RDX
    xchg    rdx, rcx       ; Build true 128-bit quotient in RDX:RAX
    ret                    ; and return remainder in RCX=[0,RDI-1]
Sep Roland
  • 33,889
  • 7
  • 43
  • 76