Source file src/runtime/vlrt.go

     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  )
   311  

View as plain text