mirror of
https://github.com/open-goal/jak-project.git
synced 2024-10-20 21:27:52 -04:00
e9567a6e4b
* Cleanup goalc tests, fix jak2 kernel bugs * fix warnings on linux * spelling is hard
585 lines
22 KiB
C++
585 lines
22 KiB
C++
#include <regex>
|
|
#include <stdexcept>
|
|
#include <string>
|
|
#include <thread>
|
|
|
|
#include "inja.hpp"
|
|
|
|
#include "goalc/compiler/Compiler.h"
|
|
#include "gtest/gtest.h"
|
|
#include "test/goalc/framework/test_runner.h"
|
|
|
|
#include "third-party/fmt/core.h"
|
|
#include "third-party/json.hpp"
|
|
|
|
class WithMinimalGameTests : public ::testing::Test {
|
|
public:
|
|
static void SetUpTestSuite() {
|
|
shared_compiler = std::make_unique<SharedCompiler>(GameVersion::Jak1);
|
|
try {
|
|
shared_compiler->compiler.run_front_end_on_string("(build-kernel)");
|
|
} catch (std::exception& e) {
|
|
fprintf(stderr, "caught exception %s\n", e.what());
|
|
EXPECT_TRUE(false);
|
|
}
|
|
shared_compiler->runtime_thread = std::thread(GoalTest::runtime_with_kernel_jak1);
|
|
shared_compiler->runner.c = &shared_compiler->compiler;
|
|
|
|
shared_compiler->compiler.run_test_from_string(
|
|
"(dgo-load \"kernel\" global (link-flag output-load-msg output-load-true-msg execute-login "
|
|
"print-login) #x200000)");
|
|
|
|
const auto minimal_files = {"goal_src/jak1/engine/math/vector-h.gc"};
|
|
for (auto& file : minimal_files) {
|
|
shared_compiler->compiler.run_test_from_string(fmt::format("(ml \"{}\")", file));
|
|
}
|
|
|
|
shared_compiler->compiler.run_test_from_string("(set! *use-old-listener-print* #t)");
|
|
}
|
|
|
|
static void TearDownTestSuite() {
|
|
shared_compiler->compiler.shutdown_target();
|
|
shared_compiler->runtime_thread.join();
|
|
shared_compiler.reset();
|
|
}
|
|
|
|
void SetUp() {
|
|
GoalTest::createDirIfAbsent(GoalTest::getTemplateDir(testCategory));
|
|
GoalTest::createDirIfAbsent(GoalTest::getGeneratedDir(testCategory));
|
|
}
|
|
|
|
void TearDown() {}
|
|
|
|
struct SharedCompiler {
|
|
SharedCompiler(GameVersion v) : compiler(v) {}
|
|
std::thread runtime_thread;
|
|
Compiler compiler;
|
|
GoalTest::CompilerTestRunner runner;
|
|
};
|
|
|
|
static std::unique_ptr<SharedCompiler> shared_compiler;
|
|
|
|
std::string testCategory = "with_game";
|
|
inja::Environment env{GoalTest::getTemplateDir(testCategory),
|
|
GoalTest::getGeneratedDir(testCategory)};
|
|
};
|
|
|
|
std::unique_ptr<WithMinimalGameTests::SharedCompiler> WithMinimalGameTests::shared_compiler;
|
|
|
|
struct VectorFloatRegister {
|
|
float x = 0;
|
|
float y = 0;
|
|
float z = 0;
|
|
float w = 0;
|
|
|
|
void setJson(nlohmann::json& data, std::string vectorKey) {
|
|
data[fmt::format("{}x", vectorKey)] = x;
|
|
data[fmt::format("{}y", vectorKey)] = y;
|
|
data[fmt::format("{}z", vectorKey)] = z;
|
|
data[fmt::format("{}w", vectorKey)] = w;
|
|
}
|
|
|
|
float getBroadcastElement(emitter::Register::VF_ELEMENT bc, float defValue) {
|
|
switch (bc) {
|
|
case emitter::Register::VF_ELEMENT::X:
|
|
return x;
|
|
case emitter::Register::VF_ELEMENT::Y:
|
|
return y;
|
|
case emitter::Register::VF_ELEMENT::Z:
|
|
return z;
|
|
case emitter::Register::VF_ELEMENT::W:
|
|
return w;
|
|
default:
|
|
return defValue;
|
|
}
|
|
}
|
|
|
|
std::string toGOALFormat() {
|
|
std::string answer = fmt::format("({:.4f}, {:.4f}, {:.4f}, {:.4f})", x, y, z, w);
|
|
// {fmt} formats negative 0 as "-0.000", just going to flip any negative zeros to positives as I
|
|
// don't think is an OpenGOAL issue
|
|
// Additionally, GOAL doesn't have -/+ Inf it seems, so replace with NaN. -nan is also just NaN
|
|
return std::regex_replace(std::regex_replace(answer, std::regex("-0.0000"), "0.0000"),
|
|
std::regex("nan|inf|-nan|-inf"), "NaN");
|
|
}
|
|
|
|
std::string toGOALFormat(float) {
|
|
std::string answer = fmt::format("{:.4f}", x);
|
|
// {fmt} formats negative 0 as "-0.000", just going to flip any negative zeros to positives as I
|
|
// don't think is an OpenGOAL issue
|
|
// Additionally, GOAL doesn't have -/+ Inf it seems, so replace with NaN
|
|
return std::regex_replace(std::regex_replace(answer, std::regex("-0.0000"), "0.0000"),
|
|
std::regex("nan|inf|-nan|-inf"), "NaN");
|
|
}
|
|
};
|
|
|
|
struct VectorFloatTestCase {
|
|
VectorFloatRegister dest = {11, 22, 33, 44};
|
|
int destinationMask = -1;
|
|
emitter::Register::VF_ELEMENT bc = emitter::Register::VF_ELEMENT::NONE;
|
|
|
|
std::string getOperationBroadcast() {
|
|
switch (bc) {
|
|
case emitter::Register::VF_ELEMENT::X:
|
|
return ".x";
|
|
case emitter::Register::VF_ELEMENT::Y:
|
|
return ".y";
|
|
case emitter::Register::VF_ELEMENT::Z:
|
|
return ".z";
|
|
case emitter::Register::VF_ELEMENT::W:
|
|
return ".w";
|
|
default:
|
|
return "";
|
|
}
|
|
}
|
|
|
|
virtual VectorFloatRegister getExpectedResult() = 0;
|
|
virtual void setJson(nlohmann::json& data, std::string func) = 0;
|
|
|
|
virtual ~VectorFloatTestCase() = default;
|
|
};
|
|
|
|
struct VectorFloatTestCase_TwoOperand : VectorFloatTestCase {
|
|
VectorFloatRegister input1 = {1.5, -1.5, 0.0, 100.5};
|
|
VectorFloatRegister input2 = {-5.5, -0.0, 10.0, 7.5};
|
|
|
|
std::function<float(float, float)> operation;
|
|
|
|
VectorFloatRegister getExpectedResult() {
|
|
VectorFloatRegister expectedResult;
|
|
expectedResult.x = destinationMask & 0b0001
|
|
? operation(input1.x, input2.getBroadcastElement(bc, input2.x))
|
|
: dest.x;
|
|
expectedResult.y = destinationMask & 0b0010
|
|
? operation(input1.y, input2.getBroadcastElement(bc, input2.y))
|
|
: dest.y;
|
|
expectedResult.z = destinationMask & 0b0100
|
|
? operation(input1.z, input2.getBroadcastElement(bc, input2.z))
|
|
: dest.z;
|
|
expectedResult.w = destinationMask & 0b1000
|
|
? operation(input1.w, input2.getBroadcastElement(bc, input2.w))
|
|
: dest.w;
|
|
return expectedResult;
|
|
}
|
|
|
|
void setJson(nlohmann::json& data, std::string func) {
|
|
input1.setJson(data, "v1");
|
|
input2.setJson(data, "v2");
|
|
dest.setJson(data, "dest");
|
|
data["operation"] = fmt::format(func);
|
|
if (destinationMask == -1) {
|
|
data["destinationMask"] = false;
|
|
} else {
|
|
data["destinationMask"] = fmt::format("{:b}", destinationMask);
|
|
}
|
|
}
|
|
};
|
|
|
|
std::vector<VectorFloatTestCase_TwoOperand> vectorMathCaseGen_TwoOperand() {
|
|
std::vector<VectorFloatTestCase_TwoOperand> cases = {};
|
|
for (int i = 0; i <= 15; i++) {
|
|
VectorFloatTestCase_TwoOperand testCase = VectorFloatTestCase_TwoOperand();
|
|
testCase.destinationMask = i;
|
|
cases.push_back(testCase);
|
|
// Re-add each case with each broadcast variant
|
|
for (int j = 0; j < 4; j++) {
|
|
VectorFloatTestCase_TwoOperand testCaseBC = VectorFloatTestCase_TwoOperand();
|
|
testCaseBC.destinationMask = i;
|
|
testCaseBC.bc = static_cast<emitter::Register::VF_ELEMENT>(j);
|
|
cases.push_back(testCaseBC);
|
|
}
|
|
}
|
|
return cases;
|
|
}
|
|
|
|
class VectorFloatParameterizedTestFixtureWithRunner_TwoOperand
|
|
: public WithMinimalGameTests,
|
|
public ::testing::WithParamInterface<VectorFloatTestCase_TwoOperand> {
|
|
protected:
|
|
std::string templateFile = "test-vector-math-2-operand.template.gc";
|
|
};
|
|
|
|
// NOTE - an excellent article -
|
|
// https://www.sandordargo.com/blog/2019/04/24/parameterized-testing-with-gtest
|
|
|
|
// --- 2 Operand VF Operations
|
|
|
|
TEST_P(VectorFloatParameterizedTestFixtureWithRunner_TwoOperand, VF_ADD_XYZW_DEST) {
|
|
VectorFloatTestCase_TwoOperand testCase = GetParam();
|
|
testCase.operation = [](float x, float y) { return x + y; };
|
|
|
|
nlohmann::json data;
|
|
testCase.setJson(data, fmt::format(".add{}.vf", testCase.getOperationBroadcast()));
|
|
|
|
std::string outFile = shared_compiler->runner.test_file_name(
|
|
fmt::format("vector-math-add{}-{{}}.generated.gc", testCase.getOperationBroadcast()));
|
|
env.write(templateFile, data, outFile);
|
|
shared_compiler->runner.run_test(
|
|
testCategory, outFile, {fmt::format("{}\n0\n", testCase.getExpectedResult().toGOALFormat())});
|
|
}
|
|
|
|
TEST_P(VectorFloatParameterizedTestFixtureWithRunner_TwoOperand, VF_SUB_XYZW_DEST) {
|
|
VectorFloatTestCase_TwoOperand testCase = GetParam();
|
|
testCase.operation = [](float x, float y) { return x - y; };
|
|
|
|
nlohmann::json data;
|
|
testCase.setJson(data, fmt::format(".sub{}.vf", testCase.getOperationBroadcast()));
|
|
|
|
std::string outFile = shared_compiler->runner.test_file_name(
|
|
fmt::format("vector-math-sub{}-{{}}.generated.gc", testCase.getOperationBroadcast()));
|
|
env.write(templateFile, data, outFile);
|
|
shared_compiler->runner.run_test(
|
|
testCategory, outFile, {fmt::format("{}\n0\n", testCase.getExpectedResult().toGOALFormat())});
|
|
}
|
|
|
|
TEST_P(VectorFloatParameterizedTestFixtureWithRunner_TwoOperand, VF_MUL_XYZW_DEST) {
|
|
VectorFloatTestCase_TwoOperand testCase = GetParam();
|
|
testCase.operation = [](float x, float y) { return x * y; };
|
|
|
|
nlohmann::json data;
|
|
testCase.setJson(data, fmt::format(".mul{}.vf", testCase.getOperationBroadcast()));
|
|
|
|
std::string outFile = shared_compiler->runner.test_file_name(
|
|
fmt::format("vector-math-mul{}-{{}}.generated.gc", testCase.getOperationBroadcast()));
|
|
env.write(templateFile, data, outFile);
|
|
shared_compiler->runner.run_test(
|
|
testCategory, outFile, {fmt::format("{}\n0\n", testCase.getExpectedResult().toGOALFormat())});
|
|
}
|
|
|
|
TEST_P(VectorFloatParameterizedTestFixtureWithRunner_TwoOperand, VF_MIN_XYZW_DEST) {
|
|
VectorFloatTestCase_TwoOperand testCase = GetParam();
|
|
testCase.operation = [](float x, float y) { return fmin(x, y); };
|
|
|
|
nlohmann::json data;
|
|
testCase.setJson(data, fmt::format(".min{}.vf", testCase.getOperationBroadcast()));
|
|
|
|
std::string outFile = shared_compiler->runner.test_file_name(
|
|
fmt::format("vector-math-min{}-{{}}.generated.gc", testCase.getOperationBroadcast()));
|
|
env.write(templateFile, data, outFile);
|
|
shared_compiler->runner.run_test(
|
|
testCategory, outFile, {fmt::format("{}\n0\n", testCase.getExpectedResult().toGOALFormat())});
|
|
}
|
|
|
|
TEST_P(VectorFloatParameterizedTestFixtureWithRunner_TwoOperand, VF_MAX_XYZW_DEST) {
|
|
VectorFloatTestCase_TwoOperand testCase = GetParam();
|
|
testCase.operation = [](float x, float y) { return fmax(x, y); };
|
|
|
|
nlohmann::json data;
|
|
testCase.setJson(data, fmt::format(".max{}.vf", testCase.getOperationBroadcast()));
|
|
|
|
std::string outFile = shared_compiler->runner.test_file_name(
|
|
fmt::format("vector-math-max{}-{{}}.generated.gc", testCase.getOperationBroadcast()));
|
|
env.write(templateFile, data, outFile);
|
|
shared_compiler->runner.run_test(
|
|
testCategory, outFile, {fmt::format("{}\n0\n", testCase.getExpectedResult().toGOALFormat())});
|
|
}
|
|
|
|
INSTANTIATE_TEST_SUITE_P(WithGameTests_VectorFloatTests,
|
|
VectorFloatParameterizedTestFixtureWithRunner_TwoOperand,
|
|
::testing::ValuesIn(vectorMathCaseGen_TwoOperand()));
|
|
|
|
// --- 1 Operand VF Operations
|
|
|
|
struct VectorFloatTestCase_SingleOperand : VectorFloatTestCase {
|
|
VectorFloatRegister input1 = {1.5, -1.5, 0.0, 100.5};
|
|
|
|
std::function<float(float)> operation;
|
|
|
|
VectorFloatRegister getExpectedResult() {
|
|
VectorFloatRegister expectedResult;
|
|
expectedResult.x =
|
|
destinationMask & 0b0001 ? operation(input1.getBroadcastElement(bc, input1.x)) : dest.x;
|
|
expectedResult.y =
|
|
destinationMask & 0b0010 ? operation(input1.getBroadcastElement(bc, input1.y)) : dest.y;
|
|
expectedResult.z =
|
|
destinationMask & 0b0100 ? operation(input1.getBroadcastElement(bc, input1.z)) : dest.z;
|
|
expectedResult.w =
|
|
destinationMask & 0b1000 ? operation(input1.getBroadcastElement(bc, input1.w)) : dest.w;
|
|
return expectedResult;
|
|
}
|
|
|
|
void setJson(nlohmann::json& data, std::string func) {
|
|
input1.setJson(data, "v1");
|
|
dest.setJson(data, "dest");
|
|
data["operation"] = fmt::format(func);
|
|
if (destinationMask == -1) {
|
|
data["destinationMask"] = false;
|
|
} else {
|
|
data["destinationMask"] = fmt::format("{:b}", destinationMask);
|
|
}
|
|
}
|
|
};
|
|
|
|
std::vector<VectorFloatTestCase_SingleOperand> vectorMathCaseGen_SingleOperand_NoBroadcast() {
|
|
std::vector<VectorFloatTestCase_SingleOperand> cases = {};
|
|
for (int i = 0; i <= 15; i++) {
|
|
VectorFloatTestCase_SingleOperand testCase = VectorFloatTestCase_SingleOperand();
|
|
testCase.destinationMask = i;
|
|
cases.push_back(testCase);
|
|
}
|
|
return cases;
|
|
}
|
|
|
|
class VectorFloatParameterizedTestFixtureWithRunner_SingleOperand
|
|
: public WithMinimalGameTests,
|
|
public ::testing::WithParamInterface<VectorFloatTestCase_SingleOperand> {
|
|
protected:
|
|
std::string templateFile = "test-vector-math-1-operand.template.gc";
|
|
};
|
|
|
|
TEST_P(VectorFloatParameterizedTestFixtureWithRunner_SingleOperand, VF_ABS_DEST) {
|
|
VectorFloatTestCase_SingleOperand testCase = GetParam();
|
|
testCase.operation = [](float x) { return fabs(x); };
|
|
|
|
nlohmann::json data;
|
|
testCase.setJson(data, ".abs.vf");
|
|
|
|
std::string outFile = shared_compiler->runner.test_file_name("vector-math-abs-{}.generated.gc");
|
|
env.write(templateFile, data, outFile);
|
|
shared_compiler->runner.run_test(
|
|
testCategory, outFile, {fmt::format("{}\n0\n", testCase.getExpectedResult().toGOALFormat())});
|
|
}
|
|
|
|
INSTANTIATE_TEST_SUITE_P(WithGameTests_VectorFloatTests,
|
|
VectorFloatParameterizedTestFixtureWithRunner_SingleOperand,
|
|
::testing::ValuesIn(vectorMathCaseGen_SingleOperand_NoBroadcast()));
|
|
|
|
// --- 2 Operand With ACC VF Operations
|
|
// TODO - these pollute tests, it would be nicer long-term to move these into the framework
|
|
// namespace
|
|
|
|
struct VectorFloatTestCase_TwoOperandACC : VectorFloatTestCase {
|
|
VectorFloatRegister input1 = {1.5, -1.5, 0.0, 100.5};
|
|
VectorFloatRegister input2 = {-5.5, -0.0, 10.0, 7.5};
|
|
VectorFloatRegister acc = {-15.5, -0.0, 20.0, 70.5};
|
|
|
|
std::function<float(float, float, float)> operation;
|
|
|
|
VectorFloatRegister getExpectedResult() {
|
|
VectorFloatRegister expectedResult;
|
|
expectedResult.x = destinationMask & 0b0001
|
|
? operation(input1.x, input2.getBroadcastElement(bc, input2.x), acc.x)
|
|
: dest.x;
|
|
expectedResult.y = destinationMask & 0b0010
|
|
? operation(input1.y, input2.getBroadcastElement(bc, input2.y), acc.y)
|
|
: dest.y;
|
|
expectedResult.z = destinationMask & 0b0100
|
|
? operation(input1.z, input2.getBroadcastElement(bc, input2.z), acc.z)
|
|
: dest.z;
|
|
expectedResult.w = destinationMask & 0b1000
|
|
? operation(input1.w, input2.getBroadcastElement(bc, input2.w), acc.w)
|
|
: dest.w;
|
|
return expectedResult;
|
|
}
|
|
|
|
void setJson(nlohmann::json& data, std::string func) {
|
|
input1.setJson(data, "v1");
|
|
input2.setJson(data, "v2");
|
|
acc.setJson(data, "acc");
|
|
dest.setJson(data, "dest");
|
|
data["operation"] = fmt::format(func);
|
|
if (destinationMask == -1) {
|
|
data["destinationMask"] = false;
|
|
} else {
|
|
data["destinationMask"] = fmt::format("{:b}", destinationMask);
|
|
}
|
|
}
|
|
};
|
|
|
|
// TODO - unnecessary duplication for these generation methods, use some templates (only the type
|
|
// changes)
|
|
std::vector<VectorFloatTestCase_TwoOperandACC> vectorMathCaseGen_TwoOperandACC() {
|
|
std::vector<VectorFloatTestCase_TwoOperandACC> cases = {};
|
|
for (int i = 0; i <= 15; i++) {
|
|
VectorFloatTestCase_TwoOperandACC testCase = VectorFloatTestCase_TwoOperandACC();
|
|
testCase.destinationMask = i;
|
|
cases.push_back(testCase);
|
|
// Re-add each case with each broadcast variant
|
|
for (int j = 0; j < 4; j++) {
|
|
VectorFloatTestCase_TwoOperandACC testCaseBC = VectorFloatTestCase_TwoOperandACC();
|
|
testCaseBC.destinationMask = i;
|
|
testCaseBC.bc = static_cast<emitter::Register::VF_ELEMENT>(j);
|
|
cases.push_back(testCaseBC);
|
|
}
|
|
}
|
|
return cases;
|
|
}
|
|
|
|
class VectorFloatParameterizedTestFixtureWithRunner_TwoOperandACC
|
|
: public WithMinimalGameTests,
|
|
public ::testing::WithParamInterface<VectorFloatTestCase_TwoOperandACC> {
|
|
protected:
|
|
std::string templateFile = "test-vector-math-2-operand-acc.template.gc";
|
|
};
|
|
|
|
TEST_P(VectorFloatParameterizedTestFixtureWithRunner_TwoOperandACC, VF_MUL_ADD_XYZW_DEST) {
|
|
VectorFloatTestCase_TwoOperandACC testCase = GetParam();
|
|
testCase.operation = [](float x, float y, float acc) { return (x * y) + acc; };
|
|
|
|
nlohmann::json data;
|
|
testCase.setJson(data, fmt::format(".add.mul{}.vf", testCase.getOperationBroadcast()));
|
|
|
|
std::string outFile = shared_compiler->runner.test_file_name(
|
|
fmt::format("vector-math-add-mul{}-{{}}.generated.gc", testCase.getOperationBroadcast()));
|
|
env.write(templateFile, data, outFile);
|
|
shared_compiler->runner.run_test(
|
|
testCategory, outFile, {fmt::format("{}\n0\n", testCase.getExpectedResult().toGOALFormat())});
|
|
}
|
|
|
|
TEST_P(VectorFloatParameterizedTestFixtureWithRunner_TwoOperandACC, VF_MUL_SUB_XYZW_DEST) {
|
|
VectorFloatTestCase_TwoOperandACC testCase = GetParam();
|
|
testCase.operation = [](float x, float y, float acc) { return acc - (x * y); };
|
|
|
|
nlohmann::json data;
|
|
testCase.setJson(data, fmt::format(".sub.mul{}.vf", testCase.getOperationBroadcast()));
|
|
|
|
std::string outFile = shared_compiler->runner.test_file_name(
|
|
fmt::format("vector-math-sub-mul{}-{{}}.generated.gc", testCase.getOperationBroadcast()));
|
|
env.write(templateFile, data, outFile);
|
|
shared_compiler->runner.run_test(
|
|
testCategory, outFile, {fmt::format("{}\n0\n", testCase.getExpectedResult().toGOALFormat())});
|
|
}
|
|
|
|
INSTANTIATE_TEST_SUITE_P(WithGameTests_VectorFloatTests,
|
|
VectorFloatParameterizedTestFixtureWithRunner_TwoOperandACC,
|
|
::testing::ValuesIn(vectorMathCaseGen_TwoOperandACC()));
|
|
|
|
// ---- Two Operand Quotient Register Operations
|
|
|
|
struct VectorFloatTestCase_TwoOperandQuotient : VectorFloatTestCase {
|
|
VectorFloatRegister input1 = {1.5, -1.5, 0.0, 100.5};
|
|
VectorFloatRegister input2 = {-5.5, -0.0, 10.0, 10.0};
|
|
|
|
int fsf = 0;
|
|
int ftf = 0;
|
|
|
|
std::function<float(float, float)> operation;
|
|
|
|
VectorFloatRegister getExpectedResult() {
|
|
float operand1 =
|
|
input1.getBroadcastElement(static_cast<emitter::Register::VF_ELEMENT>(fsf), input1.x);
|
|
float operand2 =
|
|
input2.getBroadcastElement(static_cast<emitter::Register::VF_ELEMENT>(ftf), input2.x);
|
|
float result = operation(operand1, operand2);
|
|
VectorFloatRegister expectedResult;
|
|
expectedResult.x = result;
|
|
expectedResult.y = result;
|
|
expectedResult.z = result;
|
|
expectedResult.w = result;
|
|
return expectedResult;
|
|
}
|
|
|
|
void setJson(nlohmann::json& data, std::string func) {
|
|
input1.setJson(data, "v1");
|
|
input2.setJson(data, "v2");
|
|
dest.setJson(data, "dest");
|
|
data["operation"] = fmt::format(func);
|
|
data["ftf"] = fmt::format("{:b}", ftf);
|
|
data["fsf"] = fmt::format("{:b}", fsf);
|
|
}
|
|
};
|
|
|
|
std::vector<VectorFloatTestCase_TwoOperandQuotient> vectorMathCaseGen_TwoOperandQuotient() {
|
|
std::vector<VectorFloatTestCase_TwoOperandQuotient> cases = {};
|
|
for (int i = 0; i <= 3; i++) {
|
|
VectorFloatTestCase_TwoOperandQuotient testCase = VectorFloatTestCase_TwoOperandQuotient();
|
|
testCase.fsf = i;
|
|
for (int j = 0; j <= 3; j++) {
|
|
testCase.ftf = j;
|
|
cases.push_back(testCase);
|
|
}
|
|
}
|
|
return cases;
|
|
}
|
|
|
|
class VectorFloatParameterizedTestFixtureWithRunner_TwoOperandQuotient
|
|
: public WithMinimalGameTests,
|
|
public ::testing::WithParamInterface<VectorFloatTestCase_TwoOperandQuotient> {
|
|
protected:
|
|
std::string templateFile = "test-vector-math-division.template.gc";
|
|
};
|
|
|
|
TEST_P(VectorFloatParameterizedTestFixtureWithRunner_TwoOperandQuotient, VF_DIV_FTF_FSF) {
|
|
VectorFloatTestCase_TwoOperandQuotient testCase = GetParam();
|
|
testCase.operation = [](float x, float y) { return x / y; };
|
|
|
|
nlohmann::json data;
|
|
testCase.setJson(data, ".div.vf");
|
|
|
|
std::string outFile = shared_compiler->runner.test_file_name("vector-math-div-{}.generated.gc");
|
|
env.write(templateFile, data, outFile);
|
|
shared_compiler->runner.run_test(
|
|
testCategory, outFile,
|
|
{fmt::format("{}\n0\n",
|
|
testCase.getExpectedResult().toGOALFormat(testCase.getExpectedResult().x))});
|
|
}
|
|
|
|
INSTANTIATE_TEST_SUITE_P(WithGameTests_VectorFloatTests,
|
|
VectorFloatParameterizedTestFixtureWithRunner_TwoOperandQuotient,
|
|
::testing::ValuesIn(vectorMathCaseGen_TwoOperandQuotient()));
|
|
|
|
// ---- Single Operand Quotient Register Operations
|
|
|
|
struct VectorFloatTestCase_OneOperandQuotient : VectorFloatTestCase {
|
|
VectorFloatRegister input1 = {2, -2, 0.0, 100};
|
|
|
|
int ftf = 0;
|
|
|
|
std::function<float(float)> operation;
|
|
|
|
VectorFloatRegister getExpectedResult() {
|
|
float operand1 =
|
|
input1.getBroadcastElement(static_cast<emitter::Register::VF_ELEMENT>(ftf), input1.x);
|
|
float result = operation(operand1);
|
|
VectorFloatRegister expectedResult;
|
|
expectedResult.x = result;
|
|
expectedResult.y = result;
|
|
expectedResult.z = result;
|
|
expectedResult.w = result;
|
|
return expectedResult;
|
|
}
|
|
|
|
void setJson(nlohmann::json& data, std::string func) {
|
|
input1.setJson(data, "v1");
|
|
dest.setJson(data, "dest");
|
|
data["operation"] = fmt::format(func);
|
|
data["ftf"] = fmt::format("{:b}", ftf);
|
|
}
|
|
};
|
|
|
|
std::vector<VectorFloatTestCase_OneOperandQuotient> vectorMathCaseGen_OneOperandQuotient() {
|
|
std::vector<VectorFloatTestCase_OneOperandQuotient> cases = {};
|
|
for (int i = 0; i <= 3; i++) {
|
|
VectorFloatTestCase_OneOperandQuotient testCase = VectorFloatTestCase_OneOperandQuotient();
|
|
testCase.ftf = i;
|
|
cases.push_back(testCase);
|
|
}
|
|
return cases;
|
|
}
|
|
|
|
class VectorFloatParameterizedTestFixtureWithRunner_OneOperandQuotient
|
|
: public WithMinimalGameTests,
|
|
public ::testing::WithParamInterface<VectorFloatTestCase_OneOperandQuotient> {
|
|
protected:
|
|
std::string templateFile = "test-vector-math-sqrt.template.gc";
|
|
};
|
|
|
|
TEST_P(VectorFloatParameterizedTestFixtureWithRunner_OneOperandQuotient, VF_SQRT_FTF) {
|
|
VectorFloatTestCase_OneOperandQuotient testCase = GetParam();
|
|
testCase.operation = [](float x) { return sqrt(x); };
|
|
|
|
nlohmann::json data;
|
|
testCase.setJson(data, ".sqrt.vf");
|
|
|
|
std::string outFile = shared_compiler->runner.test_file_name("vector-math-sqrt-{}.generated.gc");
|
|
env.write(templateFile, data, outFile);
|
|
shared_compiler->runner.run_test(
|
|
testCategory, outFile,
|
|
{fmt::format("{}\n0\n",
|
|
testCase.getExpectedResult().toGOALFormat(testCase.getExpectedResult().x))});
|
|
}
|
|
|
|
INSTANTIATE_TEST_SUITE_P(WithGameTests_VectorFloatTests,
|
|
VectorFloatParameterizedTestFixtureWithRunner_OneOperandQuotient,
|
|
::testing::ValuesIn(vectorMathCaseGen_OneOperandQuotient()));
|