| // Inferno's libkern/vlrt-arm.c | |
| // https://bitbucket.org/inferno-os/inferno-os/src/default/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. | |
| // +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 _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<<sh | xlo>>(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 | |
| } | |
| //go:nosplit | |
| // nosplit because division is used in syscall context in nanotime on darwin/386 | |
| // and darwin/arm where stack splits are not allowed. | |
| 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 for GOARCH=386 GO386=387. | |
| // 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 | |
| controlWord32 = 0x3f + 0<<8 + 0<<10 | |
| controlWord64trunc = 0x3f + 2<<8 + 3<<10 | |
| ) |