1156cd587Sjoerg/*===-- umodsi3.S - 32-bit unsigned integer 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 __umodsi3 (32-bit unsigned integer modulus) 11156cd587Sjoerg * function for the ARM 32-bit architecture. 12156cd587Sjoerg * 13156cd587Sjoerg *===----------------------------------------------------------------------===*/ 14156cd587Sjoerg 15156cd587Sjoerg#include "../assembly.h" 16156cd587Sjoerg 17156cd587Sjoerg .syntax unified 18156cd587Sjoerg .text 19190e92d8Sjoerg#if __ARM_ARCH_ISA_THUMB == 2 20190e92d8Sjoerg .thumb 21190e92d8Sjoerg#endif 22190e92d8Sjoerg 23190e92d8Sjoerg@ unsigned int __umodsi3(unsigned int divident, unsigned int divisor) 24190e92d8Sjoerg@ Calculate and return the remainder of the (unsigned) division. 25190e92d8Sjoerg 26156cd587Sjoerg .p2align 2 27*ef84fd3bSjoerg#if __ARM_ARCH_ISA_THUMB == 2 28*ef84fd3bSjoergDEFINE_COMPILERRT_THUMB_FUNCTION(__umodsi3) 29*ef84fd3bSjoerg#else 30156cd587SjoergDEFINE_COMPILERRT_FUNCTION(__umodsi3) 31*ef84fd3bSjoerg#endif 32156cd587Sjoerg#if __ARM_ARCH_EXT_IDIV__ 33156cd587Sjoerg tst r1, r1 34156cd587Sjoerg beq LOCAL_LABEL(divby0) 35190e92d8Sjoerg udiv r2, r0, r1 36190e92d8Sjoerg mls r0, r2, r1, r0 37156cd587Sjoerg bx lr 38156cd587Sjoerg#else 39156cd587Sjoerg cmp r1, #1 40156cd587Sjoerg bcc LOCAL_LABEL(divby0) 41190e92d8Sjoerg ITT(eq) 42156cd587Sjoerg moveq r0, #0 43156cd587Sjoerg JMPc(lr, eq) 44156cd587Sjoerg cmp r0, r1 45190e92d8Sjoerg IT(cc) 46156cd587Sjoerg JMPc(lr, cc) 47156cd587Sjoerg /* 48156cd587Sjoerg * Implement division using binary long division algorithm. 49156cd587Sjoerg * 50156cd587Sjoerg * r0 is the numerator, r1 the denominator. 51156cd587Sjoerg * 52156cd587Sjoerg * The code before JMP computes the correct shift I, so that 53156cd587Sjoerg * r0 and (r1 << I) have the highest bit set in the same position. 54156cd587Sjoerg * At the time of JMP, ip := .Ldiv0block - 8 * I. 55156cd587Sjoerg * This depends on the fixed instruction size of block. 56190e92d8Sjoerg * For ARM mode, this is 8 Bytes, for THUMB mode 10 Bytes. 57156cd587Sjoerg * 58156cd587Sjoerg * block(shift) implements the test-and-update-quotient core. 59156cd587Sjoerg * It assumes (r0 << shift) can be computed without overflow and 60156cd587Sjoerg * that (r0 << shift) < 2 * r1. The quotient is stored in r3. 61156cd587Sjoerg */ 62156cd587Sjoerg 63156cd587Sjoerg# ifdef __ARM_FEATURE_CLZ 64156cd587Sjoerg clz ip, r0 65156cd587Sjoerg clz r3, r1 66156cd587Sjoerg /* r0 >= r1 implies clz(r0) <= clz(r1), so ip <= r3. */ 67156cd587Sjoerg sub r3, r3, ip 68190e92d8Sjoerg# if __ARM_ARCH_ISA_THUMB == 2 69190e92d8Sjoerg adr ip, LOCAL_LABEL(div0block) + 1 70190e92d8Sjoerg sub ip, ip, r3, lsl #1 71190e92d8Sjoerg# else 72156cd587Sjoerg adr ip, LOCAL_LABEL(div0block) 73190e92d8Sjoerg# endif 74156cd587Sjoerg sub ip, ip, r3, lsl #3 75156cd587Sjoerg bx ip 76156cd587Sjoerg# else 77190e92d8Sjoerg# if __ARM_ARCH_ISA_THUMB == 2 78190e92d8Sjoerg# error THUMB mode requires CLZ or UDIV 79190e92d8Sjoerg# endif 80156cd587Sjoerg mov r2, r0 81156cd587Sjoerg adr ip, LOCAL_LABEL(div0block) 82156cd587Sjoerg 83156cd587Sjoerg lsr r3, r2, #16 84156cd587Sjoerg cmp r3, r1 85156cd587Sjoerg movhs r2, r3 86156cd587Sjoerg subhs ip, ip, #(16 * 8) 87156cd587Sjoerg 88156cd587Sjoerg lsr r3, r2, #8 89156cd587Sjoerg cmp r3, r1 90156cd587Sjoerg movhs r2, r3 91156cd587Sjoerg subhs ip, ip, #(8 * 8) 92156cd587Sjoerg 93156cd587Sjoerg lsr r3, r2, #4 94156cd587Sjoerg cmp r3, r1 95156cd587Sjoerg movhs r2, r3 96156cd587Sjoerg subhs ip, #(4 * 8) 97156cd587Sjoerg 98156cd587Sjoerg lsr r3, r2, #2 99156cd587Sjoerg cmp r3, r1 100156cd587Sjoerg movhs r2, r3 101156cd587Sjoerg subhs ip, ip, #(2 * 8) 102156cd587Sjoerg 103156cd587Sjoerg /* Last block, no need to update r2 or r3. */ 104156cd587Sjoerg cmp r1, r2, lsr #1 105156cd587Sjoerg subls ip, ip, #(1 * 8) 106156cd587Sjoerg 107156cd587Sjoerg JMP(ip) 108156cd587Sjoerg# endif 109156cd587Sjoerg 110156cd587Sjoerg#define IMM # 111156cd587Sjoerg 112156cd587Sjoerg#define block(shift) \ 113156cd587Sjoerg cmp r0, r1, lsl IMM shift; \ 114190e92d8Sjoerg IT(hs); \ 115190e92d8Sjoerg WIDE(subhs) r0, r0, r1, lsl IMM shift 116156cd587Sjoerg 117156cd587Sjoerg block(31) 118156cd587Sjoerg block(30) 119156cd587Sjoerg block(29) 120156cd587Sjoerg block(28) 121156cd587Sjoerg block(27) 122156cd587Sjoerg block(26) 123156cd587Sjoerg block(25) 124156cd587Sjoerg block(24) 125156cd587Sjoerg block(23) 126156cd587Sjoerg block(22) 127156cd587Sjoerg block(21) 128156cd587Sjoerg block(20) 129156cd587Sjoerg block(19) 130156cd587Sjoerg block(18) 131156cd587Sjoerg block(17) 132156cd587Sjoerg block(16) 133156cd587Sjoerg block(15) 134156cd587Sjoerg block(14) 135156cd587Sjoerg block(13) 136156cd587Sjoerg block(12) 137156cd587Sjoerg block(11) 138156cd587Sjoerg block(10) 139156cd587Sjoerg block(9) 140156cd587Sjoerg block(8) 141156cd587Sjoerg block(7) 142156cd587Sjoerg block(6) 143156cd587Sjoerg block(5) 144156cd587Sjoerg block(4) 145156cd587Sjoerg block(3) 146156cd587Sjoerg block(2) 147156cd587Sjoerg block(1) 148156cd587SjoergLOCAL_LABEL(div0block): 149156cd587Sjoerg block(0) 150156cd587Sjoerg JMP(lr) 151156cd587Sjoerg#endif /* __ARM_ARCH_EXT_IDIV__ */ 152156cd587Sjoerg 153156cd587SjoergLOCAL_LABEL(divby0): 154156cd587Sjoerg mov r0, #0 155156cd587Sjoerg#ifdef __ARM_EABI__ 156156cd587Sjoerg b __aeabi_idiv0 157156cd587Sjoerg#else 158156cd587Sjoerg JMP(lr) 159156cd587Sjoerg#endif 160156cd587Sjoerg 161156cd587SjoergEND_COMPILERRT_FUNCTION(__umodsi3) 162