From e9567a6e4b08330e2fe6b25bce8fcc4353be553f Mon Sep 17 00:00:00 2001 From: water111 <48171810+water111@users.noreply.github.com> Date: Sun, 17 Jul 2022 14:12:11 -0400 Subject: [PATCH] Cleanup goalc tests, fix jak2 kernel bugs (#1669) * Cleanup goalc tests, fix jak2 kernel bugs * fix warnings on linux * spelling is hard --- decompiler/config/jak2/all-types.gc | 20 +- game/graphics/pipelines/opengl.cpp | 4 - game/kernel/jak1/kscheme.cpp | 4 +- game/mips2c/functions/collide_cache.cpp | 14 - game/mips2c/functions/collide_edge_grab.cpp | 17 +- goal_src/jak2/kernel/gkernel-h.gc | 16 +- goalc/build_level/collide_bvh.cpp | 59 -- test/goalc/CMakeLists.txt | 14 +- test/goalc/all_goalc_template_tests.cpp | 6 - test/goalc/framework/test_runner.cpp | 23 +- test/goalc/framework/test_runner.h | 20 +- .../source_templates/jak2/kernel-test.gc | 227 +++++ test/goalc/test_arithmetic.cpp | 3 +- test/goalc/test_collections.cpp | 30 +- test/goalc/test_compiler.cpp | 58 -- test/goalc/test_control_statements.cpp | 78 +- test/goalc/test_debugger.cpp | 13 +- test/goalc/test_goal_kernel.cpp | 2 +- test/goalc/test_goal_kernel2.cpp | 151 ++++ test/goalc/test_jak2_compiler.cpp | 55 ++ test/goalc/test_type_consistency.cpp | 34 + test/goalc/test_variables.cpp | 66 +- test/goalc/test_vector_float.cpp | 584 +++++++++++++ test/goalc/test_with_game.cpp | 826 +++--------------- third-party/xdelta3/xdelta3/xdelta3.h | 8 + 25 files changed, 1312 insertions(+), 1020 deletions(-) delete mode 100644 test/goalc/all_goalc_template_tests.cpp create mode 100644 test/goalc/source_templates/jak2/kernel-test.gc create mode 100644 test/goalc/test_goal_kernel2.cpp create mode 100644 test/goalc/test_jak2_compiler.cpp create mode 100644 test/goalc/test_type_consistency.cpp create mode 100644 test/goalc/test_vector_float.cpp diff --git a/decompiler/config/jak2/all-types.gc b/decompiler/config/jak2/all-types.gc index 44e5221e3..eee31c6a0 100644 --- a/decompiler/config/jak2/all-types.gc +++ b/decompiler/config/jak2/all-types.gc @@ -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 ) diff --git a/game/graphics/pipelines/opengl.cpp b/game/graphics/pipelines/opengl.cpp index f31cb4432..7f7f07d88 100644 --- a/game/graphics/pipelines/opengl.cpp +++ b/game/graphics/pipelines/opengl.cpp @@ -112,10 +112,6 @@ bool HasError() { } } -void FocusCallback(GLFWwindow* window, int focused) { - glfwSetWindowAttrib(window, GLFW_FLOATING, focused); -} - } // namespace static bool gl_inited = false; diff --git a/game/kernel/jak1/kscheme.cpp b/game/kernel/jak1/kscheme.cpp index aac69cb74..51c8607cd 100644 --- a/game/kernel/jak1/kscheme.cpp +++ b/game/kernel/jak1/kscheme.cpp @@ -1038,14 +1038,14 @@ u64 call_method_of_type(u64 arg, Ptr 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>(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); } } diff --git a/game/mips2c/functions/collide_cache.cpp b/game/mips2c/functions/collide_cache.cpp index 923cf987d..f489aac1d 100644 --- a/game/mips2c/functions/collide_cache.cpp +++ b/game/mips2c/functions/collide_cache.cpp @@ -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 diff --git a/game/mips2c/functions/collide_edge_grab.cpp b/game/mips2c/functions/collide_edge_grab.cpp index a52f46211..5f7a61d18 100644 --- a/game/mips2c/functions/collide_edge_grab.cpp +++ b/game/mips2c/functions/collide_edge_grab.cpp @@ -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 \ No newline at end of file diff --git a/goal_src/jak2/kernel/gkernel-h.gc b/goal_src/jak2/kernel/gkernel-h.gc index 328f815ca..c7d27d359 100644 --- a/goal_src/jak2/kernel/gkernel-h.gc +++ b/goal_src/jak2/kernel/gkernel-h.gc @@ -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) + ) ) \ No newline at end of file diff --git a/goalc/build_level/collide_bvh.cpp b/goalc/build_level/collide_bvh.cpp index 719d12a34..049fb2c63 100644 --- a/goalc/build_level/collide_bvh.cpp +++ b/goalc/build_level/collide_bvh.cpp @@ -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::max()); - bbox.maxs.fill(-std::numeric_limits::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& 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 diff --git a/test/goalc/CMakeLists.txt b/test/goalc/CMakeLists.txt index d146e4148..1adf702fd 100644 --- a/test/goalc/CMakeLists.txt +++ b/test/goalc/CMakeLists.txt @@ -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 diff --git a/test/goalc/all_goalc_template_tests.cpp b/test/goalc/all_goalc_template_tests.cpp deleted file mode 100644 index 80cab9919..000000000 --- a/test/goalc/all_goalc_template_tests.cpp +++ /dev/null @@ -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" diff --git a/test/goalc/framework/test_runner.cpp b/test/goalc/framework/test_runner.cpp index 835f34374..4429e7fad 100644 --- a/test/goalc/framework/test_runner.cpp +++ b/test/goalc/framework/test_runner.cpp @@ -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& expected, + std::optional 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& 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(argv)); @@ -111,12 +119,18 @@ void runtime_no_kernel_jak2() { exec_runtime(argc, const_cast(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(argv)); } +void runtime_with_kernel_jak2() { + constexpr int argc = 6; + const char* argv[argc] = {"", "-fakeiso", "-debug", "-nodisplay", "-nosound", "-jak2"}; + exec_runtime(argc, const_cast(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 diff --git a/test/goalc/framework/test_runner.h b/test/goalc/framework/test_runner.h index d86c1640a..b274d660e 100644 --- a/test/goalc/framework/test_runner.h +++ b/test/goalc/framework/test_runner.h @@ -4,10 +4,12 @@ #include #include -#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& expected, std::optional truncate = {}); + void run_static_test(std::string& testCategory, + const std::string& test_file, + const std::vector& expected, + std::optional truncate = {}); + void run_test(const std::string& test_category, const std::string& test_file, const std::vector& expected, std::optional 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 diff --git a/test/goalc/source_templates/jak2/kernel-test.gc b/test/goalc/source_templates/jak2/kernel-test.gc new file mode 100644 index 000000000..a5c7880aa --- /dev/null +++ b/test/goalc/source_templates/jak2/kernel-test.gc @@ -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) + + ) + ) + ) diff --git a/test/goalc/test_arithmetic.cpp b/test/goalc/test_arithmetic.cpp index 450009aed..80143c833 100644 --- a/test/goalc/test_arithmetic.cpp +++ b/test/goalc/test_arithmetic.cpp @@ -1,7 +1,6 @@ // https://github.com/google/googletest/blob/master/googletest/docs/advanced.md#value-parameterized-tests #include -#include #include #include #include @@ -119,7 +118,7 @@ class ArithmeticTests : public testing::TestWithParam { // Per-test-suite set-up. // Called before the first test in this test suite. static void SetUpTestSuite() { - runtime_thread = std::make_unique(std::thread((GoalTest::runtime_no_kernel))); + runtime_thread = std::make_unique(std::thread(GoalTest::runtime_no_kernel_jak1)); compiler = std::make_unique(GameVersion::Jak1); runner = std::make_unique(); runner->c = compiler.get(); diff --git a/test/goalc/test_collections.cpp b/test/goalc/test_collections.cpp index 887eb498a..dca4e3cdc 100644 --- a/test/goalc/test_collections.cpp +++ b/test/goalc/test_collections.cpp @@ -1,21 +1,11 @@ -#include -#include -#include -#include -#include #include #include -#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 { public: static void SetUpTestSuite() { - runtime_thread = std::make_unique(std::thread((GoalTest::runtime_no_kernel))); + runtime_thread = std::make_unique(std::thread(GoalTest::runtime_no_kernel_jak1)); compiler = std::make_unique(GameVersion::Jak1); runner = std::make_unique(); runner->c = compiler.get(); @@ -50,8 +40,6 @@ class CollectionTests : public testing::TestWithParam { static std::unique_ptr runner; std::string testCategory = "collections"; - inja::Environment env{GoalTest::getTemplateDir(testCategory), - GoalTest::getGeneratedDir(testCategory)}; }; std::unique_ptr CollectionTests::runtime_thread; @@ -59,22 +47,22 @@ std::unique_ptr CollectionTests::compiler; std::unique_ptr 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"}); } diff --git a/test/goalc/test_compiler.cpp b/test/goalc/test_compiler.cpp index 1b72d1f8b..de23e731e 100644 --- a/test/goalc/test_compiler.cpp +++ b/test/goalc/test_compiler.cpp @@ -1,65 +1,7 @@ -#include -#include - -#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 { - public: - static void SetUpTestSuite() { - runtime_thread = std::make_unique(std::thread((GoalTest::runtime_no_kernel_jak2))); - compiler = std::make_unique(GameVersion::Jak2); - runner = std::make_unique(); - 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 runtime_thread; - static std::unique_ptr compiler; - static std::unique_ptr runner; - - std::string testCategory = "jak2"; - inja::Environment env{GoalTest::getTemplateDir(testCategory), - GoalTest::getGeneratedDir(testCategory)}; -}; - -std::unique_ptr Jak2GoalcTests::runtime_thread; -std::unique_ptr Jak2GoalcTests::compiler; -std::unique_ptr 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"}); -} \ No newline at end of file diff --git a/test/goalc/test_control_statements.cpp b/test/goalc/test_control_statements.cpp index 72d8071fb..6c44357cc 100644 --- a/test/goalc/test_control_statements.cpp +++ b/test/goalc/test_control_statements.cpp @@ -1,21 +1,11 @@ -#include -#include -#include -#include -#include #include #include -#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 { public: static void SetUpTestSuite() { - runtime_thread = std::make_unique(std::thread((GoalTest::runtime_no_kernel))); + runtime_thread = std::make_unique(std::thread(GoalTest::runtime_no_kernel_jak1)); compiler = std::make_unique(GameVersion::Jak1); runner = std::make_unique(); runner->c = compiler.get(); @@ -50,8 +40,6 @@ class ControlStatementTests : public testing::TestWithParam runner; std::string testCategory = "control-statements"; - inja::Environment env{GoalTest::getTemplateDir(testCategory), - GoalTest::getGeneratedDir(testCategory)}; }; std::unique_ptr ControlStatementTests::runtime_thread; @@ -59,50 +47,50 @@ std::unique_ptr ControlStatementTests::compiler; std::unique_ptr 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"}); } diff --git a/test/goalc/test_debugger.cpp b/test/goalc/test_debugger.cpp index 270773be8..dbce885a9 100644 --- a/test/goalc/test_debugger.cpp +++ b/test/goalc/test_debugger.cpp @@ -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); diff --git a/test/goalc/test_goal_kernel.cpp b/test/goalc/test_goal_kernel.cpp index 6796b7bbb..2a02f8b82 100644 --- a/test/goalc/test_goal_kernel.cpp +++ b/test/goalc/test_goal_kernel.cpp @@ -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)"); } diff --git a/test/goalc/test_goal_kernel2.cpp b/test/goalc/test_goal_kernel2.cpp new file mode 100644 index 000000000..fd237d2b7 --- /dev/null +++ b/test/goalc/test_goal_kernel2.cpp @@ -0,0 +1,151 @@ + +#include +#include + +#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(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 shared_compiler; +}; + +std::unique_ptr 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); +} diff --git a/test/goalc/test_jak2_compiler.cpp b/test/goalc/test_jak2_compiler.cpp new file mode 100644 index 000000000..3359bfd53 --- /dev/null +++ b/test/goalc/test_jak2_compiler.cpp @@ -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 { + public: + static void SetUpTestSuite() { + runtime_thread = std::make_unique(std::thread(GoalTest::runtime_no_kernel_jak2)); + compiler = std::make_unique(GameVersion::Jak2); + runner = std::make_unique(); + 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 runtime_thread; + static std::unique_ptr compiler; + static std::unique_ptr runner; + + std::string testCategory = "jak2"; +}; + +std::unique_ptr Jak2GoalcTests::runtime_thread; +std::unique_ptr Jak2GoalcTests::compiler; +std::unique_ptr 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"}); +} \ No newline at end of file diff --git a/test/goalc/test_type_consistency.cpp b/test/goalc/test_type_consistency.cpp new file mode 100644 index 000000000..85565989a --- /dev/null +++ b/test/goalc/test_type_consistency.cpp @@ -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"); +} \ No newline at end of file diff --git a/test/goalc/test_variables.cpp b/test/goalc/test_variables.cpp index 420a2e2a4..a0c312f95 100644 --- a/test/goalc/test_variables.cpp +++ b/test/goalc/test_variables.cpp @@ -1,21 +1,11 @@ -#include -#include -#include -#include -#include #include #include -#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 { public: static void SetUpTestSuite() { shared_compiler = std::make_unique(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 { static std::unique_ptr shared_compiler; std::string testCategory = "variables"; - inja::Environment env{GoalTest::getTemplateDir(testCategory), - GoalTest::getGeneratedDir(testCategory)}; }; std::unique_ptr 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 = diff --git a/test/goalc/test_vector_float.cpp b/test/goalc/test_vector_float.cpp new file mode 100644 index 000000000..1df45c980 --- /dev/null +++ b/test/goalc/test_vector_float.cpp @@ -0,0 +1,584 @@ +#include +#include +#include +#include + +#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(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 shared_compiler; + + std::string testCategory = "with_game"; + inja::Environment env{GoalTest::getTemplateDir(testCategory), + GoalTest::getGeneratedDir(testCategory)}; +}; + +std::unique_ptr 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 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 vectorMathCaseGen_TwoOperand() { + std::vector 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(j); + cases.push_back(testCaseBC); + } + } + return cases; +} + +class VectorFloatParameterizedTestFixtureWithRunner_TwoOperand + : public WithMinimalGameTests, + public ::testing::WithParamInterface { + 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 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 vectorMathCaseGen_SingleOperand_NoBroadcast() { + std::vector 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 { + 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 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 vectorMathCaseGen_TwoOperandACC() { + std::vector 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(j); + cases.push_back(testCaseBC); + } + } + return cases; +} + +class VectorFloatParameterizedTestFixtureWithRunner_TwoOperandACC + : public WithMinimalGameTests, + public ::testing::WithParamInterface { + 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 operation; + + VectorFloatRegister getExpectedResult() { + float operand1 = + input1.getBroadcastElement(static_cast(fsf), input1.x); + float operand2 = + input2.getBroadcastElement(static_cast(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 vectorMathCaseGen_TwoOperandQuotient() { + std::vector 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 { + 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 operation; + + VectorFloatRegister getExpectedResult() { + float operand1 = + input1.getBroadcastElement(static_cast(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 vectorMathCaseGen_OneOperandQuotient() { + std::vector 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 { + 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())); diff --git a/test/goalc/test_with_game.cpp b/test/goalc/test_with_game.cpp index 1f47f885d..18b121835 100644 --- a/test/goalc/test_with_game.cpp +++ b/test/goalc/test_with_game.cpp @@ -1,14 +1,8 @@ -#include #include -#include #include -#include -#include #include #include -#include "inja.hpp" - #include "common/util/FileUtil.h" #include "game/mips2c/mips2c_table.h" @@ -19,7 +13,6 @@ #include "test/goalc/framework/test_runner.h" #include "third-party/fmt/core.h" -#include "third-party/json.hpp" class WithGameTests : public ::testing::Test { public: @@ -34,7 +27,7 @@ class WithGameTests : public ::testing::Test { fprintf(stderr, "caught exception %s\n", e.what()); EXPECT_TRUE(false); } - 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_file( @@ -65,66 +58,10 @@ class WithGameTests : public ::testing::Test { static std::unique_ptr shared_compiler; std::string testCategory = "with_game"; - inja::Environment env{GoalTest::getTemplateDir(testCategory), - GoalTest::getGeneratedDir(testCategory)}; }; std::unique_ptr WithGameTests::shared_compiler; -class WithMinimalGameTests : public ::testing::Test { - public: - static void SetUpTestSuite() { - shared_compiler = std::make_unique(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)); - 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 shared_compiler; - - std::string testCategory = "with_game"; - inja::Environment env{GoalTest::getTemplateDir(testCategory), - GoalTest::getGeneratedDir(testCategory)}; -}; - -std::unique_ptr WithMinimalGameTests::shared_compiler; - namespace { std::vector get_test_pass_string(const std::string& name, int count) { return {fmt::format("Test \"{}\": {} Passes\n0\n", name, count)}; @@ -136,212 +73,207 @@ TEST_F(WithGameTests, MakeSystem) { } TEST_F(WithGameTests, ReturnConstant) { - shared_compiler->runner.run_static_test(env, testCategory, "defun-return-constant.static.gc", + shared_compiler->runner.run_static_test(testCategory, "defun-return-constant.static.gc", {"12\n"}); } TEST_F(WithGameTests, ReturnSymbol) { - shared_compiler->runner.run_static_test(env, testCategory, "defun-return-symbol.static.gc", - {"42\n"}); + shared_compiler->runner.run_static_test(testCategory, "defun-return-symbol.static.gc", {"42\n"}); } TEST_F(WithGameTests, MinMax) { - shared_compiler->runner.run_static_test(env, testCategory, "test-min-max.gc", {"10\n"}); + shared_compiler->runner.run_static_test(testCategory, "test-min-max.gc", {"10\n"}); } TEST_F(WithGameTests, BoxedFloat) { - shared_compiler->runner.run_static_test(env, testCategory, "test-bfloat.gc", + shared_compiler->runner.run_static_test(testCategory, "test-bfloat.gc", {"data 1.2330 print 1.2330 type bfloat\n0\n"}); } TEST_F(WithGameTests, BasicTypeCheck) { - shared_compiler->runner.run_static_test(env, testCategory, "test-basic-type-check.gc", + shared_compiler->runner.run_static_test(testCategory, "test-basic-type-check.gc", {"#f#t#t#f#t#f#t#t\n0\n"}); } TEST_F(WithGameTests, ConditionBoolean) { - shared_compiler->runner.run_static_test(env, testCategory, "test-condition-boolean.gc", {"4\n"}); + shared_compiler->runner.run_static_test(testCategory, "test-condition-boolean.gc", {"4\n"}); } TEST_F(WithGameTests, TypeType) { - shared_compiler->runner.run_static_test(env, testCategory, "test-type-type.gc", {"#t#f\n0\n"}); + shared_compiler->runner.run_static_test(testCategory, "test-type-type.gc", {"#t#f\n0\n"}); } TEST_F(WithGameTests, AccessInlineArray) { - shared_compiler->runner.run_static_test(env, testCategory, "test-access-inline-array.gc", + shared_compiler->runner.run_static_test(testCategory, "test-access-inline-array.gc", {"1.2345\n0\n"}); } TEST_F(WithGameTests, FindParentMethod) { - shared_compiler->runner.run_static_test(env, testCategory, "test-find-parent-method.gc", + shared_compiler->runner.run_static_test(testCategory, "test-find-parent-method.gc", {"\"test pass!\"\n0\n"}); } TEST_F(WithGameTests, Ref) { - shared_compiler->runner.run_static_test(env, testCategory, "test-ref.gc", {"83\n"}); + shared_compiler->runner.run_static_test(testCategory, "test-ref.gc", {"83\n"}); } TEST_F(WithGameTests, PairASzie) { - shared_compiler->runner.run_static_test(env, testCategory, "test-pair-asize.gc", {"8\n"}); + shared_compiler->runner.run_static_test(testCategory, "test-pair-asize.gc", {"8\n"}); } TEST_F(WithGameTests, Last) { - shared_compiler->runner.run_static_test(env, testCategory, "test-last.gc", {"d\n0\n"}); + shared_compiler->runner.run_static_test(testCategory, "test-last.gc", {"d\n0\n"}); } TEST_F(WithGameTests, Sort) { shared_compiler->runner.run_static_test( - env, testCategory, "test-sort.gc", + testCategory, "test-sort.gc", {"(24 16 32 56 72 1234 -34 25 654)\n(1234 654 72 56 32 25 24 16 -34)\n0\n"}); } TEST_F(WithGameTests, Sort2) { shared_compiler->runner.run_static_test( - env, testCategory, "test-sort-2.gc", + testCategory, "test-sort-2.gc", {"(24 16 32 56 72 1234 -34 25 654)\n(-34 16 24 25 32 56 72 654 1234)\n0\n"}); } TEST_F(WithGameTests, Sort3) { shared_compiler->runner.run_static_test( - env, testCategory, "test-sort-3.gc", + testCategory, "test-sort-3.gc", {"(24 16 32 56 72 1234 -34 25 654)\n(-34 16 24 25 32 56 72 654 1234)\n0\n"}); } TEST_F(WithGameTests, PairLength) { - shared_compiler->runner.run_static_test(env, testCategory, "test-pair-length.gc", {"6\n"}); + shared_compiler->runner.run_static_test(testCategory, "test-pair-length.gc", {"6\n"}); } TEST_F(WithGameTests, Member1) { - shared_compiler->runner.run_static_test(env, testCategory, "test-member-1.gc", {"(c d)\n0\n"}); + shared_compiler->runner.run_static_test(testCategory, "test-member-1.gc", {"(c d)\n0\n"}); } TEST_F(WithGameTests, Member2) { - shared_compiler->runner.run_static_test(env, testCategory, "test-member-2.gc", {"#f\n0\n"}); + shared_compiler->runner.run_static_test(testCategory, "test-member-2.gc", {"#f\n0\n"}); } TEST_F(WithGameTests, Assoc1) { - shared_compiler->runner.run_static_test(env, testCategory, "test-assoc-1.gc", {"w\n0\n"}); + shared_compiler->runner.run_static_test(testCategory, "test-assoc-1.gc", {"w\n0\n"}); } TEST_F(WithGameTests, Assoc2) { - shared_compiler->runner.run_static_test(env, testCategory, "test-assoc-2.gc", {"#f\n0\n"}); + shared_compiler->runner.run_static_test(testCategory, "test-assoc-2.gc", {"#f\n0\n"}); } TEST_F(WithGameTests, Assoce1) { - shared_compiler->runner.run_static_test(env, testCategory, "test-assoce-1.gc", {"x\n0\n"}); + shared_compiler->runner.run_static_test(testCategory, "test-assoce-1.gc", {"x\n0\n"}); } TEST_F(WithGameTests, Assoce2) { - shared_compiler->runner.run_static_test(env, testCategory, "test-assoce-2.gc", {"x\n0\n"}); + shared_compiler->runner.run_static_test(testCategory, "test-assoce-2.gc", {"x\n0\n"}); } TEST_F(WithGameTests, Append) { - shared_compiler->runner.run_static_test(env, testCategory, "test-append.gc", - {"(a b c d e)\n0\n"}); + shared_compiler->runner.run_static_test(testCategory, "test-append.gc", {"(a b c d e)\n0\n"}); } TEST_F(WithGameTests, DeleteList) { - shared_compiler->runner.run_static_test(env, testCategory, "test-delete-list.gc", - {"(a b d e)\n0\n"}); + shared_compiler->runner.run_static_test(testCategory, "test-delete-list.gc", {"(a b d e)\n0\n"}); } TEST_F(WithGameTests, DeleteCar) { - shared_compiler->runner.run_static_test(env, testCategory, "test-delete-car.gc", + shared_compiler->runner.run_static_test(testCategory, "test-delete-car.gc", {"((a . b) (e . f))\n#f\n0\n"}); } TEST_F(WithGameTests, InsertCar) { - shared_compiler->runner.run_static_test(env, testCategory, "test-insert-cons.gc", + shared_compiler->runner.run_static_test(testCategory, "test-insert-cons.gc", {"((c . w) (a . b) (e . f))\n0\n"}); } TEST_F(WithGameTests, InlineArrayClass) { - shared_compiler->runner.run_static_test(env, testCategory, "test-new-inline-array-class.gc", + shared_compiler->runner.run_static_test(testCategory, "test-new-inline-array-class.gc", {"2824\n"}); } TEST_F(WithGameTests, Memcpy) { - shared_compiler->runner.run_static_test(env, testCategory, "test-memcpy.gc", {"13\n"}); + shared_compiler->runner.run_static_test(testCategory, "test-memcpy.gc", {"13\n"}); } TEST_F(WithGameTests, Memset) { - shared_compiler->runner.run_static_test(env, testCategory, "test-memset.gc", {"11\n"}); + shared_compiler->runner.run_static_test(testCategory, "test-memset.gc", {"11\n"}); } TEST_F(WithGameTests, BintegerPrint) { - shared_compiler->runner.run_static_test(env, testCategory, "test-binteger-print.gc", - {"-17\n0\n"}); + shared_compiler->runner.run_static_test(testCategory, "test-binteger-print.gc", {"-17\n0\n"}); } TEST_F(WithGameTests, TestTests) { shared_compiler->runner.run_static_test( - env, testCategory, "test-tests.gc", + testCategory, "test-tests.gc", {"Test Failed On Test 0: \"unknown\"\nTest Failed On Test 0: " "\"test\"\nTest \"test-of-test\": 1 Passes\n0\n"}); } TEST_F(WithGameTests, TypeArrays) { - shared_compiler->runner.run_static_test(env, testCategory, "test-type-arrays.gc", + shared_compiler->runner.run_static_test(testCategory, "test-type-arrays.gc", {"Test \"test-type-arrays\": 3 Passes\n0\n"}); } TEST_F(WithGameTests, NumberComparison) { - shared_compiler->runner.run_static_test(env, testCategory, "test-number-comparison.gc", + shared_compiler->runner.run_static_test(testCategory, "test-number-comparison.gc", {"Test \"number-comparison\": 14 Passes\n0\n"}); } TEST_F(WithGameTests, ApproxPi) { - shared_compiler->runner.run_static_test(env, testCategory, "test-approx-pi.gc", + shared_compiler->runner.run_static_test(testCategory, "test-approx-pi.gc", get_test_pass_string("approx-pi", 4)); } TEST_F(WithGameTests, ApproxPiStack) { - shared_compiler->runner.run_static_test(env, testCategory, "test-approx-pi-stack.gc", + shared_compiler->runner.run_static_test(testCategory, "test-approx-pi-stack.gc", get_test_pass_string("approx-pi-stack", 4)); } TEST_F(WithGameTests, DynamicType) { - shared_compiler->runner.run_static_test(env, testCategory, "test-dynamic-type.gc", + shared_compiler->runner.run_static_test(testCategory, "test-dynamic-type.gc", get_test_pass_string("dynamic-type", 4)); } TEST_F(WithGameTests, StringType) { - shared_compiler->runner.run_static_test(env, testCategory, "test-string-type.gc", + shared_compiler->runner.run_static_test(testCategory, "test-string-type.gc", get_test_pass_string("string-type", 4)); } TEST_F(WithGameTests, NewString) { - shared_compiler->runner.run_static_test(env, testCategory, "test-new-string.gc", + shared_compiler->runner.run_static_test(testCategory, "test-new-string.gc", get_test_pass_string("new-string", 5)); } TEST_F(WithGameTests, AddrOf) { - shared_compiler->runner.run_static_test(env, testCategory, "test-addr-of.gc", + shared_compiler->runner.run_static_test(testCategory, "test-addr-of.gc", get_test_pass_string("addr-of", 2)); } TEST_F(WithGameTests, SetSelf) { - shared_compiler->runner.run_static_test(env, testCategory, "test-set-self.gc", {"#t\n0\n"}); + shared_compiler->runner.run_static_test(testCategory, "test-set-self.gc", {"#t\n0\n"}); } TEST_F(WithGameTests, NewArray) { - shared_compiler->runner.run_static_test(env, testCategory, "test-new-array.gc", + shared_compiler->runner.run_static_test(testCategory, "test-new-array.gc", get_test_pass_string("new-array", 8)); } TEST_F(WithGameTests, NewStaticStructureIntegers) { - shared_compiler->runner.run_static_test(env, testCategory, - "test-new-static-structure-integers.gc", + shared_compiler->runner.run_static_test(testCategory, "test-new-static-structure-integers.gc", get_test_pass_string("new-static-structure-integers", 7)); } TEST_F(WithGameTests, NewStaticBasic) { - shared_compiler->runner.run_static_test(env, testCategory, "test-new-static-basic.gc", + shared_compiler->runner.run_static_test(testCategory, "test-new-static-basic.gc", get_test_pass_string("new-static-basic", 12)); } TEST_F(WithGameTests, VectorDot) { - shared_compiler->runner.run_static_test(env, testCategory, "test-vector-dot.gc", + shared_compiler->runner.run_static_test(testCategory, "test-vector-dot.gc", get_test_pass_string("vector-dot", 1)); } @@ -366,7 +298,7 @@ TEST_F(WithGameTests, DebuggerDisassemble) { } TEST_F(WithGameTests, GameText) { - shared_compiler->runner.run_static_test(env, testCategory, "test-game-text.gc", + shared_compiler->runner.run_static_test(testCategory, "test-game-text.gc", get_test_pass_string("game-text", 5)); } @@ -378,7 +310,7 @@ TEST_F(WithGameTests, GameCount) { shared_compiler->compiler.run_test_from_string( "(dgo-load \"engine\" global (link-flag output-load-msg output-load-true-msg execute-login " "print-login) #x200000)"); - shared_compiler->runner.run_static_test(env, testCategory, "test-game-count.gc", + shared_compiler->runner.run_static_test(testCategory, "test-game-count.gc", get_test_pass_string("game-count", 4)); // don't leave behind a weird version of the game-count file. fs::remove(file_util::get_file_path({"out", "jak1", "iso", "ENGINE.CGO"})); @@ -386,27 +318,26 @@ TEST_F(WithGameTests, GameCount) { } TEST_F(WithGameTests, BitFieldAccess) { - shared_compiler->runner.run_static_test(env, testCategory, "test-bitfield-access.gc", + shared_compiler->runner.run_static_test(testCategory, "test-bitfield-access.gc", {"#tfffffffffffff344f213ffffffffffffffff\n0\n"}); } TEST_F(WithGameTests, SimpleBitField) { - shared_compiler->runner.run_static_test(env, testCategory, "test-set-bitfield.gc", - {"#t50.3432\n0\n"}); + shared_compiler->runner.run_static_test(testCategory, "test-set-bitfield.gc", {"#t50.3432\n0\n"}); } TEST_F(WithGameTests, StaticBitField) { - shared_compiler->runner.run_static_test(env, testCategory, "test-static-bitfield.gc", + shared_compiler->runner.run_static_test(testCategory, "test-static-bitfield.gc", {"#t50.3432\n0\n"}); } TEST_F(WithGameTests, TrickyBitField) { - shared_compiler->runner.run_static_test(env, testCategory, "test-bitfield-tricky-access.gc", + shared_compiler->runner.run_static_test(testCategory, "test-bitfield-tricky-access.gc", get_test_pass_string("bitfield-tricky-access", 14)); } TEST_F(WithGameTests, Bitfield128) { - shared_compiler->runner.run_static_test(env, testCategory, "test-access-bitfield128.gc", + shared_compiler->runner.run_static_test(testCategory, "test-access-bitfield128.gc", {"-abcdbeef 77777777 66666666 12347890\n" "-abcdbeef 77777777 66666666 00000001\n" "-abcdbeef 77777777 00000002 00000001\n" @@ -419,46 +350,46 @@ TEST_F(WithGameTests, Bitfield128) { } TEST_F(WithGameTests, Math) { - shared_compiler->runner.run_static_test(env, testCategory, "test-math.gc", + shared_compiler->runner.run_static_test(testCategory, "test-math.gc", get_test_pass_string("math", 31)); } TEST_F(WithGameTests, Sqrtf) { - shared_compiler->runner.run_static_test(env, testCategory, "sqrtf.gc", {"2.2360\n0\n"}); + shared_compiler->runner.run_static_test(testCategory, "sqrtf.gc", {"2.2360\n0\n"}); } TEST_F(WithGameTests, StaticPairs) { shared_compiler->runner.run_static_test( - env, testCategory, "test-static-pair-1.gc", + testCategory, "test-static-pair-1.gc", {"(1 (w . a) beans 2 (-1 -2) twelve (a . \"test\"))\n0\n"}); } TEST_F(WithGameTests, FancyStatic) { shared_compiler->runner.run_static_test( - env, testCategory, "test-fancy-static-fields.gc", + testCategory, "test-fancy-static-fields.gc", {"\"name\" 12 12.3400 (a b c) 5 33 4 kernel-context asdf\n0\n"}); } TEST_F(WithGameTests, IntegerBoxedArray) { shared_compiler->runner.run_static_test( - env, testCategory, "test-integer-boxed-array.gc", + testCategory, "test-integer-boxed-array.gc", {"0 0 1 2 2 4 3 6 4 8 5 10 6 12 7 14 8 16 9 18 10 20 11 22 12 40 6 array\n0\n"}); } TEST_F(WithGameTests, StaticBoxedArray) { - shared_compiler->runner.run_static_test(env, testCategory, "test-static-boxed-array.gc", + shared_compiler->runner.run_static_test(testCategory, "test-static-boxed-array.gc", {"4 asdf \"test\" (a b) 0 object 12 12\n0\n"}); } TEST_F(WithGameTests, SizeOf) { - shared_compiler->runner.run_static_test(env, testCategory, "test-size-of.gc", + shared_compiler->runner.run_static_test(testCategory, "test-size-of.gc", {"size of dma-bucket is 16\n" "size of ints: 2 4 16\n" "size of stack array is 16\n0\n"}); } TEST_F(WithGameTests, EnumAndBitfieldTypes) { - shared_compiler->runner.run_static_test(env, testCategory, "test-bitfield-and-enum-types.gc", + shared_compiler->runner.run_static_test(testCategory, "test-bitfield-and-enum-types.gc", {"content type: uint16\n" // runtime type is u16 "content type: uint16\n" "bitfield spacing: 2\n" // u16 spacing @@ -472,7 +403,7 @@ TEST_F(WithGameTests, EnumAndBitfieldTypes) { TEST_F(WithGameTests, Trig) { shared_compiler->runner.run_static_test( - env, testCategory, "test-trig.gc", + testCategory, "test-trig.gc", {"2.0000\n" // 2 deg "-45.0000\n" // -45 deg "1.2000\n" @@ -547,7 +478,7 @@ TEST_F(WithGameTests, Trig) { TEST_F(WithGameTests, Vector) { shared_compiler->runner.run_static_test( - env, testCategory, "test-vector.gc", + testCategory, "test-vector.gc", {"[ -4.0000] [ 8.0000] [ -4.0000] [ 0.0000]\n" "[ 3.0000] [ 4.0000] [ 5.0000] [ 1.0000]\n" "[ 5.0000] [ 12.0000] [ 21.0000] [ 1.0000]\n" @@ -580,7 +511,7 @@ TEST_F(WithGameTests, Vector) { } TEST_F(WithGameTests, InlinedPackedBasics) { - shared_compiler->runner.run_static_test(env, testCategory, "inlined-packed-basics.gc", + shared_compiler->runner.run_static_test(testCategory, "inlined-packed-basics.gc", {"rec stride: 48\n" "offset of float: 40\n" "offset: 16\n" @@ -591,7 +522,7 @@ TEST_F(WithGameTests, InlinedPackedBasics) { } TEST_F(WithGameTests, PartialDefineTypeField) { - shared_compiler->runner.run_static_test(env, testCategory, "test-partial-define-type-field.gc", + shared_compiler->runner.run_static_test(testCategory, "test-partial-define-type-field.gc", {"#f\n" "0\n"}); } @@ -601,47 +532,45 @@ TEST_F(WithGameTests, PartialDefineTypeField) { // ---- One off Tests TEST_F(WithGameTests, VFOuterProduct) { - shared_compiler->runner.run_static_test(env, testCategory, "test-vector-outer-product.gc", + shared_compiler->runner.run_static_test(testCategory, "test-vector-outer-product.gc", {"(-4.0000, 8.0000, -4.0000, 999.0000)\n0\n"}); } TEST_F(WithGameTests, VFLoadAndStore) { - shared_compiler->runner.run_static_test(env, testCategory, "test-vf-load-and-store.gc", + shared_compiler->runner.run_static_test(testCategory, "test-vf-load-and-store.gc", {"2.0000\n0\n"}); } TEST_F(WithGameTests, VFSimpleMath) { - shared_compiler->runner.run_static_test(env, testCategory, "test-basic-vector-math.gc", + shared_compiler->runner.run_static_test(testCategory, "test-basic-vector-math.gc", {"55.0000\n0\n"}); } TEST_F(WithGameTests, VFLoadStatic) { - shared_compiler->runner.run_static_test(env, testCategory, "test-load-static-vector.gc", + shared_compiler->runner.run_static_test(testCategory, "test-load-static-vector.gc", {"5.3000\n0\n"}); } TEST_F(WithGameTests, XMMSpill) { - shared_compiler->runner.run_static_test(env, testCategory, "test-xmm-spill.gc", - {"253.0000\n0\n"}); + shared_compiler->runner.run_static_test(testCategory, "test-xmm-spill.gc", {"253.0000\n0\n"}); } TEST_F(WithGameTests, BoxedArrayIndex) { - shared_compiler->runner.run_static_test(env, testCategory, "test-boxed-array-index.gc", - {"18\n0\n"}); + shared_compiler->runner.run_static_test(testCategory, "test-boxed-array-index.gc", {"18\n0\n"}); } TEST_F(WithGameTests, LocalVars) { - shared_compiler->runner.run_static_test(env, testCategory, "test-local-vars.gc", + shared_compiler->runner.run_static_test(testCategory, "test-local-vars.gc", {"y is \"test\", x is 12, z is 3.2000\n0\n"}); } TEST_F(WithGameTests, ShortCircuit) { - shared_compiler->runner.run_static_test(env, testCategory, "test-short-circuit.gc", + shared_compiler->runner.run_static_test(testCategory, "test-short-circuit.gc", get_test_pass_string("short-circuit", 13)); } TEST_F(WithGameTests, VectorFloatToInt) { - shared_compiler->runner.run_static_test(env, testCategory, "test-vector-int-float-conversions.gc", + shared_compiler->runner.run_static_test(testCategory, "test-vector-int-float-conversions.gc", {"1.0000 -2.0000 3.0000 4.0000\n" "1 -2 3 4\n" "1.0000 -2.0000 3.0000 4.0000\n" @@ -650,7 +579,7 @@ TEST_F(WithGameTests, VectorFloatToInt) { TEST_F(WithGameTests, PWShifts) { shared_compiler->runner.run_static_test( - env, testCategory, "test-pw-shifts.gc", + testCategory, "test-pw-shifts.gc", {"ffffffffaafffff0 ffffffffbbfffff0 ffffffffccfffff0 ffffffffddfffff0\n" "ffffffffeabffffc ffffffffeefffffc fffffffff33ffffc fffffffff77ffffc\n" "ffffffffafffff00 ffffffffbfffff00 ffffffffcfffff00 ffffffffdfffff00\n" @@ -659,39 +588,39 @@ TEST_F(WithGameTests, PWShifts) { } TEST_F(WithGameTests, StaticArray) { - shared_compiler->runner.run_static_test(env, testCategory, "test-static-array.gc", + shared_compiler->runner.run_static_test(testCategory, "test-static-array.gc", {"1 2 -10\n" "0\n"}); } TEST_F(WithGameTests, StaticInlineArray) { shared_compiler->runner.run_static_test( - env, testCategory, "test-static-inline-array.gc", + testCategory, "test-static-inline-array.gc", {"test-basic-for-static-inline test-basic-for-static-inline #x4 #x4 \"hello\"\n" "#x0 #x0 \"hello\"\n" "0\n"}); } TEST_F(WithGameTests, StaticArrayField) { - shared_compiler->runner.run_static_test(env, testCategory, "test-static-array-field.gc", + shared_compiler->runner.run_static_test(testCategory, "test-static-array-field.gc", {"\"ghjkl\"\n" "0\n"}); } TEST_F(WithGameTests, ArrayRefStatic) { - shared_compiler->runner.run_static_test(env, testCategory, "test-array-ref-static.gc", + shared_compiler->runner.run_static_test(testCategory, "test-array-ref-static.gc", {"test-not-inline-inline-array-type 12 asdf 13 bean 14\n" "0\n"}); } TEST_F(WithGameTests, TypeReference) { - shared_compiler->runner.run_static_test(env, testCategory, "test-type-ref.gc", + shared_compiler->runner.run_static_test(testCategory, "test-type-ref.gc", {"string #t basic some-unknown-type 20 0\n" "0\n"}); } TEST_F(WithGameTests, StaticFieldInlineArray) { - shared_compiler->runner.run_static_test(env, testCategory, "test-static-field-inline-arrays.gc", + shared_compiler->runner.run_static_test(testCategory, "test-static-field-inline-arrays.gc", {"\"second\" \"first\"\n" "basic-elt #x4 #x4\n" "two\n" @@ -702,7 +631,7 @@ TEST_F(WithGameTests, StaticFieldInlineArray) { } TEST_F(WithGameTests, I128Simple) { - shared_compiler->runner.run_static_test(env, testCategory, "test-i128-simple.gc", + shared_compiler->runner.run_static_test(testCategory, "test-i128-simple.gc", {"[0] #x707172737475767778797a7b7c7d7e7f\n" "[1] #x606162636465666768696a6b6c6d6e6f\n" "[2] #x505152535455565758595a5b5c5d5e5f\n" @@ -717,7 +646,7 @@ TEST_F(WithGameTests, I128Simple) { // TODO - add tests TEST_F(WithGameTests, Pextlw) { - shared_compiler->runner.run_static_test(env, testCategory, "test-pextlw.gc", + shared_compiler->runner.run_static_test(testCategory, "test-pextlw.gc", {"#x07060504171615140302010013121110\n" "#x0f0e0d0c1f1e1d1c0b0a09081b1a1918\n" "#x07060504030201001716151413121110\n" @@ -730,7 +659,7 @@ TEST_F(WithGameTests, Pextlw) { TEST_F(WithGameTests, Matrix) { shared_compiler->runner.run_static_test( - env, testCategory, "test-matrix.gc", + testCategory, "test-matrix.gc", {"mat-mult\n" "\t[ 80.0000] [ 70.0000] [ 60.0000] [ 50.0000]\n" "\t[ 240.0000] [ 214.0000] [ 188.0000] [ 162.0000]\n" @@ -800,7 +729,7 @@ TEST_F(WithGameTests, Matrix) { } TEST_F(WithGameTests, WeirdMultiply) { - shared_compiler->runner.run_static_test(env, testCategory, "test-weird-multiplies.gc", + shared_compiler->runner.run_static_test(testCategory, "test-weird-multiplies.gc", {"2 100000002\n" "100000000 100000000\n" "55555552 -3 7ffffffffffffffb -5\n" @@ -809,7 +738,7 @@ TEST_F(WithGameTests, WeirdMultiply) { TEST_F(WithGameTests, Function128) { shared_compiler->runner.run_static_test( - env, testCategory, "test-function128.gc", + testCategory, "test-function128.gc", {"#\n" "#\n" "#\n" @@ -819,36 +748,36 @@ TEST_F(WithGameTests, Function128) { } TEST_F(WithGameTests, AddrOfVar) { - shared_compiler->runner.run_static_test(env, testCategory, "test-addr-of-var.gc", + shared_compiler->runner.run_static_test(testCategory, "test-addr-of-var.gc", {"x: 25 y: 35 z: 35\n" "x: 13 y: 35 z: 15\n" "0\n"}); } TEST_F(WithGameTests, SoundName) { - shared_compiler->runner.run_static_test(env, testCategory, "test-sound-name.gc", + shared_compiler->runner.run_static_test(testCategory, "test-sound-name.gc", {"#t #f #f\n" "0\n"}); } TEST_F(WithGameTests, StaticLambda) { - shared_compiler->runner.run_static_test(env, testCategory, "test-static-lambda.gc", + shared_compiler->runner.run_static_test(testCategory, "test-static-lambda.gc", {"Add: 30 sub: -10\n0\n"}); } TEST_F(WithGameTests, MethodReplace) { - shared_compiler->runner.run_static_test(env, testCategory, "test-method-replace.gc", + shared_compiler->runner.run_static_test(testCategory, "test-method-replace.gc", {"relocate! foo: 123 heap: 1 name: 2\n0\n"}); } TEST_F(WithGameTests, Behaviors) { - shared_compiler->runner.run_static_test(env, testCategory, "test-behaviors.gc", + shared_compiler->runner.run_static_test(testCategory, "test-behaviors.gc", {"function self: 123\n" "method obj: 456 self: 123\n0\n"}); } TEST_F(WithGameTests, RaySphere) { - shared_compiler->runner.run_static_test(env, testCategory, "test-ray-sphere.gc", + shared_compiler->runner.run_static_test(testCategory, "test-ray-sphere.gc", {"Got 0.2346\n" "Got -100000000.0000\n" "Got -100000000.0000\n" @@ -857,7 +786,7 @@ TEST_F(WithGameTests, RaySphere) { } TEST_F(WithGameTests, PandPorPnor) { - shared_compiler->runner.run_static_test(env, testCategory, "test-pand-por-pnor.gc", + shared_compiler->runner.run_static_test(testCategory, "test-pand-por-pnor.gc", {"#x1f1f1d0f0f0f0d0b0f0f0d0707070503\n" "#xe0e0e2f0f0f0f2f4f0f0f2f8f8f8fafc\n" "#x0200000c0a0808080200000402000000\n" @@ -868,50 +797,50 @@ TEST_F(WithGameTests, PandPorPnor) { } TEST_F(WithGameTests, StackInlineArray) { - shared_compiler->runner.run_static_test(env, testCategory, "test-stack-inline-array.gc", + shared_compiler->runner.run_static_test(testCategory, "test-stack-inline-array.gc", {"#x8\n" "#x30\n0\n"}); } TEST_F(WithGameTests, GetEnumVals) { - shared_compiler->runner.run_static_test(env, testCategory, "test-get-enum-vals.gc", + shared_compiler->runner.run_static_test(testCategory, "test-get-enum-vals.gc", {"((thing1 . 1) (thing3 . 3) " "(thing5 . 5))\n0\n"}); } TEST_F(WithGameTests, SetU64FromFloat) { shared_compiler->runner.run_static_test( - env, testCategory, "test-set-u64-from-float.gc", + testCategory, "test-set-u64-from-float.gc", {"-12.0000 #xffffffffc1400000 #xc1400000 #xffffffff\n0\n"}); } TEST_F(WithGameTests, TrickyFloatBehavior) { - shared_compiler->runner.run_static_test(env, testCategory, "tricky-floats.gc", + shared_compiler->runner.run_static_test(testCategory, "tricky-floats.gc", {"#xffffffff80000000 1.0000 #xffffffffbf800000\n0\n"}); } TEST_F(WithGameTests, ProcessAllocation) { - shared_compiler->runner.run_static_test(env, testCategory, "test-kernel-alloc.gc", + shared_compiler->runner.run_static_test(testCategory, "test-kernel-alloc.gc", {"diff is 16\n0\n"}); } TEST_F(WithGameTests, MethodCallForwardDeclared) { - shared_compiler->runner.run_static_test(env, testCategory, "test-forward-declared-method.gc", + shared_compiler->runner.run_static_test(testCategory, "test-forward-declared-method.gc", {"4 12\n0\n"}); } TEST_F(WithGameTests, PointerInStatic) { - shared_compiler->runner.run_static_test(env, testCategory, "test-false-in-static-pointer.gc", + shared_compiler->runner.run_static_test(testCategory, "test-false-in-static-pointer.gc", {"#f\n0\n"}); } TEST_F(WithGameTests, StackSingleton) { - shared_compiler->runner.run_static_test(env, testCategory, "test-stack-singleton.gc", + shared_compiler->runner.run_static_test(testCategory, "test-stack-singleton.gc", {"#f #f #f #f #t\n0\n"}); } TEST_F(WithGameTests, StackSingletonType) { - shared_compiler->runner.run_static_test(env, testCategory, "test-stack-singleton-type.gc", + shared_compiler->runner.run_static_test(testCategory, "test-stack-singleton-type.gc", {"#t\n0\n"}); } @@ -927,561 +856,12 @@ extern void link(); TEST_F(WithGameTests, Mips2CBasic) { Mips2C::gLinkedFunctionTable.reg("test-func", Mips2C::test_func::execute, 0); - shared_compiler->runner.run_static_test(env, testCategory, "test-mips2c-call.gc", {"36\n0\n"}); + shared_compiler->runner.run_static_test(testCategory, "test-mips2c-call.gc", {"36\n0\n"}); } TEST_F(WithGameTests, Mips2C_CallGoal) { Mips2C::gLinkedFunctionTable.reg("test-func2", Mips2C::goal_call_test::execute, 128); Mips2C::goal_call_test::link(); - shared_compiler->runner.run_static_test(env, testCategory, "test-mips2c-goal.gc", + shared_compiler->runner.run_static_test(testCategory, "test-mips2c-goal.gc", {"1 2 3 4 5 6 7 8\n12\n"}); } - -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"); -} - -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 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 vectorMathCaseGen_TwoOperand() { - std::vector 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(j); - cases.push_back(testCaseBC); - } - } - return cases; -} - -class VectorFloatParameterizedTestFixtureWithRunner_TwoOperand - : public WithMinimalGameTests, - public ::testing::WithParamInterface { - 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 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 vectorMathCaseGen_SingleOperand_NoBroadcast() { - std::vector 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 { - 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 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 vectorMathCaseGen_TwoOperandACC() { - std::vector 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(j); - cases.push_back(testCaseBC); - } - } - return cases; -} - -class VectorFloatParameterizedTestFixtureWithRunner_TwoOperandACC - : public WithMinimalGameTests, - public ::testing::WithParamInterface { - 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 operation; - - VectorFloatRegister getExpectedResult() { - float operand1 = - input1.getBroadcastElement(static_cast(fsf), input1.x); - float operand2 = - input2.getBroadcastElement(static_cast(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 vectorMathCaseGen_TwoOperandQuotient() { - std::vector 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 { - 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 operation; - - VectorFloatRegister getExpectedResult() { - float operand1 = - input1.getBroadcastElement(static_cast(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 vectorMathCaseGen_OneOperandQuotient() { - std::vector 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 { - 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())); diff --git a/third-party/xdelta3/xdelta3/xdelta3.h b/third-party/xdelta3/xdelta3/xdelta3.h index b9b6fe026..699e64941 100644 --- a/third-party/xdelta3/xdelta3/xdelta3.h +++ b/third-party/xdelta3/xdelta3/xdelta3.h @@ -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"