2024-04-04 04:18:36 -06:00

95 lines
2.1 KiB
ArmAsm

.syntax unified
/*
* Calculates rx / 10 and places the result in rd. Clobbers the value of
* temporary register rt. The value in rx is unmodified.
*
* 0xCCCCCCCD >> 35 approximately equals 0.1
* Performs a 64 bit multiply of 0xCCCCCCCD and rx, shifts the high 32 bits
* by 3, and discards the low bits. This results in a division by 10 that
* works for all unsigned values of rx. This satifies the constraints of
* the Granlund-Montgomery integer division algorithm.
*/
.macro udiv10 rd, rx, rt
ldr \rt, =0xCCCCCCCD
umull \rt, \rd, \rx, \rt
lsrs \rd, $3
.endm
.macro udiv100 rd, rx, rt
ldr \rt, =0x51EB851F
umull \rt, \rd, \rx, \rt
lsrs \rd, $5
.endm
.macro udiv1000 rd, rx, rt
ldr \rt, =0x10624DD3
umull \rt, \rd, \rx, \rt
lsrs \rd, $6
.endm
.macro udiv10000 rd, rx, rt
ldr \rt, =0xD1B71759
umull \rt, \rd, \rx, \rt
lsrs \rd, $13
.endm
/*
* When using the Granlund-Montgomery integer division algorithm, the magic
* number produced does not fit inside the int32 range. GM produces:
* m = 0x14F8B588F
* k = 17
*
* This division uses the output produces by clang for a division by 100000.
* I don't understand why it works, but it does. It also needs one extra
* temporary register to preserve the value of rx.
*/
.macro udiv100000 rd, rx, rt, rtt
lsr \rtt, \rx, $5
ldr \rt, =0xA7C5AC5
umull \rt, \rd, \rtt, \rt
lsrs \rd, $7
.endm
.macro udiv1000000 rd, rx, rt
ldr \rt, =0x431BDE83
umull \rt, \rd, \rx, \rt
lsrs \rd, $18
.endm
.macro udiv10000000 rd, rx, rt
ldr \rt, =0x6B5FCA6B
umull \rt, \rd, \rx, \rt
lsrs \rd, $22
.endm
.macro udiv100000000 rd, rx, rt
ldr \rt, =0x55E63B89
umull \rt, \rd, \rx, \rt
lsrs \rd, $25
.endm
/*
* Same situation as udiv100000
*/
.macro udiv1000000000 rd, rx, rt, rtt
lsr \rtt, \rx, $9
ldr \rt, =0x44B83
umull \rt, \rd, \rtt, \rt
lsrs \rd, $7
.endm
/*
* Calculates rx % 10 and places the result in rd. Clobbers the value of
* temporary register rt
*
* Calculates the modulo by calculating the truncated division by 10,
* multiplying by 10, and finding the difference between the original value.
*/
.macro umod10 rd, rx, rt
udiv10 \rd, \rx, \rt
mov \rt, $10
mul \rd, \rt
subs \rd, \rx, \rd
.endm