2019-04-29 06:47:49 +08:00
|
|
|
//===-- udivmodsi4.S - 32-bit unsigned integer divide and modulus ---------===//
|
|
|
|
//
|
|
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
//
|
|
|
|
// This file implements the __udivmodsi4 (32-bit unsigned integer divide and
|
|
|
|
// modulus) function for the ARM 32-bit architecture.
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
2011-03-19 00:35:02 +08:00
|
|
|
|
|
|
|
#include "../assembly.h"
|
|
|
|
|
2014-01-24 21:43:35 +08:00
|
|
|
.syntax unified
|
|
|
|
.text
|
[builtins][ARM] Select correct code fragments when compiling for Thumb1/Thum2/ARM ISA
Summary:
Value of __ARM_ARCH_ISA_THUMB isn't based on the actual compilation
mode (-mthumb, -marm), it reflect's capability of given CPU.
Due to this:
•use tbumb and thumb2 insteand of __ARM_ARCH_ISA_THUMB
•use '.thumb' directive consistently in all affected files
•decorate all thumb functions using DEFINE_COMPILERRT_THUMB_FUNCTION()
(This is based off Michal's patch https://reviews.llvm.org/D30938)
Reviewers: dim, rengolin, compnerd, strejda
Reviewed By: compnerd
Subscribers: peter.smith, kubamracek, mgorny, javed.absar, kristof.beyls, jamesduley, aemerson, llvm-commits
Differential Revision: https://reviews.llvm.org/D31220
llvm-svn: 310884
2017-08-15 04:48:47 +08:00
|
|
|
DEFINE_CODE_STATE
|
2014-07-21 04:53:37 +08:00
|
|
|
|
2014-08-10 04:17:43 +08:00
|
|
|
@ unsigned int __udivmodsi4(unsigned int divident, unsigned int divisor,
|
|
|
|
@ unsigned int *remainder)
|
|
|
|
@ Calculate the quotient and remainder of the (unsigned) division. The return
|
|
|
|
@ value is the quotient, the remainder is placed in the variable.
|
|
|
|
|
2014-01-24 21:43:35 +08:00
|
|
|
.p2align 2
|
2014-10-07 10:39:13 +08:00
|
|
|
DEFINE_COMPILERRT_FUNCTION(__udivmodsi4)
|
2013-10-25 14:26:44 +08:00
|
|
|
#if __ARM_ARCH_EXT_IDIV__
|
2013-05-25 03:38:11 +08:00
|
|
|
tst r1, r1
|
2014-01-24 21:43:35 +08:00
|
|
|
beq LOCAL_LABEL(divby0)
|
2013-05-25 03:38:11 +08:00
|
|
|
mov r3, r0
|
|
|
|
udiv r0, r3, r1
|
|
|
|
mls r1, r0, r1, r3
|
|
|
|
str r1, [r2]
|
|
|
|
bx lr
|
|
|
|
#else
|
2014-01-24 21:43:35 +08:00
|
|
|
cmp r1, #1
|
|
|
|
bcc LOCAL_LABEL(divby0)
|
|
|
|
beq LOCAL_LABEL(divby1)
|
|
|
|
cmp r0, r1
|
|
|
|
bcc LOCAL_LABEL(quotient0)
|
2019-04-29 06:47:49 +08:00
|
|
|
|
|
|
|
// Implement division using binary long division algorithm.
|
|
|
|
//
|
|
|
|
// r0 is the numerator, r1 the denominator.
|
|
|
|
//
|
|
|
|
// The code before JMP computes the correct shift I, so that
|
|
|
|
// r0 and (r1 << I) have the highest bit set in the same position.
|
|
|
|
// At the time of JMP, ip := .Ldiv0block - 12 * I.
|
|
|
|
// This depends on the fixed instruction size of block.
|
|
|
|
// For ARM mode, this is 12 Bytes, for THUMB mode 14 Bytes.
|
|
|
|
//
|
|
|
|
// block(shift) implements the test-and-update-quotient core.
|
|
|
|
// It assumes (r0 << shift) can be computed without overflow and
|
|
|
|
// that (r0 << shift) < 2 * r1. The quotient is stored in r3.
|
2014-01-24 21:43:35 +08:00
|
|
|
|
|
|
|
# ifdef __ARM_FEATURE_CLZ
|
|
|
|
clz ip, r0
|
|
|
|
clz r3, r1
|
2019-04-29 06:47:49 +08:00
|
|
|
// r0 >= r1 implies clz(r0) <= clz(r1), so ip <= r3.
|
2014-01-24 21:43:35 +08:00
|
|
|
sub r3, r3, ip
|
[builtins][ARM] Select correct code fragments when compiling for Thumb1/Thum2/ARM ISA
Summary:
Value of __ARM_ARCH_ISA_THUMB isn't based on the actual compilation
mode (-mthumb, -marm), it reflect's capability of given CPU.
Due to this:
•use tbumb and thumb2 insteand of __ARM_ARCH_ISA_THUMB
•use '.thumb' directive consistently in all affected files
•decorate all thumb functions using DEFINE_COMPILERRT_THUMB_FUNCTION()
(This is based off Michal's patch https://reviews.llvm.org/D30938)
Reviewers: dim, rengolin, compnerd, strejda
Reviewed By: compnerd
Subscribers: peter.smith, kubamracek, mgorny, javed.absar, kristof.beyls, jamesduley, aemerson, llvm-commits
Differential Revision: https://reviews.llvm.org/D31220
llvm-svn: 310884
2017-08-15 04:48:47 +08:00
|
|
|
# if defined(USE_THUMB_2)
|
2014-07-21 04:53:37 +08:00
|
|
|
adr ip, LOCAL_LABEL(div0block) + 1
|
|
|
|
sub ip, ip, r3, lsl #1
|
|
|
|
# else
|
2014-07-21 04:00:26 +08:00
|
|
|
adr ip, LOCAL_LABEL(div0block)
|
2014-07-21 04:53:37 +08:00
|
|
|
# endif
|
2014-01-24 21:43:35 +08:00
|
|
|
sub ip, ip, r3, lsl #2
|
|
|
|
sub ip, ip, r3, lsl #3
|
|
|
|
mov r3, #0
|
|
|
|
bx ip
|
|
|
|
# else
|
[builtins][ARM] Select correct code fragments when compiling for Thumb1/Thum2/ARM ISA
Summary:
Value of __ARM_ARCH_ISA_THUMB isn't based on the actual compilation
mode (-mthumb, -marm), it reflect's capability of given CPU.
Due to this:
•use tbumb and thumb2 insteand of __ARM_ARCH_ISA_THUMB
•use '.thumb' directive consistently in all affected files
•decorate all thumb functions using DEFINE_COMPILERRT_THUMB_FUNCTION()
(This is based off Michal's patch https://reviews.llvm.org/D30938)
Reviewers: dim, rengolin, compnerd, strejda
Reviewed By: compnerd
Subscribers: peter.smith, kubamracek, mgorny, javed.absar, kristof.beyls, jamesduley, aemerson, llvm-commits
Differential Revision: https://reviews.llvm.org/D31220
llvm-svn: 310884
2017-08-15 04:48:47 +08:00
|
|
|
# if defined(USE_THUMB_2)
|
2014-07-21 04:53:37 +08:00
|
|
|
# error THUMB mode requires CLZ or UDIV
|
|
|
|
# endif
|
2014-01-24 21:43:35 +08:00
|
|
|
str r4, [sp, #-8]!
|
|
|
|
|
|
|
|
mov r4, r0
|
2014-07-21 04:00:26 +08:00
|
|
|
adr ip, LOCAL_LABEL(div0block)
|
2014-01-24 21:43:35 +08:00
|
|
|
|
|
|
|
lsr r3, r4, #16
|
|
|
|
cmp r3, r1
|
|
|
|
movhs r4, r3
|
|
|
|
subhs ip, ip, #(16 * 12)
|
|
|
|
|
|
|
|
lsr r3, r4, #8
|
|
|
|
cmp r3, r1
|
|
|
|
movhs r4, r3
|
|
|
|
subhs ip, ip, #(8 * 12)
|
|
|
|
|
|
|
|
lsr r3, r4, #4
|
|
|
|
cmp r3, r1
|
|
|
|
movhs r4, r3
|
|
|
|
subhs ip, #(4 * 12)
|
|
|
|
|
|
|
|
lsr r3, r4, #2
|
|
|
|
cmp r3, r1
|
|
|
|
movhs r4, r3
|
|
|
|
subhs ip, ip, #(2 * 12)
|
|
|
|
|
2019-04-29 06:47:49 +08:00
|
|
|
// Last block, no need to update r3 or r4.
|
2014-01-24 21:43:35 +08:00
|
|
|
cmp r1, r4, lsr #1
|
|
|
|
subls ip, ip, #(1 * 12)
|
|
|
|
|
2019-04-29 06:47:49 +08:00
|
|
|
ldr r4, [sp], #8 // restore r4, we are done with it.
|
2014-01-24 21:43:35 +08:00
|
|
|
mov r3, #0
|
|
|
|
|
|
|
|
JMP(ip)
|
|
|
|
# endif
|
|
|
|
|
|
|
|
#define IMM #
|
|
|
|
|
2014-07-27 10:01:15 +08:00
|
|
|
#define block(shift) \
|
|
|
|
cmp r0, r1, lsl IMM shift; \
|
|
|
|
ITT(hs); \
|
2014-07-27 10:01:24 +08:00
|
|
|
WIDE(addhs) r3, r3, IMM (1 << shift); \
|
|
|
|
WIDE(subhs) r0, r0, r1, lsl IMM shift
|
2014-01-24 21:43:35 +08:00
|
|
|
|
|
|
|
block(31)
|
|
|
|
block(30)
|
|
|
|
block(29)
|
|
|
|
block(28)
|
|
|
|
block(27)
|
|
|
|
block(26)
|
|
|
|
block(25)
|
|
|
|
block(24)
|
|
|
|
block(23)
|
|
|
|
block(22)
|
|
|
|
block(21)
|
|
|
|
block(20)
|
|
|
|
block(19)
|
|
|
|
block(18)
|
|
|
|
block(17)
|
|
|
|
block(16)
|
|
|
|
block(15)
|
|
|
|
block(14)
|
|
|
|
block(13)
|
|
|
|
block(12)
|
|
|
|
block(11)
|
|
|
|
block(10)
|
|
|
|
block(9)
|
|
|
|
block(8)
|
|
|
|
block(7)
|
|
|
|
block(6)
|
|
|
|
block(5)
|
|
|
|
block(4)
|
|
|
|
block(3)
|
|
|
|
block(2)
|
|
|
|
block(1)
|
2014-07-21 04:00:26 +08:00
|
|
|
LOCAL_LABEL(div0block):
|
2014-01-24 21:43:35 +08:00
|
|
|
block(0)
|
|
|
|
|
|
|
|
str r0, [r2]
|
|
|
|
mov r0, r3
|
|
|
|
JMP(lr)
|
|
|
|
|
|
|
|
LOCAL_LABEL(quotient0):
|
|
|
|
str r0, [r2]
|
|
|
|
mov r0, #0
|
|
|
|
JMP(lr)
|
|
|
|
|
|
|
|
LOCAL_LABEL(divby1):
|
|
|
|
mov r3, #0
|
|
|
|
str r3, [r2]
|
|
|
|
JMP(lr)
|
2019-04-29 06:47:49 +08:00
|
|
|
#endif // __ARM_ARCH_EXT_IDIV__
|
2014-01-24 21:43:35 +08:00
|
|
|
|
|
|
|
LOCAL_LABEL(divby0):
|
|
|
|
mov r0, #0
|
|
|
|
#ifdef __ARM_EABI__
|
|
|
|
b __aeabi_idiv0
|
|
|
|
#else
|
|
|
|
JMP(lr)
|
2013-05-25 03:38:11 +08:00
|
|
|
#endif
|
2014-01-24 21:43:35 +08:00
|
|
|
|
|
|
|
END_COMPILERRT_FUNCTION(__udivmodsi4)
|
2016-06-23 06:09:42 +08:00
|
|
|
|
|
|
|
NO_EXEC_STACK_DIRECTIVE
|
|
|
|
|