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"
21 @ unsigned int __udivmodsi4(unsigned int divident, unsigned int divisor,
22 @ unsigned int *remainder)
23 @ Calculate the quotient and remainder of the (unsigned) division. The return
24 @ value is the quotient, the remainder is placed in the variable.
27 DEFINE_COMPILERRT_FUNCTION(__udivmodsi4)
28 #if __ARM_ARCH_EXT_IDIV__
30 beq LOCAL_LABEL(divby0)
38 bcc LOCAL_LABEL(divby0)
39 beq LOCAL_LABEL(divby1)
41 bcc LOCAL_LABEL(quotient0)
43 * Implement division using binary long division algorithm.
45 * r0 is the numerator, r1 the denominator.
47 * The code before JMP computes the correct shift I, so that
48 * r0 and (r1 << I) have the highest bit set in the same position.
49 * At the time of JMP, ip := .Ldiv0block - 12 * I.
50 * This depends on the fixed instruction size of block.
51 * For ARM mode, this is 12 Bytes, for THUMB mode 14 Bytes.
53 * block(shift) implements the test-and-update-quotient core.
54 * It assumes (r0 << shift) can be computed without overflow and
55 * that (r0 << shift) < 2 * r1. The quotient is stored in r3.
58 # ifdef __ARM_FEATURE_CLZ
61 /* r0 >= r1 implies clz(r0) <= clz(r1), so ip <= r3. */
63 # if defined(USE_THUMB_2)
64 adr ip, LOCAL_LABEL(div0block) + 1
65 sub ip, ip, r3, lsl #1
67 adr ip, LOCAL_LABEL(div0block)
69 sub ip, ip, r3, lsl #2
70 sub ip, ip, r3, lsl #3
74 # if defined(USE_THUMB_2)
75 # error THUMB mode requires CLZ or UDIV
80 adr ip, LOCAL_LABEL(div0block)
85 subhs ip, ip, #(16 * 12)
90 subhs ip, ip, #(8 * 12)
100 subhs ip, ip, #(2 * 12)
102 /* Last block, no need to update r3 or r4. */
104 subls ip, ip, #(1 * 12)
106 ldr r4, [sp], #8 /* restore r4, we are done with it. */
114 #define block(shift) \
115 cmp r0, r1, lsl IMM shift; \
117 WIDE(addhs) r3, r3, IMM (1 << shift); \
118 WIDE(subhs) r0, r0, r1, lsl IMM shift
151 LOCAL_LABEL(div0block):
158 LOCAL_LABEL(quotient0):
167 #endif /* __ARM_ARCH_EXT_IDIV__ */
177 END_COMPILERRT_FUNCTION(__udivmodsi4)
179 NO_EXEC_STACK_DIRECTIVE