github.com/geraldss/go/src@v0.0.0-20210511222824-ac7d0ebfc235/runtime/vlop_arm.s (about) 1 // Inferno's libkern/vlop-arm.s 2 // https://bitbucket.org/inferno-os/inferno-os/src/master/libkern/vlop-arm.s 3 // 4 // Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. 5 // Revisions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com). All rights reserved. 6 // Portions Copyright 2009 The Go Authors. All rights reserved. 7 // 8 // Permission is hereby granted, free of charge, to any person obtaining a copy 9 // of this software and associated documentation files (the "Software"), to deal 10 // in the Software without restriction, including without limitation the rights 11 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 // copies of the Software, and to permit persons to whom the Software is 13 // furnished to do so, subject to the following conditions: 14 // 15 // The above copyright notice and this permission notice shall be included in 16 // all copies or substantial portions of the Software. 17 // 18 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24 // THE SOFTWARE. 25 26 #include "go_asm.h" 27 #include "go_tls.h" 28 #include "funcdata.h" 29 #include "textflag.h" 30 31 // func runtime·udiv(n, d uint32) (q, r uint32) 32 // compiler knowns the register usage of this function 33 // Reference: 34 // Sloss, Andrew et. al; ARM System Developer's Guide: Designing and Optimizing System Software 35 // Morgan Kaufmann; 1 edition (April 8, 2004), ISBN 978-1558608740 36 #define Rq R0 // input d, output q 37 #define Rr R1 // input n, output r 38 #define Rs R2 // three temporary variables 39 #define RM R3 40 #define Ra R11 41 42 // Be careful: Ra == R11 will be used by the linker for synthesized instructions. 43 // Note: this function does not have a frame. 44 TEXT runtime·udiv(SB),NOSPLIT|NOFRAME,$0 45 MOVBU internal∕cpu·ARM+const_offsetARMHasIDIVA(SB), Ra 46 CMP $0, Ra 47 BNE udiv_hardware 48 49 CLZ Rq, Rs // find normalizing shift 50 MOVW.S Rq<<Rs, Ra 51 MOVW $fast_udiv_tab<>-64(SB), RM 52 ADD.NE Ra>>25, RM, Ra // index by most significant 7 bits of divisor 53 MOVBU.NE (Ra), Ra 54 55 SUB.S $7, Rs 56 RSB $0, Rq, RM // M = -q 57 MOVW.PL Ra<<Rs, Rq 58 59 // 1st Newton iteration 60 MUL.PL RM, Rq, Ra // a = -q*d 61 BMI udiv_by_large_d 62 MULAWT Ra, Rq, Rq, Rq // q approx q-(q*q*d>>32) 63 TEQ RM->1, RM // check for d=0 or d=1 64 65 // 2nd Newton iteration 66 MUL.NE RM, Rq, Ra 67 MOVW.NE $0, Rs 68 MULAL.NE Rq, Ra, (Rq,Rs) 69 BEQ udiv_by_0_or_1 70 71 // q now accurate enough for a remainder r, 0<=r<3*d 72 MULLU Rq, Rr, (Rq,Rs) // q = (r * q) >> 32 73 ADD RM, Rr, Rr // r = n - d 74 MULA RM, Rq, Rr, Rr // r = n - (q+1)*d 75 76 // since 0 <= n-q*d < 3*d; thus -d <= r < 2*d 77 CMN RM, Rr // t = r-d 78 SUB.CS RM, Rr, Rr // if (t<-d || t>=0) r=r+d 79 ADD.CC $1, Rq 80 ADD.PL RM<<1, Rr 81 ADD.PL $2, Rq 82 RET 83 84 // use hardware divider 85 udiv_hardware: 86 DIVUHW Rq, Rr, Rs 87 MUL Rs, Rq, RM 88 RSB Rr, RM, Rr 89 MOVW Rs, Rq 90 RET 91 92 udiv_by_large_d: 93 // at this point we know d>=2^(31-6)=2^25 94 SUB $4, Ra, Ra 95 RSB $0, Rs, Rs 96 MOVW Ra>>Rs, Rq 97 MULLU Rq, Rr, (Rq,Rs) 98 MULA RM, Rq, Rr, Rr 99 100 // q now accurate enough for a remainder r, 0<=r<4*d 101 CMN Rr>>1, RM // if(r/2 >= d) 102 ADD.CS RM<<1, Rr 103 ADD.CS $2, Rq 104 CMN Rr, RM 105 ADD.CS RM, Rr 106 ADD.CS $1, Rq 107 RET 108 109 udiv_by_0_or_1: 110 // carry set if d==1, carry clear if d==0 111 BCC udiv_by_0 112 MOVW Rr, Rq 113 MOVW $0, Rr 114 RET 115 116 udiv_by_0: 117 MOVW $runtime·panicdivide(SB), R11 118 B (R11) 119 120 // var tab [64]byte 121 // tab[0] = 255; for i := 1; i <= 63; i++ { tab[i] = (1<<14)/(64+i) } 122 // laid out here as little-endian uint32s 123 DATA fast_udiv_tab<>+0x00(SB)/4, $0xf4f8fcff 124 DATA fast_udiv_tab<>+0x04(SB)/4, $0xe6eaedf0 125 DATA fast_udiv_tab<>+0x08(SB)/4, $0xdadde0e3 126 DATA fast_udiv_tab<>+0x0c(SB)/4, $0xcfd2d4d7 127 DATA fast_udiv_tab<>+0x10(SB)/4, $0xc5c7cacc 128 DATA fast_udiv_tab<>+0x14(SB)/4, $0xbcbec0c3 129 DATA fast_udiv_tab<>+0x18(SB)/4, $0xb4b6b8ba 130 DATA fast_udiv_tab<>+0x1c(SB)/4, $0xacaeb0b2 131 DATA fast_udiv_tab<>+0x20(SB)/4, $0xa5a7a8aa 132 DATA fast_udiv_tab<>+0x24(SB)/4, $0x9fa0a2a3 133 DATA fast_udiv_tab<>+0x28(SB)/4, $0x999a9c9d 134 DATA fast_udiv_tab<>+0x2c(SB)/4, $0x93949697 135 DATA fast_udiv_tab<>+0x30(SB)/4, $0x8e8f9092 136 DATA fast_udiv_tab<>+0x34(SB)/4, $0x898a8c8d 137 DATA fast_udiv_tab<>+0x38(SB)/4, $0x85868788 138 DATA fast_udiv_tab<>+0x3c(SB)/4, $0x81828384 139 GLOBL fast_udiv_tab<>(SB), RODATA, $64 140 141 // The linker will pass numerator in R8 142 #define Rn R8 143 // The linker expects the result in RTMP 144 #define RTMP R11 145 146 TEXT runtime·_divu(SB), NOSPLIT, $16-0 147 // It's not strictly true that there are no local pointers. 148 // It could be that the saved registers Rq, Rr, Rs, and Rm 149 // contain pointers. However, the only way this can matter 150 // is if the stack grows (which it can't, udiv is nosplit) 151 // or if a fault happens and more frames are added to 152 // the stack due to deferred functions. 153 // In the latter case, the stack can grow arbitrarily, 154 // and garbage collection can happen, and those 155 // operations care about pointers, but in that case 156 // the calling frame is dead, and so are the saved 157 // registers. So we can claim there are no pointers here. 158 NO_LOCAL_POINTERS 159 MOVW Rq, 4(R13) 160 MOVW Rr, 8(R13) 161 MOVW Rs, 12(R13) 162 MOVW RM, 16(R13) 163 164 MOVW Rn, Rr /* numerator */ 165 MOVW g_m(g), Rq 166 MOVW m_divmod(Rq), Rq /* denominator */ 167 BL runtime·udiv(SB) 168 MOVW Rq, RTMP 169 MOVW 4(R13), Rq 170 MOVW 8(R13), Rr 171 MOVW 12(R13), Rs 172 MOVW 16(R13), RM 173 RET 174 175 TEXT runtime·_modu(SB), NOSPLIT, $16-0 176 NO_LOCAL_POINTERS 177 MOVW Rq, 4(R13) 178 MOVW Rr, 8(R13) 179 MOVW Rs, 12(R13) 180 MOVW RM, 16(R13) 181 182 MOVW Rn, Rr /* numerator */ 183 MOVW g_m(g), Rq 184 MOVW m_divmod(Rq), Rq /* denominator */ 185 BL runtime·udiv(SB) 186 MOVW Rr, RTMP 187 MOVW 4(R13), Rq 188 MOVW 8(R13), Rr 189 MOVW 12(R13), Rs 190 MOVW 16(R13), RM 191 RET 192 193 TEXT runtime·_div(SB),NOSPLIT,$16-0 194 NO_LOCAL_POINTERS 195 MOVW Rq, 4(R13) 196 MOVW Rr, 8(R13) 197 MOVW Rs, 12(R13) 198 MOVW RM, 16(R13) 199 MOVW Rn, Rr /* numerator */ 200 MOVW g_m(g), Rq 201 MOVW m_divmod(Rq), Rq /* denominator */ 202 CMP $0, Rr 203 BGE d1 204 RSB $0, Rr, Rr 205 CMP $0, Rq 206 BGE d2 207 RSB $0, Rq, Rq 208 d0: 209 BL runtime·udiv(SB) /* none/both neg */ 210 MOVW Rq, RTMP 211 B out1 212 d1: 213 CMP $0, Rq 214 BGE d0 215 RSB $0, Rq, Rq 216 d2: 217 BL runtime·udiv(SB) /* one neg */ 218 RSB $0, Rq, RTMP 219 out1: 220 MOVW 4(R13), Rq 221 MOVW 8(R13), Rr 222 MOVW 12(R13), Rs 223 MOVW 16(R13), RM 224 RET 225 226 TEXT runtime·_mod(SB),NOSPLIT,$16-0 227 NO_LOCAL_POINTERS 228 MOVW Rq, 4(R13) 229 MOVW Rr, 8(R13) 230 MOVW Rs, 12(R13) 231 MOVW RM, 16(R13) 232 MOVW Rn, Rr /* numerator */ 233 MOVW g_m(g), Rq 234 MOVW m_divmod(Rq), Rq /* denominator */ 235 CMP $0, Rq 236 RSB.LT $0, Rq, Rq 237 CMP $0, Rr 238 BGE m1 239 RSB $0, Rr, Rr 240 BL runtime·udiv(SB) /* neg numerator */ 241 RSB $0, Rr, RTMP 242 B out 243 m1: 244 BL runtime·udiv(SB) /* pos numerator */ 245 MOVW Rr, RTMP 246 out: 247 MOVW 4(R13), Rq 248 MOVW 8(R13), Rr 249 MOVW 12(R13), Rs 250 MOVW 16(R13), RM 251 RET 252 253 // _mul64by32 and _div64by32 not implemented on arm 254 TEXT runtime·_mul64by32(SB), NOSPLIT, $0 255 MOVW $0, R0 256 MOVW (R0), R1 // crash 257 258 TEXT runtime·_div64by32(SB), NOSPLIT, $0 259 MOVW $0, R0 260 MOVW (R0), R1 // crash