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
28package runtime
29
30import "unsafe"
31
32const (
33	sign32 = 1 << (32 - 1)
34	sign64 = 1 << (64 - 1)
35)
36
37func float64toint64(d float64) (y uint64) {
38	_d2v(&y, d)
39	return
40}
41
42func float64touint64(d float64) (y uint64) {
43	_d2v(&y, d)
44	return
45}
46
47func int64tofloat64(y int64) float64 {
48	if y < 0 {
49		return -uint64tofloat64(-uint64(y))
50	}
51	return uint64tofloat64(uint64(y))
52}
53
54func 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
61func int64tofloat32(y int64) float32 {
62	if y < 0 {
63		return -uint64tofloat32(-uint64(y))
64	}
65	return uint64tofloat32(uint64(y))
66}
67
68func 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
91func _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}
139func 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
151func 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
163func 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
194func 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
219func _mul64by32(lo64 *uint64, a uint64, b uint32) (hi32 uint32)
220
221//go:noescape
222func _div64by32(a uint64, b uint32, r *uint32) (q uint32)
223
224//go:nosplit
225func 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
269func 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
307var (
308	controlWord64      uint16 = 0x3f + 2<<8 + 0<<10
309	controlWord64trunc uint16 = 0x3f + 2<<8 + 3<<10
310)
311