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