rsc.io/go@v0.0.0-20150416155037-e040fd465409/src/runtime/vlop_arm.s (about) 1 // Inferno's libkern/vlop-arm.s 2 // http://code.google.com/p/inferno-os/source/browse/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 "textflag.h" 29 30 /* replaced use of R10 by R11 because the former can be the data segment base register */ 31 32 TEXT _mulv(SB), NOSPLIT, $0 33 MOVW l0+0(FP), R2 /* l0 */ 34 MOVW h0+4(FP), R11 /* h0 */ 35 MOVW l1+8(FP), R4 /* l1 */ 36 MOVW h1+12(FP), R5 /* h1 */ 37 MULLU R4, R2, (R7,R6) 38 MUL R11, R4, R8 39 ADD R8, R7 40 MUL R2, R5, R8 41 ADD R8, R7 42 MOVW R6, ret_lo+16(FP) 43 MOVW R7, ret_hi+20(FP) 44 RET 45 46 // trampoline for _sfloat2. passes LR as arg0 and 47 // saves registers R0-R13 and CPSR on the stack. R0-R12 and CPSR flags can 48 // be changed by _sfloat2. 49 TEXT _sfloat(SB), NOSPLIT, $68-0 // 4 arg + 14*4 saved regs + cpsr + return value 50 MOVW R14, 4(R13) 51 MOVW R0, 8(R13) 52 MOVW $12(R13), R0 53 MOVM.IA.W [R1-R12], (R0) 54 MOVW $72(R13), R1 // correct for frame size 55 MOVW R1, 60(R13) 56 WORD $0xe10f1000 // mrs r1, cpsr 57 MOVW R1, 64(R13) 58 // Disable preemption of this goroutine during _sfloat2 by 59 // m->locks++ and m->locks-- around the call. 60 // Rescheduling this goroutine may cause the loss of the 61 // contents of the software floating point registers in 62 // m->freghi, m->freglo, m->fflag, if the goroutine is moved 63 // to a different m or another goroutine runs on this m. 64 // Rescheduling at ordinary function calls is okay because 65 // all registers are caller save, but _sfloat2 and the things 66 // that it runs are simulating the execution of individual 67 // program instructions, and those instructions do not expect 68 // the floating point registers to be lost. 69 // An alternative would be to move the software floating point 70 // registers into G, but they do not need to be kept at the 71 // usual places a goroutine reschedules (at function calls), 72 // so it would be a waste of 132 bytes per G. 73 MOVW g_m(g), R8 74 MOVW m_locks(R8), R1 75 ADD $1, R1 76 MOVW R1, m_locks(R8) 77 MOVW $1, R1 78 MOVW R1, m_softfloat(R8) 79 BL runtime·_sfloat2(SB) 80 MOVW 68(R13), R0 81 MOVW g_m(g), R8 82 MOVW m_locks(R8), R1 83 SUB $1, R1 84 MOVW R1, m_locks(R8) 85 MOVW $0, R1 86 MOVW R1, m_softfloat(R8) 87 MOVW R0, 0(R13) 88 MOVW 64(R13), R1 89 WORD $0xe128f001 // msr cpsr_f, r1 90 MOVW $12(R13), R0 91 // Restore R1-R12, R0. 92 MOVM.IA.W (R0), [R1-R12] 93 MOVW 8(R13), R0 94 RET 95 96 // trampoline for _sfloat2 panic. 97 // _sfloat2 instructs _sfloat to return here. 98 // We need to push a fake saved LR onto the stack, 99 // load the signal fault address into LR, and jump 100 // to the real sigpanic. 101 // This simulates what sighandler does for a memory fault. 102 TEXT runtime·_sfloatpanic(SB),NOSPLIT,$-4 103 MOVW $0, R0 104 MOVW.W R0, -4(R13) 105 MOVW g_sigpc(g), LR 106 B runtime·sigpanic(SB) 107 108 // func udiv(n, d uint32) (q, r uint32) 109 // Reference: 110 // Sloss, Andrew et. al; ARM System Developer's Guide: Designing and Optimizing System Software 111 // Morgan Kaufmann; 1 edition (April 8, 2004), ISBN 978-1558608740 112 #define Rq R0 // input d, output q 113 #define Rr R1 // input n, output r 114 #define Rs R2 // three temporary variables 115 #define RM R3 116 #define Ra R11 117 118 // Be careful: Ra == R11 will be used by the linker for synthesized instructions. 119 TEXT udiv<>(SB),NOSPLIT,$-4 120 CLZ Rq, Rs // find normalizing shift 121 MOVW.S Rq<<Rs, Ra 122 MOVW $fast_udiv_tab<>-64(SB), RM 123 ADD.NE Ra>>25, RM, Ra // index by most significant 7 bits of divisor 124 MOVBU.NE (Ra), Ra 125 126 SUB.S $7, Rs 127 RSB $0, Rq, RM // M = -q 128 MOVW.PL Ra<<Rs, Rq 129 130 // 1st Newton iteration 131 MUL.PL RM, Rq, Ra // a = -q*d 132 BMI udiv_by_large_d 133 MULAWT Ra, Rq, Rq, Rq // q approx q-(q*q*d>>32) 134 TEQ RM->1, RM // check for d=0 or d=1 135 136 // 2nd Newton iteration 137 MUL.NE RM, Rq, Ra 138 MOVW.NE $0, Rs 139 MULAL.NE Rq, Ra, (Rq,Rs) 140 BEQ udiv_by_0_or_1 141 142 // q now accurate enough for a remainder r, 0<=r<3*d 143 MULLU Rq, Rr, (Rq,Rs) // q = (r * q) >> 32 144 ADD RM, Rr, Rr // r = n - d 145 MULA RM, Rq, Rr, Rr // r = n - (q+1)*d 146 147 // since 0 <= n-q*d < 3*d; thus -d <= r < 2*d 148 CMN RM, Rr // t = r-d 149 SUB.CS RM, Rr, Rr // if (t<-d || t>=0) r=r+d 150 ADD.CC $1, Rq 151 ADD.PL RM<<1, Rr 152 ADD.PL $2, Rq 153 RET 154 155 udiv_by_large_d: 156 // at this point we know d>=2^(31-6)=2^25 157 SUB $4, Ra, Ra 158 RSB $0, Rs, Rs 159 MOVW Ra>>Rs, Rq 160 MULLU Rq, Rr, (Rq,Rs) 161 MULA RM, Rq, Rr, Rr 162 163 // q now accurate enough for a remainder r, 0<=r<4*d 164 CMN Rr>>1, RM // if(r/2 >= d) 165 ADD.CS RM<<1, Rr 166 ADD.CS $2, Rq 167 CMN Rr, RM 168 ADD.CS RM, Rr 169 ADD.CS $1, Rq 170 RET 171 172 udiv_by_0_or_1: 173 // carry set if d==1, carry clear if d==0 174 BCC udiv_by_0 175 MOVW Rr, Rq 176 MOVW $0, Rr 177 RET 178 179 udiv_by_0: 180 // The ARM toolchain expects it can emit references to DIV and MOD 181 // instructions. The linker rewrites each pseudo-instruction into 182 // a sequence that pushes two values onto the stack and then calls 183 // _divu, _modu, _div, or _mod (below), all of which have a 16-byte 184 // frame plus the saved LR. The traceback routine knows the expanded 185 // stack frame size at the pseudo-instruction call site, but it 186 // doesn't know that the frame has a non-standard layout. In particular, 187 // it expects to find a saved LR in the bottom word of the frame. 188 // Unwind the stack back to the pseudo-instruction call site, copy the 189 // saved LR where the traceback routine will look for it, and make it 190 // appear that panicdivide was called from that PC. 191 MOVW 0(R13), LR 192 ADD $20, R13 193 MOVW 8(R13), R1 // actual saved LR 194 MOVW R1, 0(R13) // expected here for traceback 195 B runtime·panicdivide(SB) 196 197 // var tab [64]byte 198 // tab[0] = 255; for i := 1; i <= 63; i++ { tab[i] = (1<<14)/(64+i) } 199 // laid out here as little-endian uint32s 200 DATA fast_udiv_tab<>+0x00(SB)/4, $0xf4f8fcff 201 DATA fast_udiv_tab<>+0x04(SB)/4, $0xe6eaedf0 202 DATA fast_udiv_tab<>+0x08(SB)/4, $0xdadde0e3 203 DATA fast_udiv_tab<>+0x0c(SB)/4, $0xcfd2d4d7 204 DATA fast_udiv_tab<>+0x10(SB)/4, $0xc5c7cacc 205 DATA fast_udiv_tab<>+0x14(SB)/4, $0xbcbec0c3 206 DATA fast_udiv_tab<>+0x18(SB)/4, $0xb4b6b8ba 207 DATA fast_udiv_tab<>+0x1c(SB)/4, $0xacaeb0b2 208 DATA fast_udiv_tab<>+0x20(SB)/4, $0xa5a7a8aa 209 DATA fast_udiv_tab<>+0x24(SB)/4, $0x9fa0a2a3 210 DATA fast_udiv_tab<>+0x28(SB)/4, $0x999a9c9d 211 DATA fast_udiv_tab<>+0x2c(SB)/4, $0x93949697 212 DATA fast_udiv_tab<>+0x30(SB)/4, $0x8e8f9092 213 DATA fast_udiv_tab<>+0x34(SB)/4, $0x898a8c8d 214 DATA fast_udiv_tab<>+0x38(SB)/4, $0x85868788 215 DATA fast_udiv_tab<>+0x3c(SB)/4, $0x81828384 216 GLOBL fast_udiv_tab<>(SB), RODATA, $64 217 218 // The linker will pass numerator in RTMP, and it also 219 // expects the result in RTMP 220 #define RTMP R11 221 222 TEXT _divu(SB), NOSPLIT, $16 223 MOVW Rq, 4(R13) 224 MOVW Rr, 8(R13) 225 MOVW Rs, 12(R13) 226 MOVW RM, 16(R13) 227 228 MOVW RTMP, Rr /* numerator */ 229 MOVW den+0(FP), Rq /* denominator */ 230 BL udiv<>(SB) 231 MOVW Rq, RTMP 232 MOVW 4(R13), Rq 233 MOVW 8(R13), Rr 234 MOVW 12(R13), Rs 235 MOVW 16(R13), RM 236 RET 237 238 TEXT _modu(SB), NOSPLIT, $16 239 MOVW Rq, 4(R13) 240 MOVW Rr, 8(R13) 241 MOVW Rs, 12(R13) 242 MOVW RM, 16(R13) 243 244 MOVW RTMP, Rr /* numerator */ 245 MOVW den+0(FP), Rq /* denominator */ 246 BL udiv<>(SB) 247 MOVW Rr, RTMP 248 MOVW 4(R13), Rq 249 MOVW 8(R13), Rr 250 MOVW 12(R13), Rs 251 MOVW 16(R13), RM 252 RET 253 254 TEXT _div(SB),NOSPLIT,$16 255 MOVW Rq, 4(R13) 256 MOVW Rr, 8(R13) 257 MOVW Rs, 12(R13) 258 MOVW RM, 16(R13) 259 MOVW RTMP, Rr /* numerator */ 260 MOVW den+0(FP), Rq /* denominator */ 261 CMP $0, Rr 262 BGE d1 263 RSB $0, Rr, Rr 264 CMP $0, Rq 265 BGE d2 266 RSB $0, Rq, Rq 267 d0: 268 BL udiv<>(SB) /* none/both neg */ 269 MOVW Rq, RTMP 270 B out1 271 d1: 272 CMP $0, Rq 273 BGE d0 274 RSB $0, Rq, Rq 275 d2: 276 BL udiv<>(SB) /* one neg */ 277 RSB $0, Rq, RTMP 278 out1: 279 MOVW 4(R13), Rq 280 MOVW 8(R13), Rr 281 MOVW 12(R13), Rs 282 MOVW 16(R13), RM 283 RET 284 285 TEXT _mod(SB),NOSPLIT,$16 286 MOVW Rq, 4(R13) 287 MOVW Rr, 8(R13) 288 MOVW Rs, 12(R13) 289 MOVW RM, 16(R13) 290 MOVW RTMP, Rr /* numerator */ 291 MOVW den+0(FP), Rq /* denominator */ 292 CMP $0, Rq 293 RSB.LT $0, Rq, Rq 294 CMP $0, Rr 295 BGE m1 296 RSB $0, Rr, Rr 297 BL udiv<>(SB) /* neg numerator */ 298 RSB $0, Rr, RTMP 299 B out 300 m1: 301 BL udiv<>(SB) /* pos numerator */ 302 MOVW Rr, RTMP 303 out: 304 MOVW 4(R13), Rq 305 MOVW 8(R13), Rr 306 MOVW 12(R13), Rs 307 MOVW 16(R13), RM 308 RET 309 310 // _mul64by32 and _div64by32 not implemented on arm 311 TEXT runtime·_mul64by32(SB), NOSPLIT, $0 312 MOVW $0, R0 313 MOVW (R0), R1 // crash 314 315 TEXT runtime·_div64by32(SB), NOSPLIT, $0 316 MOVW $0, R0 317 MOVW (R0), R1 // crash