From 1b5b9a2469fd1a879af56db7af5fa1c0717d8cf0 Mon Sep 17 00:00:00 2001 From: water111 <48171810+water111@users.noreply.github.com> Date: Wed, 17 Feb 2021 00:57:21 -0500 Subject: [PATCH] add sqrt (#270) --- goalc/compiler/Compiler.h | 1 + goalc/compiler/IR.cpp | 10 +++++++++- goalc/compiler/IR.h | 2 +- goalc/compiler/compilation/Asm.cpp | 5 ++++- goalc/compiler/compilation/Atoms.cpp | 1 + goalc/compiler/compilation/Math.cpp | 13 +++++++++++++ goalc/emitter/IGen.h | 11 +++++++++++ test/goalc/source_templates/with_game/sqrtf.gc | 2 ++ test/goalc/test_with_game.cpp | 6 +++++- test/test_emitter.cpp | 10 ++++++++++ 10 files changed, 57 insertions(+), 4 deletions(-) create mode 100644 test/goalc/source_templates/with_game/sqrtf.gc diff --git a/goalc/compiler/Compiler.h b/goalc/compiler/Compiler.h index 288de91caf..d225757781 100644 --- a/goalc/compiler/Compiler.h +++ b/goalc/compiler/Compiler.h @@ -434,6 +434,7 @@ class Compiler { 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); + Val* compile_sqrtf(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 cecba5c15a..bcb2b66989 100644 --- a/goalc/compiler/IR.cpp +++ b/goalc/compiler/IR.cpp @@ -618,6 +618,8 @@ std::string IR_FloatMath::print() { return fmt::format("maxss {}, {}", m_dest->print(), m_arg->print()); case FloatMathKind::MIN_SS: return fmt::format("minss {}, {}", m_dest->print(), m_arg->print()); + case FloatMathKind::SQRT_SS: + return fmt::format("sqrtss {}, {}", m_dest->print(), m_arg->print()); default: throw std::runtime_error("Unsupported FloatMathKind"); } @@ -626,7 +628,9 @@ std::string IR_FloatMath::print() { RegAllocInstr IR_FloatMath::to_rai() { RegAllocInstr rai; rai.write.push_back(m_dest->ireg()); - rai.read.push_back(m_dest->ireg()); + if (m_kind != FloatMathKind::SQRT_SS) { + rai.read.push_back(m_dest->ireg()); + } rai.read.push_back(m_arg->ireg()); return rai; } @@ -659,6 +663,10 @@ void IR_FloatMath::do_codegen(emitter::ObjectGenerator* gen, gen->add_instr( IGen::minss_xmm_xmm(get_reg(m_dest, allocs, irec), get_reg(m_arg, allocs, irec)), irec); break; + case FloatMathKind::SQRT_SS: + gen->add_instr(IGen::sqrts_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 a155ebc3cf..eac6b02b80 100644 --- a/goalc/compiler/IR.h +++ b/goalc/compiler/IR.h @@ -212,7 +212,7 @@ class IR_IntegerMath : public IR { u8 m_shift_amount = 0; }; -enum class FloatMathKind { DIV_SS, MUL_SS, ADD_SS, SUB_SS, MIN_SS, MAX_SS }; +enum class FloatMathKind { DIV_SS, MUL_SS, ADD_SS, SUB_SS, MIN_SS, MAX_SS, SQRT_SS }; class IR_FloatMath : public IR { public: diff --git a/goalc/compiler/compilation/Asm.cpp b/goalc/compiler/compilation/Asm.cpp index 2e98d46539..e219b6806a 100644 --- a/goalc/compiler/compilation/Asm.cpp +++ b/goalc/compiler/compilation/Asm.cpp @@ -328,7 +328,7 @@ Val* Compiler::compile_asm_svf(const goos::Object& form, const goos::Object& res } void Compiler::check_vector_float_regs(const goos::Object& form, - Env* env, + Env*, std::vector> args) { for (std::pair arg : args) { if (!arg.second->settable() || arg.second->ireg().reg_class != RegClass::VECTOR_FLOAT) { @@ -791,6 +791,9 @@ emitter::Register::VF_ELEMENT Compiler::ftf_fsf_to_vector_element(u8 val) { return emitter::Register::VF_ELEMENT::Z; case 0b11: return emitter::Register::VF_ELEMENT::W; + default: + throw_compiler_error_no_code("Invalid vector element {}", (int)val); + return emitter::Register::VF_ELEMENT::NONE; } } diff --git a/goalc/compiler/compilation/Atoms.cpp b/goalc/compiler/compilation/Atoms.cpp index 3342259dd1..fcfd5daad4 100644 --- a/goalc/compiler/compilation/Atoms.cpp +++ b/goalc/compiler/compilation/Atoms.cpp @@ -194,6 +194,7 @@ static const std::unordered_map< {"&+", &Compiler::compile_pointer_add}, {"fmax", &Compiler::compile_fmax}, {"fmin", &Compiler::compile_fmin}, + {"sqrtf", &Compiler::compile_sqrtf}, // 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 78b1ef1a2c..c4c023e6c3 100644 --- a/goalc/compiler/compilation/Math.cpp +++ b/goalc/compiler/compilation/Math.cpp @@ -245,6 +245,19 @@ Val* Compiler::compile_fmax(const goos::Object& form, const goos::Object& rest, return result; } +Val* Compiler::compile_sqrtf(const goos::Object& form, const goos::Object& rest, Env* env) { + auto args = get_va(form, rest); + va_check(form, args, {{}}, {}); + + auto first_val = compile_error_guard(args.unnamed.at(0), env); + if (get_math_mode(first_val->type()) != MATH_FLOAT) { + throw_compiler_error(form, "Must use a float for sqrtf"); + } + auto result = env->make_fpr(first_val->type()); + env->emit_ir(FloatMathKind::SQRT_SS, result, first_val->to_fpr(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 1ecd9cad3b..a86c8b944a 100644 --- a/goalc/emitter/IGen.h +++ b/goalc/emitter/IGen.h @@ -1897,6 +1897,17 @@ class IGen { return instr; } + static Instruction sqrts_xmm(Register dst, Register src) { + assert(dst.is_xmm()); + assert(src.is_xmm()); + Instruction instr(0xf3); + instr.set_op2(0x0f); + instr.set_op3(0x51); + instr.set_modrm_and_rex(dst.hw_id(), src.hw_id(), 3, false); + instr.swap_op0_rex(); + return instr; + } + /*! * Multiply two floats in xmm's */ diff --git a/test/goalc/source_templates/with_game/sqrtf.gc b/test/goalc/source_templates/with_game/sqrtf.gc new file mode 100644 index 0000000000..047619991e --- /dev/null +++ b/test/goalc/source_templates/with_game/sqrtf.gc @@ -0,0 +1,2 @@ +(format #t "~f~%" (sqrtf 5.0)) +0 \ No newline at end of file diff --git a/test/goalc/test_with_game.cpp b/test/goalc/test_with_game.cpp index e8be466604..165f0d855c 100644 --- a/test/goalc/test_with_game.cpp +++ b/test/goalc/test_with_game.cpp @@ -321,6 +321,10 @@ TEST_F(WithGameTests, Math) { runner.run_static_test(env, testCategory, "test-math.gc", get_test_pass_string("math", 31)); } +TEST_F(WithGameTests, Sqrtf) { + runner.run_static_test(env, testCategory, "sqrtf.gc", {"2.2360\n0\n"}); +} + TEST_F(WithGameTests, StaticPairs) { runner.run_static_test(env, testCategory, "test-static-pair-1.gc", {"(1 (w . a) beans 2 (-1 -2) twelve (a . \"test\"))\n0\n"}); @@ -425,7 +429,7 @@ struct VectorFloatRegister { std::regex("nan|inf|-nan|-inf"), "NaN"); } - std::string toGOALFormat(float val) { + 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 diff --git a/test/test_emitter.cpp b/test/test_emitter.cpp index 1c72477fde..fe816078d2 100644 --- a/test/test_emitter.cpp +++ b/test/test_emitter.cpp @@ -3889,3 +3889,13 @@ TEST(EmitterXMM, StackStoreFull8) { tester.emit(IGen::store128_gpr64_xmm128_s8(RSP, XMM0 + 13, -12)); EXPECT_EQ(tester.dump_to_hex_string(true), "660F7F5C24F466440F7F6C24F4"); } + +TEST(EmitterXMM, SqrtS) { + CodeTester tester; + tester.init_code_buffer(1024); + tester.emit(IGen::sqrts_xmm(XMM0 + 1, XMM0 + 2)); + tester.emit(IGen::sqrts_xmm(XMM0 + 11, XMM0 + 2)); + tester.emit(IGen::sqrts_xmm(XMM0 + 1, XMM0 + 12)); + tester.emit(IGen::sqrts_xmm(XMM0 + 11, XMM0 + 12)); + EXPECT_EQ(tester.dump_to_hex_string(true), "F30F51CAF3440F51DAF3410F51CCF3450F51DC"); +} \ No newline at end of file