140a9f42b634a651c8bcb48e04a4cb8ccff7058f
[openpower-isa.git] / src / openpower / test / fmv_fcvt / fmv_fcvt.py
1 from openpower.test.common import TestAccumulatorBase, skip_case
2 from openpower.insndb.asm import SVP64Asm
3 from openpower.test.state import ExpectedState
4 from openpower.simulator.program import Program
5 from openpower.decoder.isa.caller import SVP64State
6 from openpower.fpscr import FPSCRState
7 from openpower.consts import MSR
8 import struct
9 import math
10 import functools
11
12
13 @functools.lru_cache()
14 def _cached_program(*instrs):
15 return Program(list(SVP64Asm(list(instrs))), bigendian=False)
16
17
18 def bitcast_int_to_fp(bits, bfp32):
19 if bfp32:
20 return struct.unpack("<f", struct.pack("<L", bits))[0]
21 return struct.unpack("<d", struct.pack("<Q", bits))[0]
22
23
24 def bitcast_fp_to_int(fp, bfp32):
25 if bfp32:
26 return struct.unpack("<L", struct.pack("<f", fp))[0]
27 return struct.unpack("<Q", struct.pack("<d", fp))[0]
28
29
30 def fp_bits_add(fp, amount, bfp32=False):
31 """add `amount` to the IEEE 754 bits representing `fp`"""
32 return bitcast_int_to_fp(amount + bitcast_fp_to_int(fp, bfp32), bfp32)
33
34
35 def round_even(v):
36 """round v to the nearest integer, with ties rounding to the even integer
37 """
38 v = float(v)
39 return int(v - math.remainder(v, 1.0))
40
41
42 def do_round(v, round_mode):
43 if round_mode == 0:
44 return round_even(v)
45 if round_mode == 1:
46 return math.trunc(v)
47 if round_mode == 2:
48 return math.ceil(v)
49 if round_mode == 3:
50 return math.floor(v)
51 assert False, "invalid round_mode"
52
53
54 class FMvFCvtCases(TestAccumulatorBase):
55 def toint_helper(self, *, inp, expected=None, test_title="", inp_bits=None,
56 signed=True, _32bit=True, CVM, RN, VE):
57 if CVM & 1:
58 round_mode = 1 # trunc
59 else:
60 round_mode = RN
61 max_v = 2 ** 64 - 1
62 if _32bit:
63 max_v >>= 32
64 min_v = 0
65 if signed:
66 max_v >>= 1
67 min_v = ~max_v
68 inp = float(inp)
69 if inp_bits is None:
70 inp_bits = struct.unpack("<Q", struct.pack("<d", inp))[0]
71 if expected is None:
72 if CVM >> 1 == 0: # openpower semantics
73 if math.isnan(inp):
74 expected = min_v
75 elif inp > max_v:
76 expected = max_v
77 elif inp < min_v:
78 expected = min_v
79 else:
80 expected = do_round(inp, round_mode)
81 elif CVM >> 1 == 1: # saturating semantics
82 if math.isnan(inp):
83 expected = 0
84 elif inp > max_v:
85 expected = max_v
86 elif inp < min_v:
87 expected = min_v
88 else:
89 expected = do_round(inp, round_mode)
90 elif CVM >> 1 == 2: # js semantics
91 if math.isfinite(inp):
92 expected = do_round(inp, round_mode)
93 else:
94 expected = 0
95 if _32bit:
96 expected %= 2 ** 32
97 if signed and expected >> 31:
98 expected -= 2 ** 32
99 expected %= 2 ** 64
100 IT = (not signed) + (not _32bit) * 2
101 with self.subTest(inp=inp.hex(), inp_bits=hex(inp_bits),
102 test_title=test_title,
103 signed=signed, _32bit=_32bit, CVM=CVM, RN=RN, VE=VE):
104 lst = [f"fcvttgo. 3,0,{CVM},{IT}"]
105 gprs = [0] * 32
106 fprs = [0] * 32
107 fprs[0] = inp_bits
108 gprs[3] = 0xabcdef9876543210
109 initial_fpscr = FPSCRState()
110 initial_fpscr.RN = RN
111 initial_fpscr.VE = VE
112 e = ExpectedState(pc=4, int_regs=gprs, fp_regs=fprs)
113 fpscr = FPSCRState(initial_fpscr)
114 if math.isnan(inp) and (inp_bits & 2 ** 51) == 0: # SNaN
115 fpscr.VXSNAN = 1
116 fpscr.FX = 1
117 overflow = True
118 if math.isfinite(inp):
119 overflow = not (min_v <= do_round(inp, round_mode) <= max_v)
120 if overflow:
121 fpscr.VXCVI = 1
122 fpscr.FX = 1
123 e.so = 1
124 e.ov = 0b11
125 elif do_round(inp, round_mode) != inp: # inexact
126 fpscr.XX = 1
127 fpscr.FX = 1
128 fpscr.FI = 1
129 fpscr.FPRF = 0 # undefined value we happen to pick
130 if not overflow:
131 fpscr.FR = abs(do_round(inp, round_mode)) > abs(inp)
132 if overflow and fpscr.VE:
133 # FIXME: #1087 proposes to change pseudocode of fcvt* to
134 # always write output, this implements reading RT when output
135 # isn't written, which is terrible
136 # https://bugs.libre-soc.org/show_bug.cgi?id=1087#c21
137 expected = e.intregs[3]
138 e.pc = 0x700
139 e.sprs['SRR0'] = 0 # insn is at address 0
140 e.sprs['SRR1'] = e.msr | (1 << (63 - 43))
141 e.msr = 0x9000000000000001
142 lt = bool(expected & (1 << 63))
143 gt = not lt and expected != 0
144 eq = expected == 0
145 e.crregs[0] = (lt << 3) | (gt << 2) | (eq << 1) | e.so
146 e.intregs[3] = expected
147 with self.subTest(expected_VXSNAN=fpscr.VXSNAN,
148 expected_VXCVI=fpscr.VXCVI,
149 expected_XX=fpscr.XX,
150 expected_FI=fpscr.FI,
151 expected=hex(expected)):
152 e.fpscr = int(fpscr)
153 self.add_case(
154 _cached_program(*lst), gprs, fpregs=fprs, expected=e,
155 initial_fpscr=int(initial_fpscr))
156
157 def toint(self, inp, expected=None, test_title="", inp_bits=None,
158 signed=True, _32bit=True):
159 for CVM in range(6):
160 for RN in range(1 if CVM & 1 else 4):
161 for VE in range(2):
162 self.toint_helper(
163 inp=inp, expected=expected if CVM == 5 else None,
164 test_title=test_title, inp_bits=inp_bits,
165 signed=signed, _32bit=_32bit, CVM=CVM, RN=RN, VE=VE)
166
167 def case_js_toint32(self):
168 min_value = pow(2, -1074)
169 # test cases from:
170 # https://chromium.googlesource.com/v8/v8.git/+/d94dfc2b01f988566aa410ce871588cf23b1285d/test/mjsunit/toint32.js
171 # Copyright 2008 the V8 project authors. All rights reserved.
172 # Redistribution and use in source and binary forms, with or without
173 # modification, are permitted provided that the following conditions are
174 # met:
175 #
176 # * Redistributions of source code must retain the above copyright
177 # notice, this list of conditions and the following disclaimer.
178 # * Redistributions in binary form must reproduce the above
179 # copyright notice, this list of conditions and the following
180 # disclaimer in the documentation and/or other materials provided
181 # with the distribution.
182 # * Neither the name of Google Inc. nor the names of its
183 # contributors may be used to endorse or promote products derived
184 # from this software without specific prior written permission.
185 #
186 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
187 # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
188 # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
189 # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
190 # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
191 # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
192 # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
193 # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
194 # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
195 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
196 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
197
198 self.toint(math.inf, 0, "Inf")
199 self.toint(-math.inf, 0, "-Inf")
200 self.toint(math.nan, 0, "NaN")
201 self.toint(math.nan, 0, "SNaN", inp_bits=0x7ff0_0000_0000_0001)
202 self.toint(0.0, 0, "zero")
203 self.toint(-0.0, 0, "-zero")
204 self.toint(min_value, 0)
205 self.toint(-min_value, 0)
206 self.toint(0.1, 0)
207 self.toint(-0.1, 0)
208 self.toint(1, 1, "one")
209 self.toint(1.1, 1, "onepointone")
210 self.toint(-1, -1, "-one")
211 self.toint(0.6, 0, "truncate positive (0.6)")
212 self.toint(1.6, 1, "truncate positive (1.6)")
213 self.toint(-0.6, 0, "truncate negative (-0.6)")
214 self.toint(-1.6, -1, "truncate negative (-1.6)")
215 self.toint(2147483647, 2147483647)
216 self.toint(2147483648, -2147483648)
217 self.toint(2147483649, -2147483647)
218 self.toint(4294967295, -1)
219 self.toint(4294967296, 0)
220 self.toint(4294967297, 1)
221 self.toint(-2147483647, -2147483647)
222 self.toint(-2147483648, -2147483648)
223 self.toint(-2147483649, 2147483647)
224 self.toint(-4294967295, 1)
225 self.toint(-4294967296, 0)
226 self.toint(-4294967297, -1)
227 self.toint(2147483648.25, -2147483648)
228 self.toint(2147483648.5, -2147483648)
229 self.toint(2147483648.75, -2147483648)
230 self.toint(4294967295.25, -1)
231 self.toint(4294967295.5, -1)
232 self.toint(4294967295.75, -1)
233 self.toint(3000000000.25, -1294967296)
234 self.toint(3000000000.5, -1294967296)
235 self.toint(3000000000.75, -1294967296)
236 self.toint(-2147483648.25, -2147483648)
237 self.toint(-2147483648.5, -2147483648)
238 self.toint(-2147483648.75, -2147483648)
239 self.toint(-4294967295.25, 1)
240 self.toint(-4294967295.5, 1)
241 self.toint(-4294967295.75, 1)
242 self.toint(-3000000000.25, 1294967296)
243 self.toint(-3000000000.5, 1294967296)
244 self.toint(-3000000000.75, 1294967296)
245 base = pow(2, 64)
246 self.toint(base + 0, 0)
247 self.toint(base + 1117, 0)
248 self.toint(base + 2234, 4096)
249 self.toint(base + 3351, 4096)
250 self.toint(base + 4468, 4096)
251 self.toint(base + 5585, 4096)
252 self.toint(base + 6702, 8192)
253 self.toint(base + 7819, 8192)
254 self.toint(base + 8936, 8192)
255 self.toint(base + 10053, 8192)
256 self.toint(base + 11170, 12288)
257 self.toint(base + 12287, 12288)
258 self.toint(base + 13404, 12288)
259 self.toint(base + 14521, 16384)
260 self.toint(base + 15638, 16384)
261 self.toint(base + 16755, 16384)
262 self.toint(base + 17872, 16384)
263 self.toint(base + 18989, 20480)
264 self.toint(base + 20106, 20480)
265 self.toint(base + 21223, 20480)
266 self.toint(base + 22340, 20480)
267 self.toint(base + 23457, 24576)
268 self.toint(base + 24574, 24576)
269 self.toint(base + 25691, 24576)
270 self.toint(base + 26808, 28672)
271 self.toint(base + 27925, 28672)
272 self.toint(base + 29042, 28672)
273 self.toint(base + 30159, 28672)
274 self.toint(base + 31276, 32768)
275 # bignum is (2 ^ 53 - 1) * 2 ^ 31 - highest number with bit 31 set.
276 bignum = pow(2, 84) - pow(2, 31)
277 self.toint(bignum, -pow(2, 31))
278 self.toint(-bignum, -pow(2, 31))
279 self.toint(2 * bignum, 0)
280 self.toint(-(2 * bignum), 0)
281 self.toint(bignum - pow(2, 31), 0)
282 self.toint(-(bignum - pow(2, 31)), 0)
283 # max_fraction is largest number below 1.
284 max_fraction = (1 - pow(2, -53))
285 self.toint(max_fraction, 0)
286 self.toint(-max_fraction, 0)
287
288 def case_js_touint32(self):
289 min_value = pow(2, -1074)
290 # test cases from:
291 # https://chromium.googlesource.com/v8/v8.git/+/d94dfc2b01f988566aa410ce871588cf23b1285d/test/mjsunit/touint32.js
292 # with identical copyright notice as in case_js_toint32
293 self.toint(0, 0, "0", signed=False)
294 self.toint(-0, 0, "-0", signed=False)
295 self.toint(math.inf, 0, "Infinity", signed=False)
296 self.toint(-math.inf, 0, "-Infinity", signed=False)
297 self.toint(math.nan, 0, "NaN", signed=False)
298 self.toint(math.nan, 0, "SNaN", inp_bits=0x7ff0_0000_0000_0001,
299 signed=False)
300 self.toint(min_value, 0, "MIN", signed=False)
301 self.toint(-min_value, 0, "-MIN", signed=False)
302 self.toint(0.1, 0, "0.1", signed=False)
303 self.toint(-0.1, 0, "-0.1", signed=False)
304 self.toint(1, 1, "1", signed=False)
305 self.toint(1.1, 1, "1.1", signed=False)
306 self.toint(-1, 4294967295, "-1", signed=False)
307 self.toint(-1.1, 4294967295, "-1.1", signed=False)
308 self.toint(2147483647, 2147483647, "2147483647", signed=False)
309 self.toint(2147483648, 2147483648, "2147483648", signed=False)
310 self.toint(2147483649, 2147483649, "2147483649", signed=False)
311 self.toint(4294967295, 4294967295, "4294967295", signed=False)
312 self.toint(4294967296, 0, "4294967296", signed=False)
313 self.toint(4294967297, 1, "4294967297", signed=False)
314 self.toint(-2147483647, 2147483649, "-2147483647", signed=False)
315 self.toint(-2147483648, 2147483648, "-2147483648", signed=False)
316 self.toint(-2147483649, 2147483647, "-2147483649", signed=False)
317 self.toint(-4294967295, 1, "-4294967295", signed=False)
318 self.toint(-4294967296, 0, "-4294967296", signed=False)
319 self.toint(-4294967297, 4294967295, "-4294967297", signed=False)
320
321 def case_js_toint64(self):
322 # 64-bit equivalent of javascript's toint32
323 min_value = pow(2, -1074)
324 # test cases derived from:
325 # https://chromium.googlesource.com/v8/v8.git/+/d94dfc2b01f988566aa410ce871588cf23b1285d/test/mjsunit/toint32.js
326 # with identical copyright notice as in case_js_toint32
327
328 self.toint(math.inf, 0, "Inf", _32bit=False)
329 self.toint(-math.inf, 0, "-Inf", _32bit=False)
330 self.toint(math.nan, 0, "NaN", _32bit=False)
331 self.toint(math.nan, 0, "SNaN",
332 inp_bits=0x7ff0_0000_0000_0001, _32bit=False)
333 self.toint(0.0, 0, "zero", _32bit=False)
334 self.toint(-0.0, 0, "-zero", _32bit=False)
335 self.toint(min_value, 0, _32bit=False)
336 self.toint(-min_value, 0, _32bit=False)
337 self.toint(0.1, 0, _32bit=False)
338 self.toint(-0.1, 0, _32bit=False)
339 self.toint(1, 1, "one", _32bit=False)
340 self.toint(1.1, 1, "onepointone", _32bit=False)
341 self.toint(-1, -1, "-one", _32bit=False)
342 self.toint(0.6, 0, "truncate positive (0.6)", _32bit=False)
343 self.toint(1.6, 1, "truncate positive (1.6)", _32bit=False)
344 self.toint(-0.6, 0, "truncate negative (-0.6)", _32bit=False)
345 self.toint(-1.6, -1, "truncate negative (-1.6)", _32bit=False)
346 self.toint(fp_bits_add(2**63, -1), _32bit=False)
347 self.toint(2**63, _32bit=False)
348 self.toint(fp_bits_add(2**63, 1), _32bit=False)
349 self.toint(fp_bits_add(2**64, -1), _32bit=False)
350 self.toint(2**64, 0, _32bit=False)
351 self.toint(fp_bits_add(2**64, 1), _32bit=False)
352 self.toint(-fp_bits_add(2**63, -1), _32bit=False)
353 self.toint(-(2**63), _32bit=False)
354 self.toint(-fp_bits_add(2**63, 1), _32bit=False)
355 self.toint(-fp_bits_add(2**64, -1), _32bit=False)
356 self.toint(-(2**64), 0, _32bit=False)
357 self.toint(-fp_bits_add(2**64, 1), _32bit=False)
358 self.toint(2147483648.25, _32bit=False)
359 self.toint(2147483648.5, _32bit=False)
360 self.toint(2147483648.75, _32bit=False)
361 self.toint(4294967295.25, _32bit=False)
362 self.toint(4294967295.5, _32bit=False)
363 self.toint(4294967295.75, _32bit=False)
364 self.toint(3000000000.25, _32bit=False)
365 self.toint(3000000000.5, _32bit=False)
366 self.toint(3000000000.75, _32bit=False)
367 self.toint(-2147483648.25, _32bit=False)
368 self.toint(-2147483648.5, _32bit=False)
369 self.toint(-2147483648.75, _32bit=False)
370 self.toint(-4294967295.25, _32bit=False)
371 self.toint(-4294967295.5, _32bit=False)
372 self.toint(-4294967295.75, _32bit=False)
373 self.toint(-3000000000.25, _32bit=False)
374 self.toint(-3000000000.5, _32bit=False)
375 self.toint(-3000000000.75, _32bit=False)
376 base = pow(2, 64)
377 self.toint(base + 0, _32bit=False)
378 self.toint(base + 1117, _32bit=False)
379 self.toint(base + 2234, _32bit=False)
380 self.toint(base + 3351, _32bit=False)
381 self.toint(base + 4468, _32bit=False)
382 self.toint(base + 5585, _32bit=False)
383 self.toint(base + 6702, _32bit=False)
384 self.toint(base + 7819, _32bit=False)
385 self.toint(base + 8936, _32bit=False)
386 self.toint(base + 10053, _32bit=False)
387 self.toint(base + 11170, _32bit=False)
388 self.toint(base + 12287, _32bit=False)
389 self.toint(base + 13404, _32bit=False)
390 self.toint(base + 14521, _32bit=False)
391 self.toint(base + 15638, _32bit=False)
392 self.toint(base + 16755, _32bit=False)
393 self.toint(base + 17872, _32bit=False)
394 self.toint(base + 18989, _32bit=False)
395 self.toint(base + 20106, _32bit=False)
396 self.toint(base + 21223, _32bit=False)
397 self.toint(base + 22340, _32bit=False)
398 self.toint(base + 23457, _32bit=False)
399 self.toint(base + 24574, _32bit=False)
400 self.toint(base + 25691, _32bit=False)
401 self.toint(base + 26808, _32bit=False)
402 self.toint(base + 27925, _32bit=False)
403 self.toint(base + 29042, _32bit=False)
404 self.toint(base + 30159, _32bit=False)
405 self.toint(base + 31276, _32bit=False)
406 # bignum is (2 ^ 53 - 1) * 2 ^ 31 - highest number with bit 31 set.
407 bignum = pow(2, 84) - pow(2, 31)
408 self.toint(bignum, _32bit=False)
409 self.toint(-bignum, _32bit=False)
410 self.toint(2 * bignum, _32bit=False)
411 self.toint(-(2 * bignum), _32bit=False)
412 self.toint(bignum - pow(2, 31), _32bit=False)
413 self.toint(-(bignum - pow(2, 31)), _32bit=False)
414 # max_fraction is largest number below 1.
415 max_fraction = (1 - pow(2, -53))
416 self.toint(max_fraction, 0, _32bit=False)
417 self.toint(-max_fraction, 0, _32bit=False)
418
419 def case_js_touint64(self):
420 # 64-bit equivalent of javascript's touint32
421 min_value = pow(2, -1074)
422 # test cases derived from:
423 # https://chromium.googlesource.com/v8/v8.git/+/d94dfc2b01f988566aa410ce871588cf23b1285d/test/mjsunit/touint32.js
424 # with identical copyright notice as in case_js_toint32
425 self.toint(0, 0, "0", signed=False, _32bit=False)
426 self.toint(-0, 0, "-0", signed=False, _32bit=False)
427 self.toint(math.inf, 0, "Infinity", signed=False, _32bit=False)
428 self.toint(-math.inf, 0, "-Infinity", signed=False, _32bit=False)
429 self.toint(math.nan, 0, "NaN", signed=False, _32bit=False)
430 self.toint(math.nan, 0, "SNaN", inp_bits=0x7ff0_0000_0000_0001,
431 signed=False, _32bit=False)
432 self.toint(min_value, 0, "MIN", signed=False, _32bit=False)
433 self.toint(-min_value, 0, "-MIN", signed=False, _32bit=False)
434 self.toint(0.1, 0, "0.1", signed=False, _32bit=False)
435 self.toint(-0.1, 0, "-0.1", signed=False, _32bit=False)
436 self.toint(1, 1, "1", signed=False, _32bit=False)
437 self.toint(1.1, 1, "1.1", signed=False, _32bit=False)
438 self.toint(-1, 2**64 - 1, "-1", signed=False, _32bit=False)
439 self.toint(-1.1, 2**64 - 1, "-1.1", signed=False, _32bit=False)
440 self.toint(fp_bits_add(2**63, -1), signed=False, _32bit=False)
441 self.toint(2**63, signed=False, _32bit=False)
442 self.toint(fp_bits_add(2**63, 1), signed=False, _32bit=False)
443 self.toint(fp_bits_add(2**64, -1), signed=False, _32bit=False)
444 self.toint(2**64, 0, signed=False, _32bit=False)
445 self.toint(fp_bits_add(2**64, 1), signed=False, _32bit=False)
446 self.toint(-fp_bits_add(2**63, -1), signed=False, _32bit=False)
447 self.toint(-(2**63), signed=False, _32bit=False)
448 self.toint(-fp_bits_add(2**63, 1), signed=False, _32bit=False)
449 self.toint(-fp_bits_add(2**64, -1), signed=False, _32bit=False)
450 self.toint(-(2**64), 0, signed=False, _32bit=False)
451 self.toint(-fp_bits_add(2**64, 1), signed=False, _32bit=False)
452
453 @staticmethod
454 @functools.lru_cache(maxsize=None)
455 def _fcvtfg_fpscr(RN, set_XX, FR, FPRF, fpscr_unmodified):
456 """ cached FPSCR computation for fcvtfg_one since that part is slow """
457 initial_fpscr = FPSCRState()
458 initial_fpscr.RN = RN
459 fpscr = FPSCRState(initial_fpscr)
460 if set_XX:
461 fpscr.XX = 1
462 fpscr.FX = 1
463 fpscr.FI = 1
464 fpscr.FR = FR
465 fpscr.FPRF = FPRF
466 if fpscr_unmodified:
467 fpscr = FPSCRState(initial_fpscr)
468 return initial_fpscr, fpscr
469
470 def fcvtfg_one(self, inp, bfp32, IT, Rc, RN):
471 inp %= 2 ** 64
472 inp_width = 64 if IT & 0b10 else 32
473 inp_value = inp % 2 ** inp_width
474 if IT & 0b1 == 0:
475 # signed
476 if inp_value >> (inp_width - 1):
477 # negative
478 inp_value -= 2 ** inp_width
479 # cast to nearby f32/f64
480 inp_fp = fp_bits_add(inp_value, 0, bfp32=bfp32)
481 if inp_fp == inp_value: # exact conversion -- no rounding necessary
482 expected_fp = inp_fp
483 expected_bits = bitcast_fp_to_int(expected_fp, bfp32=False)
484 else:
485 # get the fp value on either side of the exact value.
486 # we need to get several values and select 2 because int -> fp
487 # conversion in fp_bits_add could be off by a bit due to
488 # rounding/double-rounding.
489 # we can ignore weirdness around infinity because input values
490 # can't get big enough to convert to infinity for bfp32/64.
491 # we can ignore weirdness around zero because small integers
492 # always convert exactly, and therefore don't reach this
493 # `else` block.
494 fp_values = sorted(
495 fp_bits_add(inp_value, i, bfp32=bfp32) for i in range(-2, 3))
496 while fp_values[-2] > inp_value:
497 fp_values.pop()
498 prev_fp = fp_values[-2]
499 next_fp = fp_values[-1]
500 # if fp values are big enough to not be exact, they are always
501 # integers.
502 prev_int = int(prev_fp)
503 next_int = int(next_fp)
504 prev_fp_is_even = bitcast_fp_to_int(prev_fp, bfp32=bfp32) & 1 == 0
505 halfway = 2 * inp_value == prev_int + next_int
506 prev_is_closer = 2 * inp_value < prev_int + next_int
507 if RN == 0:
508 # round to nearest
509 use_prev = (halfway and prev_fp_is_even) or prev_is_closer
510 elif RN == 1:
511 # trunc
512 use_prev = abs(prev_int) < abs(next_int)
513 elif RN == 2:
514 # ceil
515 use_prev = False
516 else:
517 assert RN == 3, "invalid RN"
518 # floor
519 use_prev = True
520 if use_prev:
521 expected_fp = prev_fp
522 else:
523 expected_fp = next_fp
524 expected_bits = bitcast_fp_to_int(expected_fp, bfp32=False)
525 set_XX = FR = False
526 if expected_fp != inp_value:
527 set_XX = True
528 FR = abs(expected_fp) > abs(inp_value)
529 if expected_fp < 0:
530 FPRF = "- Normal Number"
531 elif expected_fp > 0:
532 FPRF = "+ Normal Number"
533 else:
534 # integer conversion never gives -0.0
535 FPRF = "+ Zero"
536
537 # defined to not modify FPSCR since the conversion is always exact
538 fpscr_unmodified = inp_width == 32 and not bfp32
539
540 initial_fpscr, fpscr = self._fcvtfg_fpscr(
541 RN=RN, set_XX=set_XX, FR=FR, FPRF=FPRF,
542 fpscr_unmodified=fpscr_unmodified)
543 if Rc:
544 cr1 = int(fpscr.FX) << 3
545 cr1 |= int(fpscr.FEX) << 2
546 cr1 |= int(fpscr.VX) << 1
547 cr1 |= int(fpscr.OX)
548 else:
549 cr1 = 0
550 with self.subTest(
551 inp=hex(inp), bfp32=bfp32, IT=IT, Rc=Rc, RN=RN,
552 expected_fp=expected_fp.hex(), expected_bits=hex(expected_bits),
553 XX=fpscr.XX, FR=fpscr.FR, FPRF=bin(int(fpscr.FPRF)), CR1=bin(cr1),
554 ):
555 s = "s" if bfp32 else ""
556 rc_str = "." if Rc else ""
557 lst = [f"fcvtfg{s}{rc_str} 0,3,{IT}"]
558 gprs = [0] * 32
559 fprs = [0] * 32
560 gprs[3] = inp
561 e = ExpectedState(pc=4, int_regs=gprs, fp_regs=fprs)
562 e.crregs[1] = cr1
563 e.fpregs[0] = expected_bits
564 e.fpscr = int(fpscr)
565 self.add_case(
566 _cached_program(*lst), gprs, fpregs=fprs, expected=e,
567 initial_fpscr=int(initial_fpscr))
568
569 def fcvtfg(self, inp):
570 for bfp32 in (False, True):
571 for IT in range(4):
572 for Rc in (False, True):
573 for RN in range(4):
574 self.fcvtfg_one(inp, bfp32, IT, Rc, RN)
575
576 def case_fcvtfg(self):
577 inp_values = {0}
578 for sh in (0, 22, 23, 24, 31, 52, 53, 54, 63):
579 for offset in range(-2, 3):
580 for offset_sh in range(64):
581 v = 1 << sh
582 v += offset << offset_sh
583 v %= 2 ** 64
584 inp_values.add(v)
585 for i in sorted(inp_values):
586 self.fcvtfg(i)
587
588 def fmv(self, gpr_bits, bfp32, Rc):
589 if bfp32:
590 gpr_bits %= 2 ** 32
591 if gpr_bits & 0x7f80_0000 == 0x7f80_0000: # inf or nan
592 fpr_bits = (gpr_bits & 0x8000_0000) << 32
593 fpr_bits |= 0x7ff0_0000_0000_0000
594 fpr_bits |= (gpr_bits & 0x7f_ffff) << 29
595 else:
596 fpr_bits = bitcast_fp_to_int(bitcast_int_to_fp(
597 gpr_bits, bfp32=True), bfp32=False)
598 else:
599 gpr_bits %= 2 ** 64
600 fpr_bits = gpr_bits
601 with self.subTest(gpr_bits=hex(gpr_bits), fpr_bits=hex(fpr_bits),
602 bfp32=bfp32, Rc=Rc):
603 s = "s" if bfp32 else ""
604 rc_str = "." if Rc else ""
605 tg_p = _cached_program(f"fmvtg{s}{rc_str} 3, 0")
606 # fmvfg[s]. shouldn't exist since Rc=1 is basically useless due to
607 # fmv* not changing any FPSCR bits
608 fg_p = _cached_program(f"fmvfg{s} 0, 3")
609 tg_gprs = [0] * 32
610 fg_gprs = [0] * 32
611 tg_fprs = [0] * 32
612 fg_fprs = [0] * 32
613 tg_fprs[0] = fpr_bits
614 fg_gprs[3] = gpr_bits
615 tg_e = ExpectedState(pc=4, int_regs=tg_gprs, fp_regs=tg_fprs)
616 fg_e = ExpectedState(pc=4, int_regs=fg_gprs, fp_regs=fg_fprs)
617 tg_lt = bool(gpr_bits & (1 << 63))
618 tg_gt = not tg_lt and gpr_bits != 0
619 tg_eq = gpr_bits == 0
620 if Rc:
621 tg_e.crregs[0] = (
622 (tg_lt << 3) | (tg_gt << 2) | (tg_eq << 1) | tg_e.so)
623 fg_e.fpregs[0] = fpr_bits
624 tg_e.intregs[3] = gpr_bits
625 self.add_case(fg_p, fg_gprs, fpregs=fg_fprs, expected=fg_e)
626 self.add_case(tg_p, tg_gprs, fpregs=tg_fprs, expected=tg_e)
627
628 def case_fmv(self):
629 inp_values = {0}
630 for sh in (0, 22, 23, 24, 31, 52, 53, 54, 63):
631 for offset in range(-2, 3):
632 for offset_sh in range(64):
633 v = 1 << sh
634 v += offset << offset_sh
635 v %= 2 ** 64
636 inp_values.add(v)
637 for i in sorted(inp_values):
638 for bfp32 in (False, True):
639 for Rc in (False, True):
640 self.fmv(i, bfp32, Rc)
641
642
643 class SVP64FMvFCvtCases(TestAccumulatorBase):
644 @skip_case("FIXME: rewrite to fmv/fcvt tests")
645 def case_sv_fmaxmag19(self):
646 lst = list(SVP64Asm(["sv.fmaxmag19 *32,*64,*96"]))
647 gprs = [0] * 128
648 fprs = [0] * 128
649 svstate = SVP64State()
650 svstate.vl = 32
651 svstate.maxvl = 32
652 r = range(svstate.vl)
653 for i, rev_i in zip(r, reversed(r)):
654 fprs[64 + i] = struct.unpack("<Q", struct.pack("<d", i))[0]
655 fprs[96 + i] = struct.unpack("<Q", struct.pack("<d", rev_i))[0]
656 e = ExpectedState(pc=8, int_regs=gprs, fp_regs=fprs)
657 e.fpregs[32] = 0x403f000000000000
658 e.fpregs[33] = 0x403e000000000000
659 e.fpregs[34] = 0x403d000000000000
660 e.fpregs[35] = 0x403c000000000000
661 e.fpregs[36] = 0x403b000000000000
662 e.fpregs[37] = 0x403a000000000000
663 e.fpregs[38] = 0x4039000000000000
664 e.fpregs[39] = 0x4038000000000000
665 e.fpregs[40] = 0x4037000000000000
666 e.fpregs[41] = 0x4036000000000000
667 e.fpregs[42] = 0x4035000000000000
668 e.fpregs[43] = 0x4034000000000000
669 e.fpregs[44] = 0x4033000000000000
670 e.fpregs[45] = 0x4032000000000000
671 e.fpregs[46] = 0x4031000000000000
672 e.fpregs[47] = 0x4030000000000000
673 e.fpregs[48] = 0x4030000000000000
674 e.fpregs[49] = 0x4031000000000000
675 e.fpregs[50] = 0x4032000000000000
676 e.fpregs[51] = 0x4033000000000000
677 e.fpregs[52] = 0x4034000000000000
678 e.fpregs[53] = 0x4035000000000000
679 e.fpregs[54] = 0x4036000000000000
680 e.fpregs[55] = 0x4037000000000000
681 e.fpregs[56] = 0x4038000000000000
682 e.fpregs[57] = 0x4039000000000000
683 e.fpregs[58] = 0x403a000000000000
684 e.fpregs[59] = 0x403b000000000000
685 e.fpregs[60] = 0x403c000000000000
686 e.fpregs[61] = 0x403d000000000000
687 e.fpregs[62] = 0x403e000000000000
688 e.fpregs[63] = 0x403f000000000000
689 self.add_case(Program(lst, False), gprs, fpregs=fprs,
690 initial_svstate=svstate, expected=e)