__div_64_32使用的算法

时间:2018-01-05 09:38:54

标签: assembly powerpc integer-division

经过一些研究后,我无法找出Linux内核中__div_64_32函数使用的分割算法:

# arch/powerpc/boot/div64.S
#include "ppc_asm.h"

    .globl __div64_32
__div64_32:
    lwz r5,0(r3)    # get the dividend into r5/r6
    lwz r6,4(r3)
    cmplw   r5,r4
    li  r7,0
    li  r8,0
    blt 1f
    divwu   r7,r5,r4    # if dividend.hi >= divisor,
    mullw   r0,r7,r4    # quotient.hi = dividend.hi / divisor
    subf.   r5,r0,r5    # dividend.hi %= divisor
    beq 3f
1:  mr  r11,r5      # here dividend.hi != 0
    andis.  r0,r5,0xc000
    bne 2f
    cntlzw  r0,r5       # we are shifting the dividend right
    li  r10,-1      # to make it < 2^32, and shifting
    srw r10,r10,r0  # the divisor right the same amount,
    addc    r9,r4,r10   # rounding up (so the estimate cannot
    andc    r11,r6,r10  # ever be too large, only too small)
    andc    r9,r9,r10
    addze   r9,r9
    or  r11,r5,r11
    rotlw   r9,r9,r0
    rotlw   r11,r11,r0
    divwu   r11,r11,r9  # then we divide the shifted quantities
2:  mullw   r10,r11,r4  # to get an estimate of the quotient,
    mulhwu  r9,r11,r4   # multiply the estimate by the divisor,
    subfc   r6,r10,r6   # take the product from the divisor,
    add r8,r8,r11   # and add the estimate to the accumulated
    subfe.  r5,r9,r5    # quotient
    bne 1b
3:  cmplw   r6,r4
    blt 4f
    divwu   r0,r6,r4    # perform the remaining 32-bit division
    mullw   r10,r0,r4   # and get the remainder
    add r8,r8,r0
    subf    r6,r10,r6
4:  stw r7,0(r3)    # return the quotient in *r3
    stw r8,4(r3)
    mr  r3,r6       # return the remainder in r3
    blr

根据我的理解,除法分两个步骤进行,但我对&#34;估计商数&#34;概念。

此外,考虑到功能代码,我不明白这个特定指令的作用:

andis.  r0,r5,0xc000 # why this 0xC000 value ?

有没有人对这段代码有更多解释?

1 个答案:

答案 0 :(得分:2)

主要功能是:

r5:r6 -> r7:r8 * r4 + r6

它被分解为:

0 Load:
    Load from memory
    Set the temp registers
    Make the first division (divwu  r7,r5,r4)

1 Divide Loop:
    Shift left 
    Take carre of carry
    Divide

2 Accumulate Loop:
    Accumulate
    If hight part != 0 goto 1

3 Last low division:
    Divide the low part the old way 32 bit / 32bit

4 Store result:

在第一次除法(第0部分结束)之后,被除数(r5)的高度部分的剩余部分低于除数(r4)。 我们不能再分了。我们必须改变它并记住应用的转变。所以我们计算r5 cntlzw r0,r5中的前导0。我们将股息转移到这个数额,除以,转回。

使用的算法是r5 / r3 =(r5 * 2 ^ x / r3)/ 2 ^ x。困难在于进位,溢出......

你提出了一个很好的问题:为什么andis. r0,r5,0xc000。 来自文档:andis. rz,rv,i: rz16−31 = rv & (i << 16), rz32−63 = rz0−15 = 0。来自python:bin(0xc000 << 16) = 0b11000000000000000000000000000000。因此,如果设置了dividend.hi的第一位或第二位,我们就不应该转移。

第一个被设置好了,我们向零移动这么无用,我们只是松散的时间。如果第二位被设置...我的猜测是我们可能在分割后立即转移时溢出一些东西。特别是因为我们在标签1的开头尽可能地向左移动(尽可能地增大x会减少循环次数)。

最后他称之为估计量,我们称之为累加器。他把它们称为估算器,因为它们每次都会累积较小的数字。

Salut Bordeaux de Rennes!