This commit is contained in:
water 2020-11-28 20:53:13 -05:00
parent 5b4b5c238e
commit dc32b59217
14 changed files with 240 additions and 10 deletions

50
doc/code_status.md Normal file
View File

@ -0,0 +1,50 @@
## gcommon.gc
Missing stuff.
## gstring-h.gc
Empty file.
## gkernel-h.gc
Likely missing some macros. Missing `handle`, a child type of integer.
## gkernel.gc
Missing lots of stuff. Will need x86-64 inline assembly and some tweaking for x86.
## pskernel.gc
Possibly can be entirely left out. Seems to be mostly unused, or only used for PS2 debugging?
## gstring.gc
Missing lots
## dgo-h.gc
Done!
## gstate.gc
Not started, probably needs state support in the compiler
## types.gc
Needs child types of integer
## vu-macros.gc
Empty.
## math.gc
Has a unit test for a lot of functions.
rand-vu-init, rand-vu, rand-vu-nostep, rand-vu-float-range, rand-vu-percent?, rand-vu-int-range, rand-vu-int-count aren't implemented
rand-uint31-gen might be wrong.
## vector.gc
Partially done
## gravity-h.gc
Empty file
## bounding-box-h.gc
Just types. Done!
## matrix-h.gc
Types and one function. Done, but the matrix-copy! function isn't that efficient.
## quaternion-h.gc
Done!

View File

@ -5,3 +5,43 @@
;; name in dgo: bounding-box-h
;; dgos: GAME, ENGINE
;; Types related to bounding boxes.
;; floating point bounding box.
(deftype bounding-box (structure)
((min vector :inline :offset-assert 0)
(max vector :inline :offset-assert 16)
)
:method-count-assert 16
:size-assert #x20
:flag-assert #x1000000020
(:methods
(dummy-9 () none 9)
(dummy-10 () none 10)
(dummy-11 () none 11)
(dummy-12 () none 12)
(dummy-13 () none 13)
(dummy-14 () none 14)
(dummy-15 () none 15)
)
)
;; integer (word) bounding box.
(deftype bounding-box4w (structure)
((min vector4w :inline :offset-assert 0)
(max vector4w :inline :offset-assert 16)
)
:method-count-assert 9
:size-assert #x20
:flag-assert #x900000020
)
;; bounding both that has both a box and box4w.
(deftype bounding-box-both (structure)
((box bounding-box :inline :offset-assert 0)
(box4w bounding-box4w :inline :offset-assert 32)
)
:method-count-assert 9
:size-assert #x40
:flag-assert #x900000040
)

View File

@ -148,13 +148,32 @@
;; I wonder who wrote this code.
(set! (-> *random-generator* seed) #x666EDD1E)
(defmacro sext32-64 (x)
`(sarv (shlv ,x 32) 32)
)
(defun rand-uint31-gen ((gen random-generator))
"Generate a supposedly random integer"
(let ((result (-> gen seed)))
"Generate a supposedly random integer.
Note, this might not quite be right.
But the highest bit is always zero, like it says
and it looks kinda random to me."
(let* ((sd (-> gen seed))
;; addiu v1, r0, 16807
(+! result 16807)
;; to 32 bit, doing sign extension.
(set! result (shlv result 32))
(set! result (sarv result 32))
;; mult3 v0, v1, a1
(prod (imul64 16807 sd))
;; mfhi v1
(hi (shrv prod 32)) ;; sign extend this?
(lo (sarv (shlv prod 32) 32))
;; daddu v1, v1, v1
(v1 (+ hi hi))
;; srl a1, v0, 31
(a1 (logand #xffffffff (shrv lo 31)))
;; or v1, v1, a1
;; daddu v0, v0 v1
(result (+ lo (logior v1 a1)))
)
(set! result (shrv (logand #xffffffff (shlv result 1)) 1))
(set! (-> gen seed) result)
result
)
)

View File

@ -5,3 +5,45 @@
;; name in dgo: matrix-h
;; dgos: GAME, ENGINE
;; matrix-h
(deftype matrix (structure)
((data float 16 :offset-assert 0)
(vector vector 4 :offset 0)
(quad uint128 4 :offset 0)
)
:method-count-assert 10
:size-assert #x40
:flag-assert #xa00000040
(:methods
(dummy-9 () none 9)
)
)
(deftype matrix3 (structure)
((data float 12 :offset-assert 0)
(vector vector 3 :offset 0)
(quad uint128 3 :offset 0)
)
:method-count-assert 9
:size-assert #x30
:flag-assert #x900000030
)
;; guess on signs here
(deftype matrix4h (structure)
((data int16 16 :offset-assert 0)
(vector4h vector4h 4 :offset 0)
(long int64 4 :offset 0)
)
:method-count-assert 9
:size-assert #x20
:flag-assert #x900000020
)
(defun matrix-copy! ((dst matrix) (src matrix))
"Copy src to dst."
;; actual implementation is in assembly, unrolled quad copies, loads/stores spaced out.
(dotimes (i 16 dst)
(set! (-> dst data i) (-> src data i))
)
)

View File

@ -5,3 +5,18 @@
;; name in dgo: quaternion-h
;; dgos: GAME, ENGINE
(deftype quaternion (structure)
((data float 4 :offset-assert 0)
(x float :offset 0)
(y float :offset 4)
(z float :offset 8)
(w float :offset 12)
(vec vector :inline :offset 0)
(quad uint128 :offset 0)
)
:method-count-assert 9
:size-assert #x10
:flag-assert #x900000010
)
(define *unity-quaternion* (new 'static 'quaternion :x 0.0 :y 0.0 :z 0.0 :w 1.0))

View File

@ -218,9 +218,9 @@ class Compiler {
// Math
Val* compile_add(const goos::Object& form, const goos::Object& rest, Env* env);
Val* compile_sub(const goos::Object& form, const goos::Object& rest, Env* env);
Val* compile_mul(const goos::Object& form, const goos::Object& rest, Env* env);
Val* compile_imul64(const goos::Object& form, const goos::Object& rest, Env* env);
Val* compile_div(const goos::Object& form, const goos::Object& rest, Env* env);
Val* compile_shlv(const goos::Object& form, const goos::Object& rest, Env* env);
Val* compile_sarv(const goos::Object& form, const goos::Object& rest, Env* env);

View File

@ -400,6 +400,8 @@ std::string IR_IntegerMath::print() {
return fmt::format("subi {}, {}", m_dest->print(), m_arg->print());
case IntegerMathKind::IMUL_32:
return fmt::format("imul {}, {}", m_dest->print(), m_arg->print());
case IntegerMathKind::IMUL_64:
return fmt::format("imul64 {}, {}", m_dest->print(), m_arg->print());
case IntegerMathKind::IDIV_32:
return fmt::format("idiv {}, {}", m_dest->print(), m_arg->print());
case IntegerMathKind::IMOD_32:
@ -483,13 +485,15 @@ void IR_IntegerMath::do_codegen(emitter::ObjectGenerator* gen,
gen->add_instr(IGen::imul_gpr32_gpr32(dr, get_reg(m_arg, allocs, irec)), irec);
gen->add_instr(IGen::movsx_r64_r32(dr, dr), irec);
} break;
case IntegerMathKind::IMUL_64: {
auto dr = get_reg(m_dest, allocs, irec);
gen->add_instr(IGen::imul_gpr64_gpr64(dr, get_reg(m_arg, allocs, irec)), irec);
} break;
case IntegerMathKind::IDIV_32: {
gen->add_instr(IGen::cdq(), irec);
gen->add_instr(IGen::idiv_gpr32(get_reg(m_arg, allocs, irec)), irec);
gen->add_instr(IGen::movsx_r64_r32(get_reg(m_dest, allocs, irec), emitter::RAX), irec);
} break;
case IntegerMathKind::IMOD_32: {
gen->add_instr(IGen::cdq(), irec);
gen->add_instr(IGen::idiv_gpr32(get_reg(m_arg, allocs, irec)), irec);

View File

@ -193,6 +193,7 @@ enum class IntegerMathKind {
ADD_64,
SUB_64,
IMUL_32,
IMUL_64,
IDIV_32,
SHLV_64,
SARV_64,

View File

@ -101,6 +101,7 @@ static const std::unordered_map<
{"+", &Compiler::compile_add},
{"-", &Compiler::compile_sub},
{"*", &Compiler::compile_mul},
{"imul64", &Compiler::compile_imul64},
{"/", &Compiler::compile_div},
{"shlv", &Compiler::compile_shlv},
{"shrv", &Compiler::compile_shrv},

View File

@ -160,6 +160,7 @@ Val* Compiler::compile_mul(const goos::Object& form, const goos::Object& rest, E
auto math_type = get_math_mode(first_type);
switch (math_type) {
case MATH_INT: {
// todo, signed vs unsigned?
auto result = env->make_gpr(first_type);
env->emit(std::make_unique<IR_RegSet>(result, first_val->to_gpr(env)));
@ -194,6 +195,41 @@ Val* Compiler::compile_mul(const goos::Object& form, const goos::Object& rest, E
return get_none();
}
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()) {
throw_compile_error(form, "Invalid * form");
}
// look at the first value to determine the math mode
auto first_val = compile_error_guard(args.unnamed.at(0), env);
auto first_type = first_val->type();
auto math_type = get_math_mode(first_type);
switch (math_type) {
case MATH_INT: {
auto result = env->make_gpr(first_type);
env->emit(std::make_unique<IR_RegSet>(result, first_val->to_gpr(env)));
for (size_t i = 1; i < args.unnamed.size(); i++) {
env->emit(std::make_unique<IR_IntegerMath>(
IntegerMathKind::IMUL_64, result,
to_math_type(compile_error_guard(args.unnamed.at(i), env), math_type, env)
->to_gpr(env)));
}
return result;
}
case MATH_FLOAT:
case MATH_INVALID:
throw_compile_error(
form, "Cannot determine the math mode for object of type " + first_type.print());
break;
default:
assert(false);
}
assert(false);
return get_none();
}
Val* Compiler::compile_sub(const goos::Object& form, const goos::Object& rest, Env* env) {
auto args = get_va(form, rest);
if (!args.named.empty() || args.unnamed.empty()) {

View File

@ -1387,6 +1387,19 @@ class IGen {
return instr;
}
/*!
* Multiply gprs (64-bit, signed).
* DANGER - this treats all operands as 64-bit. This is not like the EE.
*/
static Instruction imul_gpr64_gpr64(Register dst, Register src) {
Instruction instr(0xf);
instr.set_op2(0xaf);
assert(dst.is_gpr());
assert(src.is_gpr());
instr.set_modrm_and_rex(dst.hw_id(), src.hw_id(), 3, true);
return instr;
}
/*!
* Divide (idiv, 32 bit)
* todo UNTESTED

View File

@ -0,0 +1,2 @@
(* #x12341234 #x12341234)

View File

@ -0,0 +1,2 @@
(imul64 #x12341234 #x12341234)

View File

@ -236,3 +236,8 @@ TEST_F(ArithmeticTests, Subtraction) {
runner.run_static_test(env, testCategory, "subtract-2.static.gc", {"4\n"});
runner.run_static_test(env, testCategory, "subtract-let.static.gc", {"3\n"});
}
TEST_F(ArithmeticTests, Multiplication2) {
runner.run_static_test(env, testCategory, "multiply32.static.gc", {"-1234478448\n"});
runner.run_static_test(env, testCategory, "multiply64.static.gc", {"93270638141856400\n"});
}