Home | History | Annotate | Line # | Download | only in quad
__aeabi_ldivmod.S revision 1.12
      1 /*-
      2  * Copyright (c) 2012 The NetBSD Foundation, Inc.
      3  * All rights reserved.
      4  *
      5  * This code is derived from software contributed to The NetBSD Foundation
      6  * by Matt Thomas of 3am Software Foundry.
      7  *
      8  * Redistribution and use in source and binary forms, with or without
      9  * modification, are permitted provided that the following conditions
     10  * are met:
     11  * 1. Redistributions of source code must retain the above copyright
     12  *    notice, this list of conditions and the following disclaimer.
     13  * 2. Redistributions in binary form must reproduce the above copyright
     14  *    notice, this list of conditions and the following disclaimer in the
     15  *    documentation and/or other materials provided with the distribution.
     16  *
     17  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     18  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     19  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     20  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     21  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     22  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     23  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     24  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     25  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     26  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     27  * POSSIBILITY OF SUCH DAMAGE.
     28  */
     29 
     30 #include <machine/asm.h>
     31 
     32 RCSID("$NetBSD: __aeabi_ldivmod.S,v 1.12 2013/08/19 03:27:34 matt Exp $")
     33 
     34 #ifdef __ARMEB__
     35 #define	ALO	r1	/* incoming numerator, outgoing quotient */
     36 #define	AHI	r0	/* incoming numerator, outgoing quotient */
     37 #define	BLO	r3	/* incoming denominator, outgoing remainder */
     38 #define	BHI	r2	/* incoming denominator, outgoing remainder */
     39 #else
     40 #define	ALO	r0	/* incoming numerator, outgoing quotient */
     41 #define	AHI	r1	/* incoming numerator, outgoing quotient */
     42 #define	BLO	r2	/* incoming denominator, outgoing remainder */
     43 #define	BHI	r3	/* incoming denominator, outgoing remainder */
     44 #endif
     45 
     46 ENTRY(__aeabi_ldivmod)
     47 #ifdef __ARM_EABI__
     48 	.fnstart
     49 	.cfi_startproc
     50 #endif
     51 #if !defined(_KERNEL) && !defined(_STANDALONE)
     52 #if !defined(__thumb__)
     53 	orrs	ip, BLO, BHI
     54 	beq	.Ldivbyzero
     55 #elif defined(_ARM_ARCH_T2)
     56 	cbnz	BLO, 1f
     57 	cbz	BHI, .Ldivbyzero
     58 #else
     59 	cmp	BLO, #0
     60 	bne	1f
     61 	cmp	BHI, #0
     62 	beq	.Ldivbyzero
     63 #endif
     64 1:
     65 #endif
     66 
     67 	push	{r4-r6, lr}
     68 #ifdef __ARM_EABI__
     69 	.cfi_def_cfa_offset 16
     70 	.cfi_offset 14, -4
     71 	.cfi_offset 6, -8
     72 	.cfi_offset 5, -12
     73 	.cfi_offset 4, -16
     74 #endif
     75 #define	NEG	r5
     76 	movs	NEG, #0
     77 
     78 	cmp	BHI, #0
     79 	bge	2f
     80 	movs	NEG, #1		/* flip quotient sign */
     81 	bl	.Lnegate_b
     82 	bcs	.Lmaxdenom
     83 
     84 2:
     85 	cmp	AHI, #0
     86 #ifdef __thumb__
     87 	bge	3f
     88 	movs	r4, #3
     89 	eors	NEG, NEG, r4	/* flip quotient sign, flip remainder sign */
     90 	bl	.Lnegate_a
     91 3:
     92 #else
     93 	eorlt	NEG, NEG, #3	/* flip quotient sign, flip remainder sign */
     94 	bllt	.Lnegate_a
     95 #endif
     96 
     97 	/*
     98 	 * Arguments are setup, allocate some stack for the remainder
     99 	 * and call __qdivrem for the heavy lifting.
    100 	 */
    101 #ifdef __ARM_EABI__
    102 	.cfi_def_cfa_offset 32
    103 #endif
    104 	sub	sp, sp, #16
    105 #if !defined(__thumb__) || defined(_ARM_ARCH_T2)
    106 	adds	r4, sp, #8
    107 #else
    108 	mov	r4, sp
    109 	adds	r4, r4, #8
    110 #endif
    111 	str	r4, [sp]
    112 	bl	PLT_SYM(__qdivrem)
    113 	add	sp, sp, #8
    114 #ifdef __ARM_EABI__
    115 	.cfi_def_cfa_offset 24
    116 	.cfi_offset 3, -20
    117 	.cfi_offset 2, -24
    118 #endif
    119 
    120 	/*
    121 	 * The quotient is already in the right place and neither value
    122 	 * needs its sign flipped.
    123 	 */
    124 #if defined(__thumb__) && defined(_ARM_ARCH_T2)
    125 	cbz	NEG, .Lnegate_neither
    126 #else
    127 	cmp	NEG, #0		/* any signs to flip? */
    128 	beq	.Lnegate_neither
    129 #endif
    130 
    131 	cmp	NEG, #2		/* does remainder need to be negative? */
    132 	beq	.Lnegate_b_only	/* 2 means b only */
    133 	bgt	.Lnegate_both	/* 3 means both */
    134 .Lnegate_a_only:
    135 	bl	.Lnegate_a	/* 1 means a only */
    136 .Lnegate_neither:
    137 	pop	{r2-r6, pc}	/* grab b from stack */
    138 .Lnegate_both:
    139 	bl	.Lnegate_a
    140 .Lnegate_b_only:
    141 	pop	{r2-r3}		/* get remainder */
    142 #ifdef __ARM_EABI__
    143 	.cfi_def_cfa_offset 16
    144 #endif
    145 	bl	.Lnegate_b	/* negate it */
    146 	pop	{r4-r6, pc}
    147 
    148 	.align	0
    149 .Lnegate_a:
    150 #ifdef __thumb__
    151 	movs	r4, AHI
    152 	movs	AHI, #0
    153 	negs	ALO, ALO
    154 	sbcs	AHI, AHI, r4
    155 #else
    156 	negs	ALO, ALO
    157 	rsc	AHI, AHI, #0
    158 #endif
    159 	RET
    160 
    161 	.align	0
    162 .Lnegate_b:
    163 #ifdef __thumb__
    164 	movs	r4, BHI
    165 	movs	BHI, #0
    166 	negs	BLO, BLO
    167 	sbcs	BHI, BHI, r4
    168 #else
    169 	negs	BLO, BLO
    170 	rsc	BHI, BHI, #0
    171 #endif
    172 	RET
    173 
    174 	.align	0
    175 .Lmaxdenom:
    176 	/*
    177 	 * We had a carry so the denominator must have INT64_MIN
    178 	 * Also BLO and BHI never changed values so we can use
    179 	 * them to see if the numerator has the same value.  We
    180 	 * don't have to worry about sign.
    181 	 */
    182 	cmp	BHI, AHI
    183 #ifdef __thumb__
    184 	bne	1f
    185 	cmp	BLO, ALO
    186 #else
    187 	cmpeq	BLO, ALO
    188 #endif
    189 	bne	1f
    190 
    191 	/*
    192 	 * They were equal, so we return a quotient of 1 and remainder of 0.
    193 	 */
    194 	movs	ALO, #1
    195 	movs	AHI, #0
    196 	movs	BLO, #0
    197 	movs	BHI, #0
    198 	pop	{r4-r6, pc}
    199 
    200 	/*
    201 	 * Our remainder must be the numerator and our quotient is 0.
    202 	 */
    203 	.align	0
    204 1:	movs	BLO, ALO
    205 	movs	BHI, AHI
    206 	movs	ALO, #0
    207 	movs	AHI, #0
    208 	pop	{r4-r6, pc}
    209 
    210 #if !defined(_KERNEL) && !defined(_STANDALONE)
    211 	.align	0
    212 .Ldivbyzero:
    213 	push	{r0-r1,r4,lr}
    214 #ifdef __ARM_EABI__
    215 	.save	{r0-r1,r4,lr}
    216 	.cfi_def_cfa_offset 16
    217 	.cfi_offset 14, -4
    218 	.cfi_offset  4, -8
    219 #endif
    220 	cmp	AHI, #0
    221 #if !defined(__thumb__) || defined(_ARM_ARCH_T2)
    222 #ifdef __thumb__
    223 	ittee	ge
    224 #endif
    225 	mvnge	ALO, #0
    226 	mvnge	AHI, #0x80000000
    227 	movlt	ALO, #0
    228 	movlt	AHI, #0x80000000
    229 #else
    230 	blt	1f
    231 	movs	ALO, #0
    232 	mvns	ALO, ALO
    233 	mov	AHI, ALO
    234 	lsrs	AHI, AHI, #1
    235 	b	2f
    236 1:
    237 	movs	ALO, #0
    238 	movs	AHI, #1
    239 	lsls	AHI, AHI, #31
    240 2:
    241 #endif /* __thumb__ && !_ARM_ARCH_T2 */
    242 	bl	PLT_SYM(__aeabi_ldiv0)
    243 	pop	{r2-r4, pc}
    244 #endif	/* !_KERNEL && !_STANDALONE */
    245 #ifdef __ARM_EABI__
    246 	.cfi_endproc
    247 	.fnend
    248 #endif
    249 END(__aeabi_ldivmod)
    250