diff --git a/doc/code_status.md b/doc/code_status.md index 39f5ce82d..1edc90dc7 100644 --- a/doc/code_status.md +++ b/doc/code_status.md @@ -47,4 +47,19 @@ Just types. Done! Types and one function. Done, but the matrix-copy! function isn't that efficient. ## quaternion-h.gc -Done! \ No newline at end of file +Done! + +## euler-h.gc +Needs static arrays + +## transform-h.gc +Done! + +## geometry-h.gc +Done! + +## trigonometry-h.gc +Empty File. + +## transformq-h.gc +Not done. \ No newline at end of file diff --git a/goal_src/build/dgos.txt b/goal_src/build/dgos.txt index 8be3c4897..14bee9078 100644 --- a/goal_src/build/dgos.txt +++ b/goal_src/build/dgos.txt @@ -210,6 +210,8 @@ ("ENGINE.CGO" ("types-h.o" "types-h") ("vu1-macros.o" "vu1-macros") + + ;; the "math" section ("math.o" "math") ("vector-h.o" "vector-h") ("gravity-h.o" "gravity-h") @@ -228,6 +230,8 @@ ("euler.o" "euler") ("geometry.o" "geometry") ("trigonometry.o" "trigonometry") + + ("gsound-h.o" "gsound-h") ("timer-h.o" "timer-h") ("timer.o" "timer") diff --git a/goal_src/engine/geometry/geometry-h.gc b/goal_src/engine/geometry/geometry-h.gc index acd37edb0..a4106cb79 100644 --- a/goal_src/engine/geometry/geometry-h.gc +++ b/goal_src/engine/geometry/geometry-h.gc @@ -5,3 +5,32 @@ ;; name in dgo: geometry-h ;; dgos: GAME, ENGINE +;; geometry-h +(deftype curve (structure) + ((cverts uint32 :offset-assert 0) + (num-cverts int32 :offset-assert 4) + (knots uint32 :offset-assert 8) + (num-knots int32 :offset-assert 12) + (length float :offset-assert 16) + ) + :method-count-assert 9 + :size-assert #x14 + :flag-assert #x900000014 + ) + +;; geometry-h +(deftype border-plane (basic) + ((name basic :offset-assert 4) + (action basic :offset-assert 8) + (slot int8 :offset-assert 12) + (trans vector :inline :offset-assert 16) + (normal vector :inline :offset-assert 32) + ) + :method-count-assert 11 + :size-assert #x30 + :flag-assert #xb00000030 + (:methods + (dummy-9 () none 9) + (dummy-10 () none 10) + ) + ) \ No newline at end of file diff --git a/goal_src/engine/math/math.gc b/goal_src/engine/math/math.gc index ebcc28697..afe47eef5 100644 --- a/goal_src/engine/math/math.gc +++ b/goal_src/engine/math/math.gc @@ -5,30 +5,20 @@ ;; name in dgo: math ;; dgos: GAME, ENGINE +;; contains various math helpers + ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;; float macros ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; at some point, these could be more optimized. +;; at some point, this could be more optimized. +;; MIPS has an explicit abs.s instruction, but x86-64 doesn't. +;; modern clang on O3 does a comiss/branch and this is probably pretty close. (defmacro fabs (x) - ;"Floating point absolute value. On MIPS there is a abs.s instruction. - ; In the future we could consider optimizing this more for x86, but this is good enough." - `(if (< ,x 0) - (- ,x) - ,x) - ) - -(defmacro fmin (x y) - `(if (< ,x ,y) - ,x - ,y) - ) - -(defmacro fmax (x y) - `(if (> ,x ,y) - ,x - ,y) + `(if (< (the float ,x) 0) + (- (the float ,x)) + (the float ,x)) ) diff --git a/goal_src/engine/math/transform-h.gc b/goal_src/engine/math/transform-h.gc index 06cf11405..9a19be0a1 100644 --- a/goal_src/engine/math/transform-h.gc +++ b/goal_src/engine/math/transform-h.gc @@ -5,3 +5,24 @@ ;; name in dgo: transform-h ;; dgos: GAME, ENGINE + +(deftype transform (structure) + ((trans vector :inline :offset-assert 0) + (rot vector :inline :offset-assert 16) + (scale vector :inline :offset-assert 32) + ) + :method-count-assert 9 + :size-assert #x30 + :flag-assert #x900000030 + ) + + +(deftype trs (basic) + ((trans vector :inline :offset-assert 16) + (rot vector :inline :offset-assert 32) + (scale vector :inline :offset-assert 48) + ) + :method-count-assert 9 + :size-assert #x40 + :flag-assert #x900000040 + ) \ No newline at end of file diff --git a/goalc/compiler/Compiler.h b/goalc/compiler/Compiler.h index 8689c8b37..41c83a90d 100644 --- a/goalc/compiler/Compiler.h +++ b/goalc/compiler/Compiler.h @@ -231,6 +231,8 @@ class Compiler { Val* compile_logand(const goos::Object& form, const goos::Object& rest, Env* env); Val* compile_logior(const goos::Object& form, const goos::Object& rest, Env* env); Val* compile_pointer_add(const goos::Object& form, const goos::Object& rest, Env* env); + Val* compile_fmin(const goos::Object& form, const goos::Object& rest, Env* env); + Val* compile_fmax(const goos::Object& form, const goos::Object& rest, Env* env); // Function Val* compile_lambda(const goos::Object& form, const goos::Object& rest, Env* env); diff --git a/goalc/compiler/IR.cpp b/goalc/compiler/IR.cpp index 1aba46ddb..99e99ac48 100644 --- a/goalc/compiler/IR.cpp +++ b/goalc/compiler/IR.cpp @@ -522,6 +522,10 @@ std::string IR_FloatMath::print() { return fmt::format("addss {}, {}", m_dest->print(), m_arg->print()); case FloatMathKind::SUB_SS: return fmt::format("subss {}, {}", m_dest->print(), m_arg->print()); + case FloatMathKind::MAX_SS: + return fmt::format("maxss {}, {}", m_dest->print(), m_arg->print()); + case FloatMathKind::MIN_SS: + return fmt::format("minss {}, {}", m_dest->print(), m_arg->print()); default: throw std::runtime_error("Unsupported FloatMathKind"); } @@ -555,6 +559,14 @@ void IR_FloatMath::do_codegen(emitter::ObjectGenerator* gen, gen->add_instr( IGen::subss_xmm_xmm(get_reg(m_dest, allocs, irec), get_reg(m_arg, allocs, irec)), irec); break; + case FloatMathKind::MAX_SS: + gen->add_instr( + IGen::maxss_xmm_xmm(get_reg(m_dest, allocs, irec), get_reg(m_arg, allocs, irec)), irec); + break; + case FloatMathKind::MIN_SS: + gen->add_instr( + IGen::minss_xmm_xmm(get_reg(m_dest, allocs, irec), get_reg(m_arg, allocs, irec)), irec); + break; default: assert(false); } diff --git a/goalc/compiler/IR.h b/goalc/compiler/IR.h index 5671e0cf1..a79804c2d 100644 --- a/goalc/compiler/IR.h +++ b/goalc/compiler/IR.h @@ -224,7 +224,7 @@ class IR_IntegerMath : public IR { RegVal* m_arg; }; -enum class FloatMathKind { DIV_SS, MUL_SS, ADD_SS, SUB_SS }; +enum class FloatMathKind { DIV_SS, MUL_SS, ADD_SS, SUB_SS, MIN_SS, MAX_SS }; class IR_FloatMath : public IR { public: diff --git a/goalc/compiler/compilation/Atoms.cpp b/goalc/compiler/compilation/Atoms.cpp index 0b6180473..446105fbd 100644 --- a/goalc/compiler/compilation/Atoms.cpp +++ b/goalc/compiler/compilation/Atoms.cpp @@ -124,6 +124,8 @@ static const std::unordered_map< {"<", &Compiler::compile_condition_as_bool}, {">", &Compiler::compile_condition_as_bool}, {"&+", &Compiler::compile_pointer_add}, + {"fmax", &Compiler::compile_fmax}, + {"fmin", &Compiler::compile_fmin}, // BUILDER (build-dgo/build-cgo?) {"build-dgos", &Compiler::compile_build_dgo}, diff --git a/goalc/compiler/compilation/Math.cpp b/goalc/compiler/compilation/Math.cpp index 21824070d..fb05d60d4 100644 --- a/goalc/compiler/compilation/Math.cpp +++ b/goalc/compiler/compilation/Math.cpp @@ -195,6 +195,52 @@ Val* Compiler::compile_mul(const goos::Object& form, const goos::Object& rest, E return get_none(); } +Val* Compiler::compile_fmin(const goos::Object& form, const goos::Object& rest, Env* env) { + auto args = get_va(form, rest); + if (!args.named.empty() || args.unnamed.empty()) { + throw_compile_error(form, "Invalid fmin form"); + } + + // look at the first value to determine the math mode + auto first_val = compile_error_guard(args.unnamed.at(0), env); + if (get_math_mode(first_val->type()) != MATH_FLOAT) { + throw_compile_error(form, "Must use floats in fmin"); + } + auto result = env->make_xmm(first_val->type()); + env->emit(std::make_unique(result, first_val->to_xmm(env))); + for (size_t i = 1; i < args.unnamed.size(); i++) { + auto val = compile_error_guard(args.unnamed.at(i), env); + if (get_math_mode(val->type()) != MATH_FLOAT) { + throw_compile_error(form, "Must use floats in fmin"); + } + env->emit(std::make_unique(FloatMathKind::MIN_SS, result, val->to_xmm(env))); + } + return result; +} + +Val* Compiler::compile_fmax(const goos::Object& form, const goos::Object& rest, Env* env) { + auto args = get_va(form, rest); + if (!args.named.empty() || args.unnamed.empty()) { + throw_compile_error(form, "Invalid fmax form"); + } + + // look at the first value to determine the math mode + auto first_val = compile_error_guard(args.unnamed.at(0), env); + if (get_math_mode(first_val->type()) != MATH_FLOAT) { + throw_compile_error(form, "Must use floats in fmax"); + } + auto result = env->make_xmm(first_val->type()); + env->emit(std::make_unique(result, first_val->to_xmm(env))); + for (size_t i = 1; i < args.unnamed.size(); i++) { + auto val = compile_error_guard(args.unnamed.at(i), env); + if (get_math_mode(val->type()) != MATH_FLOAT) { + throw_compile_error(form, "Must use floats in fmax"); + } + env->emit(std::make_unique(FloatMathKind::MAX_SS, result, val->to_xmm(env))); + } + return result; +} + Val* Compiler::compile_imul64(const goos::Object& form, const goos::Object& rest, Env* env) { auto args = get_va(form, rest); if (!args.named.empty() || args.unnamed.empty()) { diff --git a/goalc/emitter/IGen.h b/goalc/emitter/IGen.h index a2c8814c3..111f34bf4 100644 --- a/goalc/emitter/IGen.h +++ b/goalc/emitter/IGen.h @@ -1740,6 +1740,34 @@ class IGen { return instr; } + /*! + * Floating point minimum. + */ + static Instruction minss_xmm_xmm(Register dst, Register src) { + assert(dst.is_xmm()); + assert(src.is_xmm()); + Instruction instr(0xf3); + instr.set_op2(0x0f); + instr.set_op3(0x5d); + instr.set_modrm_and_rex(dst.hw_id(), src.hw_id(), 3, false); + instr.swap_op0_rex(); + return instr; + } + + /*! + * Floating point maximum. + */ + static Instruction maxss_xmm_xmm(Register dst, Register src) { + assert(dst.is_xmm()); + assert(src.is_xmm()); + Instruction instr(0xf3); + instr.set_op2(0x0f); + instr.set_op3(0x5f); + instr.set_modrm_and_rex(dst.hw_id(), src.hw_id(), 3, false); + instr.swap_op0_rex(); + return instr; + } + /*! * Convert GPR int32 to XMM float (single precision) */ diff --git a/test/goalc/source_templates/float/float-max.static.gc b/test/goalc/source_templates/float/float-max.static.gc new file mode 100644 index 000000000..3dcef3f54 --- /dev/null +++ b/test/goalc/source_templates/float/float-max.static.gc @@ -0,0 +1,2 @@ +(define format _format) +(format #t "~,,2f~%" (fmax 1.0 2.0 -1.2 3.7 2.2)) \ No newline at end of file diff --git a/test/goalc/source_templates/float/float-min.static.gc b/test/goalc/source_templates/float/float-min.static.gc new file mode 100644 index 000000000..2457893e3 --- /dev/null +++ b/test/goalc/source_templates/float/float-min.static.gc @@ -0,0 +1,2 @@ +(define format _format) +(format #t "~,,2f~%" (fmin 1.0 2.0 -1.2 3.7 2.2)) \ No newline at end of file diff --git a/test/goalc/test_float.cpp b/test/goalc/test_float.cpp index 7f235dbeb..ec6b398ce 100644 --- a/test/goalc/test_float.cpp +++ b/test/goalc/test_float.cpp @@ -75,3 +75,8 @@ TEST_F(FloatTests, Functions) { env, testCategory, "nested-float-functions.static.gc", {"i 1.4400 3.4000\nr 10.1523\ni 1.2000 10.1523\nr 17.5432\n17.543 10.152\n0\n"}); } + +TEST_F(FloatTests, MinMax) { + runner.run_static_test(env, testCategory, "float-max.static.gc", {"3.70\n0\n"}); + runner.run_static_test(env, testCategory, "float-min.static.gc", {"-1.20\n0\n"}); +} \ No newline at end of file