Home | History | Annotate | Line # | Download | only in quad
      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.13 2014/05/06 16:02:11 joerg 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 # if !defined(__ARM_DWARF_EH__)
     49 	.fnstart
     50 # endif
     51 	.cfi_startproc
     52 #endif
     53 #if !defined(_KERNEL) && !defined(_STANDALONE)
     54 #if !defined(__thumb__)
     55 	orrs	ip, BLO, BHI
     56 	beq	.Ldivbyzero
     57 #elif defined(_ARM_ARCH_T2)
     58 	cbnz	BLO, 1f
     59 	cbz	BHI, .Ldivbyzero
     60 #else
     61 	cmp	BLO, #0
     62 	bne	1f
     63 	cmp	BHI, #0
     64 	beq	.Ldivbyzero
     65 #endif
     66 1:
     67 #endif
     68 
     69 	push	{r4-r6, lr}
     70 #ifdef __ARM_EABI__
     71 	.cfi_def_cfa_offset 16
     72 	.cfi_offset 14, -4
     73 	.cfi_offset 6, -8
     74 	.cfi_offset 5, -12
     75 	.cfi_offset 4, -16
     76 #endif
     77 #define	NEG	r5
     78 	movs	NEG, #0
     79 
     80 	cmp	BHI, #0
     81 	bge	2f
     82 	movs	NEG, #1		/* flip quotient sign */
     83 	bl	.Lnegate_b
     84 	bcs	.Lmaxdenom
     85 
     86 2:
     87 	cmp	AHI, #0
     88 #ifdef __thumb__
     89 	bge	3f
     90 	movs	r4, #3
     91 	eors	NEG, NEG, r4	/* flip quotient sign, flip remainder sign */
     92 	bl	.Lnegate_a
     93 3:
     94 #else
     95 	eorlt	NEG, NEG, #3	/* flip quotient sign, flip remainder sign */
     96 	bllt	.Lnegate_a
     97 #endif
     98 
     99 	/*
    100 	 * Arguments are setup, allocate some stack for the remainder
    101 	 * and call __qdivrem for the heavy lifting.
    102 	 */
    103 #ifdef __ARM_EABI__
    104 	.cfi_def_cfa_offset 32
    105 #endif
    106 	sub	sp, sp, #16
    107 #if !defined(__thumb__) || defined(_ARM_ARCH_T2)
    108 	adds	r4, sp, #8
    109 #else
    110 	mov	r4, sp
    111 	adds	r4, r4, #8
    112 #endif
    113 	str	r4, [sp]
    114 	bl	PLT_SYM(__qdivrem)
    115 	add	sp, sp, #8
    116 #ifdef __ARM_EABI__
    117 	.cfi_def_cfa_offset 24
    118 	.cfi_offset 3, -20
    119 	.cfi_offset 2, -24
    120 #endif
    121 
    122 	/*
    123 	 * The quotient is already in the right place and neither value
    124 	 * needs its sign flipped.
    125 	 */
    126 #if defined(__thumb__) && defined(_ARM_ARCH_T2)
    127 	cbz	NEG, .Lnegate_neither
    128 #else
    129 	cmp	NEG, #0		/* any signs to flip? */
    130 	beq	.Lnegate_neither
    131 #endif
    132 
    133 	cmp	NEG, #2		/* does remainder need to be negative? */
    134 	beq	.Lnegate_b_only	/* 2 means b only */
    135 	bgt	.Lnegate_both	/* 3 means both */
    136 .Lnegate_a_only:
    137 	bl	.Lnegate_a	/* 1 means a only */
    138 .Lnegate_neither:
    139 	pop	{r2-r6, pc}	/* grab b from stack */
    140 .Lnegate_both:
    141 	bl	.Lnegate_a
    142 .Lnegate_b_only:
    143 	pop	{r2-r3}		/* get remainder */
    144 #ifdef __ARM_EABI__
    145 	.cfi_def_cfa_offset 16
    146 #endif
    147 	bl	.Lnegate_b	/* negate it */
    148 	pop	{r4-r6, pc}
    149 
    150 	.align	0
    151 .Lnegate_a:
    152 #ifdef __thumb__
    153 	movs	r4, AHI
    154 	movs	AHI, #0
    155 	negs	ALO, ALO
    156 	sbcs	AHI, AHI, r4
    157 #else
    158 	negs	ALO, ALO
    159 	rsc	AHI, AHI, #0
    160 #endif
    161 	RET
    162 
    163 	.align	0
    164 .Lnegate_b:
    165 #ifdef __thumb__
    166 	movs	r4, BHI
    167 	movs	BHI, #0
    168 	negs	BLO, BLO
    169 	sbcs	BHI, BHI, r4
    170 #else
    171 	negs	BLO, BLO
    172 	rsc	BHI, BHI, #0
    173 #endif
    174 	RET
    175 
    176 	.align	0
    177 .Lmaxdenom:
    178 	/*
    179 	 * We had a carry so the denominator must have INT64_MIN
    180 	 * Also BLO and BHI never changed values so we can use
    181 	 * them to see if the numerator has the same value.  We
    182 	 * don't have to worry about sign.
    183 	 */
    184 	cmp	BHI, AHI
    185 #ifdef __thumb__
    186 	bne	1f
    187 	cmp	BLO, ALO
    188 #else
    189 	cmpeq	BLO, ALO
    190 #endif
    191 	bne	1f
    192 
    193 	/*
    194 	 * They were equal, so we return a quotient of 1 and remainder of 0.
    195 	 */
    196 	movs	ALO, #1
    197 	movs	AHI, #0
    198 	movs	BLO, #0
    199 	movs	BHI, #0
    200 	pop	{r4-r6, pc}
    201 
    202 	/*
    203 	 * Our remainder must be the numerator and our quotient is 0.
    204 	 */
    205 	.align	0
    206 1:	movs	BLO, ALO
    207 	movs	BHI, AHI
    208 	movs	ALO, #0
    209 	movs	AHI, #0
    210 	pop	{r4-r6, pc}
    211 
    212 #if !defined(_KERNEL) && !defined(_STANDALONE)
    213 	.align	0
    214 .Ldivbyzero:
    215 	push	{r0-r1,r4,lr}
    216 #ifdef __ARM_EABI__
    217 # if !defined(__ARM_DWARF_EH__)
    218 	.save	{r0-r1,r4,lr}
    219 # endif
    220 	.cfi_def_cfa_offset 16
    221 	.cfi_offset 14, -4
    222 	.cfi_offset  4, -8
    223 #endif
    224 	cmp	AHI, #0
    225 #if !defined(__thumb__) || defined(_ARM_ARCH_T2)
    226 #ifdef __thumb__
    227 	ittee	ge
    228 #endif
    229 	mvnge	ALO, #0
    230 	mvnge	AHI, #0x80000000
    231 	movlt	ALO, #0
    232 	movlt	AHI, #0x80000000
    233 #else
    234 	blt	1f
    235 	movs	ALO, #0
    236 	mvns	ALO, ALO
    237 	mov	AHI, ALO
    238 	lsrs	AHI, AHI, #1
    239 	b	2f
    240 1:
    241 	movs	ALO, #0
    242 	movs	AHI, #1
    243 	lsls	AHI, AHI, #31
    244 2:
    245 #endif /* __thumb__ && !_ARM_ARCH_T2 */
    246 	bl	PLT_SYM(__aeabi_ldiv0)
    247 	pop	{r2-r4, pc}
    248 #endif	/* !_KERNEL && !_STANDALONE */
    249 #ifdef __ARM_EABI__
    250 	.cfi_endproc
    251 # if !defined(__ARM_DWARF_EH__)
    252 	.fnend
    253 # endif
    254 #endif
    255 END(__aeabi_ldivmod)
    256