1 /*===-- umodsi3.S - 32-bit unsigned integer 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 __umodsi3 (32-bit unsigned integer modulus)
11 * function for the ARM 32-bit architecture.
13 *===----------------------------------------------------------------------===*/
15 #include "../assembly.h"
19 #if __ARM_ARCH_ISA_THUMB == 2
23 @ unsigned int __umodsi3(unsigned int divident, unsigned int divisor)
24 @ Calculate and return the remainder of the (unsigned) division.
27 #if __ARM_ARCH_ISA_THUMB == 2
28 DEFINE_COMPILERRT_THUMB_FUNCTION(__umodsi3)
30 DEFINE_COMPILERRT_FUNCTION(__umodsi3)
32 #if __ARM_ARCH_EXT_IDIV__
34 beq LOCAL_LABEL(divby0)
40 bcc LOCAL_LABEL(divby0)
48 * Implement division using binary long division algorithm.
50 * r0 is the numerator, r1 the denominator.
52 * The code before JMP computes the correct shift I, so that
53 * r0 and (r1 << I) have the highest bit set in the same position.
54 * At the time of JMP, ip := .Ldiv0block - 8 * I.
55 * This depends on the fixed instruction size of block.
56 * For ARM mode, this is 8 Bytes, for THUMB mode 10 Bytes.
58 * block(shift) implements the test-and-update-quotient core.
59 * It assumes (r0 << shift) can be computed without overflow and
60 * that (r0 << shift) < 2 * r1. The quotient is stored in r3.
63 # ifdef __ARM_FEATURE_CLZ
66 /* r0 >= r1 implies clz(r0) <= clz(r1), so ip <= r3. */
68 # if __ARM_ARCH_ISA_THUMB == 2
69 adr ip, LOCAL_LABEL(div0block) + 1
70 sub ip, ip, r3, lsl #1
72 adr ip, LOCAL_LABEL(div0block)
74 sub ip, ip, r3, lsl #3
77 # if __ARM_ARCH_ISA_THUMB == 2
78 # error THUMB mode requires CLZ or UDIV
81 adr ip, LOCAL_LABEL(div0block)
86 subhs ip, ip, #(16 * 8)
91 subhs ip, ip, #(8 * 8)
101 subhs ip, ip, #(2 * 8)
103 /* Last block, no need to update r2 or r3. */
105 subls ip, ip, #(1 * 8)
112 #define block(shift) \
113 cmp r0, r1, lsl IMM shift; \
115 WIDE(subhs) r0, r0, r1, lsl IMM shift
148 LOCAL_LABEL(div0block):
151 #endif /* __ARM_ARCH_EXT_IDIV__ */
161 END_COMPILERRT_FUNCTION(__umodsi3)