1// Inferno's libkern/vlrt-arm.c 2// https://bitbucket.org/inferno-os/inferno-os/src/default/libkern/vlrt-arm.c 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// +build arm 386 mips mipsle 27 28package runtime 29 30import "unsafe" 31 32const ( 33 sign32 = 1 << (32 - 1) 34 sign64 = 1 << (64 - 1) 35) 36 37func float64toint64(d float64) (y uint64) { 38 _d2v(&y, d) 39 return 40} 41 42func float64touint64(d float64) (y uint64) { 43 _d2v(&y, d) 44 return 45} 46 47func int64tofloat64(y int64) float64 { 48 if y < 0 { 49 return -uint64tofloat64(-uint64(y)) 50 } 51 return uint64tofloat64(uint64(y)) 52} 53 54func uint64tofloat64(y uint64) float64 { 55 hi := float64(uint32(y >> 32)) 56 lo := float64(uint32(y)) 57 d := hi*(1<<32) + lo 58 return d 59} 60 61func _d2v(y *uint64, d float64) { 62 x := *(*uint64)(unsafe.Pointer(&d)) 63 64 xhi := uint32(x>>32)&0xfffff | 0x100000 65 xlo := uint32(x) 66 sh := 1075 - int32(uint32(x>>52)&0x7ff) 67 68 var ylo, yhi uint32 69 if sh >= 0 { 70 sh := uint32(sh) 71 /* v = (hi||lo) >> sh */ 72 if sh < 32 { 73 if sh == 0 { 74 ylo = xlo 75 yhi = xhi 76 } else { 77 ylo = xlo>>sh | xhi<<(32-sh) 78 yhi = xhi >> sh 79 } 80 } else { 81 if sh == 32 { 82 ylo = xhi 83 } else if sh < 64 { 84 ylo = xhi >> (sh - 32) 85 } 86 } 87 } else { 88 /* v = (hi||lo) << -sh */ 89 sh := uint32(-sh) 90 if sh <= 11 { 91 ylo = xlo << sh 92 yhi = xhi<<sh | xlo>>(32-sh) 93 } else { 94 /* overflow */ 95 yhi = uint32(d) /* causes something awful */ 96 } 97 } 98 if x&sign64 != 0 { 99 if ylo != 0 { 100 ylo = -ylo 101 yhi = ^yhi 102 } else { 103 yhi = -yhi 104 } 105 } 106 107 *y = uint64(yhi)<<32 | uint64(ylo) 108} 109func uint64div(n, d uint64) uint64 { 110 // Check for 32 bit operands 111 if uint32(n>>32) == 0 && uint32(d>>32) == 0 { 112 if uint32(d) == 0 { 113 panicdivide() 114 } 115 return uint64(uint32(n) / uint32(d)) 116 } 117 q, _ := dodiv(n, d) 118 return q 119} 120 121func uint64mod(n, d uint64) uint64 { 122 // Check for 32 bit operands 123 if uint32(n>>32) == 0 && uint32(d>>32) == 0 { 124 if uint32(d) == 0 { 125 panicdivide() 126 } 127 return uint64(uint32(n) % uint32(d)) 128 } 129 _, r := dodiv(n, d) 130 return r 131} 132 133//go:nosplit 134// nosplit because division is used in syscall context in nanotime on darwin/386 135// and darwin/arm where stack splits are not allowed. 136func int64div(n, d int64) int64 { 137 // Check for 32 bit operands 138 if int64(int32(n)) == n && int64(int32(d)) == d { 139 if int32(n) == -0x80000000 && int32(d) == -1 { 140 // special case: 32-bit -0x80000000 / -1 = -0x80000000, 141 // but 64-bit -0x80000000 / -1 = 0x80000000. 142 return 0x80000000 143 } 144 if int32(d) == 0 { 145 panicdivide() 146 } 147 return int64(int32(n) / int32(d)) 148 } 149 150 nneg := n < 0 151 dneg := d < 0 152 if nneg { 153 n = -n 154 } 155 if dneg { 156 d = -d 157 } 158 uq, _ := dodiv(uint64(n), uint64(d)) 159 q := int64(uq) 160 if nneg != dneg { 161 q = -q 162 } 163 return q 164} 165 166//go:nosplit 167func int64mod(n, d int64) int64 { 168 // Check for 32 bit operands 169 if int64(int32(n)) == n && int64(int32(d)) == d { 170 if int32(d) == 0 { 171 panicdivide() 172 } 173 return int64(int32(n) % int32(d)) 174 } 175 176 nneg := n < 0 177 if nneg { 178 n = -n 179 } 180 if d < 0 { 181 d = -d 182 } 183 _, ur := dodiv(uint64(n), uint64(d)) 184 r := int64(ur) 185 if nneg { 186 r = -r 187 } 188 return r 189} 190 191//go:noescape 192func _mul64by32(lo64 *uint64, a uint64, b uint32) (hi32 uint32) 193 194//go:noescape 195func _div64by32(a uint64, b uint32, r *uint32) (q uint32) 196 197//go:nosplit 198func dodiv(n, d uint64) (q, r uint64) { 199 if GOARCH == "arm" { 200 // arm doesn't have a division instruction, so 201 // slowdodiv is the best that we can do. 202 return slowdodiv(n, d) 203 } 204 205 if GOARCH == "mips" || GOARCH == "mipsle" { 206 // No _div64by32 on mips and using only _mul64by32 doesn't bring much benefit 207 return slowdodiv(n, d) 208 } 209 210 if d > n { 211 return 0, n 212 } 213 214 if uint32(d>>32) != 0 { 215 t := uint32(n>>32) / uint32(d>>32) 216 var lo64 uint64 217 hi32 := _mul64by32(&lo64, d, t) 218 if hi32 != 0 || lo64 > n { 219 return slowdodiv(n, d) 220 } 221 return uint64(t), n - lo64 222 } 223 224 // d is 32 bit 225 var qhi uint32 226 if uint32(n>>32) >= uint32(d) { 227 if uint32(d) == 0 { 228 panicdivide() 229 } 230 qhi = uint32(n>>32) / uint32(d) 231 n -= uint64(uint32(d)*qhi) << 32 232 } else { 233 qhi = 0 234 } 235 236 var rlo uint32 237 qlo := _div64by32(n, uint32(d), &rlo) 238 return uint64(qhi)<<32 + uint64(qlo), uint64(rlo) 239} 240 241//go:nosplit 242func slowdodiv(n, d uint64) (q, r uint64) { 243 if d == 0 { 244 panicdivide() 245 } 246 247 // Set up the divisor and find the number of iterations needed. 248 capn := n 249 if n >= sign64 { 250 capn = sign64 251 } 252 i := 0 253 for d < capn { 254 d <<= 1 255 i++ 256 } 257 258 for ; i >= 0; i-- { 259 q <<= 1 260 if n >= d { 261 n -= d 262 q |= 1 263 } 264 d >>= 1 265 } 266 return q, n 267} 268 269// Floating point control word values for GOARCH=386 GO386=387. 270// Bits 0-5 are bits to disable floating-point exceptions. 271// Bits 8-9 are the precision control: 272// 0 = single precision a.k.a. float32 273// 2 = double precision a.k.a. float64 274// Bits 10-11 are the rounding mode: 275// 0 = round to nearest (even on a tie) 276// 3 = round toward zero 277var ( 278 controlWord64 uint16 = 0x3f + 2<<8 + 0<<10 279 controlWord32 = 0x3f + 0<<8 + 0<<10 280 controlWord64trunc = 0x3f + 2<<8 + 3<<10 281) 282