1156cd587Sjoerg/*===-- udivmodsi4.S - 32-bit unsigned integer divide and modulus ---------===// 2156cd587Sjoerg * 3156cd587Sjoerg * The LLVM Compiler Infrastructure 4156cd587Sjoerg * 5156cd587Sjoerg * This file is dual licensed under the MIT and the University of Illinois Open 6156cd587Sjoerg * Source Licenses. See LICENSE.TXT for details. 7156cd587Sjoerg * 8156cd587Sjoerg *===----------------------------------------------------------------------===// 9156cd587Sjoerg * 10156cd587Sjoerg * This file implements the __udivmodsi4 (32-bit unsigned integer divide and 11156cd587Sjoerg * modulus) function for the ARM 32-bit architecture. 12156cd587Sjoerg * 13156cd587Sjoerg *===----------------------------------------------------------------------===*/ 14156cd587Sjoerg 15156cd587Sjoerg#include "../assembly.h" 16156cd587Sjoerg 17156cd587Sjoerg .syntax unified 18156cd587Sjoerg .text 19190e92d8Sjoerg 20190e92d8Sjoerg#if __ARM_ARCH_ISA_THUMB == 2 21190e92d8Sjoerg .thumb 22190e92d8Sjoerg#endif 23190e92d8Sjoerg 24190e92d8Sjoerg@ unsigned int __udivmodsi4(unsigned int divident, unsigned int divisor, 25190e92d8Sjoerg@ unsigned int *remainder) 26190e92d8Sjoerg@ Calculate the quotient and remainder of the (unsigned) division. The return 27190e92d8Sjoerg@ value is the quotient, the remainder is placed in the variable. 28190e92d8Sjoerg 29156cd587Sjoerg .p2align 2 30*ef84fd3bSjoerg#if __ARM_ARCH_ISA_THUMB == 2 31*ef84fd3bSjoergDEFINE_COMPILERRT_THUMB_FUNCTION(__udivmodsi4) 32*ef84fd3bSjoerg#else 33156cd587SjoergDEFINE_COMPILERRT_FUNCTION(__udivmodsi4) 34*ef84fd3bSjoerg#endif 35156cd587Sjoerg#if __ARM_ARCH_EXT_IDIV__ 36156cd587Sjoerg tst r1, r1 37156cd587Sjoerg beq LOCAL_LABEL(divby0) 38156cd587Sjoerg mov r3, r0 39156cd587Sjoerg udiv r0, r3, r1 40156cd587Sjoerg mls r1, r0, r1, r3 41156cd587Sjoerg str r1, [r2] 42156cd587Sjoerg bx lr 43156cd587Sjoerg#else 44156cd587Sjoerg cmp r1, #1 45156cd587Sjoerg bcc LOCAL_LABEL(divby0) 46156cd587Sjoerg beq LOCAL_LABEL(divby1) 47156cd587Sjoerg cmp r0, r1 48156cd587Sjoerg bcc LOCAL_LABEL(quotient0) 49156cd587Sjoerg /* 50156cd587Sjoerg * Implement division using binary long division algorithm. 51156cd587Sjoerg * 52156cd587Sjoerg * r0 is the numerator, r1 the denominator. 53156cd587Sjoerg * 54156cd587Sjoerg * The code before JMP computes the correct shift I, so that 55156cd587Sjoerg * r0 and (r1 << I) have the highest bit set in the same position. 56156cd587Sjoerg * At the time of JMP, ip := .Ldiv0block - 12 * I. 57156cd587Sjoerg * This depends on the fixed instruction size of block. 58190e92d8Sjoerg * For ARM mode, this is 12 Bytes, for THUMB mode 14 Bytes. 59156cd587Sjoerg * 60156cd587Sjoerg * block(shift) implements the test-and-update-quotient core. 61156cd587Sjoerg * It assumes (r0 << shift) can be computed without overflow and 62156cd587Sjoerg * that (r0 << shift) < 2 * r1. The quotient is stored in r3. 63156cd587Sjoerg */ 64156cd587Sjoerg 65156cd587Sjoerg# ifdef __ARM_FEATURE_CLZ 66156cd587Sjoerg clz ip, r0 67156cd587Sjoerg clz r3, r1 68156cd587Sjoerg /* r0 >= r1 implies clz(r0) <= clz(r1), so ip <= r3. */ 69156cd587Sjoerg sub r3, r3, ip 70190e92d8Sjoerg# if __ARM_ARCH_ISA_THUMB == 2 71190e92d8Sjoerg adr ip, LOCAL_LABEL(div0block) + 1 72190e92d8Sjoerg sub ip, ip, r3, lsl #1 73190e92d8Sjoerg# else 74156cd587Sjoerg adr ip, LOCAL_LABEL(div0block) 75190e92d8Sjoerg# endif 76156cd587Sjoerg sub ip, ip, r3, lsl #2 77156cd587Sjoerg sub ip, ip, r3, lsl #3 78156cd587Sjoerg mov r3, #0 79156cd587Sjoerg bx ip 80156cd587Sjoerg# else 81190e92d8Sjoerg# if __ARM_ARCH_ISA_THUMB == 2 82190e92d8Sjoerg# error THUMB mode requires CLZ or UDIV 83190e92d8Sjoerg# endif 84156cd587Sjoerg str r4, [sp, #-8]! 85156cd587Sjoerg 86156cd587Sjoerg mov r4, r0 87156cd587Sjoerg adr ip, LOCAL_LABEL(div0block) 88156cd587Sjoerg 89156cd587Sjoerg lsr r3, r4, #16 90156cd587Sjoerg cmp r3, r1 91156cd587Sjoerg movhs r4, r3 92156cd587Sjoerg subhs ip, ip, #(16 * 12) 93156cd587Sjoerg 94156cd587Sjoerg lsr r3, r4, #8 95156cd587Sjoerg cmp r3, r1 96156cd587Sjoerg movhs r4, r3 97156cd587Sjoerg subhs ip, ip, #(8 * 12) 98156cd587Sjoerg 99156cd587Sjoerg lsr r3, r4, #4 100156cd587Sjoerg cmp r3, r1 101156cd587Sjoerg movhs r4, r3 102156cd587Sjoerg subhs ip, #(4 * 12) 103156cd587Sjoerg 104156cd587Sjoerg lsr r3, r4, #2 105156cd587Sjoerg cmp r3, r1 106156cd587Sjoerg movhs r4, r3 107156cd587Sjoerg subhs ip, ip, #(2 * 12) 108156cd587Sjoerg 109156cd587Sjoerg /* Last block, no need to update r3 or r4. */ 110156cd587Sjoerg cmp r1, r4, lsr #1 111156cd587Sjoerg subls ip, ip, #(1 * 12) 112156cd587Sjoerg 113156cd587Sjoerg ldr r4, [sp], #8 /* restore r4, we are done with it. */ 114156cd587Sjoerg mov r3, #0 115156cd587Sjoerg 116156cd587Sjoerg JMP(ip) 117156cd587Sjoerg# endif 118156cd587Sjoerg 119156cd587Sjoerg#define IMM # 120156cd587Sjoerg 121156cd587Sjoerg#define block(shift) \ 122156cd587Sjoerg cmp r0, r1, lsl IMM shift; \ 123190e92d8Sjoerg ITT(hs); \ 124190e92d8Sjoerg WIDE(addhs) r3, r3, IMM (1 << shift); \ 125190e92d8Sjoerg WIDE(subhs) r0, r0, r1, lsl IMM shift 126156cd587Sjoerg 127156cd587Sjoerg block(31) 128156cd587Sjoerg block(30) 129156cd587Sjoerg block(29) 130156cd587Sjoerg block(28) 131156cd587Sjoerg block(27) 132156cd587Sjoerg block(26) 133156cd587Sjoerg block(25) 134156cd587Sjoerg block(24) 135156cd587Sjoerg block(23) 136156cd587Sjoerg block(22) 137156cd587Sjoerg block(21) 138156cd587Sjoerg block(20) 139156cd587Sjoerg block(19) 140156cd587Sjoerg block(18) 141156cd587Sjoerg block(17) 142156cd587Sjoerg block(16) 143156cd587Sjoerg block(15) 144156cd587Sjoerg block(14) 145156cd587Sjoerg block(13) 146156cd587Sjoerg block(12) 147156cd587Sjoerg block(11) 148156cd587Sjoerg block(10) 149156cd587Sjoerg block(9) 150156cd587Sjoerg block(8) 151156cd587Sjoerg block(7) 152156cd587Sjoerg block(6) 153156cd587Sjoerg block(5) 154156cd587Sjoerg block(4) 155156cd587Sjoerg block(3) 156156cd587Sjoerg block(2) 157156cd587Sjoerg block(1) 158156cd587SjoergLOCAL_LABEL(div0block): 159156cd587Sjoerg block(0) 160156cd587Sjoerg 161156cd587Sjoerg str r0, [r2] 162156cd587Sjoerg mov r0, r3 163156cd587Sjoerg JMP(lr) 164156cd587Sjoerg 165156cd587SjoergLOCAL_LABEL(quotient0): 166156cd587Sjoerg str r0, [r2] 167156cd587Sjoerg mov r0, #0 168156cd587Sjoerg JMP(lr) 169156cd587Sjoerg 170156cd587SjoergLOCAL_LABEL(divby1): 171156cd587Sjoerg mov r3, #0 172156cd587Sjoerg str r3, [r2] 173156cd587Sjoerg JMP(lr) 174156cd587Sjoerg#endif /* __ARM_ARCH_EXT_IDIV__ */ 175156cd587Sjoerg 176156cd587SjoergLOCAL_LABEL(divby0): 177156cd587Sjoerg mov r0, #0 178156cd587Sjoerg#ifdef __ARM_EABI__ 179156cd587Sjoerg b __aeabi_idiv0 180156cd587Sjoerg#else 181156cd587Sjoerg JMP(lr) 182156cd587Sjoerg#endif 183156cd587Sjoerg 184156cd587SjoergEND_COMPILERRT_FUNCTION(__udivmodsi4) 185