|
|
|
@@ -344,222 +344,13 @@ TEST_F(WithGameTests, StaticBoxedArray) {
|
|
|
|
|
|
|
|
|
|
// VECTOR FLOAT TESTS
|
|
|
|
|
|
|
|
|
|
struct VectorFloatRegister {
|
|
|
|
|
float x = 0;
|
|
|
|
|
float y = 0;
|
|
|
|
|
float z = 0;
|
|
|
|
|
float w = 0;
|
|
|
|
|
// ---- One off Tests
|
|
|
|
|
|
|
|
|
|
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
|
|
|
|
|
return std::regex_replace(answer, std::regex("-0.0000"), "0.0000");
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
struct VectorFloatTestCase {
|
|
|
|
|
VectorFloatRegister input1 = {1.5, -1.5, 0.0, 100.5};
|
|
|
|
|
VectorFloatRegister input2 = {-5.5, -0.0, 10.0, 7.5};
|
|
|
|
|
VectorFloatRegister dest = {11, 22, 33, 44};
|
|
|
|
|
|
|
|
|
|
int destinationMask = -1;
|
|
|
|
|
emitter::Register::VF_ELEMENT bc = emitter::Register::VF_ELEMENT::NONE;
|
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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 "";
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void setJson(nlohmann::json& data, std::string func, bool twoOperands = true) {
|
|
|
|
|
input1.setJson(data, "v1");
|
|
|
|
|
data["twoOperands"] = twoOperands;
|
|
|
|
|
if (twoOperands) {
|
|
|
|
|
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> vectorMathTestCaseGen() {
|
|
|
|
|
std::string test = fmt::format("{:.4f}", -0.0);
|
|
|
|
|
|
|
|
|
|
std::vector<VectorFloatTestCase> cases = {};
|
|
|
|
|
for (int i = 0; i <= 15; i++) {
|
|
|
|
|
VectorFloatTestCase testCase = VectorFloatTestCase();
|
|
|
|
|
testCase.destinationMask = i;
|
|
|
|
|
cases.push_back(testCase);
|
|
|
|
|
// Re-add each case with each broadcast varient
|
|
|
|
|
for (int j = 0; j < 4; j++) {
|
|
|
|
|
VectorFloatTestCase testCaseBC = VectorFloatTestCase();
|
|
|
|
|
testCaseBC.destinationMask = i;
|
|
|
|
|
testCaseBC.bc = static_cast<emitter::Register::VF_ELEMENT>(j);
|
|
|
|
|
cases.push_back(testCaseBC);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return cases;
|
|
|
|
|
TEST_F(WithGameTests, VFOuterProduct) {
|
|
|
|
|
runner.run_static_test(env, testCategory, "test-vector-outer-product.gc",
|
|
|
|
|
{"(-4.0000, 8.0000, -4.0000, 999.0000)\n0\n"});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
class VectorFloatParameterizedTestFixtureWithRunner
|
|
|
|
|
: public WithGameTests,
|
|
|
|
|
public ::testing::WithParamInterface<VectorFloatTestCase> {
|
|
|
|
|
protected:
|
|
|
|
|
std::string templateFile = "test-vector-math.template.gc";
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// NOTE - an excellent article -
|
|
|
|
|
// https://www.sandordargo.com/blog/2019/04/24/parameterized-testing-with-gtest
|
|
|
|
|
|
|
|
|
|
TEST_P(VectorFloatParameterizedTestFixtureWithRunner, VF_ADD_XYZW_DEST) {
|
|
|
|
|
VectorFloatTestCase 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 = runner.test_file_name(
|
|
|
|
|
fmt::format("vector-math-add{}-{{}}.generated.gc", testCase.getOperationBroadcast()));
|
|
|
|
|
env.write(templateFile, data, outFile);
|
|
|
|
|
runner.run_test(testCategory, outFile,
|
|
|
|
|
{fmt::format("{}\n0\n", testCase.getExpectedResult().toGOALFormat())});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST_P(VectorFloatParameterizedTestFixtureWithRunner, VF_SUB_XYZW_DEST) {
|
|
|
|
|
VectorFloatTestCase 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 = runner.test_file_name(
|
|
|
|
|
fmt::format("vector-math-sub{}-{{}}.generated.gc", testCase.getOperationBroadcast()));
|
|
|
|
|
env.write(templateFile, data, outFile);
|
|
|
|
|
runner.run_test(testCategory, outFile,
|
|
|
|
|
{fmt::format("{}\n0\n", testCase.getExpectedResult().toGOALFormat())});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST_P(VectorFloatParameterizedTestFixtureWithRunner, VF_MUL_XYZW_DEST) {
|
|
|
|
|
VectorFloatTestCase 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 = runner.test_file_name(
|
|
|
|
|
fmt::format("vector-math-mul{}-{{}}.generated.gc", testCase.getOperationBroadcast()));
|
|
|
|
|
env.write(templateFile, data, outFile);
|
|
|
|
|
runner.run_test(testCategory, outFile,
|
|
|
|
|
{fmt::format("{}\n0\n", testCase.getExpectedResult().toGOALFormat())});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST_P(VectorFloatParameterizedTestFixtureWithRunner, VF_MIN_XYZW_DEST) {
|
|
|
|
|
VectorFloatTestCase 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 = runner.test_file_name(
|
|
|
|
|
fmt::format("vector-math-min{}-{{}}.generated.gc", testCase.getOperationBroadcast()));
|
|
|
|
|
env.write(templateFile, data, outFile);
|
|
|
|
|
runner.run_test(testCategory, outFile,
|
|
|
|
|
{fmt::format("{}\n0\n", testCase.getExpectedResult().toGOALFormat())});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST_P(VectorFloatParameterizedTestFixtureWithRunner, VF_MAX_XYZW_DEST) {
|
|
|
|
|
VectorFloatTestCase 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 = runner.test_file_name(
|
|
|
|
|
fmt::format("vector-math-max{}-{{}}.generated.gc", testCase.getOperationBroadcast()));
|
|
|
|
|
env.write(templateFile, data, outFile);
|
|
|
|
|
runner.run_test(testCategory, outFile,
|
|
|
|
|
{fmt::format("{}\n0\n", testCase.getExpectedResult().toGOALFormat())});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// TODO - This test runs more often than the rest, should probably be split into it's own fixture
|
|
|
|
|
// (broadcasting ignored!)
|
|
|
|
|
TEST_P(VectorFloatParameterizedTestFixtureWithRunner, VF_ABS_DEST) {
|
|
|
|
|
VectorFloatTestCase testCase = GetParam();
|
|
|
|
|
testCase.operation = [](float x, float y) {
|
|
|
|
|
// Avoid compiler warnings for unused variable, making a varient that accepts a lambda with only
|
|
|
|
|
// 1 float is just unnecessary complexity
|
|
|
|
|
(void)y;
|
|
|
|
|
return fabs(x);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
nlohmann::json data;
|
|
|
|
|
testCase.setJson(data, ".abs.vf", false);
|
|
|
|
|
|
|
|
|
|
std::string outFile = runner.test_file_name("vector-math-abs-{}.generated.gc");
|
|
|
|
|
env.write(templateFile, data, outFile);
|
|
|
|
|
runner.run_test(testCategory, outFile,
|
|
|
|
|
{fmt::format("{}\n0\n", testCase.getExpectedResult().toGOALFormat())});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
INSTANTIATE_TEST_SUITE_P(WithGameTests_VectorFloatTests,
|
|
|
|
|
VectorFloatParameterizedTestFixtureWithRunner,
|
|
|
|
|
::testing::ValuesIn(vectorMathTestCaseGen()));
|
|
|
|
|
|
|
|
|
|
TEST_F(WithGameTests, VFLoadAndStore) {
|
|
|
|
|
runner.run_static_test(env, testCategory, "test-vf-load-and-store.gc", {"2.0000\n0\n"});
|
|
|
|
|
}
|
|
|
|
@@ -596,3 +387,516 @@ TEST(TypeConsistency, TypeConsistency) {
|
|
|
|
|
compiler.run_test_no_load("test/goalc/source_templates/with_game/test-build-game.gc");
|
|
|
|
|
compiler.run_test_no_load("decompiler/config/all-types.gc");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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 val) {
|
|
|
|
|
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;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
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 WithGameTests,
|
|
|
|
|
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 = runner.test_file_name(
|
|
|
|
|
fmt::format("vector-math-add{}-{{}}.generated.gc", testCase.getOperationBroadcast()));
|
|
|
|
|
env.write(templateFile, data, outFile);
|
|
|
|
|
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 = runner.test_file_name(
|
|
|
|
|
fmt::format("vector-math-sub{}-{{}}.generated.gc", testCase.getOperationBroadcast()));
|
|
|
|
|
env.write(templateFile, data, outFile);
|
|
|
|
|
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 = runner.test_file_name(
|
|
|
|
|
fmt::format("vector-math-mul{}-{{}}.generated.gc", testCase.getOperationBroadcast()));
|
|
|
|
|
env.write(templateFile, data, outFile);
|
|
|
|
|
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 = runner.test_file_name(
|
|
|
|
|
fmt::format("vector-math-min{}-{{}}.generated.gc", testCase.getOperationBroadcast()));
|
|
|
|
|
env.write(templateFile, data, outFile);
|
|
|
|
|
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 = runner.test_file_name(
|
|
|
|
|
fmt::format("vector-math-max{}-{{}}.generated.gc", testCase.getOperationBroadcast()));
|
|
|
|
|
env.write(templateFile, data, outFile);
|
|
|
|
|
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 WithGameTests,
|
|
|
|
|
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 = runner.test_file_name("vector-math-abs-{}.generated.gc");
|
|
|
|
|
env.write(templateFile, data, outFile);
|
|
|
|
|
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 WithGameTests,
|
|
|
|
|
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 = runner.test_file_name(
|
|
|
|
|
fmt::format("vector-math-add-mul{}-{{}}.generated.gc", testCase.getOperationBroadcast()));
|
|
|
|
|
env.write(templateFile, data, outFile);
|
|
|
|
|
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 = runner.test_file_name(
|
|
|
|
|
fmt::format("vector-math-sub-mul{}-{{}}.generated.gc", testCase.getOperationBroadcast()));
|
|
|
|
|
env.write(templateFile, data, outFile);
|
|
|
|
|
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 WithGameTests,
|
|
|
|
|
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 = runner.test_file_name("vector-math-div-{}.generated.gc");
|
|
|
|
|
env.write(templateFile, data, outFile);
|
|
|
|
|
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 WithGameTests,
|
|
|
|
|
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 = runner.test_file_name("vector-math-sqrt-{}.generated.gc");
|
|
|
|
|
env.write(templateFile, data, outFile);
|
|
|
|
|
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()));
|
|
|
|
|