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