fp_min_max.cpp 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186
  1. /* This file is part of the dynarmic project.
  2. * Copyright (c) 2022 MerryMage
  3. * SPDX-License-Identifier: 0BSD
  4. */
  5. #include <vector>
  6. #include <catch2/catch_test_macros.hpp>
  7. #include <mcl/stdint.hpp>
  8. #include "./testenv.h"
  9. using namespace Dynarmic;
  10. namespace {
  11. struct TestCase {
  12. u32 a;
  13. u32 b;
  14. u32 fmax;
  15. u32 fmaxnm;
  16. u32 fmin;
  17. u32 fminnm;
  18. };
  19. const std::vector test_cases{
  20. // a b fmax fmaxnm fmin fminnm
  21. TestCase{0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, // +0.0
  22. TestCase{0x80000000, 0x80000000, 0x80000000, 0x80000000, 0x80000000, 0x80000000}, // -0.0
  23. TestCase{0x3f800000, 0x3f800000, 0x3f800000, 0x3f800000, 0x3f800000, 0x3f800000}, // +1.0
  24. TestCase{0xbf800000, 0xbf800000, 0xbf800000, 0xbf800000, 0xbf800000, 0xbf800000}, // -1.0
  25. TestCase{0x7f800000, 0x7f800000, 0x7f800000, 0x7f800000, 0x7f800000, 0x7f800000}, // +Inf
  26. TestCase{0xff800000, 0xff800000, 0xff800000, 0xff800000, 0xff800000, 0xff800000}, // -Inf
  27. TestCase{0x7fc00041, 0x7fc00041, 0x7fc00041, 0x7fc00041, 0x7fc00041, 0x7fc00041}, // QNaN
  28. TestCase{0x7f800042, 0x7f800042, 0x7fc00042, 0x7fc00042, 0x7fc00042, 0x7fc00042}, // SNaN
  29. TestCase{0x00000000, 0x80000000, 0x00000000, 0x00000000, 0x80000000, 0x80000000}, // (+0.0, -0.0)
  30. TestCase{0x3f800000, 0xbf800000, 0x3f800000, 0x3f800000, 0xbf800000, 0xbf800000}, // (+1.0, -1.0)
  31. TestCase{0x3f800000, 0x7f800000, 0x7f800000, 0x7f800000, 0x3f800000, 0x3f800000}, // (+1.0, +Inf)
  32. TestCase{0x3f800000, 0xff800000, 0x3f800000, 0x3f800000, 0xff800000, 0xff800000}, // (+1.0, -Inf)
  33. TestCase{0x7f800000, 0xff800000, 0x7f800000, 0x7f800000, 0xff800000, 0xff800000}, // (+Inf, -Inf)
  34. TestCase{0x3f800000, 0x7fc00041, 0x7fc00041, 0x3f800000, 0x7fc00041, 0x3f800000}, // (+1.0, QNaN)
  35. TestCase{0x3f800000, 0x7f800042, 0x7fc00042, 0x7fc00042, 0x7fc00042, 0x7fc00042}, // (+1.0, SNaN)
  36. TestCase{0x7f800000, 0x7fc00041, 0x7fc00041, 0x7f800000, 0x7fc00041, 0x7f800000}, // (+Inf, QNaN)
  37. TestCase{0x7f800000, 0x7f800042, 0x7fc00042, 0x7fc00042, 0x7fc00042, 0x7fc00042}, // (+Inf, SNaN)
  38. TestCase{0x7fc00041, 0x7f800042, 0x7fc00042, 0x7fc00042, 0x7fc00042, 0x7fc00042}, // (QNaN, SNaN)
  39. TestCase{0xffa57454, 0xe343a6b3, 0xffe57454, 0xffe57454, 0xffe57454, 0xffe57454},
  40. };
  41. const std::vector unidirectional_test_cases{
  42. TestCase{0x7fc00041, 0x7fc00043, 0x7fc00041, 0x7fc00041, 0x7fc00041, 0x7fc00041}, // (QNaN, QNaN)
  43. TestCase{0x7f800042, 0x7f800044, 0x7fc00042, 0x7fc00042, 0x7fc00042, 0x7fc00042}, // (SNaN, SNaN)
  44. };
  45. constexpr u32 default_nan = 0x7fc00000;
  46. bool is_nan(u32 value) {
  47. return (value & 0x7f800000) == 0x7f800000 && (value & 0x007fffff) != 0;
  48. }
  49. u32 force_default_nan(u32 value) {
  50. return is_nan(value) ? default_nan : value;
  51. }
  52. template<typename Fn>
  53. void run_test(u32 instruction, Fn fn) {
  54. A64TestEnv env;
  55. A64::Jit jit{A64::UserConfig{&env}};
  56. env.code_mem.emplace_back(instruction); // FMAX S0, S1, S2
  57. env.code_mem.emplace_back(0x14000000); // B .
  58. for (const auto base_fpcr : {0, 0x01000000}) {
  59. for (const auto test_case : test_cases) {
  60. INFO(test_case.a);
  61. INFO(test_case.b);
  62. jit.SetFpcr(base_fpcr);
  63. jit.SetVector(0, {42, 0});
  64. jit.SetVector(1, {test_case.a, 0});
  65. jit.SetVector(2, {test_case.b, 0});
  66. jit.SetPC(0);
  67. env.ticks_left = 2;
  68. jit.Run();
  69. REQUIRE(jit.GetVector(0)[0] == fn(test_case));
  70. jit.SetVector(0, {42, 0});
  71. jit.SetVector(1, {test_case.b, 0});
  72. jit.SetVector(2, {test_case.a, 0});
  73. jit.SetPC(0);
  74. env.ticks_left = 2;
  75. jit.Run();
  76. REQUIRE(jit.GetVector(0)[0] == fn(test_case));
  77. jit.SetFpcr(base_fpcr | 0x02000000);
  78. jit.SetVector(0, {42, 0});
  79. jit.SetVector(1, {test_case.a, 0});
  80. jit.SetVector(2, {test_case.b, 0});
  81. jit.SetPC(0);
  82. env.ticks_left = 2;
  83. jit.Run();
  84. REQUIRE(jit.GetVector(0)[0] == force_default_nan(fn(test_case)));
  85. jit.SetVector(0, {42, 0});
  86. jit.SetVector(1, {test_case.b, 0});
  87. jit.SetVector(2, {test_case.a, 0});
  88. jit.SetPC(0);
  89. env.ticks_left = 2;
  90. jit.Run();
  91. REQUIRE(jit.GetVector(0)[0] == force_default_nan(fn(test_case)));
  92. }
  93. for (const auto test_case : unidirectional_test_cases) {
  94. INFO(test_case.a);
  95. INFO(test_case.b);
  96. jit.SetFpcr(base_fpcr);
  97. jit.SetVector(0, {42, 0});
  98. jit.SetVector(1, {test_case.a, 0});
  99. jit.SetVector(2, {test_case.b, 0});
  100. jit.SetPC(0);
  101. env.ticks_left = 2;
  102. jit.Run();
  103. REQUIRE(jit.GetVector(0)[0] == fn(test_case));
  104. jit.SetFpcr(base_fpcr | 0x02000000);
  105. jit.SetVector(0, {42, 0});
  106. jit.SetVector(1, {test_case.a, 0});
  107. jit.SetVector(2, {test_case.b, 0});
  108. jit.SetPC(0);
  109. env.ticks_left = 2;
  110. jit.Run();
  111. REQUIRE(jit.GetVector(0)[0] == force_default_nan(fn(test_case)));
  112. }
  113. }
  114. }
  115. } // namespace
  116. TEST_CASE("A64: FMAX (scalar)", "[a64]") {
  117. run_test(0x1e224820, [](const TestCase& test_case) { return test_case.fmax; });
  118. }
  119. TEST_CASE("A64: FMIN (scalar)", "[a64]") {
  120. run_test(0x1e225820, [](const TestCase& test_case) { return test_case.fmin; });
  121. }
  122. TEST_CASE("A64: FMAXNM (scalar)", "[a64]") {
  123. run_test(0x1e226820, [](const TestCase& test_case) { return test_case.fmaxnm; });
  124. }
  125. TEST_CASE("A64: FMINNM (scalar)", "[a64]") {
  126. run_test(0x1e227820, [](const TestCase& test_case) { return test_case.fminnm; });
  127. }
  128. TEST_CASE("A64: FMAX (vector)", "[a64]") {
  129. run_test(0x4e22f420, [](const TestCase& test_case) { return test_case.fmax; });
  130. }
  131. TEST_CASE("A64: FMIN (vector)", "[a64]") {
  132. run_test(0x4ea2f420, [](const TestCase& test_case) { return test_case.fmin; });
  133. }
  134. TEST_CASE("A64: FMAXNM (vector)", "[a64]") {
  135. run_test(0x4e22c420, [](const TestCase& test_case) { return test_case.fmaxnm; });
  136. }
  137. TEST_CASE("A64: FMINNM (vector)", "[a64]") {
  138. run_test(0x4ea2c420, [](const TestCase& test_case) { return test_case.fminnm; });
  139. }