github.com/primecitizens/pcz/std@v0.2.1/core/emu64/emu64.go (about) 1 // SPDX-License-Identifier: Apache-2.0 2 // Copyright 2023 The Prime Citizens 3 // 4 // Inferno's libkern/vlrt-arm.c 5 // https://bitbucket.org/inferno-os/inferno-os/src/master/libkern/vlrt-arm.c 6 // 7 // Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. 8 // Revisions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com). All rights reserved. 9 // Portions Copyright 2009 The Go Authors. All rights reserved. 10 // 11 // Permission is hereby granted, free of charge, to any person obtaining a copy 12 // of this software and associated documentation files (the "Software"), to deal 13 // in the Software without restriction, including without limitation the rights 14 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 15 // copies of the Software, and to permit persons to whom the Software is 16 // furnished to do so, subject to the following conditions: 17 // 18 // The above copyright notice and this permission notice shall be included in 19 // all copies or substantial portions of the Software. 20 // 21 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 22 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 23 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 24 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 25 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 26 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 27 // THE SOFTWARE. 28 29 //go:build arm || 386 || mips || mipsle 30 31 package emu64 32 33 import ( 34 "unsafe" 35 36 "github.com/primecitizens/pcz/std/core/assert" 37 ) 38 39 const ( 40 sign32 = 1 << (32 - 1) 41 sign64 = 1 << (64 - 1) 42 ) 43 44 func Float64ToInt64(d float64) (y uint64) { 45 _d2v(&y, d) 46 return 47 } 48 49 func Float64ToUint64(d float64) (y uint64) { 50 _d2v(&y, d) 51 return 52 } 53 54 func Int64ToFloat64(y int64) float64 { 55 if y < 0 { 56 return -Uint64ToFloat64(-uint64(y)) 57 } 58 return Uint64ToFloat64(uint64(y)) 59 } 60 61 func Uint64ToFloat64(y uint64) float64 { 62 hi := float64(uint32(y >> 32)) 63 lo := float64(uint32(y)) 64 d := hi*(1<<32) + lo 65 return d 66 } 67 68 func Int64ToFloat32(y int64) float32 { 69 if y < 0 { 70 return -Uint64ToFloat32(-uint64(y)) 71 } 72 return Uint64ToFloat32(uint64(y)) 73 } 74 75 func Uint64ToFloat32(y uint64) float32 { 76 // divide into top 18, mid 23, and bottom 23 bits. 77 // (23-bit integers fit into a float32 without loss.) 78 top := uint32(y >> 46) 79 mid := uint32(y >> 23 & (1<<23 - 1)) 80 bot := uint32(y & (1<<23 - 1)) 81 if top == 0 { 82 return float32(mid)*(1<<23) + float32(bot) 83 } 84 if bot != 0 { 85 // Top is not zero, so the bits in bot 86 // won't make it into the final mantissa. 87 // In fact, the bottom bit of mid won't 88 // make it into the mantissa either. 89 // We only need to make sure that if top+mid 90 // is about to round down in a round-to-even 91 // scenario, and bot is not zero, we make it 92 // round up instead. 93 mid |= 1 94 } 95 return float32(top)*(1<<46) + float32(mid)*(1<<23) 96 } 97 98 func _d2v(y *uint64, d float64) { 99 x := *(*uint64)(unsafe.Pointer(&d)) 100 101 xhi := uint32(x>>32)&0xfffff | 0x100000 102 xlo := uint32(x) 103 sh := 1075 - int32(uint32(x>>52)&0x7ff) 104 105 var ylo, yhi uint32 106 if sh >= 0 { 107 sh := uint32(sh) 108 /* v = (hi||lo) >> sh */ 109 if sh < 32 { 110 if sh == 0 { 111 ylo = xlo 112 yhi = xhi 113 } else { 114 ylo = xlo>>sh | xhi<<(32-sh) 115 yhi = xhi >> sh 116 } 117 } else { 118 if sh == 32 { 119 ylo = xhi 120 } else if sh < 64 { 121 ylo = xhi >> (sh - 32) 122 } 123 } 124 } else { 125 /* v = (hi||lo) << -sh */ 126 sh := uint32(-sh) 127 if sh <= 11 { 128 ylo = xlo << sh 129 yhi = xhi<<sh | xlo>>(32-sh) 130 } else { 131 /* overflow */ 132 yhi = uint32(d) /* causes something awful */ 133 } 134 } 135 if x&sign64 != 0 { 136 if ylo != 0 { 137 ylo = -ylo 138 yhi = ^yhi 139 } else { 140 yhi = -yhi 141 } 142 } 143 144 *y = uint64(yhi)<<32 | uint64(ylo) 145 } 146 147 func Uint64Div(n, d uint64) uint64 { 148 // Check for 32 bit operands 149 if uint32(n>>32) == 0 && uint32(d>>32) == 0 { 150 if uint32(d) == 0 { 151 panicdivide() 152 } 153 return uint64(uint32(n) / uint32(d)) 154 } 155 q, _ := dodiv(n, d) 156 return q 157 } 158 159 func Uint64Mod(n, d uint64) uint64 { 160 // Check for 32 bit operands 161 if uint32(n>>32) == 0 && uint32(d>>32) == 0 { 162 if uint32(d) == 0 { 163 panicdivide() 164 } 165 return uint64(uint32(n) % uint32(d)) 166 } 167 _, r := dodiv(n, d) 168 return r 169 } 170 171 func Int64Div(n, d int64) int64 { 172 // Check for 32 bit operands 173 if int64(int32(n)) == n && int64(int32(d)) == d { 174 if int32(n) == -0x80000000 && int32(d) == -1 { 175 // special case: 32-bit -0x80000000 / -1 = -0x80000000, 176 // but 64-bit -0x80000000 / -1 = 0x80000000. 177 return 0x80000000 178 } 179 if int32(d) == 0 { 180 panicdivide() 181 } 182 return int64(int32(n) / int32(d)) 183 } 184 185 nneg := n < 0 186 dneg := d < 0 187 if nneg { 188 n = -n 189 } 190 if dneg { 191 d = -d 192 } 193 uq, _ := dodiv(uint64(n), uint64(d)) 194 q := int64(uq) 195 if nneg != dneg { 196 q = -q 197 } 198 return q 199 } 200 201 //go:nosplit 202 func Int64Mod(n, d int64) int64 { 203 // Check for 32 bit operands 204 if int64(int32(n)) == n && int64(int32(d)) == d { 205 if int32(d) == 0 { 206 panicdivide() 207 } 208 return int64(int32(n) % int32(d)) 209 } 210 211 nneg := n < 0 212 if nneg { 213 n = -n 214 } 215 if d < 0 { 216 d = -d 217 } 218 _, ur := dodiv(uint64(n), uint64(d)) 219 r := int64(ur) 220 if nneg { 221 r = -r 222 } 223 return r 224 } 225 226 //go:nosplit 227 func slowdodiv(n, d uint64) (q, r uint64) { 228 if d == 0 { 229 panicdivide() 230 } 231 232 // Set up the divisor and find the number of iterations needed. 233 capn := n 234 if n >= sign64 { 235 capn = sign64 236 } 237 i := 0 238 for d < capn { 239 d <<= 1 240 i++ 241 } 242 243 for ; i >= 0; i-- { 244 q <<= 1 245 if n >= d { 246 n -= d 247 q |= 1 248 } 249 d >>= 1 250 } 251 return q, n 252 } 253 254 func panicdivide() { assert.Throw("integer", "divide", "by", "zero") }