add floats and inline stuff

This commit is contained in:
water 2020-09-13 10:40:21 -04:00
parent 90a7e9b4b9
commit e7f8620c92
20 changed files with 434 additions and 21 deletions

View file

@ -1,3 +1,13 @@
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; OTHER STUFF
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; get list of all goal files
(asm-file "goal_src/build/all_files.gc")
;; tell compiler about stuff defined/implemented in the runtime.
(asm-file "goal_src/kernel-defs.gc")
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; BUILD SYSTEM
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
@ -23,13 +33,11 @@
)
)
;; load list of all goal files
(asm-file "goal_src/build/all_files.gc")
(defmacro e ()
`(:exit)
)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; CONDITIONAL COMPILATION
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

148
goal_src/kernel-defs.gc Normal file
View file

@ -0,0 +1,148 @@
;; kernel-defs.gc
;; everything defined in the C Kernel / runtime
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;; kscheme - InitHeapAndSymbol
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; fixed symbols
(define-extern #f symbol)
(define-extern #t symbol)
(define-extern function type)
(define-extern basic type)
(define-extern string type)
(define-extern symbol type)
(define-extern type type)
(define-extern object type)
(define-extern link-block type)
(define-extern integer type)
(define-extern sinteger type)
(define-extern uinteger type)
(define-extern binteger type)
(define-extern int8 type)
(define-extern int16 type)
(define-extern int32 type)
(define-extern int64 type)
(define-extern int128 type)
(define-extern uint8 type)
(define-extern uint16 type)
(define-extern uint32 type)
(define-extern uint64 type)
(define-extern uint128 type)
(define-extern float type)
(define-extern process-tree type)
(define-extern process type)
(define-extern thread type)
(define-extern structure type)
(define-extern pair type)
(define-extern pointer type)
(define-extern number type)
(define-extern array type)
(define-extern vu-function type)
(define-extern connectable type)
(define-extern stack-frame type)
(define-extern file-stream type)
(define-extern kheap type)
(define-extern nothing (function none))
(define-extern delete-basic (function basic none))
(define-extern static symbol)
(define-extern global kheap)
(define-extern debug kheap)
(define-extern loading-level kheap) ;; not a kheap at boot
(define-extern loading-package kheap) ;; not a kheap at boot
(define-extern process-level-heap kheap) ;; not a kheap at boot
(define-extern stack symbol)
(define-extern scratch symbol)
(define-extern *stratch-top* pointer)
(define-extern zero-func (function int))
;; asize-of-basic-func - has a bug
;; copy-basic-func - has a bug
;; level - unknown type
;; art-group
;; texture-page-dir
;; texture-page
;; sound
;; dgo
;; top-level
(define-extern string->symbol (function string symbol))
(define-extern print (function object object))
(define-extern inspect (function object object))
(define-extern load (function string kheap object))
(define-extern loado (function string kheap object))
(define-extern unload (function string none))
(define-extern _format function)
(define-extern malloc (function kheap int pointer))
(define-extern kmalloc (function kheap int int string))
(define-extern new-dynamic-structure (function kheap type int structure))
(define-extern method-set! (function type int function none)) ;; may actually return function.
(define-extern link (function pointer string int kheap int pointer))
(define-extern dgo-load (function string kheap int int))
(define-extern link-begin (function pointer string int kheap int int))
(define-extern link-resume (function int))
;; mc-run
;; mc-format
;; mc-unformat
;; mc-create-file
;; mc-save
;; mc-load
;; mc-check-result
;; mc-get-slot-info
;; mc-makefile
;; kset-language
(define-extern *debug-segment* symbol)
(define-extern *enable-method-set* int)
;; *boot-video-mode* ?
(define-extern *deci-count* int)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;; klisten - InitListener
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; *listener-link-block*
;; *listener-function*
;; kernel-dispatcher
;; kernel-packages
;; *print-column*
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;; kmachine - InitMachineScheme
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; put-display-env
;; syncv
;; sync-path
;; reset-path
;; rest-graph
;; dma-sync
;; gs-put-imr
;; gs-get-imr
;; gs-store-image
;; flush-cache
;; cpad-open
;; cpad-get-data
;; install-handler
;; install-debug-handler
;; file-stream-open
;; file-stream-close
;; file-stream-length
;; file-stream-seek
;; file-stream-read
;; file-stream-write
;; scf-get-language
;; scf-get-time
;; scf-get-aspect
;; scf-get-volume
;; scf-get-territory
;; scf-get-timeout
;; scf-get-inactive-timeout
;; dma-to-iop
;; kernel-shutdown
;; aybabtu
;; *stack-top*
;; *stack-base*
;; *stack-size*
;; *kernel-boot-message*
;; *kernel-boot-mode*
;; *kernel-boot-level*

View file

@ -5,3 +5,20 @@
;; name in dgo: gcommon
;; dgos: KERNEL
;; gcommon is the first file compiled and loaded.
;; it's expected that this function will mostly be hand-decompiled
;; The "identity" returns its input unchanged. It uses the special GOAL "object"
;; type, which can basically be anything, so this will work on integers, floats,
;; strings, structures, arrays, etc. The only things which doesn't work with "object"
;; is a 128-bit integer. The upper 64-bits of the integer will usually be lost.
(defun identity ((x object))
;; there is an optional "docstring" that can go at the beginning of a function
"Function which returns its input. The first function of the game!"
;; the last thing in the function body is the return value.
x
)

View file

@ -0,0 +1,7 @@
(defun inline-test-function-1 ((x int))
;; inline this function by default.
(declare (inline))
(* 4 x)
)
(inline-test-function-1 8)

View file

@ -0,0 +1 @@
1.234

View file

@ -0,0 +1,7 @@
(defun inline-test-function-2 ((x integer))
;; inline this function by default.
(declare (allow-inline))
(* 4 x)
)
(+ (inline-test-function-2 8) ((inline inline-test-function-2) 3))

View file

@ -0,0 +1 @@
(print (string->symbol "test-string"))

View file

@ -206,7 +206,7 @@ std::vector<std::string> Compiler::run_test(const std::string& source_code) {
std::vector<std::string> Compiler::run_test_no_load(const std::string& source_code) {
auto code = m_goos.reader.read_from_file({source_code});
auto compiled = compile_object_file("test-code", code, true);
compile_object_file("test-code", code, true);
return {};
}

View file

@ -15,6 +15,7 @@ class Compiler {
Compiler();
~Compiler();
void execute_repl();
goos::Interpreter& get_goos() { return m_goos; }
FileEnv* compile_object_file(const std::string& name, goos::Object code, bool allow_emit);
std::unique_ptr<FunctionEnv> compile_top_level_function(const std::string& name,
const goos::Object& code,
@ -40,6 +41,8 @@ class Compiler {
Val* compile_pair(const goos::Object& code, Env* env);
Val* compile_integer(const goos::Object& code, Env* env);
Val* compile_integer(s64 value, Env* env);
Val* compile_float(const goos::Object& code, Env* env);
Val* compile_float(float value, Env* env, int seg);
Val* compile_symbol(const goos::Object& form, Env* env);
Val* compile_string(const goos::Object& form, Env* env);
Val* compile_string(const std::string& str, Env* env, int seg = MAIN_SEGMENT);
@ -137,6 +140,7 @@ class Compiler {
// Function
Val* compile_lambda(const goos::Object& form, const goos::Object& rest, Env* env);
Val* compile_inline(const goos::Object& form, const goos::Object& rest, Env* env);
Val* compile_declare(const goos::Object& form, const goos::Object& rest, Env* env);
};
#endif // JAK_COMPILER_H

View file

@ -90,6 +90,10 @@ class FileEnv : public Env {
void debug_print_tl();
const std::vector<std::unique_ptr<FunctionEnv>>& functions() { return m_functions; }
const std::vector<std::unique_ptr<StaticObject>>& statics() { return m_statics; }
const FunctionEnv& top_level_function() {
assert(m_top_level_func);
return *m_top_level_func;
}
bool is_empty();
~FileEnv() = default;
@ -137,7 +141,7 @@ class FunctionEnv : public DeclareEnv {
void emit(std::unique_ptr<IR> ir) override;
void finish();
RegVal* make_ireg(TypeSpec ts, emitter::RegKind kind) override;
const std::vector<std::unique_ptr<IR>>& code() { return m_code; }
const std::vector<std::unique_ptr<IR>>& code() const { return m_code; }
int max_vars() const { return m_iregs.size(); }
const std::vector<IRegConstraint>& constraints() { return m_constraints; }
void constrain(const IRegConstraint& c) { m_constraints.push_back(c); }
@ -167,7 +171,7 @@ class FunctionEnv : public DeclareEnv {
int segment = -1;
std::string method_of_type_name = "#f";
bool is_asm_func = false;
std::vector<UnresolvedGoto> unresolved_gotos;
std::unordered_map<std::string, Val*> params;
@ -181,7 +185,6 @@ class FunctionEnv : public DeclareEnv {
std::vector<IRegConstraint> m_constraints;
// todo, unresolved gotos
AllocationResult m_regalloc_result;
bool m_is_asm_func = false;
bool m_aligned_stack_required = false;

View file

@ -194,8 +194,12 @@ void IR_RegSet::do_codegen(emitter::ObjectGenerator* gen,
if (val_reg == dest_reg) {
gen->add_instr(IGen::null(), irec);
} else {
} else if (val_reg.is_gpr() && dest_reg.is_gpr()) {
gen->add_instr(IGen::mov_gpr64_gpr64(dest_reg, val_reg), irec);
} else if (val_reg.is_xmm() && dest_reg.is_gpr()) {
gen->add_instr(IGen::movd_gpr32_xmm32(dest_reg, val_reg), irec);
} else {
assert(false);
}
}
@ -329,7 +333,7 @@ void IR_StaticVarAddr::do_codegen(emitter::ObjectGenerator* gen,
/////////////////////
// FunctionAddr
///////////////////
/////////////////////
IR_FunctionAddr::IR_FunctionAddr(const RegVal* dest, FunctionEnv* src) : m_dest(dest), m_src(src) {}
@ -354,7 +358,7 @@ void IR_FunctionAddr::do_codegen(emitter::ObjectGenerator* gen,
/////////////////////
// IntegerMath
///////////////////
/////////////////////
IR_IntegerMath::IR_IntegerMath(IntegerMathKind kind, RegVal* dest, RegVal* arg)
: m_kind(kind), m_dest(dest), m_arg(arg) {}
@ -403,3 +407,38 @@ void IR_IntegerMath::do_codegen(emitter::ObjectGenerator* gen,
assert(false);
}
}
/////////////////////
// StaticVarLoad
/////////////////////
IR_StaticVarLoad::IR_StaticVarLoad(const RegVal* dest, const StaticObject* src)
: m_dest(dest), m_src(src) {}
std::string IR_StaticVarLoad::print() {
return fmt::format("mov-svl {}, [{}]", m_dest->print(), m_src->print());
}
RegAllocInstr IR_StaticVarLoad::to_rai() {
RegAllocInstr rai;
rai.write.push_back(m_dest->ireg());
return rai;
}
void IR_StaticVarLoad::do_codegen(emitter::ObjectGenerator* gen,
const AllocationResult& allocs,
emitter::IR_Record irec) {
auto load_info = m_src->get_load_info();
assert(m_src->get_addr_offset() == 0);
if (m_dest->ireg().kind == emitter::RegKind::XMM) {
assert(load_info.load_signed == false);
assert(load_info.load_size == 4);
assert(load_info.requires_load == true);
auto instr = gen->add_instr(IGen::static_load_xmm32(get_reg(m_dest, allocs, irec), 0), irec);
gen->link_instruction_static(instr, m_src->rec, 0);
} else {
assert(false);
}
}

View file

@ -159,6 +159,20 @@ class IR_StaticVarAddr : public IR {
const StaticObject* m_src = nullptr;
};
class IR_StaticVarLoad : public IR {
public:
IR_StaticVarLoad(const RegVal* dest, const StaticObject* src);
std::string print() override;
RegAllocInstr to_rai() override;
void do_codegen(emitter::ObjectGenerator* gen,
const AllocationResult& allocs,
emitter::IR_Record irec) override;
protected:
const RegVal* m_dest = nullptr;
const StaticObject* m_src = nullptr;
};
class IR_FunctionAddr : public IR {
public:
IR_FunctionAddr(const RegVal* dest, FunctionEnv* src);
@ -199,6 +213,7 @@ class IR_IntegerMath : public IR {
void do_codegen(emitter::ObjectGenerator* gen,
const AllocationResult& allocs,
emitter::IR_Record irec) override;
IntegerMathKind get_kind() const { return m_kind; }
protected:
IntegerMathKind m_kind;

View file

@ -13,6 +13,9 @@ uint32_t push_data_to_byte_vector(T data, std::vector<uint8_t>& v) {
}
} // namespace
////////////////
// StaticString
////////////////
StaticString::StaticString(std::string data, int _seg) : text(std::move(data)), seg(_seg) {}
std::string StaticString::print() const {
@ -49,3 +52,32 @@ void StaticString::generate(emitter::ObjectGenerator* gen) {
int StaticString::get_addr_offset() const {
return BASIC_OFFSET;
}
////////////////
// StaticFloat
////////////////
StaticFloat::StaticFloat(float _value, int _seg) : value(_value), seg(_seg) {}
StaticObject::LoadInfo StaticFloat::get_load_info() const {
LoadInfo info;
info.requires_load = true;
info.load_size = 4;
info.load_signed = false;
info.prefer_xmm = true;
return info;
}
void StaticFloat::generate(emitter::ObjectGenerator* gen) {
rec = gen->add_static_to_seg(seg, 4);
auto& d = gen->get_static_data(rec);
push_data_to_byte_vector<float>(value, d);
}
int StaticFloat::get_addr_offset() const {
return 0;
}
std::string StaticFloat::print() const {
return fmt::format("(sf {})", value);
}

View file

@ -33,4 +33,15 @@ class StaticString : public StaticObject {
int get_addr_offset() const override;
};
class StaticFloat : public StaticObject {
public:
explicit StaticFloat(float _value, int _seg);
float value = 0;
int seg = -1;
std::string print() const override;
LoadInfo get_load_info() const override;
void generate(emitter::ObjectGenerator* gen) override;
int get_addr_offset() const override;
};
#endif // JAK_STATICOBJECT_H

View file

@ -6,11 +6,14 @@
* Fallback to_gpr if a more optimized one is not provided.
*/
RegVal* Val::to_gpr(Env* fe) {
// TODO - handle 128-bit stuff here!
auto rv = to_reg(fe);
if (rv->ireg().kind == emitter::RegKind::GPR) {
return rv;
} else {
throw std::runtime_error("Val::to_gpr NYI"); // todo
auto re = fe->make_gpr(m_ts);
fe->emit(std::make_unique<IR_RegSet>(re, rv));
return re;
}
}
@ -75,3 +78,9 @@ RegVal* LambdaVal::to_reg(Env* fe) {
fe->emit(std::make_unique<IR_FunctionAddr>(re, func));
return re;
}
RegVal* FloatConstantVal::to_reg(Env* fe) {
auto re = fe->make_xmm(m_ts);
fe->emit(std::make_unique<IR_StaticVarLoad>(re, m_value));
return re;
}

View file

@ -141,12 +141,12 @@ class IntegerConstantVal : public Val {
class FloatConstantVal : public Val {
public:
FloatConstantVal(TypeSpec ts, float value) : Val(std::move(ts)), m_value(value) {}
std::string print() const override { return "float-constant-" + std::to_string(m_value); }
FloatConstantVal(TypeSpec ts, StaticFloat* value) : Val(std::move(ts)), m_value(value) {}
std::string print() const override { return "float-constant-" + m_value->print(); }
RegVal* to_reg(Env* fe) override;
protected:
float m_value = -1.f;
StaticFloat* m_value = nullptr;
};
// IntegerConstant
// FloatConstant

View file

@ -68,7 +68,8 @@ static const std::unordered_map<
//
// // LAMBDA
{"lambda", &Compiler::compile_lambda},
// {"inline", &Compiler::compile_inline},
{"declare", &Compiler::compile_declare},
{"inline", &Compiler::compile_inline},
// {"with-inline", &Compiler::compile_with_inline},
// {"rlet", &Compiler::compile_rlet},
// {"mlet", &Compiler::compile_mlet},
@ -81,11 +82,6 @@ static const std::unordered_map<
{"quote", &Compiler::compile_quote},
// {"defconstant", &Compiler::compile_defconstant},
//
// {"declare", &Compiler::compile_declare},
//
//
//
//
// // OBJECT
//
// {"the", &Compiler::compile_the},
@ -150,6 +146,8 @@ Val* Compiler::compile(const goos::Object& code, Env* env) {
return compile_symbol(code, env);
case goos::ObjectType::STRING:
return compile_string(code, env);
case goos::ObjectType::FLOAT:
return compile_float(code, env);
default:
ice("Don't know how to compile " + code.print());
}
@ -256,3 +254,17 @@ Val* Compiler::compile_string(const std::string& str, Env* env, int seg) {
fie->add_static(std::move(obj));
return result;
}
Val* Compiler::compile_float(const goos::Object& code, Env* env) {
assert(code.is_float());
return compile_float(code.float_obj.value, env, MAIN_SEGMENT);
}
Val* Compiler::compile_float(float value, Env* env, int seg) {
auto obj = std::make_unique<StaticFloat>(value, seg);
auto fe = get_parent_env_of_type<FunctionEnv>(env);
auto result = fe->alloc_val<FloatConstantVal>(m_ts.make_typespec("float"), obj.get());
auto fie = get_parent_env_of_type<FileEnv>(env);
fie->add_static(std::move(obj));
return result;
}

View file

@ -282,6 +282,7 @@ Val* Compiler::compile_function_or_method_call(const goos::Object& form, Env* en
if (eval_args.empty()) {
throw_compile_error(form, "0 argument method call is impossible to figure out");
}
printf("BAD %s\n", uneval_head.print().c_str());
assert(false); // nyi
// head = compile_get_method_of_object(eval_args.front(), symbol_string(uneval_head), env);
}
@ -360,3 +361,48 @@ Val* Compiler::compile_real_function_call(const goos::Object& form,
return return_reg;
}
}
Val* Compiler::compile_declare(const goos::Object& form, const goos::Object& rest, Env* env) {
auto& settings = get_parent_env_of_type<DeclareEnv>(env)->settings;
if (settings.is_set) {
throw_compile_error(form, "function has multiple declares");
}
settings.is_set = true;
for_each_in_list(rest, [&](const goos::Object& o) {
if (!o.is_pair()) {
throw_compile_error(o, "invalid declare specification");
}
auto first = o.as_pair()->car;
auto rrest = o.as_pair()->cdr;
if (!first.is_symbol()) {
throw_compile_error(first, "invalid declare specification, expected a symbol");
}
if (first.as_symbol()->name == "inline") {
if (!rrest.is_empty_list()) {
throw_compile_error(first, "invalid inline declare");
}
settings.allow_inline = true;
settings.inline_by_default = true;
settings.save_code = true;
} else if (first.as_symbol()->name == "allow-inline") {
if (!rrest.is_empty_list()) {
throw_compile_error(first, "invalid allow-inline declare");
}
settings.allow_inline = true;
settings.inline_by_default = false;
settings.save_code = true;
} else if (first.as_symbol()->name == "asm-func") {
get_parent_env_of_type<FunctionEnv>(env)->is_asm_func = true;
}
else {
throw_compile_error(first, "unrecognized declare statement");
}
});
return get_none();
}

View file

@ -39,6 +39,7 @@ bool Compiler::is_singed_integer_or_binteger(const TypeSpec& ts) {
}
Val* Compiler::number_to_integer(Val* in, Env* env) {
(void)env;
auto ts = in->type();
if (is_binteger(ts)) {
assert(false);
@ -52,6 +53,7 @@ Val* Compiler::number_to_integer(Val* in, Env* env) {
}
Val* Compiler::number_to_binteger(Val* in, Env* env) {
(void)env;
auto ts = in->type();
if (is_binteger(ts)) {
return in;
@ -65,6 +67,7 @@ Val* Compiler::number_to_binteger(Val* in, Env* env) {
}
Val* Compiler::number_to_float(Val* in, Env* env) {
(void)env;
auto ts = in->type();
if (is_binteger(ts)) {
assert(false);

View file

@ -133,6 +133,48 @@ TEST(CompilerAndRuntime, BuildGame) {
runtime_thread.join();
}
// TODO -move these into another file?
TEST(CompilerAndRuntime, InlineIsInline) {
Compiler compiler;
auto code =
compiler.get_goos().reader.read_from_file({"goal_src", "test", "test-declare-inline.gc"});
auto compiled = compiler.compile_object_file("test-code", code, true);
EXPECT_EQ(compiled->functions().size(), 2);
auto& ir = compiled->top_level_function().code();
bool got_mult = false;
for (auto& x : ir) {
EXPECT_EQ(dynamic_cast<IR_FunctionCall*>(x.get()), nullptr);
auto as_im = dynamic_cast<IR_IntegerMath*>(x.get());
if (as_im) {
EXPECT_EQ(as_im->get_kind(), IntegerMathKind::IMUL_32);
got_mult = true;
}
}
EXPECT_TRUE(got_mult);
}
TEST(CompilerAndRuntime, AllowInline) {
Compiler compiler;
auto code =
compiler.get_goos().reader.read_from_file({"goal_src", "test", "test-inline-call.gc"});
auto compiled = compiler.compile_object_file("test-code", code, true);
EXPECT_EQ(compiled->functions().size(), 2);
auto& ir = compiled->top_level_function().code();
int got_mult = 0;
int got_call = 0;
for (auto& x : ir) {
if (dynamic_cast<IR_FunctionCall*>(x.get())) {
got_call++;
}
auto as_im = dynamic_cast<IR_IntegerMath*>(x.get());
if (as_im && as_im->get_kind() == IntegerMathKind::IMUL_32) {
got_mult++;
}
}
EXPECT_EQ(got_mult, 1);
EXPECT_EQ(got_call, 1);
}
TEST(CompilerAndRuntime, CompilerTests) {
std::thread runtime_thread([]() { exec_runtime(0, nullptr); });
Compiler compiler;
@ -184,6 +226,14 @@ TEST(CompilerAndRuntime, CompilerTests) {
runner.run_test("test-sub-2.gc", {"4\n"});
runner.run_test("test-mul-1.gc", {"-12\n"});
expected = "test-string";
runner.run_test("test-string-symbol.gc", {expected}, expected.size());
runner.run_test("test-declare-inline.gc", {"32\n"});
runner.run_test("test-inline-call.gc", {"44\n"});
// float
runner.run_test("test-floating-point-1.gc", {"1067316150\n"});
compiler.shutdown_target();
runtime_thread.join();
runner.print_summary();