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") }