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
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 _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}
109func uint64div(n, d uint64) uint64 {
110	// Check for 32 bit operands
111	if uint32(n>>32) == 0 && uint32(d>>32) == 0 {
112		if uint32(d) == 0 {
113			panicdivide()
114		}
115		return uint64(uint32(n) / uint32(d))
116	}
117	q, _ := dodiv(n, d)
118	return q
119}
120
121func uint64mod(n, d uint64) uint64 {
122	// Check for 32 bit operands
123	if uint32(n>>32) == 0 && uint32(d>>32) == 0 {
124		if uint32(d) == 0 {
125			panicdivide()
126		}
127		return uint64(uint32(n) % uint32(d))
128	}
129	_, r := dodiv(n, d)
130	return r
131}
132
133//go:nosplit
134// nosplit because division is used in syscall context in nanotime on darwin/386
135// and darwin/arm where stack splits are not allowed.
136func int64div(n, d int64) int64 {
137	// Check for 32 bit operands
138	if int64(int32(n)) == n && int64(int32(d)) == d {
139		if int32(n) == -0x80000000 && int32(d) == -1 {
140			// special case: 32-bit -0x80000000 / -1 = -0x80000000,
141			// but 64-bit -0x80000000 / -1 = 0x80000000.
142			return 0x80000000
143		}
144		if int32(d) == 0 {
145			panicdivide()
146		}
147		return int64(int32(n) / int32(d))
148	}
149
150	nneg := n < 0
151	dneg := d < 0
152	if nneg {
153		n = -n
154	}
155	if dneg {
156		d = -d
157	}
158	uq, _ := dodiv(uint64(n), uint64(d))
159	q := int64(uq)
160	if nneg != dneg {
161		q = -q
162	}
163	return q
164}
165
166//go:nosplit
167func int64mod(n, d int64) int64 {
168	// Check for 32 bit operands
169	if int64(int32(n)) == n && int64(int32(d)) == d {
170		if int32(d) == 0 {
171			panicdivide()
172		}
173		return int64(int32(n) % int32(d))
174	}
175
176	nneg := n < 0
177	if nneg {
178		n = -n
179	}
180	if d < 0 {
181		d = -d
182	}
183	_, ur := dodiv(uint64(n), uint64(d))
184	r := int64(ur)
185	if nneg {
186		r = -r
187	}
188	return r
189}
190
191//go:noescape
192func _mul64by32(lo64 *uint64, a uint64, b uint32) (hi32 uint32)
193
194//go:noescape
195func _div64by32(a uint64, b uint32, r *uint32) (q uint32)
196
197//go:nosplit
198func dodiv(n, d uint64) (q, r uint64) {
199	if GOARCH == "arm" {
200		// arm doesn't have a division instruction, so
201		// slowdodiv is the best that we can do.
202		return slowdodiv(n, d)
203	}
204
205	if GOARCH == "mips" || GOARCH == "mipsle" {
206		// No _div64by32 on mips and using only _mul64by32 doesn't bring much benefit
207		return slowdodiv(n, d)
208	}
209
210	if d > n {
211		return 0, n
212	}
213
214	if uint32(d>>32) != 0 {
215		t := uint32(n>>32) / uint32(d>>32)
216		var lo64 uint64
217		hi32 := _mul64by32(&lo64, d, t)
218		if hi32 != 0 || lo64 > n {
219			return slowdodiv(n, d)
220		}
221		return uint64(t), n - lo64
222	}
223
224	// d is 32 bit
225	var qhi uint32
226	if uint32(n>>32) >= uint32(d) {
227		if uint32(d) == 0 {
228			panicdivide()
229		}
230		qhi = uint32(n>>32) / uint32(d)
231		n -= uint64(uint32(d)*qhi) << 32
232	} else {
233		qhi = 0
234	}
235
236	var rlo uint32
237	qlo := _div64by32(n, uint32(d), &rlo)
238	return uint64(qhi)<<32 + uint64(qlo), uint64(rlo)
239}
240
241//go:nosplit
242func slowdodiv(n, d uint64) (q, r uint64) {
243	if d == 0 {
244		panicdivide()
245	}
246
247	// Set up the divisor and find the number of iterations needed.
248	capn := n
249	if n >= sign64 {
250		capn = sign64
251	}
252	i := 0
253	for d < capn {
254		d <<= 1
255		i++
256	}
257
258	for ; i >= 0; i-- {
259		q <<= 1
260		if n >= d {
261			n -= d
262			q |= 1
263		}
264		d >>= 1
265	}
266	return q, n
267}
268
269// Floating point control word values for GOARCH=386 GO386=387.
270// Bits 0-5 are bits to disable floating-point exceptions.
271// Bits 8-9 are the precision control:
272//   0 = single precision a.k.a. float32
273//   2 = double precision a.k.a. float64
274// Bits 10-11 are the rounding mode:
275//   0 = round to nearest (even on a tie)
276//   3 = round toward zero
277var (
278	controlWord64      uint16 = 0x3f + 2<<8 + 0<<10
279	controlWord32             = 0x3f + 0<<8 + 0<<10
280	controlWord64trunc        = 0x3f + 2<<8 + 3<<10
281)
282