diff --git a/tests/ctest/core/recompilers/CMakeLists.txt b/tests/ctest/core/recompilers/CMakeLists.txt index aa018d3b56..bc4b818d41 100644 --- a/tests/ctest/core/recompilers/CMakeLists.txt +++ b/tests/ctest/core/recompilers/CMakeLists.txt @@ -143,6 +143,8 @@ add_pcsx2_test(recompiler_tests vu_madd_contract_console_tests.cpp vu1_efu_console_conformance_tests.cpp vu_sticky_console_conformance_tests.cpp + vu_rsqrt_divisor_sign_tests.cpp + vu_divunit_console_conformance_tests.cpp vu_branch_console_conformance_tests.cpp vu_pipeline_console_conformance_tests.cpp vu_memory_xgkick_console_conformance_tests.cpp diff --git a/tests/ctest/core/recompilers/autocases_vurs.h b/tests/ctest/core/recompilers/autocases_vurs.h new file mode 100644 index 0000000000..a8a5c390ac --- /dev/null +++ b/tests/ctest/core/recompilers/autocases_vurs.h @@ -0,0 +1,534 @@ +// SPDX-FileCopyrightText: 2026 yaps2 Dev Team +// SPDX-License-Identifier: GPL-3.0+ +// +// Generated -- do not edit. +// +// VU0 macro-mode div-unit capture, SCPH-90000: VDIV / VSQRT / +// VRSQRT over a grid of zero, denormal, normal, exponent-255 and +// saturated operands, reading STATUS and Q after each op. `seed` +// is what CTC2 wrote to STATUS before the op ran. +#pragma once + +#include "common/Pcsx2Types.h" + +namespace console_vurs +{ +enum VursOp { VURS_DIV = 0, VURS_SQRT = 1, VURS_RSQRT = 2 }; + +struct VursCase +{ + VursOp op; + u32 fs; + u32 ft; + u32 seed; // written to STATUS with CTC2 before the op + u32 status; // STATUS after the op + u32 q; // Q after the op + const char* tag; +}; + +inline constexpr VursCase kVursCases[] = { + {VURS_RSQRT, 0x3F800000u, 0x80000000u, 0x000u, 0xC30u, 0x7FFFFFFFu, "rigcheck/rsqrt +1/-0"}, + {VURS_SQRT, 0x00000000u, 0x00000000u, 0x000u, 0x000u, 0x00000000u, "sqrt +0"}, + {VURS_SQRT, 0x00000000u, 0x80000000u, 0x000u, 0x410u, 0x00000000u, "sqrt -0"}, + {VURS_SQRT, 0x00000000u, 0x00000001u, 0x000u, 0x000u, 0x00000000u, "sqrt +denorm.min"}, + {VURS_SQRT, 0x00000000u, 0x80000001u, 0x000u, 0x410u, 0x00000000u, "sqrt -denorm.min"}, + {VURS_SQRT, 0x00000000u, 0x00400000u, 0x000u, 0x000u, 0x00000000u, "sqrt +denorm.mid"}, + {VURS_SQRT, 0x00000000u, 0x80400000u, 0x000u, 0x410u, 0x00000000u, "sqrt -denorm.mid"}, + {VURS_SQRT, 0x00000000u, 0x007FFFFFu, 0x000u, 0x000u, 0x00000000u, "sqrt +denorm.max"}, + {VURS_SQRT, 0x00000000u, 0x807FFFFFu, 0x000u, 0x410u, 0x00000000u, "sqrt -denorm.max"}, + {VURS_SQRT, 0x00000000u, 0x00800000u, 0x000u, 0x000u, 0x20000000u, "sqrt +normal.min"}, + {VURS_SQRT, 0x00000000u, 0x80800000u, 0x000u, 0x410u, 0x20000000u, "sqrt -normal.min"}, + {VURS_SQRT, 0x00000000u, 0x3F800000u, 0x000u, 0x000u, 0x3F800000u, "sqrt +1"}, + {VURS_SQRT, 0x00000000u, 0xBF800000u, 0x000u, 0x410u, 0x3F800000u, "sqrt -1"}, + {VURS_SQRT, 0x00000000u, 0x40800000u, 0x000u, 0x000u, 0x40000000u, "sqrt +4"}, + {VURS_SQRT, 0x00000000u, 0xC0800000u, 0x000u, 0x410u, 0x40000000u, "sqrt -4"}, + {VURS_SQRT, 0x00000000u, 0x7F7FFFFFu, 0x000u, 0x000u, 0x5F7FFFFFu, "sqrt +fltmax"}, + {VURS_SQRT, 0x00000000u, 0xFF7FFFFFu, 0x000u, 0x410u, 0x5F7FFFFFu, "sqrt -fltmax"}, + {VURS_SQRT, 0x00000000u, 0x7F800000u, 0x000u, 0x000u, 0x5F800000u, "sqrt +2^128"}, + {VURS_SQRT, 0x00000000u, 0xFF800000u, 0x000u, 0x410u, 0x5F800000u, "sqrt -2^128"}, + {VURS_SQRT, 0x00000000u, 0x7FFFFFFFu, 0x000u, 0x000u, 0x5FB504F3u, "sqrt +eemax"}, + {VURS_SQRT, 0x00000000u, 0xFFFFFFFFu, 0x000u, 0x410u, 0x5FB504F3u, "sqrt -eemax"}, + {VURS_SQRT, 0x00000000u, 0x00000000u, 0xFC0u, 0xFC0u, 0x00000000u, "sqrt +0"}, + {VURS_SQRT, 0x00000000u, 0x80000000u, 0xFC0u, 0xFD0u, 0x00000000u, "sqrt -0"}, + {VURS_SQRT, 0x00000000u, 0x00000001u, 0xFC0u, 0xFC0u, 0x00000000u, "sqrt +denorm.min"}, + {VURS_SQRT, 0x00000000u, 0x80000001u, 0xFC0u, 0xFD0u, 0x00000000u, "sqrt -denorm.min"}, + {VURS_SQRT, 0x00000000u, 0x00400000u, 0xFC0u, 0xFC0u, 0x00000000u, "sqrt +denorm.mid"}, + {VURS_SQRT, 0x00000000u, 0x80400000u, 0xFC0u, 0xFD0u, 0x00000000u, "sqrt -denorm.mid"}, + {VURS_SQRT, 0x00000000u, 0x007FFFFFu, 0xFC0u, 0xFC0u, 0x00000000u, "sqrt +denorm.max"}, + {VURS_SQRT, 0x00000000u, 0x807FFFFFu, 0xFC0u, 0xFD0u, 0x00000000u, "sqrt -denorm.max"}, + {VURS_SQRT, 0x00000000u, 0x00800000u, 0xFC0u, 0xFC0u, 0x20000000u, "sqrt +normal.min"}, + {VURS_SQRT, 0x00000000u, 0x80800000u, 0xFC0u, 0xFD0u, 0x20000000u, "sqrt -normal.min"}, + {VURS_SQRT, 0x00000000u, 0x3F800000u, 0xFC0u, 0xFC0u, 0x3F800000u, "sqrt +1"}, + {VURS_SQRT, 0x00000000u, 0xBF800000u, 0xFC0u, 0xFD0u, 0x3F800000u, "sqrt -1"}, + {VURS_SQRT, 0x00000000u, 0x40800000u, 0xFC0u, 0xFC0u, 0x40000000u, "sqrt +4"}, + {VURS_SQRT, 0x00000000u, 0xC0800000u, 0xFC0u, 0xFD0u, 0x40000000u, "sqrt -4"}, + {VURS_SQRT, 0x00000000u, 0x7F7FFFFFu, 0xFC0u, 0xFC0u, 0x5F7FFFFFu, "sqrt +fltmax"}, + {VURS_SQRT, 0x00000000u, 0xFF7FFFFFu, 0xFC0u, 0xFD0u, 0x5F7FFFFFu, "sqrt -fltmax"}, + {VURS_SQRT, 0x00000000u, 0x7F800000u, 0xFC0u, 0xFC0u, 0x5F800000u, "sqrt +2^128"}, + {VURS_SQRT, 0x00000000u, 0xFF800000u, 0xFC0u, 0xFD0u, 0x5F800000u, "sqrt -2^128"}, + {VURS_SQRT, 0x00000000u, 0x7FFFFFFFu, 0xFC0u, 0xFC0u, 0x5FB504F3u, "sqrt +eemax"}, + {VURS_SQRT, 0x00000000u, 0xFFFFFFFFu, 0xFC0u, 0xFD0u, 0x5FB504F3u, "sqrt -eemax"}, + {VURS_RSQRT, 0x00000000u, 0x00000000u, 0x000u, 0x410u, 0x7FFFFFFFu, "rsqrt +0 / +0"}, + {VURS_DIV, 0x00000000u, 0x00000000u, 0x000u, 0x410u, 0x7FFFFFFFu, "div +0 / +0"}, + {VURS_RSQRT, 0x80000000u, 0x00000000u, 0x000u, 0x410u, 0xFFFFFFFFu, "rsqrt -0 / +0"}, + {VURS_DIV, 0x80000000u, 0x00000000u, 0x000u, 0x410u, 0xFFFFFFFFu, "div -0 / +0"}, + {VURS_RSQRT, 0x00000001u, 0x00000000u, 0x000u, 0x410u, 0x7FFFFFFFu, "rsqrt +denorm.min / +0"}, + {VURS_DIV, 0x00000001u, 0x00000000u, 0x000u, 0x410u, 0x7FFFFFFFu, "div +denorm.min / +0"}, + {VURS_RSQRT, 0x80000001u, 0x00000000u, 0x000u, 0x410u, 0xFFFFFFFFu, "rsqrt -denorm.min / +0"}, + {VURS_DIV, 0x80000001u, 0x00000000u, 0x000u, 0x410u, 0xFFFFFFFFu, "div -denorm.min / +0"}, + {VURS_RSQRT, 0x3F800000u, 0x00000000u, 0x000u, 0x820u, 0x7FFFFFFFu, "rsqrt +1 / +0"}, + {VURS_DIV, 0x3F800000u, 0x00000000u, 0x000u, 0x820u, 0x7FFFFFFFu, "div +1 / +0"}, + {VURS_RSQRT, 0xBF800000u, 0x00000000u, 0x000u, 0x820u, 0xFFFFFFFFu, "rsqrt -1 / +0"}, + {VURS_DIV, 0xBF800000u, 0x00000000u, 0x000u, 0x820u, 0xFFFFFFFFu, "div -1 / +0"}, + {VURS_RSQRT, 0x40800000u, 0x00000000u, 0x000u, 0x820u, 0x7FFFFFFFu, "rsqrt +4 / +0"}, + {VURS_DIV, 0x40800000u, 0x00000000u, 0x000u, 0x820u, 0x7FFFFFFFu, "div +4 / +0"}, + {VURS_RSQRT, 0x7F7FFFFFu, 0x00000000u, 0x000u, 0x820u, 0x7FFFFFFFu, "rsqrt +fltmax / +0"}, + {VURS_DIV, 0x7F7FFFFFu, 0x00000000u, 0x000u, 0x820u, 0x7FFFFFFFu, "div +fltmax / +0"}, + {VURS_RSQRT, 0xFF7FFFFFu, 0x00000000u, 0x000u, 0x820u, 0xFFFFFFFFu, "rsqrt -fltmax / +0"}, + {VURS_DIV, 0xFF7FFFFFu, 0x00000000u, 0x000u, 0x820u, 0xFFFFFFFFu, "div -fltmax / +0"}, + {VURS_RSQRT, 0x7FFFFFFFu, 0x00000000u, 0x000u, 0x820u, 0x7FFFFFFFu, "rsqrt +eemax / +0"}, + {VURS_DIV, 0x7FFFFFFFu, 0x00000000u, 0x000u, 0x820u, 0x7FFFFFFFu, "div +eemax / +0"}, + {VURS_RSQRT, 0x00000000u, 0x80000000u, 0x000u, 0x410u, 0x7FFFFFFFu, "rsqrt +0 / -0"}, + {VURS_DIV, 0x00000000u, 0x80000000u, 0x000u, 0x410u, 0xFFFFFFFFu, "div +0 / -0"}, + {VURS_RSQRT, 0x80000000u, 0x80000000u, 0x000u, 0x410u, 0xFFFFFFFFu, "rsqrt -0 / -0"}, + {VURS_DIV, 0x80000000u, 0x80000000u, 0x000u, 0x410u, 0x7FFFFFFFu, "div -0 / -0"}, + {VURS_RSQRT, 0x00000001u, 0x80000000u, 0x000u, 0x410u, 0x7FFFFFFFu, "rsqrt +denorm.min / -0"}, + {VURS_DIV, 0x00000001u, 0x80000000u, 0x000u, 0x410u, 0xFFFFFFFFu, "div +denorm.min / -0"}, + {VURS_RSQRT, 0x80000001u, 0x80000000u, 0x000u, 0x410u, 0xFFFFFFFFu, "rsqrt -denorm.min / -0"}, + {VURS_DIV, 0x80000001u, 0x80000000u, 0x000u, 0x410u, 0x7FFFFFFFu, "div -denorm.min / -0"}, + {VURS_RSQRT, 0x3F800000u, 0x80000000u, 0x000u, 0xC30u, 0x7FFFFFFFu, "rsqrt +1 / -0"}, + {VURS_DIV, 0x3F800000u, 0x80000000u, 0x000u, 0x820u, 0xFFFFFFFFu, "div +1 / -0"}, + {VURS_RSQRT, 0xBF800000u, 0x80000000u, 0x000u, 0xC30u, 0xFFFFFFFFu, "rsqrt -1 / -0"}, + {VURS_DIV, 0xBF800000u, 0x80000000u, 0x000u, 0x820u, 0x7FFFFFFFu, "div -1 / -0"}, + {VURS_RSQRT, 0x40800000u, 0x80000000u, 0x000u, 0xC30u, 0x7FFFFFFFu, "rsqrt +4 / -0"}, + {VURS_DIV, 0x40800000u, 0x80000000u, 0x000u, 0x820u, 0xFFFFFFFFu, "div +4 / -0"}, + {VURS_RSQRT, 0x7F7FFFFFu, 0x80000000u, 0x000u, 0xC30u, 0x7FFFFFFFu, "rsqrt +fltmax / -0"}, + {VURS_DIV, 0x7F7FFFFFu, 0x80000000u, 0x000u, 0x820u, 0xFFFFFFFFu, "div +fltmax / -0"}, + {VURS_RSQRT, 0xFF7FFFFFu, 0x80000000u, 0x000u, 0xC30u, 0xFFFFFFFFu, "rsqrt -fltmax / -0"}, + {VURS_DIV, 0xFF7FFFFFu, 0x80000000u, 0x000u, 0x820u, 0x7FFFFFFFu, "div -fltmax / -0"}, + {VURS_RSQRT, 0x7FFFFFFFu, 0x80000000u, 0x000u, 0xC30u, 0x7FFFFFFFu, "rsqrt +eemax / -0"}, + {VURS_DIV, 0x7FFFFFFFu, 0x80000000u, 0x000u, 0x820u, 0xFFFFFFFFu, "div +eemax / -0"}, + {VURS_RSQRT, 0x00000000u, 0x00000001u, 0x000u, 0x410u, 0x7FFFFFFFu, "rsqrt +0 / +denorm.min"}, + {VURS_DIV, 0x00000000u, 0x00000001u, 0x000u, 0x410u, 0x7FFFFFFFu, "div +0 / +denorm.min"}, + {VURS_RSQRT, 0x80000000u, 0x00000001u, 0x000u, 0x410u, 0xFFFFFFFFu, "rsqrt -0 / +denorm.min"}, + {VURS_DIV, 0x80000000u, 0x00000001u, 0x000u, 0x410u, 0xFFFFFFFFu, "div -0 / +denorm.min"}, + {VURS_RSQRT, 0x00000001u, 0x00000001u, 0x000u, 0x410u, 0x7FFFFFFFu, "rsqrt +denorm.min / +denorm.min"}, + {VURS_DIV, 0x00000001u, 0x00000001u, 0x000u, 0x410u, 0x7FFFFFFFu, "div +denorm.min / +denorm.min"}, + {VURS_RSQRT, 0x80000001u, 0x00000001u, 0x000u, 0x410u, 0xFFFFFFFFu, "rsqrt -denorm.min / +denorm.min"}, + {VURS_DIV, 0x80000001u, 0x00000001u, 0x000u, 0x410u, 0xFFFFFFFFu, "div -denorm.min / +denorm.min"}, + {VURS_RSQRT, 0x3F800000u, 0x00000001u, 0x000u, 0x820u, 0x7FFFFFFFu, "rsqrt +1 / +denorm.min"}, + {VURS_DIV, 0x3F800000u, 0x00000001u, 0x000u, 0x820u, 0x7FFFFFFFu, "div +1 / +denorm.min"}, + {VURS_RSQRT, 0xBF800000u, 0x00000001u, 0x000u, 0x820u, 0xFFFFFFFFu, "rsqrt -1 / +denorm.min"}, + {VURS_DIV, 0xBF800000u, 0x00000001u, 0x000u, 0x820u, 0xFFFFFFFFu, "div -1 / +denorm.min"}, + {VURS_RSQRT, 0x40800000u, 0x00000001u, 0x000u, 0x820u, 0x7FFFFFFFu, "rsqrt +4 / +denorm.min"}, + {VURS_DIV, 0x40800000u, 0x00000001u, 0x000u, 0x820u, 0x7FFFFFFFu, "div +4 / +denorm.min"}, + {VURS_RSQRT, 0x7F7FFFFFu, 0x00000001u, 0x000u, 0x820u, 0x7FFFFFFFu, "rsqrt +fltmax / +denorm.min"}, + {VURS_DIV, 0x7F7FFFFFu, 0x00000001u, 0x000u, 0x820u, 0x7FFFFFFFu, "div +fltmax / +denorm.min"}, + {VURS_RSQRT, 0xFF7FFFFFu, 0x00000001u, 0x000u, 0x820u, 0xFFFFFFFFu, "rsqrt -fltmax / +denorm.min"}, + {VURS_DIV, 0xFF7FFFFFu, 0x00000001u, 0x000u, 0x820u, 0xFFFFFFFFu, "div -fltmax / +denorm.min"}, + {VURS_RSQRT, 0x7FFFFFFFu, 0x00000001u, 0x000u, 0x820u, 0x7FFFFFFFu, "rsqrt +eemax / +denorm.min"}, + {VURS_DIV, 0x7FFFFFFFu, 0x00000001u, 0x000u, 0x820u, 0x7FFFFFFFu, "div +eemax / +denorm.min"}, + {VURS_RSQRT, 0x00000000u, 0x80000001u, 0x000u, 0x410u, 0x7FFFFFFFu, "rsqrt +0 / -denorm.min"}, + {VURS_DIV, 0x00000000u, 0x80000001u, 0x000u, 0x410u, 0xFFFFFFFFu, "div +0 / -denorm.min"}, + {VURS_RSQRT, 0x80000000u, 0x80000001u, 0x000u, 0x410u, 0xFFFFFFFFu, "rsqrt -0 / -denorm.min"}, + {VURS_DIV, 0x80000000u, 0x80000001u, 0x000u, 0x410u, 0x7FFFFFFFu, "div -0 / -denorm.min"}, + {VURS_RSQRT, 0x00000001u, 0x80000001u, 0x000u, 0x410u, 0x7FFFFFFFu, "rsqrt +denorm.min / -denorm.min"}, + {VURS_DIV, 0x00000001u, 0x80000001u, 0x000u, 0x410u, 0xFFFFFFFFu, "div +denorm.min / -denorm.min"}, + {VURS_RSQRT, 0x80000001u, 0x80000001u, 0x000u, 0x410u, 0xFFFFFFFFu, "rsqrt -denorm.min / -denorm.min"}, + {VURS_DIV, 0x80000001u, 0x80000001u, 0x000u, 0x410u, 0x7FFFFFFFu, "div -denorm.min / -denorm.min"}, + {VURS_RSQRT, 0x3F800000u, 0x80000001u, 0x000u, 0xC30u, 0x7FFFFFFFu, "rsqrt +1 / -denorm.min"}, + {VURS_DIV, 0x3F800000u, 0x80000001u, 0x000u, 0x820u, 0xFFFFFFFFu, "div +1 / -denorm.min"}, + {VURS_RSQRT, 0xBF800000u, 0x80000001u, 0x000u, 0xC30u, 0xFFFFFFFFu, "rsqrt -1 / -denorm.min"}, + {VURS_DIV, 0xBF800000u, 0x80000001u, 0x000u, 0x820u, 0x7FFFFFFFu, "div -1 / -denorm.min"}, + {VURS_RSQRT, 0x40800000u, 0x80000001u, 0x000u, 0xC30u, 0x7FFFFFFFu, "rsqrt +4 / -denorm.min"}, + {VURS_DIV, 0x40800000u, 0x80000001u, 0x000u, 0x820u, 0xFFFFFFFFu, "div +4 / -denorm.min"}, + {VURS_RSQRT, 0x7F7FFFFFu, 0x80000001u, 0x000u, 0xC30u, 0x7FFFFFFFu, "rsqrt +fltmax / -denorm.min"}, + {VURS_DIV, 0x7F7FFFFFu, 0x80000001u, 0x000u, 0x820u, 0xFFFFFFFFu, "div +fltmax / -denorm.min"}, + {VURS_RSQRT, 0xFF7FFFFFu, 0x80000001u, 0x000u, 0xC30u, 0xFFFFFFFFu, "rsqrt -fltmax / -denorm.min"}, + {VURS_DIV, 0xFF7FFFFFu, 0x80000001u, 0x000u, 0x820u, 0x7FFFFFFFu, "div -fltmax / -denorm.min"}, + {VURS_RSQRT, 0x7FFFFFFFu, 0x80000001u, 0x000u, 0xC30u, 0x7FFFFFFFu, "rsqrt +eemax / -denorm.min"}, + {VURS_DIV, 0x7FFFFFFFu, 0x80000001u, 0x000u, 0x820u, 0xFFFFFFFFu, "div +eemax / -denorm.min"}, + {VURS_RSQRT, 0x00000000u, 0x00400000u, 0x000u, 0x410u, 0x7FFFFFFFu, "rsqrt +0 / +denorm.mid"}, + {VURS_DIV, 0x00000000u, 0x00400000u, 0x000u, 0x410u, 0x7FFFFFFFu, "div +0 / +denorm.mid"}, + {VURS_RSQRT, 0x80000000u, 0x00400000u, 0x000u, 0x410u, 0xFFFFFFFFu, "rsqrt -0 / +denorm.mid"}, + {VURS_DIV, 0x80000000u, 0x00400000u, 0x000u, 0x410u, 0xFFFFFFFFu, "div -0 / +denorm.mid"}, + {VURS_RSQRT, 0x00000001u, 0x00400000u, 0x000u, 0x410u, 0x7FFFFFFFu, "rsqrt +denorm.min / +denorm.mid"}, + {VURS_DIV, 0x00000001u, 0x00400000u, 0x000u, 0x410u, 0x7FFFFFFFu, "div +denorm.min / +denorm.mid"}, + {VURS_RSQRT, 0x80000001u, 0x00400000u, 0x000u, 0x410u, 0xFFFFFFFFu, "rsqrt -denorm.min / +denorm.mid"}, + {VURS_DIV, 0x80000001u, 0x00400000u, 0x000u, 0x410u, 0xFFFFFFFFu, "div -denorm.min / +denorm.mid"}, + {VURS_RSQRT, 0x3F800000u, 0x00400000u, 0x000u, 0x820u, 0x7FFFFFFFu, "rsqrt +1 / +denorm.mid"}, + {VURS_DIV, 0x3F800000u, 0x00400000u, 0x000u, 0x820u, 0x7FFFFFFFu, "div +1 / +denorm.mid"}, + {VURS_RSQRT, 0xBF800000u, 0x00400000u, 0x000u, 0x820u, 0xFFFFFFFFu, "rsqrt -1 / +denorm.mid"}, + {VURS_DIV, 0xBF800000u, 0x00400000u, 0x000u, 0x820u, 0xFFFFFFFFu, "div -1 / +denorm.mid"}, + {VURS_RSQRT, 0x40800000u, 0x00400000u, 0x000u, 0x820u, 0x7FFFFFFFu, "rsqrt +4 / +denorm.mid"}, + {VURS_DIV, 0x40800000u, 0x00400000u, 0x000u, 0x820u, 0x7FFFFFFFu, "div +4 / +denorm.mid"}, + {VURS_RSQRT, 0x7F7FFFFFu, 0x00400000u, 0x000u, 0x820u, 0x7FFFFFFFu, "rsqrt +fltmax / +denorm.mid"}, + {VURS_DIV, 0x7F7FFFFFu, 0x00400000u, 0x000u, 0x820u, 0x7FFFFFFFu, "div +fltmax / +denorm.mid"}, + {VURS_RSQRT, 0xFF7FFFFFu, 0x00400000u, 0x000u, 0x820u, 0xFFFFFFFFu, "rsqrt -fltmax / +denorm.mid"}, + {VURS_DIV, 0xFF7FFFFFu, 0x00400000u, 0x000u, 0x820u, 0xFFFFFFFFu, "div -fltmax / +denorm.mid"}, + {VURS_RSQRT, 0x7FFFFFFFu, 0x00400000u, 0x000u, 0x820u, 0x7FFFFFFFu, "rsqrt +eemax / +denorm.mid"}, + {VURS_DIV, 0x7FFFFFFFu, 0x00400000u, 0x000u, 0x820u, 0x7FFFFFFFu, "div +eemax / +denorm.mid"}, + {VURS_RSQRT, 0x00000000u, 0x80400000u, 0x000u, 0x410u, 0x7FFFFFFFu, "rsqrt +0 / -denorm.mid"}, + {VURS_DIV, 0x00000000u, 0x80400000u, 0x000u, 0x410u, 0xFFFFFFFFu, "div +0 / -denorm.mid"}, + {VURS_RSQRT, 0x80000000u, 0x80400000u, 0x000u, 0x410u, 0xFFFFFFFFu, "rsqrt -0 / -denorm.mid"}, + {VURS_DIV, 0x80000000u, 0x80400000u, 0x000u, 0x410u, 0x7FFFFFFFu, "div -0 / -denorm.mid"}, + {VURS_RSQRT, 0x00000001u, 0x80400000u, 0x000u, 0x410u, 0x7FFFFFFFu, "rsqrt +denorm.min / -denorm.mid"}, + {VURS_DIV, 0x00000001u, 0x80400000u, 0x000u, 0x410u, 0xFFFFFFFFu, "div +denorm.min / -denorm.mid"}, + {VURS_RSQRT, 0x80000001u, 0x80400000u, 0x000u, 0x410u, 0xFFFFFFFFu, "rsqrt -denorm.min / -denorm.mid"}, + {VURS_DIV, 0x80000001u, 0x80400000u, 0x000u, 0x410u, 0x7FFFFFFFu, "div -denorm.min / -denorm.mid"}, + {VURS_RSQRT, 0x3F800000u, 0x80400000u, 0x000u, 0xC30u, 0x7FFFFFFFu, "rsqrt +1 / -denorm.mid"}, + {VURS_DIV, 0x3F800000u, 0x80400000u, 0x000u, 0x820u, 0xFFFFFFFFu, "div +1 / -denorm.mid"}, + {VURS_RSQRT, 0xBF800000u, 0x80400000u, 0x000u, 0xC30u, 0xFFFFFFFFu, "rsqrt -1 / -denorm.mid"}, + {VURS_DIV, 0xBF800000u, 0x80400000u, 0x000u, 0x820u, 0x7FFFFFFFu, "div -1 / -denorm.mid"}, + {VURS_RSQRT, 0x40800000u, 0x80400000u, 0x000u, 0xC30u, 0x7FFFFFFFu, "rsqrt +4 / -denorm.mid"}, + {VURS_DIV, 0x40800000u, 0x80400000u, 0x000u, 0x820u, 0xFFFFFFFFu, "div +4 / -denorm.mid"}, + {VURS_RSQRT, 0x7F7FFFFFu, 0x80400000u, 0x000u, 0xC30u, 0x7FFFFFFFu, "rsqrt +fltmax / -denorm.mid"}, + {VURS_DIV, 0x7F7FFFFFu, 0x80400000u, 0x000u, 0x820u, 0xFFFFFFFFu, "div +fltmax / -denorm.mid"}, + {VURS_RSQRT, 0xFF7FFFFFu, 0x80400000u, 0x000u, 0xC30u, 0xFFFFFFFFu, "rsqrt -fltmax / -denorm.mid"}, + {VURS_DIV, 0xFF7FFFFFu, 0x80400000u, 0x000u, 0x820u, 0x7FFFFFFFu, "div -fltmax / -denorm.mid"}, + {VURS_RSQRT, 0x7FFFFFFFu, 0x80400000u, 0x000u, 0xC30u, 0x7FFFFFFFu, "rsqrt +eemax / -denorm.mid"}, + {VURS_DIV, 0x7FFFFFFFu, 0x80400000u, 0x000u, 0x820u, 0xFFFFFFFFu, "div +eemax / -denorm.mid"}, + {VURS_RSQRT, 0x00000000u, 0x007FFFFFu, 0x000u, 0x410u, 0x7FFFFFFFu, "rsqrt +0 / +denorm.max"}, + {VURS_DIV, 0x00000000u, 0x007FFFFFu, 0x000u, 0x410u, 0x7FFFFFFFu, "div +0 / +denorm.max"}, + {VURS_RSQRT, 0x80000000u, 0x007FFFFFu, 0x000u, 0x410u, 0xFFFFFFFFu, "rsqrt -0 / +denorm.max"}, + {VURS_DIV, 0x80000000u, 0x007FFFFFu, 0x000u, 0x410u, 0xFFFFFFFFu, "div -0 / +denorm.max"}, + {VURS_RSQRT, 0x00000001u, 0x007FFFFFu, 0x000u, 0x410u, 0x7FFFFFFFu, "rsqrt +denorm.min / +denorm.max"}, + {VURS_DIV, 0x00000001u, 0x007FFFFFu, 0x000u, 0x410u, 0x7FFFFFFFu, "div +denorm.min / +denorm.max"}, + {VURS_RSQRT, 0x80000001u, 0x007FFFFFu, 0x000u, 0x410u, 0xFFFFFFFFu, "rsqrt -denorm.min / +denorm.max"}, + {VURS_DIV, 0x80000001u, 0x007FFFFFu, 0x000u, 0x410u, 0xFFFFFFFFu, "div -denorm.min / +denorm.max"}, + {VURS_RSQRT, 0x3F800000u, 0x007FFFFFu, 0x000u, 0x820u, 0x7FFFFFFFu, "rsqrt +1 / +denorm.max"}, + {VURS_DIV, 0x3F800000u, 0x007FFFFFu, 0x000u, 0x820u, 0x7FFFFFFFu, "div +1 / +denorm.max"}, + {VURS_RSQRT, 0xBF800000u, 0x007FFFFFu, 0x000u, 0x820u, 0xFFFFFFFFu, "rsqrt -1 / +denorm.max"}, + {VURS_DIV, 0xBF800000u, 0x007FFFFFu, 0x000u, 0x820u, 0xFFFFFFFFu, "div -1 / +denorm.max"}, + {VURS_RSQRT, 0x40800000u, 0x007FFFFFu, 0x000u, 0x820u, 0x7FFFFFFFu, "rsqrt +4 / +denorm.max"}, + {VURS_DIV, 0x40800000u, 0x007FFFFFu, 0x000u, 0x820u, 0x7FFFFFFFu, "div +4 / +denorm.max"}, + {VURS_RSQRT, 0x7F7FFFFFu, 0x007FFFFFu, 0x000u, 0x820u, 0x7FFFFFFFu, "rsqrt +fltmax / +denorm.max"}, + {VURS_DIV, 0x7F7FFFFFu, 0x007FFFFFu, 0x000u, 0x820u, 0x7FFFFFFFu, "div +fltmax / +denorm.max"}, + {VURS_RSQRT, 0xFF7FFFFFu, 0x007FFFFFu, 0x000u, 0x820u, 0xFFFFFFFFu, "rsqrt -fltmax / +denorm.max"}, + {VURS_DIV, 0xFF7FFFFFu, 0x007FFFFFu, 0x000u, 0x820u, 0xFFFFFFFFu, "div -fltmax / +denorm.max"}, + {VURS_RSQRT, 0x7FFFFFFFu, 0x007FFFFFu, 0x000u, 0x820u, 0x7FFFFFFFu, "rsqrt +eemax / +denorm.max"}, + {VURS_DIV, 0x7FFFFFFFu, 0x007FFFFFu, 0x000u, 0x820u, 0x7FFFFFFFu, "div +eemax / +denorm.max"}, + {VURS_RSQRT, 0x00000000u, 0x807FFFFFu, 0x000u, 0x410u, 0x7FFFFFFFu, "rsqrt +0 / -denorm.max"}, + {VURS_DIV, 0x00000000u, 0x807FFFFFu, 0x000u, 0x410u, 0xFFFFFFFFu, "div +0 / -denorm.max"}, + {VURS_RSQRT, 0x80000000u, 0x807FFFFFu, 0x000u, 0x410u, 0xFFFFFFFFu, "rsqrt -0 / -denorm.max"}, + {VURS_DIV, 0x80000000u, 0x807FFFFFu, 0x000u, 0x410u, 0x7FFFFFFFu, "div -0 / -denorm.max"}, + {VURS_RSQRT, 0x00000001u, 0x807FFFFFu, 0x000u, 0x410u, 0x7FFFFFFFu, "rsqrt +denorm.min / -denorm.max"}, + {VURS_DIV, 0x00000001u, 0x807FFFFFu, 0x000u, 0x410u, 0xFFFFFFFFu, "div +denorm.min / -denorm.max"}, + {VURS_RSQRT, 0x80000001u, 0x807FFFFFu, 0x000u, 0x410u, 0xFFFFFFFFu, "rsqrt -denorm.min / -denorm.max"}, + {VURS_DIV, 0x80000001u, 0x807FFFFFu, 0x000u, 0x410u, 0x7FFFFFFFu, "div -denorm.min / -denorm.max"}, + {VURS_RSQRT, 0x3F800000u, 0x807FFFFFu, 0x000u, 0xC30u, 0x7FFFFFFFu, "rsqrt +1 / -denorm.max"}, + {VURS_DIV, 0x3F800000u, 0x807FFFFFu, 0x000u, 0x820u, 0xFFFFFFFFu, "div +1 / -denorm.max"}, + {VURS_RSQRT, 0xBF800000u, 0x807FFFFFu, 0x000u, 0xC30u, 0xFFFFFFFFu, "rsqrt -1 / -denorm.max"}, + {VURS_DIV, 0xBF800000u, 0x807FFFFFu, 0x000u, 0x820u, 0x7FFFFFFFu, "div -1 / -denorm.max"}, + {VURS_RSQRT, 0x40800000u, 0x807FFFFFu, 0x000u, 0xC30u, 0x7FFFFFFFu, "rsqrt +4 / -denorm.max"}, + {VURS_DIV, 0x40800000u, 0x807FFFFFu, 0x000u, 0x820u, 0xFFFFFFFFu, "div +4 / -denorm.max"}, + {VURS_RSQRT, 0x7F7FFFFFu, 0x807FFFFFu, 0x000u, 0xC30u, 0x7FFFFFFFu, "rsqrt +fltmax / -denorm.max"}, + {VURS_DIV, 0x7F7FFFFFu, 0x807FFFFFu, 0x000u, 0x820u, 0xFFFFFFFFu, "div +fltmax / -denorm.max"}, + {VURS_RSQRT, 0xFF7FFFFFu, 0x807FFFFFu, 0x000u, 0xC30u, 0xFFFFFFFFu, "rsqrt -fltmax / -denorm.max"}, + {VURS_DIV, 0xFF7FFFFFu, 0x807FFFFFu, 0x000u, 0x820u, 0x7FFFFFFFu, "div -fltmax / -denorm.max"}, + {VURS_RSQRT, 0x7FFFFFFFu, 0x807FFFFFu, 0x000u, 0xC30u, 0x7FFFFFFFu, "rsqrt +eemax / -denorm.max"}, + {VURS_DIV, 0x7FFFFFFFu, 0x807FFFFFu, 0x000u, 0x820u, 0xFFFFFFFFu, "div +eemax / -denorm.max"}, + {VURS_RSQRT, 0x00000000u, 0x00800000u, 0x000u, 0x000u, 0x00000000u, "rsqrt +0 / +normal.min"}, + {VURS_DIV, 0x00000000u, 0x00800000u, 0x000u, 0x000u, 0x00000000u, "div +0 / +normal.min"}, + {VURS_RSQRT, 0x80000000u, 0x00800000u, 0x000u, 0x000u, 0x80000000u, "rsqrt -0 / +normal.min"}, + {VURS_DIV, 0x80000000u, 0x00800000u, 0x000u, 0x000u, 0x80000000u, "div -0 / +normal.min"}, + {VURS_RSQRT, 0x00000001u, 0x00800000u, 0x000u, 0x000u, 0x00000000u, "rsqrt +denorm.min / +normal.min"}, + {VURS_DIV, 0x00000001u, 0x00800000u, 0x000u, 0x000u, 0x00000000u, "div +denorm.min / +normal.min"}, + {VURS_RSQRT, 0x80000001u, 0x00800000u, 0x000u, 0x000u, 0x80000000u, "rsqrt -denorm.min / +normal.min"}, + {VURS_DIV, 0x80000001u, 0x00800000u, 0x000u, 0x000u, 0x80000000u, "div -denorm.min / +normal.min"}, + {VURS_RSQRT, 0x3F800000u, 0x00800000u, 0x000u, 0x000u, 0x5F000000u, "rsqrt +1 / +normal.min"}, + {VURS_DIV, 0x3F800000u, 0x00800000u, 0x000u, 0x000u, 0x7E800000u, "div +1 / +normal.min"}, + {VURS_RSQRT, 0xBF800000u, 0x00800000u, 0x000u, 0x000u, 0xDF000000u, "rsqrt -1 / +normal.min"}, + {VURS_DIV, 0xBF800000u, 0x00800000u, 0x000u, 0x000u, 0xFE800000u, "div -1 / +normal.min"}, + {VURS_RSQRT, 0x40800000u, 0x00800000u, 0x000u, 0x000u, 0x60000000u, "rsqrt +4 / +normal.min"}, + {VURS_DIV, 0x40800000u, 0x00800000u, 0x000u, 0x000u, 0x7F800000u, "div +4 / +normal.min"}, + {VURS_RSQRT, 0x7F7FFFFFu, 0x00800000u, 0x000u, 0x000u, 0x7FFFFFFFu, "rsqrt +fltmax / +normal.min"}, + {VURS_DIV, 0x7F7FFFFFu, 0x00800000u, 0x000u, 0x000u, 0x7FFFFFFFu, "div +fltmax / +normal.min"}, + {VURS_RSQRT, 0xFF7FFFFFu, 0x00800000u, 0x000u, 0x000u, 0xFFFFFFFFu, "rsqrt -fltmax / +normal.min"}, + {VURS_DIV, 0xFF7FFFFFu, 0x00800000u, 0x000u, 0x000u, 0xFFFFFFFFu, "div -fltmax / +normal.min"}, + {VURS_RSQRT, 0x7FFFFFFFu, 0x00800000u, 0x000u, 0x000u, 0x7FFFFFFFu, "rsqrt +eemax / +normal.min"}, + {VURS_DIV, 0x7FFFFFFFu, 0x00800000u, 0x000u, 0x000u, 0x7FFFFFFFu, "div +eemax / +normal.min"}, + {VURS_RSQRT, 0x00000000u, 0x80800000u, 0x000u, 0x410u, 0x00000000u, "rsqrt +0 / -normal.min"}, + {VURS_DIV, 0x00000000u, 0x80800000u, 0x000u, 0x000u, 0x80000000u, "div +0 / -normal.min"}, + {VURS_RSQRT, 0x80000000u, 0x80800000u, 0x000u, 0x410u, 0x80000000u, "rsqrt -0 / -normal.min"}, + {VURS_DIV, 0x80000000u, 0x80800000u, 0x000u, 0x000u, 0x00000000u, "div -0 / -normal.min"}, + {VURS_RSQRT, 0x00000001u, 0x80800000u, 0x000u, 0x410u, 0x00000000u, "rsqrt +denorm.min / -normal.min"}, + {VURS_DIV, 0x00000001u, 0x80800000u, 0x000u, 0x000u, 0x80000000u, "div +denorm.min / -normal.min"}, + {VURS_RSQRT, 0x80000001u, 0x80800000u, 0x000u, 0x410u, 0x80000000u, "rsqrt -denorm.min / -normal.min"}, + {VURS_DIV, 0x80000001u, 0x80800000u, 0x000u, 0x000u, 0x00000000u, "div -denorm.min / -normal.min"}, + {VURS_RSQRT, 0x3F800000u, 0x80800000u, 0x000u, 0x410u, 0x5F000000u, "rsqrt +1 / -normal.min"}, + {VURS_DIV, 0x3F800000u, 0x80800000u, 0x000u, 0x000u, 0xFE800000u, "div +1 / -normal.min"}, + {VURS_RSQRT, 0xBF800000u, 0x80800000u, 0x000u, 0x410u, 0xDF000000u, "rsqrt -1 / -normal.min"}, + {VURS_DIV, 0xBF800000u, 0x80800000u, 0x000u, 0x000u, 0x7E800000u, "div -1 / -normal.min"}, + {VURS_RSQRT, 0x40800000u, 0x80800000u, 0x000u, 0x410u, 0x60000000u, "rsqrt +4 / -normal.min"}, + {VURS_DIV, 0x40800000u, 0x80800000u, 0x000u, 0x000u, 0xFF800000u, "div +4 / -normal.min"}, + {VURS_RSQRT, 0x7F7FFFFFu, 0x80800000u, 0x000u, 0x410u, 0x7FFFFFFFu, "rsqrt +fltmax / -normal.min"}, + {VURS_DIV, 0x7F7FFFFFu, 0x80800000u, 0x000u, 0x000u, 0xFFFFFFFFu, "div +fltmax / -normal.min"}, + {VURS_RSQRT, 0xFF7FFFFFu, 0x80800000u, 0x000u, 0x410u, 0xFFFFFFFFu, "rsqrt -fltmax / -normal.min"}, + {VURS_DIV, 0xFF7FFFFFu, 0x80800000u, 0x000u, 0x000u, 0x7FFFFFFFu, "div -fltmax / -normal.min"}, + {VURS_RSQRT, 0x7FFFFFFFu, 0x80800000u, 0x000u, 0x410u, 0x7FFFFFFFu, "rsqrt +eemax / -normal.min"}, + {VURS_DIV, 0x7FFFFFFFu, 0x80800000u, 0x000u, 0x000u, 0xFFFFFFFFu, "div +eemax / -normal.min"}, + {VURS_RSQRT, 0x00000000u, 0x3F800000u, 0x000u, 0x000u, 0x00000000u, "rsqrt +0 / +1"}, + {VURS_DIV, 0x00000000u, 0x3F800000u, 0x000u, 0x000u, 0x00000000u, "div +0 / +1"}, + {VURS_RSQRT, 0x80000000u, 0x3F800000u, 0x000u, 0x000u, 0x80000000u, "rsqrt -0 / +1"}, + {VURS_DIV, 0x80000000u, 0x3F800000u, 0x000u, 0x000u, 0x80000000u, "div -0 / +1"}, + {VURS_RSQRT, 0x00000001u, 0x3F800000u, 0x000u, 0x000u, 0x00000000u, "rsqrt +denorm.min / +1"}, + {VURS_DIV, 0x00000001u, 0x3F800000u, 0x000u, 0x000u, 0x00000000u, "div +denorm.min / +1"}, + {VURS_RSQRT, 0x80000001u, 0x3F800000u, 0x000u, 0x000u, 0x80000000u, "rsqrt -denorm.min / +1"}, + {VURS_DIV, 0x80000001u, 0x3F800000u, 0x000u, 0x000u, 0x80000000u, "div -denorm.min / +1"}, + {VURS_RSQRT, 0x3F800000u, 0x3F800000u, 0x000u, 0x000u, 0x3F800000u, "rsqrt +1 / +1"}, + {VURS_DIV, 0x3F800000u, 0x3F800000u, 0x000u, 0x000u, 0x3F800000u, "div +1 / +1"}, + {VURS_RSQRT, 0xBF800000u, 0x3F800000u, 0x000u, 0x000u, 0xBF800000u, "rsqrt -1 / +1"}, + {VURS_DIV, 0xBF800000u, 0x3F800000u, 0x000u, 0x000u, 0xBF800000u, "div -1 / +1"}, + {VURS_RSQRT, 0x40800000u, 0x3F800000u, 0x000u, 0x000u, 0x40800000u, "rsqrt +4 / +1"}, + {VURS_DIV, 0x40800000u, 0x3F800000u, 0x000u, 0x000u, 0x40800000u, "div +4 / +1"}, + {VURS_RSQRT, 0x7F7FFFFFu, 0x3F800000u, 0x000u, 0x000u, 0x7F7FFFFFu, "rsqrt +fltmax / +1"}, + {VURS_DIV, 0x7F7FFFFFu, 0x3F800000u, 0x000u, 0x000u, 0x7F7FFFFFu, "div +fltmax / +1"}, + {VURS_RSQRT, 0xFF7FFFFFu, 0x3F800000u, 0x000u, 0x000u, 0xFF7FFFFFu, "rsqrt -fltmax / +1"}, + {VURS_DIV, 0xFF7FFFFFu, 0x3F800000u, 0x000u, 0x000u, 0xFF7FFFFFu, "div -fltmax / +1"}, + {VURS_RSQRT, 0x7FFFFFFFu, 0x3F800000u, 0x000u, 0x000u, 0x7FFFFFFFu, "rsqrt +eemax / +1"}, + {VURS_DIV, 0x7FFFFFFFu, 0x3F800000u, 0x000u, 0x000u, 0x7FFFFFFFu, "div +eemax / +1"}, + {VURS_RSQRT, 0x00000000u, 0xBF800000u, 0x000u, 0x410u, 0x00000000u, "rsqrt +0 / -1"}, + {VURS_DIV, 0x00000000u, 0xBF800000u, 0x000u, 0x000u, 0x80000000u, "div +0 / -1"}, + {VURS_RSQRT, 0x80000000u, 0xBF800000u, 0x000u, 0x410u, 0x80000000u, "rsqrt -0 / -1"}, + {VURS_DIV, 0x80000000u, 0xBF800000u, 0x000u, 0x000u, 0x00000000u, "div -0 / -1"}, + {VURS_RSQRT, 0x00000001u, 0xBF800000u, 0x000u, 0x410u, 0x00000000u, "rsqrt +denorm.min / -1"}, + {VURS_DIV, 0x00000001u, 0xBF800000u, 0x000u, 0x000u, 0x80000000u, "div +denorm.min / -1"}, + {VURS_RSQRT, 0x80000001u, 0xBF800000u, 0x000u, 0x410u, 0x80000000u, "rsqrt -denorm.min / -1"}, + {VURS_DIV, 0x80000001u, 0xBF800000u, 0x000u, 0x000u, 0x00000000u, "div -denorm.min / -1"}, + {VURS_RSQRT, 0x3F800000u, 0xBF800000u, 0x000u, 0x410u, 0x3F800000u, "rsqrt +1 / -1"}, + {VURS_DIV, 0x3F800000u, 0xBF800000u, 0x000u, 0x000u, 0xBF800000u, "div +1 / -1"}, + {VURS_RSQRT, 0xBF800000u, 0xBF800000u, 0x000u, 0x410u, 0xBF800000u, "rsqrt -1 / -1"}, + {VURS_DIV, 0xBF800000u, 0xBF800000u, 0x000u, 0x000u, 0x3F800000u, "div -1 / -1"}, + {VURS_RSQRT, 0x40800000u, 0xBF800000u, 0x000u, 0x410u, 0x40800000u, "rsqrt +4 / -1"}, + {VURS_DIV, 0x40800000u, 0xBF800000u, 0x000u, 0x000u, 0xC0800000u, "div +4 / -1"}, + {VURS_RSQRT, 0x7F7FFFFFu, 0xBF800000u, 0x000u, 0x410u, 0x7F7FFFFFu, "rsqrt +fltmax / -1"}, + {VURS_DIV, 0x7F7FFFFFu, 0xBF800000u, 0x000u, 0x000u, 0xFF7FFFFFu, "div +fltmax / -1"}, + {VURS_RSQRT, 0xFF7FFFFFu, 0xBF800000u, 0x000u, 0x410u, 0xFF7FFFFFu, "rsqrt -fltmax / -1"}, + {VURS_DIV, 0xFF7FFFFFu, 0xBF800000u, 0x000u, 0x000u, 0x7F7FFFFFu, "div -fltmax / -1"}, + {VURS_RSQRT, 0x7FFFFFFFu, 0xBF800000u, 0x000u, 0x410u, 0x7FFFFFFFu, "rsqrt +eemax / -1"}, + {VURS_DIV, 0x7FFFFFFFu, 0xBF800000u, 0x000u, 0x000u, 0xFFFFFFFFu, "div +eemax / -1"}, + {VURS_RSQRT, 0x00000000u, 0x40800000u, 0x000u, 0x000u, 0x00000000u, "rsqrt +0 / +4"}, + {VURS_DIV, 0x00000000u, 0x40800000u, 0x000u, 0x000u, 0x00000000u, "div +0 / +4"}, + {VURS_RSQRT, 0x80000000u, 0x40800000u, 0x000u, 0x000u, 0x80000000u, "rsqrt -0 / +4"}, + {VURS_DIV, 0x80000000u, 0x40800000u, 0x000u, 0x000u, 0x80000000u, "div -0 / +4"}, + {VURS_RSQRT, 0x00000001u, 0x40800000u, 0x000u, 0x000u, 0x00000000u, "rsqrt +denorm.min / +4"}, + {VURS_DIV, 0x00000001u, 0x40800000u, 0x000u, 0x000u, 0x00000000u, "div +denorm.min / +4"}, + {VURS_RSQRT, 0x80000001u, 0x40800000u, 0x000u, 0x000u, 0x80000000u, "rsqrt -denorm.min / +4"}, + {VURS_DIV, 0x80000001u, 0x40800000u, 0x000u, 0x000u, 0x80000000u, "div -denorm.min / +4"}, + {VURS_RSQRT, 0x3F800000u, 0x40800000u, 0x000u, 0x000u, 0x3F000000u, "rsqrt +1 / +4"}, + {VURS_DIV, 0x3F800000u, 0x40800000u, 0x000u, 0x000u, 0x3E800000u, "div +1 / +4"}, + {VURS_RSQRT, 0xBF800000u, 0x40800000u, 0x000u, 0x000u, 0xBF000000u, "rsqrt -1 / +4"}, + {VURS_DIV, 0xBF800000u, 0x40800000u, 0x000u, 0x000u, 0xBE800000u, "div -1 / +4"}, + {VURS_RSQRT, 0x40800000u, 0x40800000u, 0x000u, 0x000u, 0x40000000u, "rsqrt +4 / +4"}, + {VURS_DIV, 0x40800000u, 0x40800000u, 0x000u, 0x000u, 0x3F800000u, "div +4 / +4"}, + {VURS_RSQRT, 0x7F7FFFFFu, 0x40800000u, 0x000u, 0x000u, 0x7EFFFFFFu, "rsqrt +fltmax / +4"}, + {VURS_DIV, 0x7F7FFFFFu, 0x40800000u, 0x000u, 0x000u, 0x7E7FFFFFu, "div +fltmax / +4"}, + {VURS_RSQRT, 0xFF7FFFFFu, 0x40800000u, 0x000u, 0x000u, 0xFEFFFFFFu, "rsqrt -fltmax / +4"}, + {VURS_DIV, 0xFF7FFFFFu, 0x40800000u, 0x000u, 0x000u, 0xFE7FFFFFu, "div -fltmax / +4"}, + {VURS_RSQRT, 0x7FFFFFFFu, 0x40800000u, 0x000u, 0x000u, 0x7F7FFFFFu, "rsqrt +eemax / +4"}, + {VURS_DIV, 0x7FFFFFFFu, 0x40800000u, 0x000u, 0x000u, 0x7EFFFFFFu, "div +eemax / +4"}, + {VURS_RSQRT, 0x00000000u, 0xC0800000u, 0x000u, 0x410u, 0x00000000u, "rsqrt +0 / -4"}, + {VURS_DIV, 0x00000000u, 0xC0800000u, 0x000u, 0x000u, 0x80000000u, "div +0 / -4"}, + {VURS_RSQRT, 0x80000000u, 0xC0800000u, 0x000u, 0x410u, 0x80000000u, "rsqrt -0 / -4"}, + {VURS_DIV, 0x80000000u, 0xC0800000u, 0x000u, 0x000u, 0x00000000u, "div -0 / -4"}, + {VURS_RSQRT, 0x00000001u, 0xC0800000u, 0x000u, 0x410u, 0x00000000u, "rsqrt +denorm.min / -4"}, + {VURS_DIV, 0x00000001u, 0xC0800000u, 0x000u, 0x000u, 0x80000000u, "div +denorm.min / -4"}, + {VURS_RSQRT, 0x80000001u, 0xC0800000u, 0x000u, 0x410u, 0x80000000u, "rsqrt -denorm.min / -4"}, + {VURS_DIV, 0x80000001u, 0xC0800000u, 0x000u, 0x000u, 0x00000000u, "div -denorm.min / -4"}, + {VURS_RSQRT, 0x3F800000u, 0xC0800000u, 0x000u, 0x410u, 0x3F000000u, "rsqrt +1 / -4"}, + {VURS_DIV, 0x3F800000u, 0xC0800000u, 0x000u, 0x000u, 0xBE800000u, "div +1 / -4"}, + {VURS_RSQRT, 0xBF800000u, 0xC0800000u, 0x000u, 0x410u, 0xBF000000u, "rsqrt -1 / -4"}, + {VURS_DIV, 0xBF800000u, 0xC0800000u, 0x000u, 0x000u, 0x3E800000u, "div -1 / -4"}, + {VURS_RSQRT, 0x40800000u, 0xC0800000u, 0x000u, 0x410u, 0x40000000u, "rsqrt +4 / -4"}, + {VURS_DIV, 0x40800000u, 0xC0800000u, 0x000u, 0x000u, 0xBF800000u, "div +4 / -4"}, + {VURS_RSQRT, 0x7F7FFFFFu, 0xC0800000u, 0x000u, 0x410u, 0x7EFFFFFFu, "rsqrt +fltmax / -4"}, + {VURS_DIV, 0x7F7FFFFFu, 0xC0800000u, 0x000u, 0x000u, 0xFE7FFFFFu, "div +fltmax / -4"}, + {VURS_RSQRT, 0xFF7FFFFFu, 0xC0800000u, 0x000u, 0x410u, 0xFEFFFFFFu, "rsqrt -fltmax / -4"}, + {VURS_DIV, 0xFF7FFFFFu, 0xC0800000u, 0x000u, 0x000u, 0x7E7FFFFFu, "div -fltmax / -4"}, + {VURS_RSQRT, 0x7FFFFFFFu, 0xC0800000u, 0x000u, 0x410u, 0x7F7FFFFFu, "rsqrt +eemax / -4"}, + {VURS_DIV, 0x7FFFFFFFu, 0xC0800000u, 0x000u, 0x000u, 0xFEFFFFFFu, "div +eemax / -4"}, + {VURS_RSQRT, 0x00000000u, 0x7F7FFFFFu, 0x000u, 0x000u, 0x00000000u, "rsqrt +0 / +fltmax"}, + {VURS_DIV, 0x00000000u, 0x7F7FFFFFu, 0x000u, 0x000u, 0x00000000u, "div +0 / +fltmax"}, + {VURS_RSQRT, 0x80000000u, 0x7F7FFFFFu, 0x000u, 0x000u, 0x80000000u, "rsqrt -0 / +fltmax"}, + {VURS_DIV, 0x80000000u, 0x7F7FFFFFu, 0x000u, 0x000u, 0x80000000u, "div -0 / +fltmax"}, + {VURS_RSQRT, 0x00000001u, 0x7F7FFFFFu, 0x000u, 0x000u, 0x00000000u, "rsqrt +denorm.min / +fltmax"}, + {VURS_DIV, 0x00000001u, 0x7F7FFFFFu, 0x000u, 0x000u, 0x00000000u, "div +denorm.min / +fltmax"}, + {VURS_RSQRT, 0x80000001u, 0x7F7FFFFFu, 0x000u, 0x000u, 0x80000000u, "rsqrt -denorm.min / +fltmax"}, + {VURS_DIV, 0x80000001u, 0x7F7FFFFFu, 0x000u, 0x000u, 0x80000000u, "div -denorm.min / +fltmax"}, + {VURS_RSQRT, 0x3F800000u, 0x7F7FFFFFu, 0x000u, 0x000u, 0x1F800001u, "rsqrt +1 / +fltmax"}, + {VURS_DIV, 0x3F800000u, 0x7F7FFFFFu, 0x000u, 0x000u, 0x00000000u, "div +1 / +fltmax"}, + {VURS_RSQRT, 0xBF800000u, 0x7F7FFFFFu, 0x000u, 0x000u, 0x9F800001u, "rsqrt -1 / +fltmax"}, + {VURS_DIV, 0xBF800000u, 0x7F7FFFFFu, 0x000u, 0x000u, 0x80000000u, "div -1 / +fltmax"}, + {VURS_RSQRT, 0x40800000u, 0x7F7FFFFFu, 0x000u, 0x000u, 0x20800001u, "rsqrt +4 / +fltmax"}, + {VURS_DIV, 0x40800000u, 0x7F7FFFFFu, 0x000u, 0x000u, 0x00800001u, "div +4 / +fltmax"}, + {VURS_RSQRT, 0x7F7FFFFFu, 0x7F7FFFFFu, 0x000u, 0x000u, 0x5F800000u, "rsqrt +fltmax / +fltmax"}, + {VURS_DIV, 0x7F7FFFFFu, 0x7F7FFFFFu, 0x000u, 0x000u, 0x3F800000u, "div +fltmax / +fltmax"}, + {VURS_RSQRT, 0xFF7FFFFFu, 0x7F7FFFFFu, 0x000u, 0x000u, 0xDF800000u, "rsqrt -fltmax / +fltmax"}, + {VURS_DIV, 0xFF7FFFFFu, 0x7F7FFFFFu, 0x000u, 0x000u, 0xBF800000u, "div -fltmax / +fltmax"}, + {VURS_RSQRT, 0x7FFFFFFFu, 0x7F7FFFFFu, 0x000u, 0x000u, 0x60000000u, "rsqrt +eemax / +fltmax"}, + {VURS_DIV, 0x7FFFFFFFu, 0x7F7FFFFFu, 0x000u, 0x000u, 0x40000000u, "div +eemax / +fltmax"}, + {VURS_RSQRT, 0x00000000u, 0xFF7FFFFFu, 0x000u, 0x410u, 0x00000000u, "rsqrt +0 / -fltmax"}, + {VURS_DIV, 0x00000000u, 0xFF7FFFFFu, 0x000u, 0x000u, 0x80000000u, "div +0 / -fltmax"}, + {VURS_RSQRT, 0x80000000u, 0xFF7FFFFFu, 0x000u, 0x410u, 0x80000000u, "rsqrt -0 / -fltmax"}, + {VURS_DIV, 0x80000000u, 0xFF7FFFFFu, 0x000u, 0x000u, 0x00000000u, "div -0 / -fltmax"}, + {VURS_RSQRT, 0x00000001u, 0xFF7FFFFFu, 0x000u, 0x410u, 0x00000000u, "rsqrt +denorm.min / -fltmax"}, + {VURS_DIV, 0x00000001u, 0xFF7FFFFFu, 0x000u, 0x000u, 0x80000000u, "div +denorm.min / -fltmax"}, + {VURS_RSQRT, 0x80000001u, 0xFF7FFFFFu, 0x000u, 0x410u, 0x80000000u, "rsqrt -denorm.min / -fltmax"}, + {VURS_DIV, 0x80000001u, 0xFF7FFFFFu, 0x000u, 0x000u, 0x00000000u, "div -denorm.min / -fltmax"}, + {VURS_RSQRT, 0x3F800000u, 0xFF7FFFFFu, 0x000u, 0x410u, 0x1F800001u, "rsqrt +1 / -fltmax"}, + {VURS_DIV, 0x3F800000u, 0xFF7FFFFFu, 0x000u, 0x000u, 0x80000000u, "div +1 / -fltmax"}, + {VURS_RSQRT, 0xBF800000u, 0xFF7FFFFFu, 0x000u, 0x410u, 0x9F800001u, "rsqrt -1 / -fltmax"}, + {VURS_DIV, 0xBF800000u, 0xFF7FFFFFu, 0x000u, 0x000u, 0x00000000u, "div -1 / -fltmax"}, + {VURS_RSQRT, 0x40800000u, 0xFF7FFFFFu, 0x000u, 0x410u, 0x20800001u, "rsqrt +4 / -fltmax"}, + {VURS_DIV, 0x40800000u, 0xFF7FFFFFu, 0x000u, 0x000u, 0x80800001u, "div +4 / -fltmax"}, + {VURS_RSQRT, 0x7F7FFFFFu, 0xFF7FFFFFu, 0x000u, 0x410u, 0x5F800000u, "rsqrt +fltmax / -fltmax"}, + {VURS_DIV, 0x7F7FFFFFu, 0xFF7FFFFFu, 0x000u, 0x000u, 0xBF800000u, "div +fltmax / -fltmax"}, + {VURS_RSQRT, 0xFF7FFFFFu, 0xFF7FFFFFu, 0x000u, 0x410u, 0xDF800000u, "rsqrt -fltmax / -fltmax"}, + {VURS_DIV, 0xFF7FFFFFu, 0xFF7FFFFFu, 0x000u, 0x000u, 0x3F800000u, "div -fltmax / -fltmax"}, + {VURS_RSQRT, 0x7FFFFFFFu, 0xFF7FFFFFu, 0x000u, 0x410u, 0x60000000u, "rsqrt +eemax / -fltmax"}, + {VURS_DIV, 0x7FFFFFFFu, 0xFF7FFFFFu, 0x000u, 0x000u, 0xC0000000u, "div +eemax / -fltmax"}, + {VURS_RSQRT, 0x00000000u, 0x7F800000u, 0x000u, 0x000u, 0x00000000u, "rsqrt +0 / +2^128"}, + {VURS_DIV, 0x00000000u, 0x7F800000u, 0x000u, 0x000u, 0x00000000u, "div +0 / +2^128"}, + {VURS_RSQRT, 0x80000000u, 0x7F800000u, 0x000u, 0x000u, 0x80000000u, "rsqrt -0 / +2^128"}, + {VURS_DIV, 0x80000000u, 0x7F800000u, 0x000u, 0x000u, 0x80000000u, "div -0 / +2^128"}, + {VURS_RSQRT, 0x00000001u, 0x7F800000u, 0x000u, 0x000u, 0x00000000u, "rsqrt +denorm.min / +2^128"}, + {VURS_DIV, 0x00000001u, 0x7F800000u, 0x000u, 0x000u, 0x00000000u, "div +denorm.min / +2^128"}, + {VURS_RSQRT, 0x80000001u, 0x7F800000u, 0x000u, 0x000u, 0x80000000u, "rsqrt -denorm.min / +2^128"}, + {VURS_DIV, 0x80000001u, 0x7F800000u, 0x000u, 0x000u, 0x80000000u, "div -denorm.min / +2^128"}, + {VURS_RSQRT, 0x3F800000u, 0x7F800000u, 0x000u, 0x000u, 0x1F800000u, "rsqrt +1 / +2^128"}, + {VURS_DIV, 0x3F800000u, 0x7F800000u, 0x000u, 0x000u, 0x00000000u, "div +1 / +2^128"}, + {VURS_RSQRT, 0xBF800000u, 0x7F800000u, 0x000u, 0x000u, 0x9F800000u, "rsqrt -1 / +2^128"}, + {VURS_DIV, 0xBF800000u, 0x7F800000u, 0x000u, 0x000u, 0x80000000u, "div -1 / +2^128"}, + {VURS_RSQRT, 0x40800000u, 0x7F800000u, 0x000u, 0x000u, 0x20800000u, "rsqrt +4 / +2^128"}, + {VURS_DIV, 0x40800000u, 0x7F800000u, 0x000u, 0x000u, 0x00800000u, "div +4 / +2^128"}, + {VURS_RSQRT, 0x7F7FFFFFu, 0x7F800000u, 0x000u, 0x000u, 0x5F7FFFFFu, "rsqrt +fltmax / +2^128"}, + {VURS_DIV, 0x7F7FFFFFu, 0x7F800000u, 0x000u, 0x000u, 0x3F7FFFFFu, "div +fltmax / +2^128"}, + {VURS_RSQRT, 0xFF7FFFFFu, 0x7F800000u, 0x000u, 0x000u, 0xDF7FFFFFu, "rsqrt -fltmax / +2^128"}, + {VURS_DIV, 0xFF7FFFFFu, 0x7F800000u, 0x000u, 0x000u, 0xBF7FFFFFu, "div -fltmax / +2^128"}, + {VURS_RSQRT, 0x7FFFFFFFu, 0x7F800000u, 0x000u, 0x000u, 0x5FFFFFFFu, "rsqrt +eemax / +2^128"}, + {VURS_DIV, 0x7FFFFFFFu, 0x7F800000u, 0x000u, 0x000u, 0x3FFFFFFFu, "div +eemax / +2^128"}, + {VURS_RSQRT, 0x00000000u, 0xFF800000u, 0x000u, 0x410u, 0x00000000u, "rsqrt +0 / -2^128"}, + {VURS_DIV, 0x00000000u, 0xFF800000u, 0x000u, 0x000u, 0x80000000u, "div +0 / -2^128"}, + {VURS_RSQRT, 0x80000000u, 0xFF800000u, 0x000u, 0x410u, 0x80000000u, "rsqrt -0 / -2^128"}, + {VURS_DIV, 0x80000000u, 0xFF800000u, 0x000u, 0x000u, 0x00000000u, "div -0 / -2^128"}, + {VURS_RSQRT, 0x00000001u, 0xFF800000u, 0x000u, 0x410u, 0x00000000u, "rsqrt +denorm.min / -2^128"}, + {VURS_DIV, 0x00000001u, 0xFF800000u, 0x000u, 0x000u, 0x80000000u, "div +denorm.min / -2^128"}, + {VURS_RSQRT, 0x80000001u, 0xFF800000u, 0x000u, 0x410u, 0x80000000u, "rsqrt -denorm.min / -2^128"}, + {VURS_DIV, 0x80000001u, 0xFF800000u, 0x000u, 0x000u, 0x00000000u, "div -denorm.min / -2^128"}, + {VURS_RSQRT, 0x3F800000u, 0xFF800000u, 0x000u, 0x410u, 0x1F800000u, "rsqrt +1 / -2^128"}, + {VURS_DIV, 0x3F800000u, 0xFF800000u, 0x000u, 0x000u, 0x80000000u, "div +1 / -2^128"}, + {VURS_RSQRT, 0xBF800000u, 0xFF800000u, 0x000u, 0x410u, 0x9F800000u, "rsqrt -1 / -2^128"}, + {VURS_DIV, 0xBF800000u, 0xFF800000u, 0x000u, 0x000u, 0x00000000u, "div -1 / -2^128"}, + {VURS_RSQRT, 0x40800000u, 0xFF800000u, 0x000u, 0x410u, 0x20800000u, "rsqrt +4 / -2^128"}, + {VURS_DIV, 0x40800000u, 0xFF800000u, 0x000u, 0x000u, 0x80800000u, "div +4 / -2^128"}, + {VURS_RSQRT, 0x7F7FFFFFu, 0xFF800000u, 0x000u, 0x410u, 0x5F7FFFFFu, "rsqrt +fltmax / -2^128"}, + {VURS_DIV, 0x7F7FFFFFu, 0xFF800000u, 0x000u, 0x000u, 0xBF7FFFFFu, "div +fltmax / -2^128"}, + {VURS_RSQRT, 0xFF7FFFFFu, 0xFF800000u, 0x000u, 0x410u, 0xDF7FFFFFu, "rsqrt -fltmax / -2^128"}, + {VURS_DIV, 0xFF7FFFFFu, 0xFF800000u, 0x000u, 0x000u, 0x3F7FFFFFu, "div -fltmax / -2^128"}, + {VURS_RSQRT, 0x7FFFFFFFu, 0xFF800000u, 0x000u, 0x410u, 0x5FFFFFFFu, "rsqrt +eemax / -2^128"}, + {VURS_DIV, 0x7FFFFFFFu, 0xFF800000u, 0x000u, 0x000u, 0xBFFFFFFFu, "div +eemax / -2^128"}, + {VURS_RSQRT, 0x00000000u, 0x7FFFFFFFu, 0x000u, 0x000u, 0x00000000u, "rsqrt +0 / +eemax"}, + {VURS_DIV, 0x00000000u, 0x7FFFFFFFu, 0x000u, 0x000u, 0x00000000u, "div +0 / +eemax"}, + {VURS_RSQRT, 0x80000000u, 0x7FFFFFFFu, 0x000u, 0x000u, 0x80000000u, "rsqrt -0 / +eemax"}, + {VURS_DIV, 0x80000000u, 0x7FFFFFFFu, 0x000u, 0x000u, 0x80000000u, "div -0 / +eemax"}, + {VURS_RSQRT, 0x00000001u, 0x7FFFFFFFu, 0x000u, 0x000u, 0x00000000u, "rsqrt +denorm.min / +eemax"}, + {VURS_DIV, 0x00000001u, 0x7FFFFFFFu, 0x000u, 0x000u, 0x00000000u, "div +denorm.min / +eemax"}, + {VURS_RSQRT, 0x80000001u, 0x7FFFFFFFu, 0x000u, 0x000u, 0x80000000u, "rsqrt -denorm.min / +eemax"}, + {VURS_DIV, 0x80000001u, 0x7FFFFFFFu, 0x000u, 0x000u, 0x80000000u, "div -denorm.min / +eemax"}, + {VURS_RSQRT, 0x3F800000u, 0x7FFFFFFFu, 0x000u, 0x000u, 0x1F3504F3u, "rsqrt +1 / +eemax"}, + {VURS_DIV, 0x3F800000u, 0x7FFFFFFFu, 0x000u, 0x000u, 0x00000000u, "div +1 / +eemax"}, + {VURS_RSQRT, 0xBF800000u, 0x7FFFFFFFu, 0x000u, 0x000u, 0x9F3504F3u, "rsqrt -1 / +eemax"}, + {VURS_DIV, 0xBF800000u, 0x7FFFFFFFu, 0x000u, 0x000u, 0x80000000u, "div -1 / +eemax"}, + {VURS_RSQRT, 0x40800000u, 0x7FFFFFFFu, 0x000u, 0x000u, 0x203504F3u, "rsqrt +4 / +eemax"}, + {VURS_DIV, 0x40800000u, 0x7FFFFFFFu, 0x000u, 0x000u, 0x00000000u, "div +4 / +eemax"}, + {VURS_RSQRT, 0x7F7FFFFFu, 0x7FFFFFFFu, 0x000u, 0x000u, 0x5F3504F2u, "rsqrt +fltmax / +eemax"}, + {VURS_DIV, 0x7F7FFFFFu, 0x7FFFFFFFu, 0x000u, 0x000u, 0x3F000000u, "div +fltmax / +eemax"}, + {VURS_RSQRT, 0xFF7FFFFFu, 0x7FFFFFFFu, 0x000u, 0x000u, 0xDF3504F2u, "rsqrt -fltmax / +eemax"}, + {VURS_DIV, 0xFF7FFFFFu, 0x7FFFFFFFu, 0x000u, 0x000u, 0xBF000000u, "div -fltmax / +eemax"}, + {VURS_RSQRT, 0x7FFFFFFFu, 0x7FFFFFFFu, 0x000u, 0x000u, 0x5FB504F2u, "rsqrt +eemax / +eemax"}, + {VURS_DIV, 0x7FFFFFFFu, 0x7FFFFFFFu, 0x000u, 0x000u, 0x3F800000u, "div +eemax / +eemax"}, + {VURS_RSQRT, 0x00000000u, 0xFFFFFFFFu, 0x000u, 0x410u, 0x00000000u, "rsqrt +0 / -eemax"}, + {VURS_DIV, 0x00000000u, 0xFFFFFFFFu, 0x000u, 0x000u, 0x80000000u, "div +0 / -eemax"}, + {VURS_RSQRT, 0x80000000u, 0xFFFFFFFFu, 0x000u, 0x410u, 0x80000000u, "rsqrt -0 / -eemax"}, + {VURS_DIV, 0x80000000u, 0xFFFFFFFFu, 0x000u, 0x000u, 0x00000000u, "div -0 / -eemax"}, + {VURS_RSQRT, 0x00000001u, 0xFFFFFFFFu, 0x000u, 0x410u, 0x00000000u, "rsqrt +denorm.min / -eemax"}, + {VURS_DIV, 0x00000001u, 0xFFFFFFFFu, 0x000u, 0x000u, 0x80000000u, "div +denorm.min / -eemax"}, + {VURS_RSQRT, 0x80000001u, 0xFFFFFFFFu, 0x000u, 0x410u, 0x80000000u, "rsqrt -denorm.min / -eemax"}, + {VURS_DIV, 0x80000001u, 0xFFFFFFFFu, 0x000u, 0x000u, 0x00000000u, "div -denorm.min / -eemax"}, + {VURS_RSQRT, 0x3F800000u, 0xFFFFFFFFu, 0x000u, 0x410u, 0x1F3504F3u, "rsqrt +1 / -eemax"}, + {VURS_DIV, 0x3F800000u, 0xFFFFFFFFu, 0x000u, 0x000u, 0x80000000u, "div +1 / -eemax"}, + {VURS_RSQRT, 0xBF800000u, 0xFFFFFFFFu, 0x000u, 0x410u, 0x9F3504F3u, "rsqrt -1 / -eemax"}, + {VURS_DIV, 0xBF800000u, 0xFFFFFFFFu, 0x000u, 0x000u, 0x00000000u, "div -1 / -eemax"}, + {VURS_RSQRT, 0x40800000u, 0xFFFFFFFFu, 0x000u, 0x410u, 0x203504F3u, "rsqrt +4 / -eemax"}, + {VURS_DIV, 0x40800000u, 0xFFFFFFFFu, 0x000u, 0x000u, 0x80000000u, "div +4 / -eemax"}, + {VURS_RSQRT, 0x7F7FFFFFu, 0xFFFFFFFFu, 0x000u, 0x410u, 0x5F3504F2u, "rsqrt +fltmax / -eemax"}, + {VURS_DIV, 0x7F7FFFFFu, 0xFFFFFFFFu, 0x000u, 0x000u, 0xBF000000u, "div +fltmax / -eemax"}, + {VURS_RSQRT, 0xFF7FFFFFu, 0xFFFFFFFFu, 0x000u, 0x410u, 0xDF3504F2u, "rsqrt -fltmax / -eemax"}, + {VURS_DIV, 0xFF7FFFFFu, 0xFFFFFFFFu, 0x000u, 0x000u, 0x3F000000u, "div -fltmax / -eemax"}, + {VURS_RSQRT, 0x7FFFFFFFu, 0xFFFFFFFFu, 0x000u, 0x410u, 0x5FB504F2u, "rsqrt +eemax / -eemax"}, + {VURS_DIV, 0x7FFFFFFFu, 0xFFFFFFFFu, 0x000u, 0x000u, 0xBF800000u, "div +eemax / -eemax"}, + {VURS_RSQRT, 0x00000000u, 0x00000000u, 0xFC0u, 0xFD0u, 0x7FFFFFFFu, "rsqrt/seeded +0 / +0"}, + {VURS_RSQRT, 0x80000000u, 0x00000000u, 0xFC0u, 0xFD0u, 0xFFFFFFFFu, "rsqrt/seeded -0 / +0"}, + {VURS_RSQRT, 0x00000001u, 0x00000000u, 0xFC0u, 0xFD0u, 0x7FFFFFFFu, "rsqrt/seeded +denorm.min / +0"}, + {VURS_RSQRT, 0x80000001u, 0x00000000u, 0xFC0u, 0xFD0u, 0xFFFFFFFFu, "rsqrt/seeded -denorm.min / +0"}, + {VURS_RSQRT, 0x3F800000u, 0x00000000u, 0xFC0u, 0xFE0u, 0x7FFFFFFFu, "rsqrt/seeded +1 / +0"}, + {VURS_RSQRT, 0xBF800000u, 0x00000000u, 0xFC0u, 0xFE0u, 0xFFFFFFFFu, "rsqrt/seeded -1 / +0"}, + {VURS_RSQRT, 0x00000000u, 0x80000000u, 0xFC0u, 0xFD0u, 0x7FFFFFFFu, "rsqrt/seeded +0 / -0"}, + {VURS_RSQRT, 0x80000000u, 0x80000000u, 0xFC0u, 0xFD0u, 0xFFFFFFFFu, "rsqrt/seeded -0 / -0"}, + {VURS_RSQRT, 0x00000001u, 0x80000000u, 0xFC0u, 0xFD0u, 0x7FFFFFFFu, "rsqrt/seeded +denorm.min / -0"}, + {VURS_RSQRT, 0x80000001u, 0x80000000u, 0xFC0u, 0xFD0u, 0xFFFFFFFFu, "rsqrt/seeded -denorm.min / -0"}, + {VURS_RSQRT, 0x3F800000u, 0x80000000u, 0xFC0u, 0xFF0u, 0x7FFFFFFFu, "rsqrt/seeded +1 / -0"}, + {VURS_RSQRT, 0xBF800000u, 0x80000000u, 0xFC0u, 0xFF0u, 0xFFFFFFFFu, "rsqrt/seeded -1 / -0"}, + {VURS_RSQRT, 0x00000000u, 0x00000001u, 0xFC0u, 0xFD0u, 0x7FFFFFFFu, "rsqrt/seeded +0 / +denorm.min"}, + {VURS_RSQRT, 0x80000000u, 0x00000001u, 0xFC0u, 0xFD0u, 0xFFFFFFFFu, "rsqrt/seeded -0 / +denorm.min"}, + {VURS_RSQRT, 0x00000001u, 0x00000001u, 0xFC0u, 0xFD0u, 0x7FFFFFFFu, "rsqrt/seeded +denorm.min / +denorm.min"}, + {VURS_RSQRT, 0x80000001u, 0x00000001u, 0xFC0u, 0xFD0u, 0xFFFFFFFFu, "rsqrt/seeded -denorm.min / +denorm.min"}, + {VURS_RSQRT, 0x3F800000u, 0x00000001u, 0xFC0u, 0xFE0u, 0x7FFFFFFFu, "rsqrt/seeded +1 / +denorm.min"}, + {VURS_RSQRT, 0xBF800000u, 0x00000001u, 0xFC0u, 0xFE0u, 0xFFFFFFFFu, "rsqrt/seeded -1 / +denorm.min"}, + {VURS_RSQRT, 0x00000000u, 0x80000001u, 0xFC0u, 0xFD0u, 0x7FFFFFFFu, "rsqrt/seeded +0 / -denorm.min"}, + {VURS_RSQRT, 0x80000000u, 0x80000001u, 0xFC0u, 0xFD0u, 0xFFFFFFFFu, "rsqrt/seeded -0 / -denorm.min"}, + {VURS_RSQRT, 0x00000001u, 0x80000001u, 0xFC0u, 0xFD0u, 0x7FFFFFFFu, "rsqrt/seeded +denorm.min / -denorm.min"}, + {VURS_RSQRT, 0x80000001u, 0x80000001u, 0xFC0u, 0xFD0u, 0xFFFFFFFFu, "rsqrt/seeded -denorm.min / -denorm.min"}, + {VURS_RSQRT, 0x3F800000u, 0x80000001u, 0xFC0u, 0xFF0u, 0x7FFFFFFFu, "rsqrt/seeded +1 / -denorm.min"}, + {VURS_RSQRT, 0xBF800000u, 0x80000001u, 0xFC0u, 0xFF0u, 0xFFFFFFFFu, "rsqrt/seeded -1 / -denorm.min"}, + {VURS_RSQRT, 0x00000000u, 0x00400000u, 0xFC0u, 0xFD0u, 0x7FFFFFFFu, "rsqrt/seeded +0 / +denorm.mid"}, + {VURS_RSQRT, 0x80000000u, 0x00400000u, 0xFC0u, 0xFD0u, 0xFFFFFFFFu, "rsqrt/seeded -0 / +denorm.mid"}, + {VURS_RSQRT, 0x00000001u, 0x00400000u, 0xFC0u, 0xFD0u, 0x7FFFFFFFu, "rsqrt/seeded +denorm.min / +denorm.mid"}, + {VURS_RSQRT, 0x80000001u, 0x00400000u, 0xFC0u, 0xFD0u, 0xFFFFFFFFu, "rsqrt/seeded -denorm.min / +denorm.mid"}, + {VURS_RSQRT, 0x3F800000u, 0x00400000u, 0xFC0u, 0xFE0u, 0x7FFFFFFFu, "rsqrt/seeded +1 / +denorm.mid"}, + {VURS_RSQRT, 0xBF800000u, 0x00400000u, 0xFC0u, 0xFE0u, 0xFFFFFFFFu, "rsqrt/seeded -1 / +denorm.mid"}, + {VURS_RSQRT, 0x00000000u, 0x80400000u, 0xFC0u, 0xFD0u, 0x7FFFFFFFu, "rsqrt/seeded +0 / -denorm.mid"}, + {VURS_RSQRT, 0x80000000u, 0x80400000u, 0xFC0u, 0xFD0u, 0xFFFFFFFFu, "rsqrt/seeded -0 / -denorm.mid"}, + {VURS_RSQRT, 0x00000001u, 0x80400000u, 0xFC0u, 0xFD0u, 0x7FFFFFFFu, "rsqrt/seeded +denorm.min / -denorm.mid"}, + {VURS_RSQRT, 0x80000001u, 0x80400000u, 0xFC0u, 0xFD0u, 0xFFFFFFFFu, "rsqrt/seeded -denorm.min / -denorm.mid"}, + {VURS_RSQRT, 0x3F800000u, 0x80400000u, 0xFC0u, 0xFF0u, 0x7FFFFFFFu, "rsqrt/seeded +1 / -denorm.mid"}, + {VURS_RSQRT, 0xBF800000u, 0x80400000u, 0xFC0u, 0xFF0u, 0xFFFFFFFFu, "rsqrt/seeded -1 / -denorm.mid"}, + {VURS_RSQRT, 0x00000000u, 0x007FFFFFu, 0xFC0u, 0xFD0u, 0x7FFFFFFFu, "rsqrt/seeded +0 / +denorm.max"}, + {VURS_RSQRT, 0x80000000u, 0x007FFFFFu, 0xFC0u, 0xFD0u, 0xFFFFFFFFu, "rsqrt/seeded -0 / +denorm.max"}, + {VURS_RSQRT, 0x00000001u, 0x007FFFFFu, 0xFC0u, 0xFD0u, 0x7FFFFFFFu, "rsqrt/seeded +denorm.min / +denorm.max"}, + {VURS_RSQRT, 0x80000001u, 0x007FFFFFu, 0xFC0u, 0xFD0u, 0xFFFFFFFFu, "rsqrt/seeded -denorm.min / +denorm.max"}, + {VURS_RSQRT, 0x3F800000u, 0x007FFFFFu, 0xFC0u, 0xFE0u, 0x7FFFFFFFu, "rsqrt/seeded +1 / +denorm.max"}, + {VURS_RSQRT, 0xBF800000u, 0x007FFFFFu, 0xFC0u, 0xFE0u, 0xFFFFFFFFu, "rsqrt/seeded -1 / +denorm.max"}, + {VURS_RSQRT, 0x00000000u, 0x807FFFFFu, 0xFC0u, 0xFD0u, 0x7FFFFFFFu, "rsqrt/seeded +0 / -denorm.max"}, + {VURS_RSQRT, 0x80000000u, 0x807FFFFFu, 0xFC0u, 0xFD0u, 0xFFFFFFFFu, "rsqrt/seeded -0 / -denorm.max"}, + {VURS_RSQRT, 0x00000001u, 0x807FFFFFu, 0xFC0u, 0xFD0u, 0x7FFFFFFFu, "rsqrt/seeded +denorm.min / -denorm.max"}, + {VURS_RSQRT, 0x80000001u, 0x807FFFFFu, 0xFC0u, 0xFD0u, 0xFFFFFFFFu, "rsqrt/seeded -denorm.min / -denorm.max"}, + {VURS_RSQRT, 0x3F800000u, 0x807FFFFFu, 0xFC0u, 0xFF0u, 0x7FFFFFFFu, "rsqrt/seeded +1 / -denorm.max"}, + {VURS_RSQRT, 0xBF800000u, 0x807FFFFFu, 0xFC0u, 0xFF0u, 0xFFFFFFFFu, "rsqrt/seeded -1 / -denorm.max"}, + {VURS_RSQRT, 0x00000000u, 0x00800000u, 0xFC0u, 0xFC0u, 0x00000000u, "rsqrt/seeded +0 / +normal.min"}, + {VURS_RSQRT, 0x80000000u, 0x00800000u, 0xFC0u, 0xFC0u, 0x80000000u, "rsqrt/seeded -0 / +normal.min"}, + {VURS_RSQRT, 0x00000001u, 0x00800000u, 0xFC0u, 0xFC0u, 0x00000000u, "rsqrt/seeded +denorm.min / +normal.min"}, + {VURS_RSQRT, 0x80000001u, 0x00800000u, 0xFC0u, 0xFC0u, 0x80000000u, "rsqrt/seeded -denorm.min / +normal.min"}, + {VURS_RSQRT, 0x3F800000u, 0x00800000u, 0xFC0u, 0xFC0u, 0x5F000000u, "rsqrt/seeded +1 / +normal.min"}, + {VURS_RSQRT, 0xBF800000u, 0x00800000u, 0xFC0u, 0xFC0u, 0xDF000000u, "rsqrt/seeded -1 / +normal.min"}, + {VURS_RSQRT, 0x00000000u, 0x80800000u, 0xFC0u, 0xFD0u, 0x00000000u, "rsqrt/seeded +0 / -normal.min"}, + {VURS_RSQRT, 0x80000000u, 0x80800000u, 0xFC0u, 0xFD0u, 0x80000000u, "rsqrt/seeded -0 / -normal.min"}, + {VURS_RSQRT, 0x00000001u, 0x80800000u, 0xFC0u, 0xFD0u, 0x00000000u, "rsqrt/seeded +denorm.min / -normal.min"}, + {VURS_RSQRT, 0x80000001u, 0x80800000u, 0xFC0u, 0xFD0u, 0x80000000u, "rsqrt/seeded -denorm.min / -normal.min"}, + {VURS_RSQRT, 0x3F800000u, 0x80800000u, 0xFC0u, 0xFD0u, 0x5F000000u, "rsqrt/seeded +1 / -normal.min"}, + {VURS_RSQRT, 0xBF800000u, 0x80800000u, 0xFC0u, 0xFD0u, 0xDF000000u, "rsqrt/seeded -1 / -normal.min"}, + {VURS_RSQRT, 0x3F800000u, 0x80000000u, 0x000u, 0xC30u, 0x7FFFFFFFu, "rigcheck/rsqrt +1/-0 (repeat)"}, +}; + +} // namespace console_vurs diff --git a/tests/ctest/core/recompilers/vu_divunit_console_conformance_tests.cpp b/tests/ctest/core/recompilers/vu_divunit_console_conformance_tests.cpp new file mode 100644 index 0000000000..68f6b9fab2 --- /dev/null +++ b/tests/ctest/core/recompilers/vu_divunit_console_conformance_tests.cpp @@ -0,0 +1,267 @@ +// SPDX-FileCopyrightText: 2026 yaps2 Dev Team +// SPDX-License-Identifier: GPL-3.0+ + +// The VU div unit against a first-party console capture: VDIV, VSQRT and +// VRSQRT over zero, denormal, normal, exponent-255 and saturated operands, +// scoring STATUS and Q. 502 cases, table in autocases_vurs.h. +// +// The capture was taken in VU0 macro mode, where VU0's registers are +// EE-readable, so the macro engines are scored against it directly and the +// micro engines are scored on the D/I cause and sticky pair, which is the div +// unit's own output rather than the mode's bookkeeping. +// +// What it settles, and what it does not: +// +// STATUS. One rule fits all 502 rows. I comes from the operand's SIGN BIT +// for the two ops that contain a square root -- exponent field ignored, so +// -0 and the negative denormals raise it -- decided ahead of the zero test +// and independently of it. D comes from a zero divisor with a nonzero +// dividend; a zero dividend over a zero divisor raises I instead, and the +// two are exclusive. So VRSQRT over -0 is the one operand class where both +// causes stand together: the root's I and the division's D. +// +// VDIV is the control that says the sign clause belongs to the square root +// and not to the unit: a negative divisor raises nothing there. It is also +// where the two ops' quotient signs part company -- VDIV's saturated +// quotient takes the xor of the operand signs, VRSQRT's takes the dividend's +// alone, because its divisor is a square root and never negative. +// +// Q. Not settled, and not asserted row by row. PCSX2 saturates a binade low +// of the console (0x7F7FFFFF against 0x7FFFFFFF -- the VU clamp mode), and +// its DIV/SQRT/RSQRT go through a host divide rather than through the EE's +// divide-unit model in FPU.cpp. Both gaps are pinned here as exact tallies +// per engine so that neither can move unnoticed, and so that whoever ports +// eeDivide/eeSqrtBits to these call sites has a number to move. + +#include + +#include "harness/EeRecTestHarness.h" +#include "harness/MipsEncode.h" +#include "harness/RecompilerTestEnvironment.h" +#include "harness/VuEncode.h" +#include "harness/VuTestHarness.h" + +#include "VU.h" + +#include + +#include "autocases_vurs.h" + +using namespace console_vurs; + +namespace recompiler_tests +{ +namespace +{ +using namespace mips; +using namespace mips::ee; + +constexpr u32 kFs = 4, kFt = 5; +constexpr u32 kRSeed = 20, kRStatus = 8, kRQ = 9; + +// STATUS bits the div unit owns: the D/I cause pair and the two stickies they +// set. The ZSUO cause is the FMAC's and is zero throughout the capture. +constexpr u32 kDiMask = 0xC30u; + +u32 MacroOp(const VursCase& c) +{ + switch (c.op) + { + case VURS_DIV: return VDIV_C2(0, 0, kFs, kFt); + case VURS_SQRT: return VSQRT_C2(0, kFt); + default: return VRSQRT_C2(0, 0, kFs, kFt); + } +} + +void BuildMacro(EeRecTestHarness& h, const VursCase& c) +{ + h.EnableVu0Capture(); + h.SeedVu0VfBits(kFs, c.fs, c.fs, c.fs, c.fs); + h.SeedVu0VfBits(kFt, c.ft, c.ft, c.ft, c.ft); + h.LoadProgram(std::vector{ + ORI(kRSeed, 0, c.seed), + CTC2(kRSeed, REG_STATUS_FLAG), + MacroOp(c), + CFC2(kRStatus, REG_STATUS_FLAG), + CFC2(kRQ, REG_Q), + }); +} + +u32 MicroOp(const VursCase& c) +{ + switch (c.op) + { + case VURS_DIV: return vu::VDIV_L(kFs, 0, kFt, 0); + case VURS_SQRT: return vu::VSQRT_L(kFt, 0); + default: return vu::VRSQRT_L(kFs, 0, kFt, 0); + } +} + +// The div unit's flags reach STATUS up to 13 cycles downstream in micro mode +// (mVUanalyzeFDIV), so the program has to outrun that before either side can +// be read. Micro mode has no CTC2, so only the unseeded rows run here. +void BuildMicro(VuTestHarness& h, const VursCase& c) +{ + h.SetVfBits(kFs, c.fs, c.fs, c.fs, c.fs); + h.SetVfBits(kFt, c.ft, c.ft, c.ft, c.ft); + std::vector prog; + prog.push_back(vu::VuOp{MicroOp(c), vu::VNOP_U()}); + for (int i = 0; i < 16; ++i) + prog.push_back(vu::NopPair()); + prog.push_back(vu::VuOp{vu::VWAITQ_L(), vu::VNOP_U()}); + prog.push_back(vu::EBitNopPair()); + h.LoadProgram(prog); +} + +// Where an engine's Q lands relative to the console's. +struct QTally +{ + int ok = 0; // the console's word + int sat = 0; // the console saturated and the engine saturated a binade low + int unit = 0; // everything else: the divide unit's arithmetic +}; + +void ScoreQ(QTally& t, const VursCase& c, u32 got) +{ + if (got == c.q) + t.ok++; + else if ((c.q & 0x7FFFFFFFu) == 0x7FFFFFFFu && got == ((c.q & 0x80000000u) | 0x7F7FFFFFu)) + t.sat++; + else + t.unit++; +} +} // namespace + +TEST(VuDivUnitConsole, MacroStatusMatchesConsoleOnEveryRow) +{ + int checked = 0; + for (const VursCase& c : kVursCases) + { + SCOPED_TRACE(c.tag); + + EeRecTestHarness hj; + BuildMacro(hj, c); + hj.RunJitNoDiff(); + EXPECT_EQ(hj.GetGprJit(kRStatus) & 0xFFFu, c.status) << "[macro jit] STATUS"; + + EeRecTestHarness hi; + BuildMacro(hi, c); + hi.RunInterpOnly(); + EXPECT_EQ(hi.GetGprInterp(kRStatus) & 0xFFFu, c.status) << "[macro interp] STATUS"; + ++checked; + } + EXPECT_EQ(checked, static_cast(std::size(kVursCases))); +} + +TEST(VuDivUnitConsole, MicroCauseAndStickyMatchConsole) +{ + int checked = 0; + for (const VursCase& c : kVursCases) + { + if (c.seed != 0) + continue; + SCOPED_TRACE(c.tag); + + VuTestHarness m(0); + m.IgnoreViInDiff(REG_Q); // scored separately, and it diverges by class + BuildMicro(m, c); + m.Run(); // also diffs micro JIT against micro interp + EXPECT_EQ(m.GetViJit(REG_STATUS_FLAG) & kDiMask, c.status & kDiMask) + << "[micro jit] STATUS D/I"; + EXPECT_EQ(m.GetViInterp(REG_STATUS_FLAG) & kDiMask, c.status & kDiMask) + << "[micro interp] STATUS D/I"; + ++checked; + } + EXPECT_EQ(checked, 422); +} + +// The console's saturated quotient is the EE maximum 0x7FFFFFFF; PCSX2's is +// FLT_MAX, one binade lower. The sign is not part of that difference, so the +// class is defined with the sign carried over -- which is what makes it a +// statement about the clamp and not a place for a sign bug to hide. +TEST(VuDivUnitConsole, QSaturatesABinadeLowOfTheConsole) +{ + QTally mj, mi, uj, ui; + int consoleSaturated = 0; + for (const VursCase& c : kVursCases) + { + if ((c.q & 0x7FFFFFFFu) == 0x7FFFFFFFu) + ++consoleSaturated; + + EeRecTestHarness hj; + BuildMacro(hj, c); + hj.RunJitNoDiff(); + ScoreQ(mj, c, hj.GetGprJit(kRQ)); + + EeRecTestHarness hi; + BuildMacro(hi, c); + hi.RunInterpOnly(); + ScoreQ(mi, c, hi.GetGprInterp(kRQ)); + + if (c.seed != 0) + continue; + VuTestHarness m(0); + m.IgnoreViInDiff(REG_STATUS_FLAG); + m.IgnoreViInDiff(REG_Q); + BuildMicro(m, c); + m.Run(); + ScoreQ(uj, c, m.GetViJit(REG_Q)); + ScoreQ(ui, c, m.GetViInterp(REG_Q)); + } + + EXPECT_EQ(consoleSaturated, 226); + + // Two rows saturate on the console and come back from the emulator as + // something other than the sign-matched FLT_MAX; they fall in `unit` + // below rather than being counted as clamp-mode misses. + EXPECT_EQ(mj.sat, 224); + EXPECT_EQ(mi.sat, 226); + EXPECT_EQ(uj.sat, 176); + EXPECT_EQ(ui.sat, 178); + + // The arithmetic gap. The JIT is worse than the interpreter by 30 rows in + // each mode -- its clamp runs before anything else can look at the result. + EXPECT_EQ(mj.unit, 86); + EXPECT_EQ(mi.unit, 56); + EXPECT_EQ(uj.unit, 82); + EXPECT_EQ(ui.unit, 52); + + EXPECT_EQ(mj.ok, 192); + EXPECT_EQ(mi.ok, 220); + EXPECT_EQ(uj.ok, 164); + EXPECT_EQ(ui.ok, 192); + + EXPECT_EQ(mj.ok + mj.sat + mj.unit, static_cast(std::size(kVursCases))); + EXPECT_EQ(uj.ok + uj.sat + uj.unit, 422); +} + +// The two ops' saturated quotients take their sign by different rules, and the +// capture pins both. VDIV xors the operand signs; VRSQRT cannot, because its +// divisor is a square root. Stated on the smallest witnesses because the +// tallies above would still pass if the two rules were swapped. +TEST(VuDivUnitConsole, SaturatedQuotientSignsDifferBetweenDivAndRsqrt) +{ + int div = 0, rsqrt = 0; + for (const VursCase& c : kVursCases) + { + if ((c.q & 0x7FFFFFFFu) != 0x7FFFFFFFu || (c.ft & 0x7F800000u) != 0) + continue; + const u32 sign = c.q & 0x80000000u; + if (c.op == VURS_DIV) + { + EXPECT_EQ(sign, (c.fs ^ c.ft) & 0x80000000u) << c.tag; + ++div; + } + else if (c.op == VURS_RSQRT) + { + EXPECT_EQ(sign, c.fs & 0x80000000u) << c.tag; + ++rsqrt; + } + } + // 80 VDIV rows: the 8 zero-exponent divisors over all 10 dividends. 130 + // VRSQRT rows: the same 80, the seeded pass's 8 x 6, and the two rig-check + // repeats of the row the earlier capture already held. + EXPECT_EQ(div, 80); + EXPECT_EQ(rsqrt, 130); +} +} // namespace recompiler_tests diff --git a/tests/ctest/core/recompilers/vu_rsqrt_divisor_sign_tests.cpp b/tests/ctest/core/recompilers/vu_rsqrt_divisor_sign_tests.cpp new file mode 100644 index 0000000000..9e16e8dc70 --- /dev/null +++ b/tests/ctest/core/recompilers/vu_rsqrt_divisor_sign_tests.cpp @@ -0,0 +1,264 @@ +// SPDX-FileCopyrightText: 2026 yaps2 Dev Team +// SPDX-License-Identifier: GPL-3.0+ + +// The div unit's flag and quotient-sign rules on hand-picked witnesses, across +// `_vuRSQRT`/`_vuSQRT`, `recCOP2_VRSQRT`/`recCOP2_VSQRT` and +// `mVU_RSQRT`/`mVU_SQRT`. VuDivUnitConsole scores the same rules over a whole +// operand grid; this is the readable form, and it names which engine had each +// case wrong. +// +// Q's magnitude is the engines' 0x7F7FFFFF where the console gives 0x7FFFFFFF +// -- the VU clamp mode, left alone here as it is there. The sign is not part +// of that difference and is asserted against the console. + +#include + +#include "harness/EeRecTestHarness.h" +#include "harness/MipsEncode.h" +#include "harness/RecompilerTestEnvironment.h" +#include "harness/VuEncode.h" +#include "harness/VuTestHarness.h" + +#include "VU.h" + +#include + +namespace recompiler_tests +{ +namespace +{ +using namespace mips; +using namespace mips::ee; +using namespace vu; + +inline VuOp LowerOnly(u32 lower) { return VuOp{lower, VNOP_U()}; } +inline VuOp WaitQPair() { return VuOp{VWAITQ_L(), VNOP_U()}; } + +constexpr u32 kFs = 4, kFt = 5; +constexpr u32 kRStatus = 8, kRQ = 9; + +// Cause D|I (0x30) plus the sticky pair they set (0xC00). Everything outside +// this mask is the ZSUO cause, which no div-unit op touches. +constexpr u32 kDiMask = 0xC30u; +constexpr u32 kI = 0x410u; // cause I + sticky I +constexpr u32 kD = 0x820u; // cause D + sticky D + +struct Row +{ + const char* what; + u32 fs; + u32 ft; + u32 di; // expected STATUS & kDiMask + u32 q; +}; + +// Every row is checked on all four engines. 0/0 goes to its own test below. +constexpr Row kRows[] = { + // Under xor both quotients would come back with the opposite sign, so this + // pair alone refutes it. + {"+1 / -0", 0x3F800000u, 0x80000000u, kI | kD, 0x7F7FFFFFu}, + {"-1 / -0", 0xBF800000u, 0x80000000u, kI | kD, 0xFF7FFFFFu}, + + // Positive divisor, D alone: says the pair above moved for the sign bit + // and not because the whole zero branch changed. + {"+1 / +0", 0x3F800000u, 0x00000000u, kD, 0x7F7FFFFFu}, + {"-1 / +0", 0xBF800000u, 0x00000000u, kD, 0xFF7FFFFFu}, + + // Zero exponent, nonzero mantissa: the VU has no denormals, so this + // reaches the zero branch too. + {"+1 / -denorm", 0x3F800000u, 0x80000001u, kI | kD, 0x7F7FFFFFu}, + + // Nonzero divisors: the sign bit still decides I, and nothing raises D. + {"+1 / -4", 0x3F800000u, 0xC0800000u, kI, 0x3F000000u}, + {"-1 / -4", 0xBF800000u, 0xC0800000u, kI, 0xBF000000u}, + {"+1 / +4", 0x3F800000u, 0x40800000u, 0, 0x3F000000u}, +}; + +void BuildMacro(EeRecTestHarness& h, u32 fs, u32 ft) +{ + h.EnableVu0Capture(); + h.SeedVu0VfBits(kFs, fs, fs, fs, fs); + h.SeedVu0VfBits(kFt, ft, ft, ft, ft); + h.LoadProgram(std::vector{ + CTC2(0, REG_STATUS_FLAG), // clear the sticky field the prologue left + VRSQRT_C2(0, 0, kFs, kFt), + CFC2(kRStatus, REG_STATUS_FLAG), + CFC2(kRQ, REG_Q), + }); +} + +// The FDIV flag reaches STATUS 13 cycles after an RSQRT (mVUanalyzeFDIV), so +// the program has to run past that before the JIT side can be read. +void BuildMicro(VuTestHarness& h, u32 fs, u32 ft) +{ + h.SetVfBits(kFs, fs, fs, fs, fs); + h.SetVfBits(kFt, ft, ft, ft, ft); + std::vector prog; + prog.push_back(LowerOnly(VRSQRT_L(kFs, 0, kFt, 0))); + for (int i = 0; i < 16; ++i) + prog.push_back(NopPair()); + prog.push_back(WaitQPair()); + prog.push_back(EBitNopPair()); + h.LoadProgram(prog); +} +} // namespace + +// "+1 / -0" and "+1 / -denorm" were red on all three engines; the rest hold +// the surrounding behaviour still. +TEST(VuRsqrtDivisorSign, InvalidComesFromTheDivisorSignBitAlone) +{ + for (const Row& r : kRows) + { + SCOPED_TRACE(r.what); + + EeRecTestHarness hj; + BuildMacro(hj, r.fs, r.ft); + hj.RunJitNoDiff(); + EXPECT_EQ(hj.GetGprJit(kRStatus) & kDiMask, r.di) << "[macro jit] STATUS"; + + EeRecTestHarness hi; + BuildMacro(hi, r.fs, r.ft); + hi.RunInterpOnly(); + EXPECT_EQ(hi.GetGprInterp(kRStatus) & kDiMask, r.di) << "[macro interp] STATUS"; + + VuTestHarness m(0); + BuildMicro(m, r.fs, r.ft); + m.Run(); // also diffs micro JIT against micro interp + EXPECT_EQ(m.GetViJit(REG_STATUS_FLAG) & kDiMask, r.di) << "[micro jit] STATUS"; + EXPECT_EQ(m.GetViInterp(REG_STATUS_FLAG) & kDiMask, r.di) << "[micro interp] STATUS"; + } +} + +// Asserted as the whole word so the magnitude is held still too, then as the +// sign alone, which is the half the console can arbitrate. +TEST(VuRsqrtDivisorSign, QuotientSignIsTheDividendsAlone) +{ + for (const Row& r : kRows) + { + SCOPED_TRACE(r.what); + + EeRecTestHarness hj; + BuildMacro(hj, r.fs, r.ft); + hj.RunJitNoDiff(); + EXPECT_EQ(hj.GetGprJit(kRQ), r.q) << "[macro jit] Q"; + + EeRecTestHarness hi; + BuildMacro(hi, r.fs, r.ft); + hi.RunInterpOnly(); + EXPECT_EQ(hi.GetGprInterp(kRQ), r.q) << "[macro interp] Q"; + + VuTestHarness m(0); + BuildMicro(m, r.fs, r.ft); + m.Run(); + EXPECT_EQ(m.GetViJit(REG_Q), r.q) << "[micro jit] Q"; + EXPECT_EQ(m.GetViInterp(REG_Q), r.q) << "[micro interp] Q"; + + EXPECT_EQ(r.q & 0x80000000u, r.fs & 0x80000000u) << "quotient sign is the dividend's"; + } +} + +// The row autocases_vusticky.h already held before the div-unit grid existed: +// cause and sticky D|I together, and a positive quotient over a negative zero. +TEST(VuRsqrtDivisorSign, MatchesTheConsoleRowForOneOverNegativeZero) +{ + EeRecTestHarness h; + BuildMacro(h, 0x3F800000u, 0x80000000u); + h.RunJitNoDiff(); + EXPECT_EQ(h.GetGprJit(kRStatus) & kDiMask, 0xC30u); + EXPECT_EQ(h.GetGprJit(kRQ) & 0x80000000u, 0x00000000u); + EXPECT_EQ(0x7FFFFFFFu & 0x80000000u, h.GetGprJit(kRQ) & 0x80000000u) + << "console returned 0x7FFFFFFF; the magnitude is the VU clamp mode, the sign is not"; +} + +// Three of the four engines used to raise both causes here and return ±0. +TEST(VuRsqrtDivisorSign, ZeroOverZeroRaisesInvalidWithoutDivideByZero) +{ + struct { const char* what; u32 fs; u32 ft; u32 q; } rows[] = { + {"+0 / +0", 0x00000000u, 0x00000000u, 0x7F7FFFFFu}, + {"+0 / -0", 0x00000000u, 0x80000000u, 0x7F7FFFFFu}, + {"-0 / +0", 0x80000000u, 0x00000000u, 0xFF7FFFFFu}, + {"-0 / -0", 0x80000000u, 0x80000000u, 0xFF7FFFFFu}, + }; + + for (const auto& r : rows) + { + SCOPED_TRACE(r.what); + + EeRecTestHarness hj; + BuildMacro(hj, r.fs, r.ft); + hj.RunJitNoDiff(); + EXPECT_EQ(hj.GetGprJit(kRStatus) & kDiMask, kI) << "[macro jit] STATUS"; + EXPECT_EQ(hj.GetGprJit(kRQ), r.q) << "[macro jit] Q"; + + EeRecTestHarness hi; + BuildMacro(hi, r.fs, r.ft); + hi.RunInterpOnly(); + EXPECT_EQ(hi.GetGprInterp(kRStatus) & kDiMask, kI) << "[macro interp] STATUS"; + EXPECT_EQ(hi.GetGprInterp(kRQ), r.q) << "[macro interp] Q"; + + VuTestHarness m(0); + BuildMicro(m, r.fs, r.ft); + m.Run(); + EXPECT_EQ(m.GetViJit(REG_STATUS_FLAG) & kDiMask, kI) << "[micro jit] STATUS"; + EXPECT_EQ(m.GetViJit(REG_Q), r.q) << "[micro jit] Q"; + EXPECT_EQ(m.GetViInterp(REG_STATUS_FLAG) & kDiMask, kI) << "[micro interp] STATUS"; + EXPECT_EQ(m.GetViInterp(REG_Q), r.q) << "[micro interp] Q"; + } +} + +// VSQRT shared the defect: only mVU_SQRT tested the sign bit, so the other +// three lost I on -0 and on the denormals vuDouble flushes to it. +TEST(VuRsqrtDivisorSign, SqrtInvalidComesFromTheSignBitToo) +{ + struct { const char* what; u32 ft; u32 di; } rows[] = { + {"sqrt -0", 0x80000000u, kI}, + {"sqrt -denorm.min", 0x80000001u, kI}, + {"sqrt -denorm.max", 0x807FFFFFu, kI}, + {"sqrt +0", 0x00000000u, 0}, + {"sqrt +denorm.max", 0x007FFFFFu, 0}, + {"sqrt -4", 0xC0800000u, kI}, + {"sqrt +4", 0x40800000u, 0}, + }; + + for (const auto& r : rows) + { + SCOPED_TRACE(r.what); + + EeRecTestHarness hj; + hj.EnableVu0Capture(); + hj.SeedVu0VfBits(kFt, r.ft, r.ft, r.ft, r.ft); + hj.LoadProgram(std::vector{ + CTC2(0, REG_STATUS_FLAG), + VSQRT_C2(0, kFt), + CFC2(kRStatus, REG_STATUS_FLAG), + }); + hj.RunJitNoDiff(); + EXPECT_EQ(hj.GetGprJit(kRStatus) & kDiMask, r.di) << "[macro jit] STATUS"; + + EeRecTestHarness hi; + hi.EnableVu0Capture(); + hi.SeedVu0VfBits(kFt, r.ft, r.ft, r.ft, r.ft); + hi.LoadProgram(std::vector{ + CTC2(0, REG_STATUS_FLAG), + VSQRT_C2(0, kFt), + CFC2(kRStatus, REG_STATUS_FLAG), + }); + hi.RunInterpOnly(); + EXPECT_EQ(hi.GetGprInterp(kRStatus) & kDiMask, r.di) << "[macro interp] STATUS"; + + VuTestHarness m(0); + m.SetVfBits(kFt, r.ft, r.ft, r.ft, r.ft); + std::vector prog; + prog.push_back(LowerOnly(VSQRT_L(kFt, 0))); + for (int i = 0; i < 16; ++i) + prog.push_back(NopPair()); + prog.push_back(WaitQPair()); + prog.push_back(EBitNopPair()); + m.LoadProgram(prog); + m.Run(); + EXPECT_EQ(m.GetViJit(REG_STATUS_FLAG) & kDiMask, r.di) << "[micro jit] STATUS"; + EXPECT_EQ(m.GetViInterp(REG_STATUS_FLAG) & kDiMask, r.di) << "[micro interp] STATUS"; + } +} +} // namespace recompiler_tests +