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 32RCSID("$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 46ENTRY(__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 661: 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 862: 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 933: 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 2061: 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 2401: 241 movs ALO, #0 242 movs AHI, #1 243 lsls AHI, AHI, #31 2442: 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 255END(__aeabi_ldivmod) 256