1 /*===-- udivmodsi4.S - 32-bit unsigned integer divide and modulus ---------===//
3 * The LLVM Compiler Infrastructure
5 * This file is dual licensed under the MIT and the University of Illinois Open
6 * Source Licenses. See LICENSE.TXT for details.
8 *===----------------------------------------------------------------------===//
10 * This file implements the __udivmodsi4 (32-bit unsigned integer divide and
11 * modulus) function for the ARM 32-bit architecture.
13 *===----------------------------------------------------------------------===*/
15 #include "../assembly.h"
20 #if __ARM_ARCH_ISA_THUMB == 2
24 @ unsigned int __udivmodsi4(unsigned int divident, unsigned int divisor,
25 @ unsigned int *remainder)
26 @ Calculate the quotient and remainder of the (unsigned) division. The return
27 @ value is the quotient, the remainder is placed in the variable.
30 #if __ARM_ARCH_ISA_THUMB == 2
31 DEFINE_COMPILERRT_THUMB_FUNCTION(__udivmodsi4)
33 DEFINE_COMPILERRT_FUNCTION(__udivmodsi4)
35 #if __ARM_ARCH_EXT_IDIV__
37 beq LOCAL_LABEL(divby0)
45 bcc LOCAL_LABEL(divby0)
46 beq LOCAL_LABEL(divby1)
48 bcc LOCAL_LABEL(quotient0)
50 * Implement division using binary long division algorithm.
52 * r0 is the numerator, r1 the denominator.
54 * The code before JMP computes the correct shift I, so that
55 * r0 and (r1 << I) have the highest bit set in the same position.
56 * At the time of JMP, ip := .Ldiv0block - 12 * I.
57 * This depends on the fixed instruction size of block.
58 * For ARM mode, this is 12 Bytes, for THUMB mode 14 Bytes.
60 * block(shift) implements the test-and-update-quotient core.
61 * It assumes (r0 << shift) can be computed without overflow and
62 * that (r0 << shift) < 2 * r1. The quotient is stored in r3.
65 # ifdef __ARM_FEATURE_CLZ
68 /* r0 >= r1 implies clz(r0) <= clz(r1), so ip <= r3. */
70 # if __ARM_ARCH_ISA_THUMB == 2
71 adr ip, LOCAL_LABEL(div0block) + 1
72 sub ip, ip, r3, lsl #1
74 adr ip, LOCAL_LABEL(div0block)
76 sub ip, ip, r3, lsl #2
77 sub ip, ip, r3, lsl #3
81 # if __ARM_ARCH_ISA_THUMB == 2
82 # error THUMB mode requires CLZ or UDIV
87 adr ip, LOCAL_LABEL(div0block)
92 subhs ip, ip, #(16 * 12)
97 subhs ip, ip, #(8 * 12)
107 subhs ip, ip, #(2 * 12)
109 /* Last block, no need to update r3 or r4. */
111 subls ip, ip, #(1 * 12)
113 ldr r4, [sp], #8 /* restore r4, we are done with it. */
121 #define block(shift) \
122 cmp r0, r1, lsl IMM shift; \
124 WIDE(addhs) r3, r3, IMM (1 << shift); \
125 WIDE(subhs) r0, r0, r1, lsl IMM shift
158 LOCAL_LABEL(div0block):
165 LOCAL_LABEL(quotient0):
174 #endif /* __ARM_ARCH_EXT_IDIV__ */
184 END_COMPILERRT_FUNCTION(__udivmodsi4)
186 NO_EXEC_STACK_DIRECTIVE