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"
19 #if defined(USE_THUMB_PROLOGUE)
23 @ unsigned int __udivmodsi4(unsigned int divident, unsigned int divisor,
24 @ unsigned int *remainder)
25 @ Calculate the quotient and remainder of the (unsigned) division. The return
26 @ value is the quotient, the remainder is placed in the variable.
29 #if defined(USE_THUMB_PROLOGUE)
30 DEFINE_COMPILERRT_THUMB_FUNCTION(__udivmodsi4)
32 DEFINE_COMPILERRT_FUNCTION(__udivmodsi4)
34 #if __ARM_ARCH_EXT_IDIV__
36 beq LOCAL_LABEL(divby0)
44 bcc LOCAL_LABEL(divby0)
45 beq LOCAL_LABEL(divby1)
47 bcc LOCAL_LABEL(quotient0)
49 * Implement division using binary long division algorithm.
51 * r0 is the numerator, r1 the denominator.
53 * The code before JMP computes the correct shift I, so that
54 * r0 and (r1 << I) have the highest bit set in the same position.
55 * At the time of JMP, ip := .Ldiv0block - 12 * I.
56 * This depends on the fixed instruction size of block.
57 * For ARM mode, this is 12 Bytes, for THUMB mode 14 Bytes.
59 * block(shift) implements the test-and-update-quotient core.
60 * It assumes (r0 << shift) can be computed without overflow and
61 * that (r0 << shift) < 2 * r1. The quotient is stored in r3.
64 # ifdef __ARM_FEATURE_CLZ
67 /* r0 >= r1 implies clz(r0) <= clz(r1), so ip <= r3. */
69 # if defined(USE_THUMB_2)
70 adr ip, LOCAL_LABEL(div0block) + 1
71 sub ip, ip, r3, lsl #1
73 adr ip, LOCAL_LABEL(div0block)
75 sub ip, ip, r3, lsl #2
76 sub ip, ip, r3, lsl #3
80 # if defined(USE_THUMB_2)
81 # error THUMB mode requires CLZ or UDIV
86 adr ip, LOCAL_LABEL(div0block)
91 subhs ip, ip, #(16 * 12)
96 subhs ip, ip, #(8 * 12)
106 subhs ip, ip, #(2 * 12)
108 /* Last block, no need to update r3 or r4. */
110 subls ip, ip, #(1 * 12)
112 ldr r4, [sp], #8 /* restore r4, we are done with it. */
120 #define block(shift) \
121 cmp r0, r1, lsl IMM shift; \
123 WIDE(addhs) r3, r3, IMM (1 << shift); \
124 WIDE(subhs) r0, r0, r1, lsl IMM shift
157 LOCAL_LABEL(div0block):
164 LOCAL_LABEL(quotient0):
173 #endif /* __ARM_ARCH_EXT_IDIV__ */
183 END_COMPILERRT_FUNCTION(__udivmodsi4)
185 NO_EXEC_STACK_DIRECTIVE