1 //===-- udivmodsi4.S - 32-bit unsigned integer divide and modulus ---------===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
9 // This file implements the __udivmodsi4 (32-bit unsigned integer divide and
10 // modulus) function for the ARM 32-bit architecture.
12 //===----------------------------------------------------------------------===//
14 #include "../assembly.h"
20 @ unsigned int __udivmodsi4(unsigned int divident, unsigned int divisor,
21 @ unsigned int *remainder)
22 @ Calculate the quotient and remainder of the (unsigned) division. The return
23 @ value is the quotient, the remainder is placed in the variable.
26 DEFINE_COMPILERRT_FUNCTION(__udivmodsi4)
27 #if __ARM_ARCH_EXT_IDIV__
29 beq LOCAL_LABEL(divby0)
37 bcc LOCAL_LABEL(divby0)
38 beq LOCAL_LABEL(divby1)
40 bcc LOCAL_LABEL(quotient0)
42 // Implement division using binary long division algorithm.
44 // r0 is the numerator, r1 the denominator.
46 // The code before JMP computes the correct shift I, so that
47 // r0 and (r1 << I) have the highest bit set in the same position.
48 // At the time of JMP, ip := .Ldiv0block - 12 * I.
49 // This depends on the fixed instruction size of block.
50 // For ARM mode, this is 12 Bytes, for THUMB mode 14 Bytes.
52 // block(shift) implements the test-and-update-quotient core.
53 // It assumes (r0 << shift) can be computed without overflow and
54 // that (r0 << shift) < 2 * r1. The quotient is stored in r3.
56 # ifdef __ARM_FEATURE_CLZ
59 // r0 >= r1 implies clz(r0) <= clz(r1), so ip <= r3.
61 # if defined(USE_THUMB_2)
62 adr ip, LOCAL_LABEL(div0block) + 1
63 sub ip, ip, r3, lsl #1
65 adr ip, LOCAL_LABEL(div0block)
67 sub ip, ip, r3, lsl #2
68 sub ip, ip, r3, lsl #3
72 # if defined(USE_THUMB_2)
73 # error THUMB mode requires CLZ or UDIV
78 adr ip, LOCAL_LABEL(div0block)
83 subhs ip, ip, #(16 * 12)
88 subhs ip, ip, #(8 * 12)
98 subhs ip, ip, #(2 * 12)
100 // Last block, no need to update r3 or r4.
102 subls ip, ip, #(1 * 12)
104 ldr r4, [sp], #8 // restore r4, we are done with it.
112 #define block(shift) \
113 cmp r0, r1, lsl IMM shift; \
115 WIDE(addhs) r3, r3, IMM (1 << shift); \
116 WIDE(subhs) r0, r0, r1, lsl IMM shift
149 LOCAL_LABEL(div0block):
156 LOCAL_LABEL(quotient0):
165 #endif // __ARM_ARCH_EXT_IDIV__
175 END_COMPILERRT_FUNCTION(__udivmodsi4)
177 NO_EXEC_STACK_DIRECTIVE