Home | History | Annotate | Download | only in runtime
      1 // Inferno's libkern/vlrt-arm.c
      2 // https://bitbucket.org/inferno-os/inferno-os/src/default/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 // +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 _d2v(y *uint64, d float64) {
     62 	x := *(*uint64)(unsafe.Pointer(&d))
     63 
     64 	xhi := uint32(x>>32)&0xfffff | 0x100000
     65 	xlo := uint32(x)
     66 	sh := 1075 - int32(uint32(x>>52)&0x7ff)
     67 
     68 	var ylo, yhi uint32
     69 	if sh >= 0 {
     70 		sh := uint32(sh)
     71 		/* v = (hi||lo) >> sh */
     72 		if sh < 32 {
     73 			if sh == 0 {
     74 				ylo = xlo
     75 				yhi = xhi
     76 			} else {
     77 				ylo = xlo>>sh | xhi<<(32-sh)
     78 				yhi = xhi >> sh
     79 			}
     80 		} else {
     81 			if sh == 32 {
     82 				ylo = xhi
     83 			} else if sh < 64 {
     84 				ylo = xhi >> (sh - 32)
     85 			}
     86 		}
     87 	} else {
     88 		/* v = (hi||lo) << -sh */
     89 		sh := uint32(-sh)
     90 		if sh <= 11 {
     91 			ylo = xlo << sh
     92 			yhi = xhi<<sh | xlo>>(32-sh)
     93 		} else {
     94 			/* overflow */
     95 			yhi = uint32(d) /* causes something awful */
     96 		}
     97 	}
     98 	if x&sign64 != 0 {
     99 		if ylo != 0 {
    100 			ylo = -ylo
    101 			yhi = ^yhi
    102 		} else {
    103 			yhi = -yhi
    104 		}
    105 	}
    106 
    107 	*y = uint64(yhi)<<32 | uint64(ylo)
    108 }
    109 
    110 func uint64div(n, d uint64) uint64 {
    111 	// Check for 32 bit operands
    112 	if uint32(n>>32) == 0 && uint32(d>>32) == 0 {
    113 		if uint32(d) == 0 {
    114 			panicdivide()
    115 		}
    116 		return uint64(uint32(n) / uint32(d))
    117 	}
    118 	q, _ := dodiv(n, d)
    119 	return q
    120 }
    121 
    122 func uint64mod(n, d uint64) uint64 {
    123 	// Check for 32 bit operands
    124 	if uint32(n>>32) == 0 && uint32(d>>32) == 0 {
    125 		if uint32(d) == 0 {
    126 			panicdivide()
    127 		}
    128 		return uint64(uint32(n) % uint32(d))
    129 	}
    130 	_, r := dodiv(n, d)
    131 	return r
    132 }
    133 
    134 func int64div(n, d int64) int64 {
    135 	// Check for 32 bit operands
    136 	if int64(int32(n)) == n && int64(int32(d)) == d {
    137 		if int32(n) == -0x80000000 && int32(d) == -1 {
    138 			// special case: 32-bit -0x80000000 / -1 = -0x80000000,
    139 			// but 64-bit -0x80000000 / -1 = 0x80000000.
    140 			return 0x80000000
    141 		}
    142 		if int32(d) == 0 {
    143 			panicdivide()
    144 		}
    145 		return int64(int32(n) / int32(d))
    146 	}
    147 
    148 	nneg := n < 0
    149 	dneg := d < 0
    150 	if nneg {
    151 		n = -n
    152 	}
    153 	if dneg {
    154 		d = -d
    155 	}
    156 	uq, _ := dodiv(uint64(n), uint64(d))
    157 	q := int64(uq)
    158 	if nneg != dneg {
    159 		q = -q
    160 	}
    161 	return q
    162 }
    163 
    164 func int64mod(n, d int64) int64 {
    165 	// Check for 32 bit operands
    166 	if int64(int32(n)) == n && int64(int32(d)) == d {
    167 		if int32(d) == 0 {
    168 			panicdivide()
    169 		}
    170 		return int64(int32(n) % int32(d))
    171 	}
    172 
    173 	nneg := n < 0
    174 	if nneg {
    175 		n = -n
    176 	}
    177 	if d < 0 {
    178 		d = -d
    179 	}
    180 	_, ur := dodiv(uint64(n), uint64(d))
    181 	r := int64(ur)
    182 	if nneg {
    183 		r = -r
    184 	}
    185 	return r
    186 }
    187 
    188 //go:noescape
    189 func _mul64by32(lo64 *uint64, a uint64, b uint32) (hi32 uint32)
    190 
    191 //go:noescape
    192 func _div64by32(a uint64, b uint32, r *uint32) (q uint32)
    193 
    194 func dodiv(n, d uint64) (q, r uint64) {
    195 	if GOARCH == "arm" {
    196 		// arm doesn't have a division instruction, so
    197 		// slowdodiv is the best that we can do.
    198 		return slowdodiv(n, d)
    199 	}
    200 
    201 	if GOARCH == "mips" || GOARCH == "mipsle" {
    202 		// No _div64by32 on mips and using only _mul64by32 doesn't bring much benefit
    203 		return slowdodiv(n, d)
    204 	}
    205 
    206 	if d > n {
    207 		return 0, n
    208 	}
    209 
    210 	if uint32(d>>32) != 0 {
    211 		t := uint32(n>>32) / uint32(d>>32)
    212 		var lo64 uint64
    213 		hi32 := _mul64by32(&lo64, d, t)
    214 		if hi32 != 0 || lo64 > n {
    215 			return slowdodiv(n, d)
    216 		}
    217 		return uint64(t), n - lo64
    218 	}
    219 
    220 	// d is 32 bit
    221 	var qhi uint32
    222 	if uint32(n>>32) >= uint32(d) {
    223 		if uint32(d) == 0 {
    224 			panicdivide()
    225 		}
    226 		qhi = uint32(n>>32) / uint32(d)
    227 		n -= uint64(uint32(d)*qhi) << 32
    228 	} else {
    229 		qhi = 0
    230 	}
    231 
    232 	var rlo uint32
    233 	qlo := _div64by32(n, uint32(d), &rlo)
    234 	return uint64(qhi)<<32 + uint64(qlo), uint64(rlo)
    235 }
    236 
    237 func slowdodiv(n, d uint64) (q, r uint64) {
    238 	if d == 0 {
    239 		panicdivide()
    240 	}
    241 
    242 	// Set up the divisor and find the number of iterations needed.
    243 	capn := n
    244 	if n >= sign64 {
    245 		capn = sign64
    246 	}
    247 	i := 0
    248 	for d < capn {
    249 		d <<= 1
    250 		i++
    251 	}
    252 
    253 	for ; i >= 0; i-- {
    254 		q <<= 1
    255 		if n >= d {
    256 			n -= d
    257 			q |= 1
    258 		}
    259 		d >>= 1
    260 	}
    261 	return q, n
    262 }
    263 
    264 // Floating point control word values for GOARCH=386 GO386=387.
    265 // Bits 0-5 are bits to disable floating-point exceptions.
    266 // Bits 8-9 are the precision control:
    267 //   0 = single precision a.k.a. float32
    268 //   2 = double precision a.k.a. float64
    269 // Bits 10-11 are the rounding mode:
    270 //   0 = round to nearest (even on a tie)
    271 //   3 = round toward zero
    272 var (
    273 	controlWord64      uint16 = 0x3f + 2<<8 + 0<<10
    274 	controlWord32             = 0x3f + 0<<8 + 0<<10
    275 	controlWord64trunc        = 0x3f + 2<<8 + 3<<10
    276 )
    277