// Inferno's libkern/vlrt-arm.c // https://bitbucket.org/inferno-os/inferno-os/src/master/libkern/vlrt-arm.c // // Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. // Revisions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com). All rights reserved. // Portions Copyright 2009 The Go Authors. All rights reserved. // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. //go:build arm || 386 || mips || mipsle package runtime import "unsafe" const ( sign32 = 1 << (32 - 1) sign64 = 1 << (64 - 1) ) func float64toint64(d float64) (y uint64) { _d2v(&y, d) return } func float64touint64(d float64) (y uint64) { _d2v(&y, d) return } func int64tofloat64(y int64) float64 { if y < 0 { return -uint64tofloat64(-uint64(y)) } return uint64tofloat64(uint64(y)) } func uint64tofloat64(y uint64) float64 { hi := float64(uint32(y >> 32)) lo := float64(uint32(y)) d := hi*(1<<32) + lo return d } func int64tofloat32(y int64) float32 { if y < 0 { return -uint64tofloat32(-uint64(y)) } return uint64tofloat32(uint64(y)) } func uint64tofloat32(y uint64) float32 { // divide into top 18, mid 23, and bottom 23 bits. // (23-bit integers fit into a float32 without loss.) top := uint32(y >> 46) mid := uint32(y >> 23 & (1<<23 - 1)) bot := uint32(y & (1<<23 - 1)) if top == 0 { return float32(mid)*(1<<23) + float32(bot) } if bot != 0 { // Top is not zero, so the bits in bot // won't make it into the final mantissa. // In fact, the bottom bit of mid won't // make it into the mantissa either. // We only need to make sure that if top+mid // is about to round down in a round-to-even // scenario, and bot is not zero, we make it // round up instead. mid |= 1 } return float32(top)*(1<<46) + float32(mid)*(1<<23) } func _d2v(y *uint64, d float64) { x := *(*uint64)(unsafe.Pointer(&d)) xhi := uint32(x>>32)&0xfffff | 0x100000 xlo := uint32(x) sh := 1075 - int32(uint32(x>>52)&0x7ff) var ylo, yhi uint32 if sh >= 0 { sh := uint32(sh) /* v = (hi||lo) >> sh */ if sh < 32 { if sh == 0 { ylo = xlo yhi = xhi } else { ylo = xlo>>sh | xhi<<(32-sh) yhi = xhi >> sh } } else { if sh == 32 { ylo = xhi } else if sh < 64 { ylo = xhi >> (sh - 32) } } } else { /* v = (hi||lo) << -sh */ sh := uint32(-sh) if sh <= 11 { ylo = xlo << sh yhi = xhi<>(32-sh) } else { /* overflow */ yhi = uint32(d) /* causes something awful */ } } if x&sign64 != 0 { if ylo != 0 { ylo = -ylo yhi = ^yhi } else { yhi = -yhi } } *y = uint64(yhi)<<32 | uint64(ylo) } func uint64div(n, d uint64) uint64 { // Check for 32 bit operands if uint32(n>>32) == 0 && uint32(d>>32) == 0 { if uint32(d) == 0 { panicdivide() } return uint64(uint32(n) / uint32(d)) } q, _ := dodiv(n, d) return q } func uint64mod(n, d uint64) uint64 { // Check for 32 bit operands if uint32(n>>32) == 0 && uint32(d>>32) == 0 { if uint32(d) == 0 { panicdivide() } return uint64(uint32(n) % uint32(d)) } _, r := dodiv(n, d) return r } func int64div(n, d int64) int64 { // Check for 32 bit operands if int64(int32(n)) == n && int64(int32(d)) == d { if int32(n) == -0x80000000 && int32(d) == -1 { // special case: 32-bit -0x80000000 / -1 = -0x80000000, // but 64-bit -0x80000000 / -1 = 0x80000000. return 0x80000000 } if int32(d) == 0 { panicdivide() } return int64(int32(n) / int32(d)) } nneg := n < 0 dneg := d < 0 if nneg { n = -n } if dneg { d = -d } uq, _ := dodiv(uint64(n), uint64(d)) q := int64(uq) if nneg != dneg { q = -q } return q } //go:nosplit func int64mod(n, d int64) int64 { // Check for 32 bit operands if int64(int32(n)) == n && int64(int32(d)) == d { if int32(d) == 0 { panicdivide() } return int64(int32(n) % int32(d)) } nneg := n < 0 if nneg { n = -n } if d < 0 { d = -d } _, ur := dodiv(uint64(n), uint64(d)) r := int64(ur) if nneg { r = -r } return r } //go:noescape func _mul64by32(lo64 *uint64, a uint64, b uint32) (hi32 uint32) //go:noescape func _div64by32(a uint64, b uint32, r *uint32) (q uint32) //go:nosplit func dodiv(n, d uint64) (q, r uint64) { if GOARCH == "arm" { // arm doesn't have a division instruction, so // slowdodiv is the best that we can do. return slowdodiv(n, d) } if GOARCH == "mips" || GOARCH == "mipsle" { // No _div64by32 on mips and using only _mul64by32 doesn't bring much benefit return slowdodiv(n, d) } if d > n { return 0, n } if uint32(d>>32) != 0 { t := uint32(n>>32) / uint32(d>>32) var lo64 uint64 hi32 := _mul64by32(&lo64, d, t) if hi32 != 0 || lo64 > n { return slowdodiv(n, d) } return uint64(t), n - lo64 } // d is 32 bit var qhi uint32 if uint32(n>>32) >= uint32(d) { if uint32(d) == 0 { panicdivide() } qhi = uint32(n>>32) / uint32(d) n -= uint64(uint32(d)*qhi) << 32 } else { qhi = 0 } var rlo uint32 qlo := _div64by32(n, uint32(d), &rlo) return uint64(qhi)<<32 + uint64(qlo), uint64(rlo) } //go:nosplit func slowdodiv(n, d uint64) (q, r uint64) { if d == 0 { panicdivide() } // Set up the divisor and find the number of iterations needed. capn := n if n >= sign64 { capn = sign64 } i := 0 for d < capn { d <<= 1 i++ } for ; i >= 0; i-- { q <<= 1 if n >= d { n -= d q |= 1 } d >>= 1 } return q, n } // Floating point control word values. // Bits 0-5 are bits to disable floating-point exceptions. // Bits 8-9 are the precision control: // // 0 = single precision a.k.a. float32 // 2 = double precision a.k.a. float64 // // Bits 10-11 are the rounding mode: // // 0 = round to nearest (even on a tie) // 3 = round toward zero var ( controlWord64 uint16 = 0x3f + 2<<8 + 0<<10 controlWord64trunc uint16 = 0x3f + 2<<8 + 3<<10 )