Cleanup goalc tests, fix jak2 kernel bugs (#1669)

* Cleanup goalc tests, fix jak2 kernel bugs

* fix warnings on linux

* spelling is hard
This commit is contained in:
water111 2022-07-17 14:12:11 -04:00 committed by GitHub
parent 12fd8a09b1
commit e9567a6e4b
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
25 changed files with 1312 additions and 1020 deletions

View file

@ -426,21 +426,25 @@
:flag-assert #x90000000c
)
;; a "catch" frame is a frame that can be "thrown" to.
;; the "throw" is a nonlocal control flow back to the state before the "catch" block.
(deftype catch-frame (stack-frame)
((sp int32 :offset-assert 12)
(ra int32 :offset-assert 16)
(freg float 6 :offset-assert 20) ;; guessed by decompiler
(rreg uint128 8 :offset-assert 48) ;; guessed by decompiler
((sp int32 :offset-assert 12)
(ra int32 :offset-assert 16)
; (freg float 6 :offset-assert 20)
; (rreg uint128 8 :offset-assert 48)
;; In OpenGOAL, we swap a rreg for 4 more fregs.
(freg float 10 :offset-assert 20) ;; only use 8
(rreg uint128 7) ;; only use 5
)
(:methods
(new (symbol type symbol function (pointer uint64)) object 0)
)
:method-count-assert 9
:size-assert #xb0
:flag-assert #x9000000b0
(:methods
(new (symbol type symbol function (pointer uint64)) object 0)
)
)
(deftype protect-frame (stack-frame)
((exit (function none) :offset-assert 12) ;; guessed by decompiler
)

View file

@ -112,10 +112,6 @@ bool HasError() {
}
}
void FocusCallback(GLFWwindow* window, int focused) {
glfwSetWindowAttrib(window, GLFW_FLOATING, focused);
}
} // namespace
static bool gl_inited = false;

View file

@ -1038,14 +1038,14 @@ u64 call_method_of_type(u64 arg, Ptr<Type> type, u32 method_id) {
if (((type.offset < SymbolTable2.offset || 0x7ffffff < type.offset) && // not in normal memory
(type.offset < 0x84000 || 0x100000 <= type.offset)) // not in kernel memory
|| ((type.offset & OFFSET_MASK) != BASIC_OFFSET)) { // invalid type
cprintf("#<#%x has invalid type ptr #x%x>\n", arg, type.offset);
cprintf("#<#%x has invalid type ptr #x%x>\n", (u32)arg, type.offset);
} else {
auto type_tag = Ptr<Ptr<Type>>(type.offset - 4);
if ((*type_tag).offset == *(s7 + FIX_SYM_TYPE_TYPE)) {
auto f = type->get_method(method_id);
return call_goal(f, arg, 0, 0, s7.offset, g_ee_main_mem);
} else {
cprintf("#<#x%x has invalid type ptr #x%x, bad type #x%x>\n", arg, type.offset,
cprintf("#<#x%x has invalid type ptr #x%x, bad type #x%x>\n", (u32)arg, type.offset,
(*type_tag).offset);
}
}

View file

@ -1,11 +1,3 @@
#if defined(__GNUC__)
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-but-set-variable"
#elif defined(__clang__)
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wunused-but-set-variable"
#endif
//--------------------------MIPS2C---------------------
#include "common/dma/gs.h"
@ -3284,9 +3276,3 @@ void link() {
} // namespace method_9_collide_puss_work
} // namespace Mips2C
#if defined(__GNUC__)
#pragma GCC diagnostic pop
#elif defined(__clang__)
#pragma clang diagnostic pop
#endif

View file

@ -1,11 +1,3 @@
#if defined(__GNUC__)
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-but-set-variable"
#elif defined(__clang__)
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wunused-but-set-variable"
#endif
//--------------------------MIPS2C---------------------
#include "game/kernel/jak1/kscheme.h"
#include "game/mips2c/mips2c_private.h"
@ -1016,11 +1008,4 @@ void link() {
}
} // namespace method_18_collide_edge_work
} // namespace Mips2C
#if defined(__GNUC__)
#pragma GCC diagnostic pop
#elif defined(__clang__)
#pragma clang diagnostic pop
#endif
} // namespace Mips2C

View file

@ -400,12 +400,15 @@
)
;; a "catch" frame is a frame that can be "thrown" to.
;; the "throw" is a nonlocal control flow back to the state befor the "catch" block.
;; the "throw" is a nonlocal control flow back to the state before the "catch" block.
(deftype catch-frame (stack-frame)
((sp int32 :offset-assert 12)
(ra int32 :offset-assert 16)
(freg float 6 :offset-assert 20)
(rreg uint128 8 :offset-assert 48)
; (freg float 6 :offset-assert 20)
; (rreg uint128 8 :offset-assert 48)
;; In OpenGOAL, we swap a rreg for 4 more fregs.
(freg float 10 :offset-assert 20) ;; only use 8
(rreg uint128 7) ;; only use 5
)
:method-count-assert 9
:size-assert #xb0
@ -688,4 +691,11 @@
((-> (the cpu-thread pp) suspend-hook) (the cpu-thread 0))
;; the kernel will set pp (possibly to a new value, if we've been relocated) on resume.
)
)
(defmacro process-deactivate ()
"deactivate (kill) the current process"
`(rlet ((pp :reg r13 :reset-here #t :type process))
(deactivate pp)
)
)

View file

@ -38,49 +38,6 @@ struct BBox {
}
};
/*!
* Make the bounding box hold this node and all its children.
*/
void add_to_bbox_recursive(const CNode& node, BBox& bbox) {
if (node.faces.empty()) {
for (auto& child : node.child_nodes) {
add_to_bbox_recursive(child, bbox);
}
} else {
for (auto& face : node.faces) {
for (auto& vert : face.v) {
bbox.mins.min_in_place(vert);
bbox.maxs.max_in_place(vert);
}
}
}
}
BBox bbox_of_node(const CNode& node) {
BBox bbox;
bbox.mins.fill(std::numeric_limits<float>::max());
bbox.maxs.fill(-std::numeric_limits<float>::max());
add_to_bbox_recursive(node, bbox);
return bbox;
}
/*!
* Make the bsphere hold this node and all its children.
*/
void update_bsphere_recursive(const CNode& node, const math::Vector3f& origin, float& r_squared) {
if (node.faces.empty()) {
for (auto& child : node.child_nodes) {
update_bsphere_recursive(child, origin, r_squared);
}
} else {
for (auto& face : node.faces) {
for (auto& vert : face.v) {
r_squared = std::max(r_squared, (vert - origin).squared_length());
}
}
}
}
void collect_vertices(const CNode& node, std::vector<math::Vector3f>& verts) {
for (auto& child : node.child_nodes) {
collect_vertices(child, verts);
@ -125,22 +82,6 @@ void compute_my_bsphere_ritters(CNode& node) {
node.bsphere.w() = std::sqrt(max_squared);
}
/*!
* Compute the bsphere of a single node.
*/
BBox compute_my_bsphere_bad(CNode& node) {
// first compute bbox.
BBox bbox = bbox_of_node(node);
float r = 0;
math::Vector3f origin = (bbox.maxs + bbox.mins) * 0.5;
update_bsphere_recursive(node, origin, r);
node.bsphere.x() = origin.x();
node.bsphere.y() = origin.y();
node.bsphere.z() = origin.z();
node.bsphere.w() = std::sqrt(r);
return bbox;
}
/*!
* Split faces in two along a coordinate plane.
* Will clear the input faces

View file

@ -1,8 +1,18 @@
set(GOALC_TEST_CASES
${CMAKE_CURRENT_LIST_DIR}/all_goalc_template_tests.cpp
${CMAKE_CURRENT_LIST_DIR}/test_arithmetic.cpp
${CMAKE_CURRENT_LIST_DIR}/test_collections.cpp
${CMAKE_CURRENT_LIST_DIR}/test_compiler.cpp
${CMAKE_CURRENT_LIST_DIR}/test_control_statements.cpp
${CMAKE_CURRENT_LIST_DIR}/test_debugger.cpp
${CMAKE_CURRENT_LIST_DIR}/test_game_no_debug.cpp
)
${CMAKE_CURRENT_LIST_DIR}/test_goal_kernel.cpp
${CMAKE_CURRENT_LIST_DIR}/test_goal_kernel2.cpp
${CMAKE_CURRENT_LIST_DIR}/test_jak2_compiler.cpp
${CMAKE_CURRENT_LIST_DIR}/test_variables.cpp
${CMAKE_CURRENT_LIST_DIR}/test_with_game.cpp
${CMAKE_CURRENT_LIST_DIR}/test_type_consistency.cpp
${CMAKE_CURRENT_LIST_DIR}/test_vector_float.cpp
)
set(GOALC_TEST_FRAMEWORK_SOURCES
${CMAKE_CURRENT_LIST_DIR}/framework/test_runner.cpp

View file

@ -1,6 +0,0 @@
#include "test_arithmetic.cpp"
#include "test_collections.cpp"
#include "test_compiler.cpp"
#include "test_control_statements.cpp"
#include "test_variables.cpp"
#include "test_with_game.cpp"

View file

@ -51,6 +51,14 @@ void CompilerTestRunner::run_static_test(inja::Environment& env,
run_test(testCategory, test_file, expected, truncate);
}
void CompilerTestRunner::run_static_test(std::string& testCategory,
const std::string& test_file,
const std::vector<std::string>& expected,
std::optional<int> truncate) {
auto env = getInjaEnvironment(testCategory);
run_static_test(env, testCategory, test_file, expected, truncate);
}
void CompilerTestRunner::run_test(const std::string& test_category,
const std::string& test_file,
const std::vector<std::string>& expected,
@ -98,7 +106,7 @@ void CompilerTestRunner::run_always_pass(const std::string& test_category,
tests.push_back({{}, {}, test_file, true});
}
void runtime_no_kernel() {
void runtime_no_kernel_jak1() {
constexpr int argc = 6;
const char* argv[argc] = {"", "-fakeiso", "-debug", "-nokernel", "-nodisplay", "-nosound"};
exec_runtime(argc, const_cast<char**>(argv));
@ -111,12 +119,18 @@ void runtime_no_kernel_jak2() {
exec_runtime(argc, const_cast<char**>(argv));
}
void runtime_with_kernel() {
void runtime_with_kernel_jak1() {
constexpr int argc = 5;
const char* argv[argc] = {"", "-fakeiso", "-debug", "-nodisplay", "-nosound"};
exec_runtime(argc, const_cast<char**>(argv));
}
void runtime_with_kernel_jak2() {
constexpr int argc = 6;
const char* argv[argc] = {"", "-fakeiso", "-debug", "-nodisplay", "-nosound", "-jak2"};
exec_runtime(argc, const_cast<char**>(argv));
}
void runtime_with_kernel_no_debug_segment() {
constexpr int argc = 5;
const char* argv[argc] = {"", "-fakeiso", "-debug-mem", "-nodisplay", "-nosound"};
@ -137,4 +151,9 @@ std::string getGeneratedDir(const std::string& category) {
std::string getFailedDir(const std::string& category) {
return file_util::get_file_path({"test/goalc/source_generated/failed", category + "/"});
}
inja::Environment getInjaEnvironment(const std::string& category) {
return inja::Environment(getTemplateDir(category), getGeneratedDir(category));
}
} // namespace GoalTest

View file

@ -4,10 +4,12 @@
#include <string>
#include <vector>
#include "inja.hpp"
#include "goalc/compiler/Compiler.h"
namespace inja {
class Environment;
}
namespace GoalTest {
std::string escaped_string(const std::string& in);
@ -32,19 +34,23 @@ struct CompilerTestRunner {
const std::vector<std::string>& expected,
std::optional<int> truncate = {});
void run_static_test(std::string& testCategory,
const std::string& test_file,
const std::vector<std::string>& expected,
std::optional<int> truncate = {});
void run_test(const std::string& test_category,
const std::string& test_file,
const std::vector<std::string>& expected,
std::optional<int> truncate = {});
void run_always_pass(const std::string& test_category, const std::string& test_file);
void print_summary();
};
void runtime_no_kernel();
void runtime_no_kernel_jak1();
void runtime_no_kernel_jak2();
void runtime_with_kernel();
void runtime_with_kernel_jak1();
void runtime_with_kernel_jak2();
void runtime_with_kernel_no_debug_segment();
void createDirIfAbsent(const std::string& path);
@ -52,4 +58,6 @@ std::string getTemplateDir(const std::string& category);
std::string getGeneratedDir(const std::string& category);
std::string getFailedDir(const std::string& category);
inja::Environment getInjaEnvironment(const std::string& category);
} // namespace GoalTest

View file

@ -0,0 +1,227 @@
(defun target-function ((a0 uint) (a1 uint) (a2 uint) (a3 uint) (a4 uint) (a5 uint))
(format #t "TARGET FUNCTION ~D ~D ~D~%" a0 a1 a2)
(format #t "~D ~D ~D~%" a3 a4 a5)
(let ((stack-arr (new 'stack-no-clear 'array 'uint8 12)))
(format #t "Stack Alignemnt ~D/16~%" (logand 15 (the uint stack-arr)))
)
(dotimes (i 10)
(format #t "proc1: ~D~%" i)
(when (> i 4)
(format #t "DEACTIVATE PROC 1~%")
(process-deactivate)
)
(suspend)
)
)
(define-extern recurse (function int (pointer int32) int))
(defun recurse ((i int) (ptr (pointer int32)))
(if (> i 0)
(recurse (- i 1) ptr)
(suspend)
)
(set! (-> ptr) (+ (-> ptr) 1))
1
)
(defun target-function-2 ()
(let ((stack-var (new 'stack-no-clear 'array 'int32 1)))
(set! (-> stack-var) 0)
(countdown (i 10)
(format #t "proc2: ~D~%" (-> stack-var))
(recurse 5 stack-var)
)
)
)
(defun kernel-test ()
(define test-process (get-process *nk-dead-pool* process 1024))
(activate test-process *active-pool* "test-proc" *kernel-dram-stack*)
(set-to-run (-> test-process main-thread)
target-function
1 2 3 4 5 6
)
(define test-process-2 (get-process *nk-dead-pool* process 1024))
;; test that the kernel fakes having process stacks on the scratchpad.
(activate test-process-2 *active-pool* "test-2" (the pointer #x70004000))
(set-to-run (-> test-process-2 main-thread)
target-function-2
0 0 0 0 0 0)
0
)
(defun check-current-proc-catch-rbx ()
;; (format 0 "last rbx = ~X~%" *last-rbx*)
(with-pp
(format 0 "PP = ~X~%" pp)
(let ((frame (-> pp stack-frame-top)))
(format 0 "FRAME0: ~A~%" frame)
(while frame
(format 0 "FRAME: ~A~%" frame)
(when (= (-> frame type) catch-frame)
(format 0 "found upcoming protect frame! ~A: ~X~%"
(-> (the catch-frame frame) name)
(-> (the catch-frame frame) rreg 0)
)
)
(set! frame (-> frame next))
)
)
)
)
(defun init-child-proc (a0 a1 a2 a3 a4 a5)
(format #t "Args: ~D ~D ~D~%" a0 a1 a2)
(format #t "~D ~D ~D~%" a3 a4 a5)
(let ((stack-arr (new 'stack-no-clear 'array 'uint8 12)))
(format #t "Stack Alignemnt ~D/16~%" (logand 15 (the uint stack-arr)))
)
(when (eq? a0 (the int 0))
(format 0 "doing child proc deactivate~%")
(check-current-proc-catch-rbx)
(process-deactivate)
)
'init-child-proc-result
)
(defun initializer-process-function (a0)
(format 0 "ipf: ~D~%" a0)
(let ((child-proc (get-process *nk-dead-pool* process 1024)))
;; let's go
(activate child-proc *active-pool* "child-proc" *kernel-dram-stack*)
(format 0 "child-proc activated...~%")
(let ((result (run-function-in-process child-proc init-child-proc a0 2 3 4 5 6)))
(format 0 "child-proc reuslt: ~D~%" result)
(format #t "run-function-in-process result: ~A~%" result)
)
)
(format 0 "proc-deactivate ~D~%" a0)
(rlet ((pp :reg r13 :reset-here #t :type process))
;; (deactivate pp)
(format 0 " proc is: #x~X~%" pp)
)
(check-current-proc-catch-rbx)
(process-deactivate)
(format 0 "proc-deactivate end?~%")
)
(defun kernel-test-2 ()
(define initalizer-process (get-process *nk-dead-pool* process 1024))
(activate initalizer-process *active-pool* "initializer-proc" *kernel-dram-stack*)
(set-to-run (-> initalizer-process main-thread)
initializer-process-function
0 0 0 0 0 0
)
(define initalizer-process-2 (get-process *nk-dead-pool* process 1024))
(activate initalizer-process-2 *active-pool* "initializer-proc-2" *kernel-dram-stack*)
(set-to-run (-> initalizer-process-2 main-thread)
initializer-process-function
1 0 0 0 0 0
)
(format 0 "kt2 return~%")
0
)
(defstate die-state (process)
:enter (lambda () (format #t "enter die~%") (none))
:exit (lambda () (format #t "exit die~%") (none))
:code (lambda ()
(format #t "time to die!~%")
(process-deactivate)
(format #t "don't see me~%")
)
)
(defun xmm-check-code (ax ay az aw)
"This function relies on saved xmm register being backed up on a context switch"
;; (declare (print-asm))
;; compiler will put these in xmm8 and xmm9 to keep them from being clobbered
(let ((x 12.34)
(y 45.63))
(dotimes (i 3)
(format #t "run xmm-check ~f ~f ~D ~D ~D ~D~%" x y ax ay az aw)
;; should preserve xmm8 and xmm9
(suspend)
)
;; get the wreck process and make it go to die state.
(go-process (process-by-name "wreck-proc" *active-pool*) die-state)
(go die-state)
(format #t "unreachable~%")
)
)
(defun xmm-wreck-code (ax ay az aw)
"This function intentionally overwrites xmm8 and xmm9 and suspends"
(while #t
(rlet ((x :class fpr :type float :reg xmm8)
(y :class fpr :type float :reg xmm9))
(set! x 99.0)
(set! y 101.0)
(format #t "wreck: ~D ~D ~D ~D~%" ax ay az aw)
(suspend)
(set! x (+ x 1.0))
(set! y (+ y 1.0))
)
)
)
;; a state.
(defstate xmm-check-state (process)
:enter (lambda (x y z w) (format #t "enter check: ~D ~D ~D ~D~%" x y z w) (none))
:exit (lambda () (format #t "exit check~%") (none))
:code xmm-check-code
)
(defstate xmm-wreck-state (process)
:enter (lambda (x y z w) (format #t "enter wreck: ~D ~D ~D ~D~%" x y z w) (none))
:exit (lambda () (format #t "exit wreck~%") (none))
:code xmm-wreck-code
)
(defun state-test ()
(let ((proc (get-process *nk-dead-pool* process 1024)))
(activate proc *active-pool* "check-proc" *kernel-dram-stack*)
(run-now-in-process proc (lambda (x y z w) (go xmm-check-state x y z w))
9 8 7 6)
)
(let ((proc (get-process *nk-dead-pool* process 1024)))
(activate proc *active-pool* "wreck-proc" *kernel-dram-stack*)
(run-next-time-in-process proc (lambda (x y z w) (go xmm-wreck-state x y z w))
3 4 5 6)
)
0
)
(defun throw-backup-test ()
(rlet ((x :reg xmm10 :class fpr :type float))
(set! x 10.10)
(let ((proc (get-process *nk-dead-pool* process 1024)))
(activate proc *active-pool* "asdf" *kernel-dram-stack*)
(format #t "value now is ~f~%" x)
(run-now-in-process proc (lambda ()
(rlet ((x2 :reg xmm10 :class fpr :type float))
(set! x2 -1.0)
)
;; this will throw back.
(process-deactivate)
)
)
(format #t "now its ~f~%" x)
)
)
)

View file

@ -1,7 +1,6 @@
// https://github.com/google/googletest/blob/master/googletest/docs/advanced.md#value-parameterized-tests
#include <chrono>
#include <cstdio>
#include <iostream>
#include <random>
#include <sstream>
@ -119,7 +118,7 @@ class ArithmeticTests : public testing::TestWithParam<IntegerParam> {
// Per-test-suite set-up.
// Called before the first test in this test suite.
static void SetUpTestSuite() {
runtime_thread = std::make_unique<std::thread>(std::thread((GoalTest::runtime_no_kernel)));
runtime_thread = std::make_unique<std::thread>(std::thread(GoalTest::runtime_no_kernel_jak1));
compiler = std::make_unique<Compiler>(GameVersion::Jak1);
runner = std::make_unique<GoalTest::CompilerTestRunner>();
runner->c = compiler.get();

View file

@ -1,21 +1,11 @@
#include <chrono>
#include <cstdio>
#include <iostream>
#include <random>
#include <sstream>
#include <string>
#include <thread>
#include "inja.hpp"
#include "game/runtime.h"
#include "goalc/compiler/Compiler.h"
#include "goalc/listener/Listener.h"
#include "gtest/gtest.h"
#include "test/goalc/framework/test_runner.h"
#include "third-party/json.hpp"
struct CollectionParam {
// TODO - Not Needed Yet
};
@ -23,7 +13,7 @@ struct CollectionParam {
class CollectionTests : public testing::TestWithParam<CollectionParam> {
public:
static void SetUpTestSuite() {
runtime_thread = std::make_unique<std::thread>(std::thread((GoalTest::runtime_no_kernel)));
runtime_thread = std::make_unique<std::thread>(std::thread(GoalTest::runtime_no_kernel_jak1));
compiler = std::make_unique<Compiler>(GameVersion::Jak1);
runner = std::make_unique<GoalTest::CompilerTestRunner>();
runner->c = compiler.get();
@ -50,8 +40,6 @@ class CollectionTests : public testing::TestWithParam<CollectionParam> {
static std::unique_ptr<GoalTest::CompilerTestRunner> runner;
std::string testCategory = "collections";
inja::Environment env{GoalTest::getTemplateDir(testCategory),
GoalTest::getGeneratedDir(testCategory)};
};
std::unique_ptr<std::thread> CollectionTests::runtime_thread;
@ -59,22 +47,22 @@ std::unique_ptr<Compiler> CollectionTests::compiler;
std::unique_ptr<GoalTest::CompilerTestRunner> CollectionTests::runner;
TEST_F(CollectionTests, Pairs) {
runner->run_static_test(env, testCategory, "empty-pair.static.gc", {"()\n0\n"});
runner->run_static_test(env, testCategory, "pair-check.static.gc", {"#t#f\n0\n"});
runner->run_static_test(testCategory, "empty-pair.static.gc", {"()\n0\n"});
runner->run_static_test(testCategory, "pair-check.static.gc", {"#t#f\n0\n"});
}
TEST_F(CollectionTests, Lists) {
runner->run_static_test(env, testCategory, "list.static.gc", {"(a b c d)\n0\n"});
runner->run_static_test(testCategory, "list.static.gc", {"(a b c d)\n0\n"});
}
TEST_F(CollectionTests, InlineArray) {
runner->run_static_test(env, testCategory, "inline-array-field.static.gc", {"16\n"});
runner->run_static_test(testCategory, "inline-array-field.static.gc", {"16\n"});
}
TEST_F(CollectionTests, Operations) {
runner->run_static_test(env, testCategory, "cons.static.gc", {"(a . b)\n0\n"});
runner->run_static_test(env, testCategory, "car-cdr-get.static.gc", {"ab\n0\n"});
runner->run_static_test(env, testCategory, "car-cdr-set.static.gc", {"(c . d)\n0\n"});
runner->run_static_test(env, testCategory, "nested-car-cdr-set.static.gc",
runner->run_static_test(testCategory, "cons.static.gc", {"(a . b)\n0\n"});
runner->run_static_test(testCategory, "car-cdr-get.static.gc", {"ab\n0\n"});
runner->run_static_test(testCategory, "car-cdr-set.static.gc", {"(c . d)\n0\n"});
runner->run_static_test(testCategory, "nested-car-cdr-set.static.gc",
{"efgh\n((e . g) f . h)\n0\n"});
}

View file

@ -1,65 +1,7 @@
#include <chrono>
#include <thread>
#include "game/runtime.h"
#include "goalc/compiler/Compiler.h"
#include "goalc/listener/Listener.h"
#include "gtest/gtest.h"
TEST(CompilerAndRuntime, ConstructCompiler) {
Compiler compiler1(GameVersion::Jak1);
Compiler compiler2(GameVersion::Jak2);
}
struct Jak2Param {
// TODO - Not Needed Yet
};
class Jak2GoalcTests : public testing::TestWithParam<Jak2Param> {
public:
static void SetUpTestSuite() {
runtime_thread = std::make_unique<std::thread>(std::thread((GoalTest::runtime_no_kernel_jak2)));
compiler = std::make_unique<Compiler>(GameVersion::Jak2);
runner = std::make_unique<GoalTest::CompilerTestRunner>();
runner->c = compiler.get();
}
static void TearDownTestSuite() {
compiler->shutdown_target();
runtime_thread->join();
runtime_thread.reset();
compiler.reset();
runner.reset();
}
void SetUp() {
GoalTest::createDirIfAbsent(GoalTest::getTemplateDir(testCategory));
GoalTest::createDirIfAbsent(GoalTest::getGeneratedDir(testCategory));
}
void TearDown() {}
static std::unique_ptr<std::thread> runtime_thread;
static std::unique_ptr<Compiler> compiler;
static std::unique_ptr<GoalTest::CompilerTestRunner> runner;
std::string testCategory = "jak2";
inja::Environment env{GoalTest::getTemplateDir(testCategory),
GoalTest::getGeneratedDir(testCategory)};
};
std::unique_ptr<std::thread> Jak2GoalcTests::runtime_thread;
std::unique_ptr<Compiler> Jak2GoalcTests::compiler;
std::unique_ptr<GoalTest::CompilerTestRunner> Jak2GoalcTests::runner;
TEST_F(Jak2GoalcTests, All) {
runner->run_static_test(env, testCategory, "jak2-mega-test.gc",
{"empty pair: () () () #t #f\n"
"empty pair type: pair\n"
"non-empty pair: (a b -12) a pair (a . b)\n"
"basic types: type symbol string function\n"
"bools: #t #f #t #f #f #t\n"
"zero: 0\n"
"parent of type: basic structure object object\n0\n"});
}

View file

@ -1,21 +1,11 @@
#include <chrono>
#include <cstdio>
#include <iostream>
#include <random>
#include <sstream>
#include <string>
#include <thread>
#include "inja.hpp"
#include "game/runtime.h"
#include "goalc/compiler/Compiler.h"
#include "goalc/listener/Listener.h"
#include "gtest/gtest.h"
#include "test/goalc/framework/test_runner.h"
#include "third-party/json.hpp"
struct ControlStatementParam {
// TODO - Not Needed Yet
};
@ -23,7 +13,7 @@ struct ControlStatementParam {
class ControlStatementTests : public testing::TestWithParam<ControlStatementParam> {
public:
static void SetUpTestSuite() {
runtime_thread = std::make_unique<std::thread>(std::thread((GoalTest::runtime_no_kernel)));
runtime_thread = std::make_unique<std::thread>(std::thread(GoalTest::runtime_no_kernel_jak1));
compiler = std::make_unique<Compiler>(GameVersion::Jak1);
runner = std::make_unique<GoalTest::CompilerTestRunner>();
runner->c = compiler.get();
@ -50,8 +40,6 @@ class ControlStatementTests : public testing::TestWithParam<ControlStatementPara
static std::unique_ptr<GoalTest::CompilerTestRunner> runner;
std::string testCategory = "control-statements";
inja::Environment env{GoalTest::getTemplateDir(testCategory),
GoalTest::getGeneratedDir(testCategory)};
};
std::unique_ptr<std::thread> ControlStatementTests::runtime_thread;
@ -59,50 +47,50 @@ std::unique_ptr<Compiler> ControlStatementTests::compiler;
std::unique_ptr<GoalTest::CompilerTestRunner> ControlStatementTests::runner;
TEST_F(ControlStatementTests, ConditionalCompilation) {
runner->run_static_test(env, testCategory, "conditional-compilation.static.gc", {"3\n"});
runner->run_static_test(testCategory, "conditional-compilation.static.gc", {"3\n"});
}
TEST_F(ControlStatementTests, Blocks) {
runner->run_static_test(env, testCategory, "nested-blocks-1.static.gc", {"7\n"});
runner->run_static_test(env, testCategory, "nested-blocks-2.static.gc", {"8\n"});
runner->run_static_test(env, testCategory, "nested-blocks-3.static.gc", {"7\n"});
runner->run_static_test(testCategory, "nested-blocks-1.static.gc", {"7\n"});
runner->run_static_test(testCategory, "nested-blocks-2.static.gc", {"8\n"});
runner->run_static_test(testCategory, "nested-blocks-3.static.gc", {"7\n"});
}
TEST_F(ControlStatementTests, GoTo) {
runner->run_static_test(env, testCategory, "goto.static.gc", {"3\n"});
runner->run_static_test(testCategory, "goto.static.gc", {"3\n"});
}
TEST_F(ControlStatementTests, Branch) {
runner->run_static_test(env, testCategory, "return-value-of-if.static.gc", {"123\n"});
runner->run_static_test(testCategory, "return-value-of-if.static.gc", {"123\n"});
}
TEST_F(ControlStatementTests, DoTimes) {
runner->run_static_test(env, testCategory, "dotimes.static.gc", {"4950\n"});
runner->run_static_test(testCategory, "dotimes.static.gc", {"4950\n"});
}
TEST_F(ControlStatementTests, Factorial) {
runner->run_static_test(env, testCategory, "factorial-recursive.static.gc", {"3628800\n"});
runner->run_static_test(env, testCategory, "factorial-iterative.static.gc", {"3628800\n"});
runner->run_static_test(testCategory, "factorial-recursive.static.gc", {"3628800\n"});
runner->run_static_test(testCategory, "factorial-iterative.static.gc", {"3628800\n"});
}
TEST_F(ControlStatementTests, Definitions) {
runner->run_static_test(env, testCategory, "defun-return-constant.static.gc", {"12\n"});
runner->run_static_test(env, testCategory, "defun-return-symbol.static.gc", {"42\n"});
runner->run_static_test(testCategory, "defun-return-constant.static.gc", {"12\n"});
runner->run_static_test(testCategory, "defun-return-symbol.static.gc", {"42\n"});
}
TEST_F(ControlStatementTests, ReturnValue) {
runner->run_static_test(env, testCategory, "return.static.gc", {"77\n"});
runner->run_static_test(env, testCategory, "return-arg.static.gc", {"23\n"});
runner->run_static_test(env, testCategory, "return-colors.static.gc", {"77\n"});
runner->run_static_test(testCategory, "return.static.gc", {"77\n"});
runner->run_static_test(testCategory, "return-arg.static.gc", {"23\n"});
runner->run_static_test(testCategory, "return-colors.static.gc", {"77\n"});
}
TEST_F(ControlStatementTests, Calling) {
runner->run_static_test(env, testCategory, "nested-call.static.gc", {"2\n"});
runner->run_static_test(env, testCategory, "simple-call.static.gc", {"30\n"});
runner->run_static_test(testCategory, "nested-call.static.gc", {"2\n"});
runner->run_static_test(testCategory, "simple-call.static.gc", {"30\n"});
}
TEST_F(ControlStatementTests, Anonymous) {
runner->run_static_test(env, testCategory, "lambda-1.static.gc", {"2\n"});
runner->run_static_test(testCategory, "lambda-1.static.gc", {"2\n"});
}
TEST_F(ControlStatementTests, InlineIsInline) {
@ -121,7 +109,7 @@ TEST_F(ControlStatementTests, InlineIsInline) {
}
}
EXPECT_TRUE(got_mult);
runner->run_static_test(env, testCategory, "declare-inline.static.gc", {"32\n"});
runner->run_static_test(testCategory, "declare-inline.static.gc", {"32\n"});
}
TEST_F(ControlStatementTests, AllowInline) {
@ -143,54 +131,54 @@ TEST_F(ControlStatementTests, AllowInline) {
}
EXPECT_EQ(got_mult, 1);
EXPECT_EQ(got_call, 1);
runner->run_static_test(env, testCategory, "inline-call.static.gc", {"44\n"});
runner->run_static_test(testCategory, "inline-call.static.gc", {"44\n"});
}
TEST_F(ControlStatementTests, ReturnNone) {
runner->run_static_test(env, testCategory, "function-returning-none.static.gc", {"1\n"});
runner->run_static_test(testCategory, "function-returning-none.static.gc", {"1\n"});
}
TEST_F(ControlStatementTests, InlineBlock1) {
runner->run_static_test(env, testCategory, "inline-with-block-1.static.gc", {"1\n"});
runner->run_static_test(testCategory, "inline-with-block-1.static.gc", {"1\n"});
}
TEST_F(ControlStatementTests, InlineBlock2) {
runner->run_static_test(env, testCategory, "inline-with-block-2.static.gc", {"3\n"});
runner->run_static_test(testCategory, "inline-with-block-2.static.gc", {"3\n"});
}
TEST_F(ControlStatementTests, InlineBlock3) {
runner->run_static_test(env, testCategory, "inline-with-block-3.static.gc", {"4\n"});
runner->run_static_test(testCategory, "inline-with-block-3.static.gc", {"4\n"});
}
TEST_F(ControlStatementTests, InlineBlock4) {
runner->run_static_test(env, testCategory, "inline-with-block-4.static.gc", {"3.0000\n0\n"});
runner->run_static_test(testCategory, "inline-with-block-4.static.gc", {"3.0000\n0\n"});
}
TEST_F(ControlStatementTests, ReturnFromTrick) {
runner->run_static_test(env, testCategory, "return-from-trick.static.gc", {"1\n"});
runner->run_static_test(testCategory, "return-from-trick.static.gc", {"1\n"});
}
TEST_F(ControlStatementTests, Set) {
runner->run_static_test(env, testCategory, "set-symbol.static.gc", {"22\n"});
runner->run_static_test(testCategory, "set-symbol.static.gc", {"22\n"});
}
TEST_F(ControlStatementTests, Protect) {
runner->run_static_test(env, testCategory, "protect.static.gc", {"33\n"});
runner->run_static_test(testCategory, "protect.static.gc", {"33\n"});
}
TEST_F(ControlStatementTests, Align) {
runner->run_static_test(env, testCategory, "align16-1.static.gc", {"80\n"});
runner->run_static_test(env, testCategory, "align16-2.static.gc", {"64\n"});
runner->run_static_test(testCategory, "align16-1.static.gc", {"80\n"});
runner->run_static_test(testCategory, "align16-2.static.gc", {"64\n"});
}
TEST_F(ControlStatementTests, Defsmacro) {
runner->run_static_test(env, testCategory, "defsmacro-defgmacro.static.gc", {"20\n"});
runner->run_static_test(testCategory, "defsmacro-defgmacro.static.gc", {"20\n"});
}
TEST_F(ControlStatementTests, Desfun) {
runner->run_static_test(env, testCategory, "desfun.static.gc", {"4\n"});
runner->run_static_test(testCategory, "desfun.static.gc", {"4\n"});
}
TEST_F(ControlStatementTests, DeReference) {
runner->run_static_test(env, testCategory, "methods.static.gc", {"#t#t\n0\n"});
runner->run_static_test(testCategory, "methods.static.gc", {"#t#t\n0\n"});
}

View file

@ -1,5 +1,4 @@
#include "common/log/log.h"
#include "common/util/Timer.h"
#include "goalc/compiler/Compiler.h"
#include "gtest/gtest.h"
@ -38,7 +37,7 @@ TEST(Jak1Debugger, DebuggerBasicConnect) {
// evidently you can't ptrace threads in your own process, so we need to run the runtime in a
// separate process.
if (!fork()) {
GoalTest::runtime_no_kernel();
GoalTest::runtime_no_kernel_jak1();
exit(0);
} else {
connect_compiler_and_debugger(compiler, true);
@ -55,7 +54,7 @@ TEST(Jak1Debugger, DebuggerBreakAndContinue) {
// evidently you can't ptrace threads in your own process, so we need to run the runtime in a
// separate process.
if (!fork()) {
GoalTest::runtime_no_kernel();
GoalTest::runtime_no_kernel_jak1();
exit(0);
} else {
connect_compiler_and_debugger(compiler, true);
@ -77,7 +76,7 @@ TEST(Jak1Debugger, DebuggerReadMemory) {
// evidently you can't ptrace threads in your own process, so we need to run the runtime in a
// separate process.
if (!fork()) {
GoalTest::runtime_no_kernel();
GoalTest::runtime_no_kernel_jak1();
exit(0);
} else {
connect_compiler_and_debugger(compiler, true);
@ -101,7 +100,7 @@ TEST(Jak1Debugger, DebuggerWriteMemory) {
// evidently you can't ptrace threads in your own process, so we need to run the runtime in a
// separate process.
if (!fork()) {
GoalTest::runtime_no_kernel();
GoalTest::runtime_no_kernel_jak1();
exit(0);
} else {
connect_compiler_and_debugger(compiler, true);
@ -132,7 +131,7 @@ TEST(Jak1Debugger, Symbol) {
// evidently you can't ptrace threads in your own process, so we need to run the runtime in a
// separate process.
if (!fork()) {
GoalTest::runtime_no_kernel();
GoalTest::runtime_no_kernel_jak1();
exit(0);
} else {
connect_compiler_and_debugger(compiler, true);
@ -162,7 +161,7 @@ TEST(Jak1Debugger, SimpleBreakpoint) {
Compiler compiler(GameVersion::Jak1);
if (!fork()) {
GoalTest::runtime_no_kernel();
GoalTest::runtime_no_kernel_jak1();
exit(0);
} else {
connect_compiler_and_debugger(compiler, false);

View file

@ -19,7 +19,7 @@ class Jak1KernelTest : public testing::Test {
}
printf("Starting GOAL Kernel...\n");
shared_compiler->runtime_thread = std::thread(GoalTest::runtime_with_kernel);
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("(set! *use-old-listener-print* #t)");
}

View file

@ -0,0 +1,151 @@
#include <memory>
#include <thread>
#include "goalc/compiler/Compiler.h"
#include "gtest/gtest.h"
#include "test/goalc/framework/test_runner.h"
class Jak2KernelTest : public testing::Test {
public:
static void SetUpTestSuite() {
shared_compiler = std::make_unique<SharedCompiler>(GameVersion::Jak2);
printf("Building kernel...\n");
try {
// a macro in goal-lib.gc
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);
}
printf("Starting GOAL Kernel...\n");
shared_compiler->runtime_thread = std::thread(GoalTest::runtime_with_kernel_jak2);
shared_compiler->runner.c = &shared_compiler->compiler;
shared_compiler->compiler.run_test_from_string("(set! *use-old-listener-print* #t)");
}
static void TearDownTestSuite() {
// send message to shutdown
shared_compiler->compiler.shutdown_target();
// wait for shutdown.
shared_compiler->runtime_thread.join();
shared_compiler.reset();
}
void SetUp() {}
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::unique_ptr<Jak2KernelTest::SharedCompiler> Jak2KernelTest::shared_compiler;
namespace {
std::string send_code_and_get_multiple_responses(const std::string& code,
int n_responses,
GoalTest::CompilerTestRunner* runner) {
auto& listener = runner->c->listener();
// record all print messages
listener.record_messages(ListenerMessageKind::MSG_PRINT);
// run the test.
runner->c->compile_and_send_from_string(code);
std::string result;
while (listener.get_received_message_count() < n_responses) {
std::this_thread::sleep_for(std::chrono::microseconds(1000));
}
auto messages = listener.stop_recording_messages();
for (auto& m : messages) {
result += m;
}
return result;
}
} // namespace
TEST_F(Jak2KernelTest, Basic) {
shared_compiler->runner.c->run_test_from_string(
"(ml \"test/goalc/source_templates/jak2/kernel-test.gc\")");
std::string result =
send_code_and_get_multiple_responses("(kernel-test)", 10, &shared_compiler->runner);
std::string expected =
"0\n"
"proc2: 0\n"
"TARGET FUNCTION 1 2 3\n"
"4 5 6\n"
"Stack Alignemnt 0/16\n"
"proc1: 0\n"
"proc2: 6\n"
"proc1: 1\n"
"proc2: 12\n"
"proc1: 2\n"
"proc2: 18\n"
"proc1: 3\n"
"proc2: 24\n"
"proc1: 4\n"
"proc2: 30\n"
"proc1: 5\n"
"DEACTIVATE PROC 1\n"
"proc2: 36\n"
"proc2: 42\n"
"proc2: 48\n"
"proc2: 54\n";
EXPECT_EQ(expected, result);
}
TEST_F(Jak2KernelTest, RunFunctionInProcess) {
shared_compiler->runner.c->run_test_from_string(
"(ml \"test/goalc/source_templates/jak2/kernel-test.gc\")");
std::string result =
send_code_and_get_multiple_responses("(kernel-test-2)", 1, &shared_compiler->runner);
std::string expected =
"0\n"
"Args: 1 2 3\n"
"4 5 6\n"
"Stack Alignemnt 0/16\n"
"run-function-in-process result: init-child-proc-result\n"
"Args: 0 2 3\n"
"4 5 6\n"
"Stack Alignemnt 0/16\n"
"run-function-in-process result: #f\n";
EXPECT_EQ(expected, result);
}
TEST_F(Jak2KernelTest, StateAndXmm) {
shared_compiler->runner.c->run_test_from_string(
"(ml \"test/goalc/source_templates/jak2/kernel-test.gc\")");
std::string result =
send_code_and_get_multiple_responses("(state-test)", 5, &shared_compiler->runner);
std::string expected =
"0\nenter wreck: 3 4 5 6\nwreck: 3 4 5 6\nenter check: 9 8 7 6\nrun xmm-check 12.3400 "
"45.6300 9 8 7 6\nwreck: 3 4 5 6\nrun xmm-check 12.3400 45.6300 9 8 7 6\nwreck: 3 4 5 6\nrun "
"xmm-check 12.3400 45.6300 9 8 7 6\nwreck: 3 4 5 6\nexit check\nenter die\ntime to "
"die!\nexit die\nexit wreck\nenter die\ntime to die!\nexit die\n";
EXPECT_EQ(expected, result);
}
TEST_F(Jak2KernelTest, ThrowXmm) {
shared_compiler->runner.c->run_test_from_string(
"(ml \"test/goalc/source_templates/jak2/kernel-test.gc\")");
std::string result =
send_code_and_get_multiple_responses("(throw-backup-test)", 1, &shared_compiler->runner);
std::string expected =
"value now is 10.1000\n"
"now its 10.1000\n"
"0\n";
EXPECT_EQ(expected, result);
}

View file

@ -0,0 +1,55 @@
#include "gtest/gtest.h"
#include "test/goalc/framework/test_runner.h"
// Tests for Jak 2's compiler/runtime, without game-specific code (ENGINE/GAME)
struct Jak2Param {
// TODO - Not Needed Yet
};
class Jak2GoalcTests : public testing::TestWithParam<Jak2Param> {
public:
static void SetUpTestSuite() {
runtime_thread = std::make_unique<std::thread>(std::thread(GoalTest::runtime_no_kernel_jak2));
compiler = std::make_unique<Compiler>(GameVersion::Jak2);
runner = std::make_unique<GoalTest::CompilerTestRunner>();
runner->c = compiler.get();
}
static void TearDownTestSuite() {
compiler->shutdown_target();
runtime_thread->join();
runtime_thread.reset();
compiler.reset();
runner.reset();
}
void SetUp() {
GoalTest::createDirIfAbsent(GoalTest::getTemplateDir(testCategory));
GoalTest::createDirIfAbsent(GoalTest::getGeneratedDir(testCategory));
}
void TearDown() {}
static std::unique_ptr<std::thread> runtime_thread;
static std::unique_ptr<Compiler> compiler;
static std::unique_ptr<GoalTest::CompilerTestRunner> runner;
std::string testCategory = "jak2";
};
std::unique_ptr<std::thread> Jak2GoalcTests::runtime_thread;
std::unique_ptr<Compiler> Jak2GoalcTests::compiler;
std::unique_ptr<GoalTest::CompilerTestRunner> Jak2GoalcTests::runner;
TEST_F(Jak2GoalcTests, All) {
runner->run_static_test(testCategory, "jak2-mega-test.gc",
{"empty pair: () () () #t #f\n"
"empty pair type: pair\n"
"non-empty pair: (a b -12) a pair (a . b)\n"
"basic types: type symbol string function\n"
"bools: #t #f #t #f #f #t\n"
"zero: 0\n"
"parent of type: basic structure object object\n0\n"});
}

View file

@ -0,0 +1,34 @@
#include "goalc/compiler/Compiler.h"
#include "gtest/gtest.h"
void add_expected_type_mismatches(Compiler& c) {
c.add_ignored_define_extern_symbol("draw-drawable-tree-tfrag");
c.add_ignored_define_extern_symbol("draw-drawable-tree-trans-tfrag");
c.add_ignored_define_extern_symbol("draw-drawable-tree-dirt-tfrag");
c.add_ignored_define_extern_symbol("draw-drawable-tree-ice-tfrag");
c.add_ignored_define_extern_symbol("tfrag-init-buffer");
}
TEST(Jak1TypeConsistency, MANUAL_TEST_TypeConsistencyWithBuildFirst) {
Compiler compiler(GameVersion::Jak1);
compiler.enable_throw_on_redefines();
add_expected_type_mismatches(compiler);
compiler.run_test_no_load("test/goalc/source_templates/with_game/test-build-all-code.gc");
compiler.run_test_no_load("decompiler/config/all-types.gc");
}
TEST(Jak1TypeConsistency, TypeConsistency) {
Compiler compiler(GameVersion::Jak1);
compiler.enable_throw_on_redefines();
add_expected_type_mismatches(compiler);
compiler.run_test_no_load("decompiler/config/all-types.gc");
compiler.run_test_no_load("test/goalc/source_templates/with_game/test-build-all-code.gc");
}
TEST(Jak2TypeConsistency, TypeConsistency) {
Compiler compiler(GameVersion::Jak2);
compiler.enable_throw_on_redefines();
add_expected_type_mismatches(compiler);
compiler.run_test_no_load("decompiler/config/jak2/all-types.gc");
compiler.run_test_no_load("test/goalc/source_templates/with_game/test-build-all-code.gc");
}

View file

@ -1,21 +1,11 @@
#include <chrono>
#include <cstdio>
#include <iostream>
#include <random>
#include <sstream>
#include <string>
#include <thread>
#include "inja.hpp"
#include "game/runtime.h"
#include "goalc/compiler/Compiler.h"
#include "goalc/listener/Listener.h"
#include "gtest/gtest.h"
#include "test/goalc/framework/test_runner.h"
#include "third-party/json.hpp"
struct VariableParam {
// TODO - Not Needed Yet
};
@ -24,7 +14,7 @@ class VariableTests : public testing::TestWithParam<VariableParam> {
public:
static void SetUpTestSuite() {
shared_compiler = std::make_unique<SharedCompiler>(GameVersion::Jak1);
shared_compiler->runtime_thread = std::thread((GoalTest::runtime_no_kernel));
shared_compiler->runtime_thread = std::thread(GoalTest::runtime_no_kernel_jak1);
shared_compiler->runner.c = &shared_compiler->compiler;
}
@ -51,91 +41,85 @@ class VariableTests : public testing::TestWithParam<VariableParam> {
static std::unique_ptr<SharedCompiler> shared_compiler;
std::string testCategory = "variables";
inja::Environment env{GoalTest::getTemplateDir(testCategory),
GoalTest::getGeneratedDir(testCategory)};
};
std::unique_ptr<VariableTests::SharedCompiler> VariableTests::shared_compiler;
TEST_F(VariableTests, Globals) {
shared_compiler->runner.run_static_test(env, testCategory, "defglobalconstant-1.static.gc",
{"17\n"});
shared_compiler->runner.run_static_test(env, testCategory, "defglobalconstant-2.static.gc",
{"18\n"});
shared_compiler->runner.run_static_test(testCategory, "defglobalconstant-1.static.gc", {"17\n"});
shared_compiler->runner.run_static_test(testCategory, "defglobalconstant-2.static.gc", {"18\n"});
}
TEST_F(VariableTests, Definitions) {
shared_compiler->runner.run_static_test(env, testCategory, "define.static.gc", {"17\n"});
shared_compiler->runner.run_static_test(testCategory, "define.static.gc", {"17\n"});
}
TEST_F(VariableTests, Let) {
shared_compiler->runner.run_static_test(env, testCategory, "let.static.gc", {"30\n"});
shared_compiler->runner.run_static_test(env, testCategory, "let-star.static.gc", {"30\n"});
shared_compiler->runner.run_static_test(env, testCategory, "mlet.static.gc", {"10\n"});
shared_compiler->runner.run_static_test(testCategory, "let.static.gc", {"30\n"});
shared_compiler->runner.run_static_test(testCategory, "let-star.static.gc", {"30\n"});
shared_compiler->runner.run_static_test(testCategory, "mlet.static.gc", {"10\n"});
}
TEST_F(VariableTests, StackVars) {
shared_compiler->runner.run_static_test(env, testCategory, "stack-ints.gc", {"12\n"});
shared_compiler->runner.run_static_test(env, testCategory, "stack-ints-2.gc", {"1\n"});
shared_compiler->runner.run_static_test(testCategory, "stack-ints.gc", {"12\n"});
shared_compiler->runner.run_static_test(testCategory, "stack-ints-2.gc", {"1\n"});
}
TEST_F(VariableTests, Bitfields) {
shared_compiler->runner.run_static_test(env, testCategory, "bitfield-enums.gc", {"5\n"});
shared_compiler->runner.run_static_test(env, testCategory, "integer-enums.gc", {"11\n"});
shared_compiler->runner.run_static_test(testCategory, "bitfield-enums.gc", {"5\n"});
shared_compiler->runner.run_static_test(testCategory, "integer-enums.gc", {"11\n"});
}
TEST_F(VariableTests, InlineAsm) {
shared_compiler->runner.run_static_test(env, testCategory, "inline-asm.static.gc", {"1\n"});
shared_compiler->runner.run_static_test(testCategory, "inline-asm.static.gc", {"1\n"});
}
TEST_F(VariableTests, StaticBitfieldField) {
shared_compiler->runner.run_static_test(env, testCategory, "static-bitfield-field.gc", {"22\n"});
shared_compiler->runner.run_static_test(testCategory, "static-bitfield-field.gc", {"22\n"});
}
TEST_F(VariableTests, StackArrayAlignment) {
shared_compiler->runner.run_static_test(env, testCategory, "stack-array-align.gc", {"3\n"});
shared_compiler->runner.run_static_test(testCategory, "stack-array-align.gc", {"3\n"});
}
TEST_F(VariableTests, StackStructureAlignment) {
shared_compiler->runner.run_static_test(env, testCategory, "stack-structure-align.gc",
{"1234\n"});
shared_compiler->runner.run_static_test(testCategory, "stack-structure-align.gc", {"1234\n"});
}
TEST_F(VariableTests, GetSymbol) {
shared_compiler->runner.run_static_test(env, testCategory, "get-symbol-1.static.gc",
shared_compiler->runner.run_static_test(testCategory, "get-symbol-1.static.gc",
{"1375524\n"}); // 0x14fd24 in hex
shared_compiler->runner.run_static_test(env, testCategory, "get-symbol-2.static.gc",
shared_compiler->runner.run_static_test(testCategory, "get-symbol-2.static.gc",
{"1375532\n"}); // 0x14fd2c in hex
}
TEST_F(VariableTests, Constants) {
// TODO - shared_compiler->runner.run_static_test(env, testCategory,
// TODO - shared_compiler->runner.run_static_test(testCategory,
// "string-constant-1.static.gc");
std::string expected = "\"test string!\"";
shared_compiler->runner.run_static_test(env, testCategory, "string-constant-2.static.gc",
{expected}, expected.size());
shared_compiler->runner.run_static_test(testCategory, "string-constant-2.static.gc", {expected},
expected.size());
}
TEST_F(VariableTests, Symbols) {
shared_compiler->runner.run_static_test(env, testCategory, "quote-symbol.static.gc",
{"banana\n0\n"});
shared_compiler->runner.run_static_test(testCategory, "quote-symbol.static.gc", {"banana\n0\n"});
std::string expected = "test-string";
shared_compiler->runner.run_static_test(env, testCategory, "string-symbol.static.gc", {expected},
shared_compiler->runner.run_static_test(testCategory, "string-symbol.static.gc", {expected},
expected.size());
}
TEST_F(VariableTests, Formatting) {
shared_compiler->runner.run_static_test(env, testCategory, "format-reg-order.static.gc",
shared_compiler->runner.run_static_test(testCategory, "format-reg-order.static.gc",
{"test 1 2 3 4 5 6\n0\n"});
}
TEST_F(VariableTests, DeReference) {
shared_compiler->runner.run_static_test(env, testCategory, "deref-simple.static.gc",
shared_compiler->runner.run_static_test(testCategory, "deref-simple.static.gc",
{"structure\n0\n"});
}
TEST_F(VariableTests, Pointers) {
shared_compiler->runner.run_static_test(env, testCategory, "pointers.static.gc", {"13\n"});
shared_compiler->runner.run_static_test(testCategory, "pointers.static.gc", {"13\n"});
}
// expected =

View file

@ -0,0 +1,584 @@
#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()));

File diff suppressed because it is too large Load diff

View file

@ -22,9 +22,17 @@
#ifndef _XDELTA3_H_
#define _XDELTA3_H_
#ifndef _POSIX_SOURCE
#define _POSIX_SOURCE 200112L
#endif
#ifndef _ISOC99_SOURCE
#define _ISOC99_SOURCE
#endif
#ifndef _C99_SOURCE
#define _C99_SOURCE
#endif
#if HAVE_CONFIG_H
#include "config.h"