Path: blob/master/libs/compiler-rt/lib/builtins/arm/udivmodsi4.S
4396 views
/*===-- udivmodsi4.S - 32-bit unsigned integer divide and modulus ---------===//1*2* The LLVM Compiler Infrastructure3*4* This file is dual licensed under the MIT and the University of Illinois Open5* Source Licenses. See LICENSE.TXT for details.6*7*===----------------------------------------------------------------------===//8*9* This file implements the __udivmodsi4 (32-bit unsigned integer divide and10* modulus) function for the ARM 32-bit architecture.11*12*===----------------------------------------------------------------------===*/1314#include "../assembly.h"1516.syntax unified17.text18DEFINE_CODE_STATE1920@ unsigned int __udivmodsi4(unsigned int divident, unsigned int divisor,21@ unsigned int *remainder)22@ Calculate the quotient and remainder of the (unsigned) division. The return23@ value is the quotient, the remainder is placed in the variable.2425.p2align 226DEFINE_COMPILERRT_FUNCTION(__udivmodsi4)27#if __ARM_ARCH_EXT_IDIV__28tst r1, r129beq LOCAL_LABEL(divby0)30mov r3, r031udiv r0, r3, r132mls r1, r0, r1, r333str r1, [r2]34bx lr35#else36cmp r1, #137bcc LOCAL_LABEL(divby0)38beq LOCAL_LABEL(divby1)39cmp r0, r140bcc LOCAL_LABEL(quotient0)41/*42* Implement division using binary long division algorithm.43*44* r0 is the numerator, r1 the denominator.45*46* The code before JMP computes the correct shift I, so that47* 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.51*52* block(shift) implements the test-and-update-quotient core.53* It assumes (r0 << shift) can be computed without overflow and54* that (r0 << shift) < 2 * r1. The quotient is stored in r3.55*/5657# ifdef __ARM_FEATURE_CLZ58clz ip, r059clz r3, r160/* r0 >= r1 implies clz(r0) <= clz(r1), so ip <= r3. */61sub r3, r3, ip62# if defined(USE_THUMB_2)63adr ip, LOCAL_LABEL(div0block) + 164sub ip, ip, r3, lsl #165# else66adr ip, LOCAL_LABEL(div0block)67# endif68sub ip, ip, r3, lsl #269sub ip, ip, r3, lsl #370mov r3, #071bx ip72# else73# if defined(USE_THUMB_2)74# error THUMB mode requires CLZ or UDIV75# endif76str r4, [sp, #-8]!7778mov r4, r079adr ip, LOCAL_LABEL(div0block)8081lsr r3, r4, #1682cmp r3, r183movhs r4, r384subhs ip, ip, #(16 * 12)8586lsr r3, r4, #887cmp r3, r188movhs r4, r389subhs ip, ip, #(8 * 12)9091lsr r3, r4, #492cmp r3, r193movhs r4, r394subhs ip, #(4 * 12)9596lsr r3, r4, #297cmp r3, r198movhs r4, r399subhs ip, ip, #(2 * 12)100101/* Last block, no need to update r3 or r4. */102cmp r1, r4, lsr #1103subls ip, ip, #(1 * 12)104105ldr r4, [sp], #8 /* restore r4, we are done with it. */106mov r3, #0107108JMP(ip)109# endif110111#define IMM #112113#define block(shift) \114cmp r0, r1, lsl IMM shift; \115ITT(hs); \116WIDE(addhs) r3, r3, IMM (1 << shift); \117WIDE(subhs) r0, r0, r1, lsl IMM shift118119block(31)120block(30)121block(29)122block(28)123block(27)124block(26)125block(25)126block(24)127block(23)128block(22)129block(21)130block(20)131block(19)132block(18)133block(17)134block(16)135block(15)136block(14)137block(13)138block(12)139block(11)140block(10)141block(9)142block(8)143block(7)144block(6)145block(5)146block(4)147block(3)148block(2)149block(1)150LOCAL_LABEL(div0block):151block(0)152153str r0, [r2]154mov r0, r3155JMP(lr)156157LOCAL_LABEL(quotient0):158str r0, [r2]159mov r0, #0160JMP(lr)161162LOCAL_LABEL(divby1):163mov r3, #0164str r3, [r2]165JMP(lr)166#endif /* __ARM_ARCH_EXT_IDIV__ */167168LOCAL_LABEL(divby0):169mov r0, #0170#ifdef __ARM_EABI__171b __aeabi_idiv0172#else173JMP(lr)174#endif175176END_COMPILERRT_FUNCTION(__udivmodsi4)177178NO_EXEC_STACK_DIRECTIVE179180181