From 24fe2c78c0ec5abc8160fe383b0c1c62030a5f10 Mon Sep 17 00:00:00 2001 From: water111 <48171810+water111@users.noreply.github.com> Date: Thu, 26 Aug 2021 20:33:00 -0400 Subject: [PATCH] [goalc] Address-to-line (#783) * refactor debug info stuff before adding form to emit * source mapping working for non-macro sourced forms * support macros --- common/goos/TextDB.cpp | 90 +++++-- common/goos/TextDB.h | 22 +- goalc/compiler/CodeGenerator.cpp | 18 +- goalc/compiler/CodeGenerator.h | 6 +- goalc/compiler/Compiler.cpp | 21 +- goalc/compiler/Compiler.h | 11 +- goalc/compiler/Env.cpp | 80 +++---- goalc/compiler/Env.h | 35 +-- goalc/compiler/Util.cpp | 16 +- goalc/compiler/Val.cpp | 137 +++++------ goalc/compiler/Val.h | 46 ++-- goalc/compiler/compilation/Asm.cpp | 261 +++++++++++---------- goalc/compiler/compilation/Atoms.cpp | 8 +- goalc/compiler/compilation/Block.cpp | 19 +- goalc/compiler/compilation/ControlFlow.cpp | 44 ++-- goalc/compiler/compilation/Define.cpp | 67 +++--- goalc/compiler/compilation/Function.cpp | 45 ++-- goalc/compiler/compilation/Macro.cpp | 4 +- goalc/compiler/compilation/Math.cpp | 187 ++++++++------- goalc/compiler/compilation/State.cpp | 37 +-- goalc/compiler/compilation/Static.cpp | 34 ++- goalc/compiler/compilation/Type.cpp | 170 +++++++------- goalc/debugger/DebugInfo.cpp | 17 +- goalc/debugger/DebugInfo.h | 13 +- goalc/debugger/Debugger.cpp | 4 +- goalc/debugger/Debugger.h | 4 +- goalc/debugger/disassemble.cpp | 34 ++- goalc/debugger/disassemble.h | 9 +- goalc/emitter/ObjectGenerator.cpp | 4 +- goalc/emitter/ObjectGenerator.h | 2 +- test/goalc/test_with_game.cpp | 2 +- test/test_emitter.cpp | 2 +- 32 files changed, 772 insertions(+), 677 deletions(-) diff --git a/common/goos/TextDB.cpp b/common/goos/TextDB.cpp index 3d2c1a752a..afd555d1ac 100644 --- a/common/goos/TextDB.cpp +++ b/common/goos/TextDB.cpp @@ -21,7 +21,7 @@ namespace goos { /*! * Initialize with the given string */ -SourceText::SourceText(std::string r) : text(std::move(r)) { +SourceText::SourceText(std::string r) : m_text(std::move(r)) { // find line breaks build_offsets(); } @@ -30,14 +30,14 @@ SourceText::SourceText(std::string r) : text(std::move(r)) { * Update line break data. Should be called any time the text is updated. */ void SourceText::build_offsets() { - offset_by_line.clear(); - offset_by_line.push_back(0); - for (uint32_t i = 0; i < text.size(); i++) { - if (text[i] == '\n') { - offset_by_line.push_back(i); + m_offset_by_line.clear(); + m_offset_by_line.push_back(0); + for (uint32_t i = 0; i < m_text.size(); i++) { + if (m_text[i] == '\n') { + m_offset_by_line.push_back(i); } } - offset_by_line.push_back(text.size()); + m_offset_by_line.push_back(m_text.size()); } /*! @@ -46,8 +46,8 @@ void SourceText::build_offsets() { std::string SourceText::get_line_containing_offset(int offset) { auto range = get_containing_line(offset); int start_offset = range.first ? 1 : 0; - return text.substr(range.first + start_offset, - std::max(0, range.second - range.first - start_offset)); + return m_text.substr(range.first + start_offset, + std::max(0, range.second - range.first - start_offset)); } /*! @@ -56,8 +56,8 @@ std::string SourceText::get_line_containing_offset(int offset) { * Error if not found. */ int SourceText::get_line_idx(int offset) { - for (uint32_t line = 0; line < offset_by_line.size() - 1; line++) { - if (offset >= offset_by_line[line] && offset <= offset_by_line[line + 1]) { + for (uint32_t line = 0; line < m_offset_by_line.size() - 1; line++) { + if (offset >= m_offset_by_line[line] && offset <= m_offset_by_line[line + 1]) { return line; } } @@ -66,19 +66,19 @@ int SourceText::get_line_idx(int offset) { } int SourceText::get_offset_of_line(int line_idx) { - return offset_by_line.at(line_idx); + return m_offset_by_line.at(line_idx); } /*! * Gets the [start, end) character offset of the line containing the given offset. */ std::pair SourceText::get_containing_line(int offset) { - for (uint32_t line = 0; line < offset_by_line.size() - 1; line++) { - if (offset >= offset_by_line[line] && offset <= offset_by_line[line + 1]) { - return std::make_pair(offset_by_line[line], offset_by_line[line + 1]); + for (uint32_t line = 0; line < m_offset_by_line.size() - 1; line++) { + if (offset >= m_offset_by_line[line] && offset <= m_offset_by_line[line + 1]) { + return std::make_pair(m_offset_by_line[line], m_offset_by_line[line + 1]); } } - return std::make_pair(0, (int)text.size()); + return std::make_pair(0, (int)m_text.size()); } /*! @@ -86,7 +86,7 @@ std::pair SourceText::get_containing_line(int offset) { */ FileText::FileText(const std::string& filename, const std::string& description_name) : m_filename(filename), m_desc_name(description_name) { - text = file_util::read_text_file(m_filename); + m_text = file_util::read_text_file(m_filename); build_offsets(); } @@ -94,7 +94,7 @@ FileText::FileText(const std::string& filename, const std::string& description_n * Inform the TextDB about a source of text. */ void TextDb::insert(const std::shared_ptr& frag) { - fragments.push_back(frag); + m_fragments.push_back(frag); } /*! @@ -108,7 +108,7 @@ void TextDb::link(const Object& o, std::shared_ptr frag, int offset) TextRef ref; ref.offset = offset; ref.frag = std::move(frag); - map[o.heap_obj] = ref; + m_map[o.heap_obj] = ref; } /*! @@ -116,8 +116,8 @@ void TextDb::link(const Object& o, std::shared_ptr frag, int offset) */ std::string TextDb::get_info_for(const Object& o, bool* terminate_compiler_error) const { if (o.is_pair()) { - auto kv = map.find(o.heap_obj); - if (kv != map.end()) { + auto kv = m_map.find(o.heap_obj); + if (kv != m_map.end()) { if (terminate_compiler_error) { *terminate_compiler_error = kv->second.frag->terminate_compiler_error(); } @@ -150,6 +150,48 @@ std::string TextDb::get_info_for(const std::shared_ptr& frag, int of return result + pointer; } +std::optional TextDb::try_get_short_info(const Object& o) const { + if (o.is_pair()) { + auto it = m_map.find(o.heap_obj); + if (it != m_map.end()) { + auto& frag = it->second.frag; + // shorten the string + std::string name = frag->get_description(); + size_t start = 0; + for (size_t i = 0; i < name.size(); i++) { + if (name[i] == '/' || name[i] == '\\') { + start = i + 1; + } + } + if (start < name.size()) { + name = name.substr(start); + } + + ShortInfo result; + result.filename = name; + + int line_idx = frag->get_line_idx(it->second.offset); + result.line_idx_to_display = line_idx + 1; + + int offset_of_line = frag->get_offset_of_line(line_idx); + int offset_of_next_line = frag->get_offset_of_line(line_idx + 1); + + int line_length = offset_of_next_line - offset_of_line; + + int start_offset_in_line = it->second.offset - offset_of_line - 1; + result.pos_in_line = std::max(start_offset_in_line, 0); + result.line_text = std::string(frag->get_text() + offset_of_line + 1, line_length - 1); + return result; + } + } + + return {}; +} + +bool TextDb::has_info(const Object& o) const { + return o.is_pair() && (m_map.find(o.heap_obj) != m_map.end()); +} + /*! * Make child have the same location in the source as parent. For example, if parent generates * code that we want to be associated with the parent's location in source. @@ -158,15 +200,15 @@ std::string TextDb::get_info_for(const std::shared_ptr& frag, int of */ void TextDb::inherit_info(const Object& parent, const Object& child) { if (parent.is_pair() && child.is_pair()) { - auto parent_kv = map.find(parent.heap_obj); - if (parent_kv != map.end()) { + auto parent_kv = m_map.find(parent.heap_obj); + if (parent_kv != m_map.end()) { std::vector children = {&child}; // mark all forms as children. This will help with error messages in macros, and makes // (add-macro-to-autocomplete) work properly. while (!children.empty()) { auto top = children.back(); children.pop_back(); - if (map.insert({top->heap_obj, parent_kv->second}).second) { + if (m_map.insert({top->heap_obj, parent_kv->second}).second) { if (top->as_pair()->car.is_pair()) { children.push_back(&top->as_pair()->car); } diff --git a/common/goos/TextDB.h b/common/goos/TextDB.h index f9bd51e4a8..3418036fa4 100644 --- a/common/goos/TextDB.h +++ b/common/goos/TextDB.h @@ -18,6 +18,7 @@ #include #include #include +#include #include "common/goos/Object.h" @@ -29,8 +30,8 @@ class SourceText { public: explicit SourceText(std::string r); SourceText() = default; - const char* get_text() { return text.c_str(); } - int get_size() { return text.size(); } + const char* get_text() { return m_text.c_str(); } + int get_size() { return m_text.size(); } virtual std::string get_description() = 0; std::string get_line_containing_offset(int offset); int get_line_idx(int offset); @@ -44,8 +45,8 @@ class SourceText { protected: void build_offsets(); - std::string text; - std::vector offset_by_line; + std::string m_text; + std::vector m_offset_by_line; std::pair get_containing_line(int offset); }; @@ -91,14 +92,23 @@ struct TextRef { class TextDb { public: + struct ShortInfo { + std::string filename; + int line_idx_to_display = -1; + int pos_in_line = -1; + std::string line_text; + }; + void insert(const std::shared_ptr& frag); void link(const Object& o, std::shared_ptr frag, int offset); std::string get_info_for(const Object& o, bool* terminate_compiler_error = nullptr) const; std::string get_info_for(const std::shared_ptr& frag, int offset) const; + std::optional try_get_short_info(const Object& o) const; + bool has_info(const Object& o) const; void inherit_info(const Object& parent, const Object& child); private: - std::vector> fragments; - std::unordered_map, TextRef> map; + std::vector> m_fragments; + std::unordered_map, TextRef> m_map; }; } // namespace goos diff --git a/goalc/compiler/CodeGenerator.cpp b/goalc/compiler/CodeGenerator.cpp index 6c0e323664..3f29724b10 100644 --- a/goalc/compiler/CodeGenerator.cpp +++ b/goalc/compiler/CodeGenerator.cpp @@ -32,7 +32,9 @@ std::vector CodeGenerator::run(const TypeSystem* ts) { f->name().c_str()); throw std::runtime_error("Failed to codegen."); } - m_gen.add_function_to_seg(f->segment, &m_debug_info->add_function(f->name(), m_fe->name())); + auto rec = + m_gen.add_function_to_seg(f->segment, &m_debug_info->add_function(f->name(), m_fe->name())); + rec.debug->function = f; } // next, add all static objects. @@ -42,14 +44,14 @@ std::vector CodeGenerator::run(const TypeSystem* ts) { // next, add instructions to functions for (size_t i = 0; i < m_fe->functions().size(); i++) { - do_function(m_fe->functions().at(i).get(), i); + do_function(m_fe->functions().at(i), i); } // generate a v3 object. return m_gen.generate_data_v3(ts).to_vector(); } -void CodeGenerator::do_function(FunctionEnv* env, int f_idx) { +void CodeGenerator::do_function(const std::shared_ptr& env, int f_idx) { if (env->is_asm_func) { do_asm_function(env, f_idx, env->asm_func_saved_regs); } else { @@ -61,7 +63,7 @@ void CodeGenerator::do_function(FunctionEnv* env, int f_idx) { * Add instructions to the function, specified by index. * Generates prologues / epilogues. */ -void CodeGenerator::do_goal_function(FunctionEnv* env, int f_idx) { +void CodeGenerator::do_goal_function(const std::shared_ptr& env, int f_idx) { bool use_new_xmms = true; auto* debug = &m_debug_info->function_by_name(env->name()); @@ -161,7 +163,7 @@ void CodeGenerator::do_goal_function(FunctionEnv* env, int f_idx) { for (int ir_idx = 0; ir_idx < int(env->code().size()); ir_idx++) { auto& ir = env->code().at(ir_idx); // start of IR - auto i_rec = m_gen.add_ir(f_rec, ir->print()); + auto i_rec = m_gen.add_ir(f_rec); // load anything off the stack that was spilled and is needed. auto& bonus = allocs.stack_ops.at(ir_idx); @@ -269,7 +271,9 @@ void CodeGenerator::do_goal_function(FunctionEnv* env, int f_idx) { m_gen.add_instr_no_ir(f_rec, IGen::ret(), InstructionInfo::Kind::EPILOGUE); } -void CodeGenerator::do_asm_function(FunctionEnv* env, int f_idx, bool allow_saved_regs) { +void CodeGenerator::do_asm_function(const std::shared_ptr& env, + int f_idx, + bool allow_saved_regs) { auto f_rec = m_gen.get_existing_function_record(f_idx); const auto& allocs = env->alloc_result(); @@ -297,7 +301,7 @@ void CodeGenerator::do_asm_function(FunctionEnv* env, int f_idx, bool allow_save for (int ir_idx = 0; ir_idx < int(env->code().size()); ir_idx++) { auto& ir = env->code().at(ir_idx); // start of IR - auto i_rec = m_gen.add_ir(f_rec, ir->print()); + auto i_rec = m_gen.add_ir(f_rec); // Make sure we aren't automatically accessing the stack. if (!allocs.stack_ops.at(ir_idx).ops.empty()) { diff --git a/goalc/compiler/CodeGenerator.h b/goalc/compiler/CodeGenerator.h index 56d65c8931..bc97bcd5c5 100644 --- a/goalc/compiler/CodeGenerator.h +++ b/goalc/compiler/CodeGenerator.h @@ -20,9 +20,9 @@ class CodeGenerator { emitter::ObjectGeneratorStats get_obj_stats() const { return m_gen.get_stats(); } private: - void do_function(FunctionEnv* env, int f_idx); - void do_goal_function(FunctionEnv* env, int f_idx); - void do_asm_function(FunctionEnv* env, int f_idx, bool allow_saved_regs); + void do_function(const std::shared_ptr& env, int f_idx); + void do_goal_function(const std::shared_ptr& env, int f_idx); + void do_asm_function(const std::shared_ptr& env, int f_idx, bool allow_saved_regs); emitter::ObjectGenerator m_gen; FileEnv* m_fe = nullptr; DebugInfo* m_debug_info = nullptr; diff --git a/goalc/compiler/Compiler.cpp b/goalc/compiler/Compiler.cpp index 800dbc856a..ca1dba8b50 100644 --- a/goalc/compiler/Compiler.cpp +++ b/goalc/compiler/Compiler.cpp @@ -12,7 +12,7 @@ using namespace goos; Compiler::Compiler(std::unique_ptr repl) - : m_debugger(&m_listener), m_repl(std::move(repl)) { + : m_debugger(&m_listener, &m_goos.reader), m_repl(std::move(repl)) { m_listener.add_debugger(&m_debugger); m_ts.add_builtin_types(); m_global_env = std::make_unique(); @@ -123,9 +123,6 @@ FileEnv* Compiler::compile_object_file(const std::string& name, bool allow_emit) { auto file_env = m_global_env->add_file(name); Env* compilation_env = file_env; - if (!allow_emit) { - compilation_env = file_env->add_no_emit_env(); - } file_env->add_top_level_function( compile_top_level_function("top-level", std::move(code), compilation_env)); @@ -140,19 +137,19 @@ FileEnv* Compiler::compile_object_file(const std::string& name, std::unique_ptr Compiler::compile_top_level_function(const std::string& name, const goos::Object& code, Env* env) { - auto fe = std::make_unique(env, name); + auto fe = std::make_unique(env, name, &m_goos.reader); fe->set_segment(TOP_LEVEL_SEGMENT); auto result = compile_error_guard(code, fe.get()); // only move to return register if we actually got a result if (!dynamic_cast(result)) { - fe->emit(std::make_unique(fe->make_gpr(result->type()), result->to_gpr(fe.get()), - emitter::gRegInfo.get_gpr_ret_reg())); + fe->emit_ir(code, fe->make_gpr(result->type()), result->to_gpr(code, fe.get()), + emitter::gRegInfo.get_gpr_ret_reg()); } if (!fe->code().empty()) { - fe->emit_ir(); + fe->emit_ir(code); } fe->finish(); @@ -190,6 +187,9 @@ Val* Compiler::compile_error_guard(const goos::Object& code, Env* env) { } catch (std::runtime_error& e) { + fmt::print(fg(fmt::color::crimson) | fmt::emphasis::bold, "-- Compilation Error! --\n"); + fmt::print(fmt::emphasis::bold, "{}\n", e.what()); + auto obj_print = code.print(); if (obj_print.length() > 80) { obj_print = obj_print.substr(0, 80); @@ -280,7 +280,8 @@ std::vector Compiler::codegen_object_file(FileEnv* env) { auto result = gen.run(&m_ts); for (auto& f : env->functions()) { if (f->settings.print_asm) { - fmt::print("{}\n", debug_info->disassemble_function_by_name(f->name(), &ok)); + fmt::print("{}\n", + debug_info->disassemble_function_by_name(f->name(), &ok, &m_goos.reader)); } } auto stats = gen.get_obj_stats(); @@ -300,7 +301,7 @@ bool Compiler::codegen_and_disassemble_object_file(FileEnv* env, CodeGenerator gen(env, debug_info); *data_out = gen.run(&m_ts); bool ok = true; - *asm_out = debug_info->disassemble_all_functions(&ok); + *asm_out = debug_info->disassemble_all_functions(&ok, &m_goos.reader); return ok; } diff --git a/goalc/compiler/Compiler.h b/goalc/compiler/Compiler.h index 4f67a57869..b7b3a7cbf9 100644 --- a/goalc/compiler/Compiler.h +++ b/goalc/compiler/Compiler.h @@ -68,8 +68,8 @@ class Compiler { bool m_want_exit = false; bool m_want_reload = false; listener::Listener m_listener; - Debugger m_debugger; goos::Interpreter m_goos; + Debugger m_debugger; std::unordered_map m_symbol_types; std::unordered_map m_global_constants; std::unordered_map m_inlineable_functions; @@ -98,7 +98,8 @@ class Compiler { void set_bitfield(const goos::Object& form, BitFieldVal* dst, RegVal* src, Env* env); void set_bitfield_128(const goos::Object& form, BitFieldVal* dst, RegVal* src, Env* env); - void set_bits_in_bitfield(int size, + void set_bits_in_bitfield(const goos::Object& form, + int size, int offset, RegVal* dst, RegVal* src, @@ -346,7 +347,11 @@ class Compiler { StaticStructure* structure, int offset, Env* env); - void compile_constant_product(RegVal* dest, RegVal* src, int stride, Env* env); + void compile_constant_product(const goos::Object& form, + RegVal* dest, + RegVal* src, + int stride, + Env* env); void check_vector_float_regs(const goos::Object& form, Env* env, std::vector> args); diff --git a/goalc/compiler/Env.cpp b/goalc/compiler/Env.cpp index 3fdbd86a47..5a8fed1acf 100644 --- a/goalc/compiler/Env.cpp +++ b/goalc/compiler/Env.cpp @@ -2,19 +2,12 @@ #include "third-party/fmt/core.h" #include "Env.h" #include "IR.h" +#include "common/goos/Reader.h" /////////////////// // Env /////////////////// -/*! - * Emit IR into the function currently being compiled. - */ -void Env::emit(std::unique_ptr ir) { - // by default, we don't know how, so pass it up and hope for the best. - m_parent->emit(std::move(ir)); -} - /*! * Allocate an IRegister with the given type. */ @@ -56,6 +49,12 @@ std::unordered_map& Env::get_label_map() { return parent()->get_label_map(); } +void Env::emit(const goos::Object& form, std::unique_ptr ir) { + auto e = function_env(); + assert(e); + e->emit(form, std::move(ir), this); +} + /////////////////// // GlobalEnv /////////////////// @@ -69,15 +68,6 @@ std::string GlobalEnv::print() { return "global-env"; } -/*! - * Emit IR into the function currently being compiled. - */ -void GlobalEnv::emit(std::unique_ptr ir) { - // by default, we don't know how, so pass it up and hope for the best. - (void)ir; - throw std::runtime_error("cannot emit to GlobalEnv"); -} - /*! * Allocate an IRegister with the given type. */ @@ -113,25 +103,6 @@ FileEnv* GlobalEnv::add_file(std::string name) { return m_files.back().get(); } -/////////////////// -// NoEmitEnv -/////////////////// - -/*! - * Get the name of a NoEmitEnv - */ -std::string NoEmitEnv::print() { - return "no-emit-env"; -} - -/*! - * Emit - which is invalid - into a NoEmitEnv and throw an exception. - */ -void NoEmitEnv::emit(std::unique_ptr ir) { - (void)ir; - throw std::runtime_error("emit into a no-emit env!"); -} - /////////////////// // BlockEnv /////////////////// @@ -179,12 +150,6 @@ void FileEnv::add_top_level_function(std::unique_ptr fe) { m_top_level_func = m_functions.back().get(); } -NoEmitEnv* FileEnv::add_no_emit_env() { - assert(!m_no_emit_env); - m_no_emit_env = std::make_unique(this); - return m_no_emit_env.get(); -} - void FileEnv::debug_print_tl() { if (m_top_level_func) { for (auto& code : m_top_level_func->code()) { @@ -203,17 +168,42 @@ bool FileEnv::is_empty() { // FunctionEnv /////////////////// -FunctionEnv::FunctionEnv(Env* parent, std::string name) - : DeclareEnv(EnvKind::FUNCTION_ENV, parent), m_name(std::move(name)) {} +FunctionEnv::FunctionEnv(Env* parent, std::string name, const goos::Reader* reader) + : DeclareEnv(EnvKind::FUNCTION_ENV, parent), m_name(std::move(name)), m_reader(reader) {} std::string FunctionEnv::print() { return "function-" + m_name; } -void FunctionEnv::emit(std::unique_ptr ir) { +void FunctionEnv::emit(const goos::Object& form, std::unique_ptr ir, Env* lowest_env) { ir->add_constraints(&m_constraints, m_code.size()); m_code.push_back(std::move(ir)); + if (m_reader->db.has_info(form)) { + // if we have info, it means we came from real code and we can just use that. + m_code_debug_source.push_back(form); + } else { + // let's see if we're in a macro: + auto mac_env = lowest_env->macro_expand_env(); + if (mac_env) { + while (mac_env) { + if (m_reader->db.has_info(mac_env->macro_use_location())) { + m_code_debug_source.push_back(mac_env->macro_use_location()); + return; + } + auto parent = mac_env->parent(); + if (parent) { + mac_env = parent->macro_expand_env(); + } else { + m_code_debug_source.push_back(form); + return; + } + } + } else { + m_code_debug_source.push_back(form); + } + } } + void FunctionEnv::finish() { resolve_gotos(); } diff --git a/goalc/compiler/Env.h b/goalc/compiler/Env.h index c7b585bd8e..fae453fe50 100644 --- a/goalc/compiler/Env.h +++ b/goalc/compiler/Env.h @@ -32,7 +32,7 @@ class Env { public: explicit Env(EnvKind kind, Env* parent); virtual std::string print() = 0; - virtual void emit(std::unique_ptr ir); + void emit(const goos::Object& form, std::unique_ptr ir); virtual RegVal* make_ireg(const TypeSpec& ts, RegClass reg_class); virtual void constrain_reg(IRegConstraint constraint); // todo, remove! virtual RegVal* lexical_lookup(goos::Object sym); @@ -45,8 +45,8 @@ class Env { Env* parent() { return m_parent; } template - void emit_ir(Args&&... args) { - emit(std::make_unique(std::forward(args)...)); + void emit_ir(const goos::Object& form, Args&&... args) { + emit(form, std::make_unique(std::forward(args)...)); } FileEnv* file_env() { return m_lowest_envs.file_env; } @@ -74,7 +74,6 @@ class GlobalEnv : public Env { public: GlobalEnv(); std::string print() override; - void emit(std::unique_ptr ir) override; RegVal* make_ireg(const TypeSpec& ts, RegClass reg_class) override; void constrain_reg(IRegConstraint constraint) override; RegVal* lexical_lookup(goos::Object sym) override; @@ -87,18 +86,6 @@ class GlobalEnv : public Env { std::vector> m_files; }; -/*! - * An Env that doesn't allow emitting to go past it. Used to make sure source code that shouldn't - * generate machine code actually does this. - */ -class NoEmitEnv : public Env { - public: - explicit NoEmitEnv(Env* parent) : Env(EnvKind::OTHER_ENV, parent) {} - std::string print() override; - void emit(std::unique_ptr ir) override; - ~NoEmitEnv() = default; -}; - /*! * An Env for an entire file (or input to the REPL) */ @@ -109,9 +96,8 @@ class FileEnv : public Env { void add_function(std::unique_ptr fe); void add_top_level_function(std::unique_ptr fe); void add_static(std::unique_ptr s); - NoEmitEnv* add_no_emit_env(); void debug_print_tl(); - const std::vector>& functions() { return m_functions; } + const std::vector>& functions() { return m_functions; } const std::vector>& statics() { return m_statics; } std::string get_anon_function_name() { return "anon-function-" + std::to_string(m_anon_func_counter++); @@ -134,9 +120,8 @@ class FileEnv : public Env { protected: std::string m_name; - std::vector> m_functions; + std::vector> m_functions; std::vector> m_statics; - std::unique_ptr m_no_emit_env = nullptr; int m_anon_func_counter = 0; std::vector> m_vals; @@ -178,14 +163,15 @@ struct UnresolvedConditionalGoto { class FunctionEnv : public DeclareEnv { public: - FunctionEnv(Env* parent, std::string name); + FunctionEnv(Env* parent, std::string name, const goos::Reader* reader); std::string print() override; std::unordered_map& get_label_map() override; void set_segment(int seg) { segment = seg; } - void emit(std::unique_ptr ir) override; + void emit(const goos::Object& form, std::unique_ptr ir, Env* lowest_env); void finish(); RegVal* make_ireg(const TypeSpec& ts, RegClass reg_class) override; const std::vector>& code() const { return m_code; } + const std::vector& code_source() const { return m_code_debug_source; } int max_vars() const { return m_iregs.size(); } const std::vector& constraints() { return m_constraints; } void constrain(const IRegConstraint& c) { m_constraints.push_back(c); } @@ -239,17 +225,20 @@ class FunctionEnv : public DeclareEnv { void resolve_gotos(); std::string m_name; std::vector> m_code; + std::vector m_code_debug_source; + std::vector> m_iregs; std::vector> m_vals; std::vector> m_envs; std::vector m_constraints; - // todo, unresolved gotos + AllocationResult m_regalloc_result; bool m_aligned_stack_required = false; int m_stack_var_slots_used = 0; std::unordered_map m_labels; std::vector> m_unnamed_labels; + const goos::Reader* m_reader = nullptr; }; class BlockEnv : public Env { diff --git a/goalc/compiler/Util.cpp b/goalc/compiler/Util.cpp index 77be5dd816..24e5b56180 100644 --- a/goalc/compiler/Util.cpp +++ b/goalc/compiler/Util.cpp @@ -278,25 +278,29 @@ std::vector Compiler::get_list_as_vector(const goos::Object& o, } } -void Compiler::compile_constant_product(RegVal* dest, RegVal* src, int stride, Env* env) { +void Compiler::compile_constant_product(const goos::Object& form, + RegVal* dest, + RegVal* src, + int stride, + Env* env) { // todo - support imul with an imm. assert(stride); bool is_power_of_two = (stride & (stride - 1)) == 0; if (stride == 1) { - env->emit_ir(dest, src); + env->emit_ir(form, dest, src); } else if (is_power_of_two) { for (int i = 0; i < 16; i++) { if (stride == (1 << i)) { - env->emit_ir(dest, src); - env->emit_ir(IntegerMathKind::SHL_64, dest, i); + env->emit_ir(form, dest, src); + env->emit_ir(form, IntegerMathKind::SHL_64, dest, i); return; } } assert(false); } else { // get the multiplier - env->emit_ir(dest, stride); - env->emit_ir(IntegerMathKind::IMUL_32, dest, src); + env->emit_ir(form, dest, stride); + env->emit_ir(form, IntegerMathKind::IMUL_32, dest, src); } } \ No newline at end of file diff --git a/goalc/compiler/Val.cpp b/goalc/compiler/Val.cpp index 71aa0423cd..4c76918ec1 100644 --- a/goalc/compiler/Val.cpp +++ b/goalc/compiler/Val.cpp @@ -6,13 +6,13 @@ /*! * Fallback to_gpr if a more optimized one is not provided. */ -RegVal* Val::to_gpr(Env* fe) { - auto rv = to_reg(fe); +RegVal* Val::to_gpr(const goos::Object& form, Env* fe) { + auto rv = to_reg(form, fe); if (rv->ireg().reg_class == RegClass::GPR_64) { return rv; } else { auto re = fe->make_gpr(coerce_to_reg_type(m_ts)); - fe->emit(std::make_unique(re, rv)); + fe->emit(form, std::make_unique(re, rv)); return re; } } @@ -20,13 +20,13 @@ RegVal* Val::to_gpr(Env* fe) { /*! * Fallback to_fpr if a more optimized one is not provided. */ -RegVal* Val::to_fpr(Env* fe) { - auto rv = to_reg(fe); +RegVal* Val::to_fpr(const goos::Object& form, Env* fe) { + auto rv = to_reg(form, fe); if (rv->ireg().reg_class == RegClass::FLOAT) { return rv; } else { auto re = fe->make_fpr(coerce_to_reg_type(m_ts)); - fe->emit(std::make_unique(re, rv)); + fe->emit(form, std::make_unique(re, rv)); return re; } } @@ -34,48 +34,48 @@ RegVal* Val::to_fpr(Env* fe) { /*! * Fallback to_xmm128 if a more optimized one is not provided. */ -RegVal* Val::to_xmm128(Env* fe) { - auto rv = to_reg(fe); +RegVal* Val::to_xmm128(const goos::Object& form, Env* fe) { + auto rv = to_reg(form, fe); if (rv->ireg().reg_class == RegClass::INT_128 || rv->ireg().reg_class == RegClass::VECTOR_FLOAT) { return rv; } else { auto re = fe->make_ireg(coerce_to_reg_type(m_ts), RegClass::INT_128); - fe->emit(std::make_unique(re, rv)); + fe->emit(form, std::make_unique(re, rv)); return re; } } -RegVal* RegVal::to_reg(Env* fe) { +RegVal* RegVal::to_reg(const goos::Object& /*form*/, Env* fe) { (void)fe; return this; } -RegVal* RegVal::to_gpr(Env* fe) { +RegVal* RegVal::to_gpr(const goos::Object& form, Env* fe) { if (m_ireg.reg_class == RegClass::GPR_64) { return this; } else { auto re = fe->make_gpr(coerce_to_reg_type(m_ts)); - fe->emit(std::make_unique(re, this)); + fe->emit(form, std::make_unique(re, this)); return re; } } -RegVal* RegVal::to_fpr(Env* fe) { +RegVal* RegVal::to_fpr(const goos::Object& form, Env* fe) { if (m_ireg.reg_class == RegClass::FLOAT) { return this; } else { auto re = fe->make_fpr(coerce_to_reg_type(m_ts)); - fe->emit(std::make_unique(re, this)); + fe->emit(form, std::make_unique(re, this)); return re; } } -RegVal* RegVal::to_xmm128(Env* fe) { +RegVal* RegVal::to_xmm128(const goos::Object& form, Env* fe) { if (m_ireg.reg_class == RegClass::INT_128 || m_ireg.reg_class == RegClass::VECTOR_FLOAT) { return this; } else { auto re = fe->make_ireg(coerce_to_reg_type(m_ts), RegClass::INT_128); - fe->emit(std::make_unique(re, this)); + fe->emit(form, std::make_unique(re, this)); return re; } } @@ -88,59 +88,59 @@ const std::optional& RegVal::rlet_constraint() const { return m_rlet_constraint; } -RegVal* IntegerConstantVal::to_reg(Env* fe) { +RegVal* IntegerConstantVal::to_reg(const goos::Object& form, Env* fe) { if (m_value.uses_gpr()) { auto rv = fe->make_gpr(coerce_to_reg_type(m_ts)); - fe->emit(std::make_unique(rv, m_value.value_64())); + fe->emit(form, std::make_unique(rv, m_value.value_64())); return rv; } else { auto rv = fe->make_ireg(m_ts, RegClass::INT_128); auto gpr = fe->make_gpr(TypeSpec("object")); auto xmm_temp = fe->make_ireg(TypeSpec("object"), RegClass::INT_128); - fe->emit_ir(gpr, m_value.value_128_lo()); - fe->emit_ir(xmm_temp, gpr); - fe->emit_ir(gpr, m_value.value_128_hi()); - fe->emit_ir(rv, gpr); - fe->emit_ir(true, rv, rv, xmm_temp, IR_Int128Math3Asm::Kind::PCPYLD); + fe->emit_ir(form, gpr, m_value.value_128_lo()); + fe->emit_ir(form, xmm_temp, gpr); + fe->emit_ir(form, gpr, m_value.value_128_hi()); + fe->emit_ir(form, rv, gpr); + fe->emit_ir(form, true, rv, rv, xmm_temp, IR_Int128Math3Asm::Kind::PCPYLD); return rv; } } -RegVal* SymbolVal::to_reg(Env* fe) { +RegVal* SymbolVal::to_reg(const goos::Object& form, Env* fe) { auto re = fe->make_gpr(coerce_to_reg_type(m_ts)); - fe->emit(std::make_unique(re, m_name)); + fe->emit(form, std::make_unique(re, m_name)); return re; } -RegVal* SymbolValueVal::to_reg(Env* fe) { +RegVal* SymbolValueVal::to_reg(const goos::Object& form, Env* fe) { auto re = fe->make_gpr(coerce_to_reg_type(m_ts)); - fe->emit(std::make_unique(re, m_sym, m_sext)); + fe->emit(form, std::make_unique(re, m_sym, m_sext)); return re; } -RegVal* StaticVal::to_reg(Env* fe) { +RegVal* StaticVal::to_reg(const goos::Object& form, Env* fe) { auto re = fe->make_gpr(coerce_to_reg_type(m_ts)); - fe->emit(std::make_unique(re, obj)); + fe->emit(form, std::make_unique(re, obj)); return re; } -RegVal* LambdaVal::to_reg(Env* fe) { +RegVal* LambdaVal::to_reg(const goos::Object& form, Env* fe) { auto re = fe->make_gpr(coerce_to_reg_type(m_ts)); assert(func); - fe->emit(std::make_unique(re, func)); + fe->emit(form, std::make_unique(re, func)); return re; } -RegVal* InlinedLambdaVal::to_reg(Env* fe) { +RegVal* InlinedLambdaVal::to_reg(const goos::Object& form, Env* fe) { throw std::runtime_error("Cannot put InlinedLambdaVal in a register."); - return lv->to_reg(fe); + return lv->to_reg(form, fe); } -RegVal* FloatConstantVal::to_reg(Env* fe) { +RegVal* FloatConstantVal::to_reg(const goos::Object& form, Env* fe) { auto re = fe->make_fpr(coerce_to_reg_type(m_ts)); - fe->emit(std::make_unique(re, m_value)); + fe->emit(form, std::make_unique(re, m_value)); return re; } @@ -161,60 +161,62 @@ Val* get_constant_offset_and_base(MemoryOffsetConstantVal* in, int64_t* offset_o } } // namespace -RegVal* MemoryOffsetConstantVal::to_reg(Env* fe) { +RegVal* MemoryOffsetConstantVal::to_reg(const goos::Object& form, Env* fe) { auto re = fe->make_gpr(coerce_to_reg_type(m_ts)); s64 final_offset; auto final_base = get_constant_offset_and_base(this, &final_offset); if (final_offset == 0) { - fe->emit_ir(re, final_base->to_gpr(fe)); + fe->emit_ir(form, re, final_base->to_gpr(form, fe)); } else { - fe->emit(std::make_unique(re, int64_t(final_offset))); - fe->emit(std::make_unique(IntegerMathKind::ADD_64, re, final_base->to_gpr(fe))); + fe->emit(form, std::make_unique(re, int64_t(final_offset))); + fe->emit(form, std::make_unique(IntegerMathKind::ADD_64, re, + final_base->to_gpr(form, fe))); } return re; } -RegVal* MemoryOffsetVal::to_reg(Env* fe) { +RegVal* MemoryOffsetVal::to_reg(const goos::Object& form, Env* fe) { auto re = fe->make_gpr(coerce_to_reg_type(m_ts)); - fe->emit(std::make_unique(re, offset->to_gpr(fe))); - fe->emit(std::make_unique(IntegerMathKind::ADD_64, re, base->to_gpr(fe))); + fe->emit(form, std::make_unique(re, offset->to_gpr(form, fe))); + fe->emit(form, + std::make_unique(IntegerMathKind::ADD_64, re, base->to_gpr(form, fe))); return re; } -RegVal* MemoryDerefVal::to_reg(Env* fe) { +RegVal* MemoryDerefVal::to_reg(const goos::Object& form, Env* fe) { auto re = fe->make_ireg(coerce_to_reg_type(m_ts), info.reg); auto base_as_co = dynamic_cast(base); if (base_as_co) { s64 offset; auto final_base = get_constant_offset_and_base(base_as_co, &offset); - fe->emit_ir(re, (int)offset, final_base->to_gpr(fe), info); + fe->emit_ir(form, re, (int)offset, final_base->to_gpr(form, fe), info); } else { - auto addr = base->to_gpr(fe); - fe->emit(std::make_unique(re, 0, addr, info)); + auto addr = base->to_gpr(form, fe); + fe->emit(form, std::make_unique(re, 0, addr, info)); } return re; } -RegVal* MemoryDerefVal::to_fpr(Env* fe) { +RegVal* MemoryDerefVal::to_fpr(const goos::Object& form, Env* fe) { auto base_as_co = dynamic_cast(base); auto re = fe->make_fpr(coerce_to_reg_type(m_ts)); if (base_as_co) { s64 offset; auto final_base = get_constant_offset_and_base(base_as_co, &offset); - fe->emit_ir(re, offset, final_base->to_gpr(fe), info); + fe->emit_ir(form, re, offset, final_base->to_gpr(form, fe), info); } else { - auto addr = base->to_gpr(fe); - fe->emit(std::make_unique(re, 0, addr, info)); + auto addr = base->to_gpr(form, fe); + fe->emit(form, std::make_unique(re, 0, addr, info)); } return re; } -RegVal* AliasVal::to_reg(Env* fe) { - auto as_old_type = base->to_reg(fe); +RegVal* AliasVal::to_reg(const goos::Object& form, Env* fe) { + auto as_old_type = base->to_reg(form, fe); auto result = fe->make_ireg(m_ts, as_old_type->ireg().reg_class); - fe->emit(std::make_unique(result, as_old_type)); + fe->emit(form, std::make_unique(result, as_old_type)); return result; } @@ -226,20 +228,20 @@ std::string PairEntryVal::print() const { } } -RegVal* PairEntryVal::to_reg(Env* fe) { +RegVal* PairEntryVal::to_reg(const goos::Object& form, Env* fe) { int offset = is_car ? -2 : 2; auto re = fe->make_gpr(coerce_to_reg_type(m_ts)); MemLoadInfo info; info.reg = RegClass::GPR_64; info.sign_extend = true; info.size = 4; - fe->emit(std::make_unique(re, offset, base->to_gpr(fe), info)); + fe->emit(form, std::make_unique(re, offset, base->to_gpr(form, fe), info)); return re; } -RegVal* StackVarAddrVal::to_reg(Env* fe) { +RegVal* StackVarAddrVal::to_reg(const goos::Object& form, Env* fe) { auto re = fe->make_gpr(coerce_to_reg_type(m_ts)); - fe->emit(std::make_unique(re, m_slot)); + fe->emit(form, std::make_unique(re, m_slot)); return re; } @@ -248,7 +250,7 @@ std::string BitFieldVal::print() const { m_parent->print(), m_use_128); } -RegVal* BitFieldVal::to_reg(Env* env) { +RegVal* BitFieldVal::to_reg(const goos::Object& form, Env* env) { int start_bit = -1; auto fe = env->function_env(); RegVal* result = fe->make_ireg(coerce_to_reg_type(m_ts), RegClass::GPR_64); @@ -257,15 +259,16 @@ RegVal* BitFieldVal::to_reg(Env* env) { if (m_offset < 64) { // accessing in the lower 64 bits, we can just get the value in a GPR. start_bit = m_offset; - RegVal* gpr = m_parent->to_gpr(env); - env->emit(std::make_unique(result, gpr)); + RegVal* gpr = m_parent->to_gpr(form, env); + env->emit(form, std::make_unique(result, gpr)); } else { // we need to get the value as a 128-bit integer - auto xmm = m_parent->to_reg(env); + auto xmm = m_parent->to_reg(form, env); assert(xmm->ireg().reg_class == RegClass::INT_128); auto xmm_temp = fe->make_ireg(TypeSpec("object"), RegClass::INT_128); - env->emit_ir(true, xmm_temp, xmm, xmm, IR_Int128Math3Asm::Kind::PCPYUD); - env->emit_ir(result, xmm_temp); + env->emit_ir(form, true, xmm_temp, xmm, xmm, + IR_Int128Math3Asm::Kind::PCPYUD); + env->emit_ir(form, result, xmm_temp); start_bit = m_offset - 64; } @@ -278,7 +281,7 @@ RegVal* BitFieldVal::to_reg(Env* env) { // shift left as much as possible to kill upper bits if (epad > 0) { - env->emit(std::make_unique(IntegerMathKind::SHL_64, result, epad)); + env->emit(form, std::make_unique(IntegerMathKind::SHL_64, result, epad)); } int next_shift = epad + spad; @@ -287,9 +290,11 @@ RegVal* BitFieldVal::to_reg(Env* env) { if (next_shift > 0) { if (m_sign_extend) { - env->emit(std::make_unique(IntegerMathKind::SAR_64, result, next_shift)); + env->emit(form, + std::make_unique(IntegerMathKind::SAR_64, result, next_shift)); } else { - env->emit(std::make_unique(IntegerMathKind::SHR_64, result, next_shift)); + env->emit(form, + std::make_unique(IntegerMathKind::SHR_64, result, next_shift)); } } diff --git a/goalc/compiler/Val.h b/goalc/compiler/Val.h index d1076b7c4e..f3181dd312 100644 --- a/goalc/compiler/Val.h +++ b/goalc/compiler/Val.h @@ -33,13 +33,13 @@ class Val { } virtual std::string print() const = 0; - virtual RegVal* to_reg(Env* fe) { + virtual RegVal* to_reg(const goos::Object& /*form*/, Env* fe) { (void)fe; throw std::runtime_error("to_reg called on invalid Val: " + print()); } - virtual RegVal* to_gpr(Env* fe); - virtual RegVal* to_fpr(Env* fe); - virtual RegVal* to_xmm128(Env* fe); + virtual RegVal* to_gpr(const goos::Object& form, Env* fe); + virtual RegVal* to_fpr(const goos::Object& form, Env* fe); + virtual RegVal* to_xmm128(const goos::Object& form, Env* fe); const TypeSpec& type() const { return m_ts; } void set_type(TypeSpec ts) { m_ts = std::move(ts); } @@ -72,10 +72,10 @@ class RegVal : public Val { IRegister ireg() const override { return m_ireg; } void change_class(RegClass new_class) { m_ireg.reg_class = new_class; } std::string print() const override { return m_ireg.to_string(); }; - RegVal* to_reg(Env* fe) override; - RegVal* to_gpr(Env* fe) override; - RegVal* to_fpr(Env* fe) override; - RegVal* to_xmm128(Env* fe) override; + RegVal* to_reg(const goos::Object& form, Env* fe) override; + RegVal* to_gpr(const goos::Object& form, Env* fe) override; + RegVal* to_fpr(const goos::Object& form, Env* fe) override; + RegVal* to_xmm128(const goos::Object& form, Env* fe) override; void set_rlet_constraint(emitter::Register reg); const std::optional& rlet_constraint() const; void force_on_stack() { m_on_stack = true; } @@ -99,7 +99,7 @@ class SymbolVal : public Val { } const std::string& name() const { return m_name; } std::string print() const override { return "<" + m_name + ">"; } - RegVal* to_reg(Env* fe) override; + RegVal* to_reg(const goos::Object& form, Env* fe) override; protected: std::string m_name; @@ -114,7 +114,7 @@ class SymbolValueVal : public Val { } const std::string& name() const { return m_sym->name(); } std::string print() const override { return "[<" + name() + ">]"; } - RegVal* to_reg(Env* fe) override; + RegVal* to_reg(const goos::Object& form, Env* fe) override; const SymbolVal* sym() const { return m_sym; } protected: @@ -132,7 +132,7 @@ class LambdaVal : public Val { std::string print() const override { return "lambda-" + lambda.debug_name; } FunctionEnv* func = nullptr; Lambda lambda; - RegVal* to_reg(Env* fe) override; + RegVal* to_reg(const goos::Object& form, Env* fe) override; }; class InlinedLambdaVal : public Val { @@ -140,7 +140,7 @@ class InlinedLambdaVal : public Val { explicit InlinedLambdaVal(TypeSpec ts, LambdaVal* _lv) : Val(std::move(ts)), lv(_lv) {} std::string print() const override { return "inline-lambda-" + lv->lambda.debug_name; } LambdaVal* lv = nullptr; - RegVal* to_reg(Env* fe) override; + RegVal* to_reg(const goos::Object& form, Env* fe) override; }; class StaticVal : public Val { @@ -148,7 +148,7 @@ class StaticVal : public Val { StaticVal(StaticObject* _obj, TypeSpec _ts) : Val(std::move(_ts)), obj(_obj) {} StaticObject* obj = nullptr; std::string print() const override { return "[" + obj->print() + "]"; } - RegVal* to_reg(Env* fe) override; + RegVal* to_reg(const goos::Object& form, Env* fe) override; }; struct MemLoadInfo { @@ -177,7 +177,7 @@ class StackVarAddrVal : public Val { int slot_count() const { return m_slot_count; } std::string print() const override { return "stack-" + std::to_string(m_slot); } - RegVal* to_reg(Env* fe) override; + RegVal* to_reg(const goos::Object& form, Env* fe) override; private: int m_slot, m_slot_count; @@ -196,7 +196,7 @@ class MemoryOffsetConstantVal : public Val { std::string print() const override { return "(" + base->print() + " + " + std::to_string(offset) + ")"; } - RegVal* to_reg(Env* fe) override; + RegVal* to_reg(const goos::Object& form, Env* fe) override; Val* base = nullptr; s64 offset = 0; }; @@ -206,7 +206,7 @@ class MemoryOffsetVal : public Val { MemoryOffsetVal(TypeSpec ts, Val* _base, Val* _offset) : Val(std::move(ts)), base(_base), offset(_offset) {} std::string print() const override { return "(" + base->print() + " + " + offset->print() + ")"; } - RegVal* to_reg(Env* fe) override; + RegVal* to_reg(const goos::Object& form, Env* fe) override; Val* base = nullptr; Val* offset = nullptr; }; @@ -216,8 +216,8 @@ class MemoryDerefVal : public Val { MemoryDerefVal(TypeSpec ts, Val* _base, MemLoadInfo _info) : Val(std::move(ts)), base(_base), info(_info) {} std::string print() const override { return "[" + base->print() + "]"; } - RegVal* to_reg(Env* fe) override; - RegVal* to_fpr(Env* fe) override; + RegVal* to_reg(const goos::Object& form, Env* fe) override; + RegVal* to_fpr(const goos::Object& form, Env* fe) override; Val* base = nullptr; MemLoadInfo info; }; @@ -227,7 +227,7 @@ class PairEntryVal : public Val { PairEntryVal(TypeSpec ts, Val* _base, bool _is_car) : Val(std::move(ts)), base(_base), is_car(_is_car) {} std::string print() const override; - RegVal* to_reg(Env* fe) override; + RegVal* to_reg(const goos::Object& form, Env* fe) override; Val* base = nullptr; bool is_car = false; }; @@ -236,7 +236,7 @@ class AliasVal : public Val { public: AliasVal(TypeSpec ts, Val* _base) : Val(std::move(ts)), base(_base) {} std::string print() const override { return "alias-of-" + base->print(); } - RegVal* to_reg(Env* fe) override; + RegVal* to_reg(const goos::Object& form, Env* fe) override; Val* base = nullptr; }; @@ -248,7 +248,7 @@ class IntegerConstantVal : public Val { } std::string print() const override { return std::string("integer-constant-") + m_value.print(); } - RegVal* to_reg(Env* fe) override; + RegVal* to_reg(const goos::Object& form, Env* fe) override; const ConstantValue& value() const { return m_value; } protected: @@ -259,7 +259,7 @@ class FloatConstantVal : public Val { public: 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; + RegVal* to_reg(const goos::Object& form, Env* fe) override; protected: StaticFloat* m_value = nullptr; @@ -277,7 +277,7 @@ class BitFieldVal : public Val { m_is_settable = parent->settable(); } std::string print() const override; - RegVal* to_reg(Env* env) override; + RegVal* to_reg(const goos::Object& form, Env* env) override; int offset() const { return m_offset; } int size() const { return m_size; } bool sext() const { return m_sign_extend; } diff --git a/goalc/compiler/compilation/Asm.cpp b/goalc/compiler/compilation/Asm.cpp index 05b6dc3e54..06f279d5cb 100644 --- a/goalc/compiler/compilation/Asm.cpp +++ b/goalc/compiler/compilation/Asm.cpp @@ -123,7 +123,7 @@ Val* Compiler::compile_rlet(const goos::Object& form, const goos::Object& rest, }); if (!reset_regs.empty()) { - lenv->emit_ir(reset_regs); + lenv->emit_ir(form, reset_regs); } for (auto c : constraints) { @@ -135,7 +135,7 @@ Val* Compiler::compile_rlet(const goos::Object& form, const goos::Object& rest, auto& o = args.unnamed.at(i); result = compile_error_guard(o, lenv); if (!dynamic_cast(result)) { - result = result->to_reg(lenv); + result = result->to_reg(o, lenv); } } @@ -150,7 +150,7 @@ Val* Compiler::compile_asm_ret(const goos::Object& form, const goos::Object& res color = get_true_or_false(form, args.named.at("color")); } - env->emit_ir(color); + env->emit_ir(form, color); return get_none(); } @@ -161,11 +161,11 @@ Val* Compiler::compile_asm_pop(const goos::Object& form, const goos::Object& res if (args.has_named("color")) { color = get_true_or_false(form, args.named.at("color")); } - auto pop_dest = compile_error_guard(args.unnamed.at(0), env)->to_gpr(env); + auto pop_dest = compile_error_guard(args.unnamed.at(0), env)->to_gpr(form, env); if (!pop_dest->settable()) { throw_compiler_error(form, "Cannot pop into this destination. Got a {}.", pop_dest->print()); } - env->emit_ir(color, pop_dest); + env->emit_ir(form, color, pop_dest); return get_none(); } @@ -176,7 +176,8 @@ Val* Compiler::compile_asm_push(const goos::Object& form, const goos::Object& re if (args.has_named("color")) { color = get_true_or_false(form, args.named.at("color")); } - env->emit_ir(color, compile_error_guard(args.unnamed.at(0), env)->to_gpr(env)); + env->emit_ir(form, color, + compile_error_guard(args.unnamed.at(0), env)->to_gpr(form, env)); return get_none(); } @@ -187,12 +188,12 @@ Val* Compiler::compile_asm_sub(const goos::Object& form, const goos::Object& res if (args.has_named("color")) { color = get_true_or_false(form, args.named.at("color")); } - auto dest = compile_error_guard(args.unnamed.at(0), env)->to_gpr(env); + auto dest = compile_error_guard(args.unnamed.at(0), env)->to_gpr(form, env); if (!dest->settable()) { throw_compiler_error(form, "Cannot .sub this. Got a {}.", dest->print()); } - auto src = compile_error_guard(args.unnamed.at(1), env)->to_gpr(env); - env->emit_ir(color, dest, src); + auto src = compile_error_guard(args.unnamed.at(1), env)->to_gpr(form, env); + env->emit_ir(form, color, dest, src); return get_none(); } @@ -203,12 +204,12 @@ Val* Compiler::compile_asm_add(const goos::Object& form, const goos::Object& res if (args.has_named("color")) { color = get_true_or_false(form, args.named.at("color")); } - auto dest = compile_error_guard(args.unnamed.at(0), env)->to_gpr(env); + auto dest = compile_error_guard(args.unnamed.at(0), env)->to_gpr(form, env); if (!dest->settable()) { throw_compiler_error(form, "Cannot .add this. Got a {}.", dest->print()); } - auto src = compile_error_guard(args.unnamed.at(1), env)->to_gpr(env); - env->emit_ir(color, dest, src); + auto src = compile_error_guard(args.unnamed.at(1), env)->to_gpr(form, env); + env->emit_ir(form, color, dest, src); return get_none(); } @@ -233,12 +234,12 @@ Val* Compiler::compile_asm_load_sym(const goos::Object& form, const goos::Object color = get_true_or_false(form, args.named.at("color")); } - auto dest = compile_error_guard(args.unnamed.at(0), env)->to_gpr(env); + auto dest = compile_error_guard(args.unnamed.at(0), env)->to_gpr(form, env); if (!dest->settable()) { throw_compiler_error(form, "Cannot .load-sym this. Got a {}.", dest->print()); } - env->emit_ir(color, dest, sym_name, sext); + env->emit_ir(form, color, dest, sym_name, sext); return get_none(); } @@ -250,8 +251,8 @@ Val* Compiler::compile_asm_jr(const goos::Object& form, const goos::Object& rest color = get_true_or_false(form, args.named.at("color")); } - auto src = compile_error_guard(args.unnamed.at(0), env)->to_gpr(env); - env->emit_ir(color, src); + auto src = compile_error_guard(args.unnamed.at(0), env)->to_gpr(form, env); + env->emit_ir(form, color, src); return get_none(); } @@ -262,12 +263,12 @@ Val* Compiler::compile_asm_mov(const goos::Object& form, const goos::Object& res if (args.has_named("color")) { color = get_true_or_false(form, args.named.at("color")); } - auto dest = compile_error_guard(args.unnamed.at(0), env)->to_reg(env); + auto dest = compile_error_guard(args.unnamed.at(0), env)->to_reg(form, env); if (!dest->settable()) { throw_compiler_error(form, "Cannot .mov this. Got a {}.", dest->print()); } - auto src = compile_error_guard(args.unnamed.at(1), env)->to_reg(env); - env->emit_ir(color, dest, src); + auto src = compile_error_guard(args.unnamed.at(1), env)->to_reg(form, env); + env->emit_ir(form, color, dest, src); return get_none(); } @@ -275,7 +276,7 @@ Val* Compiler::compile_asm_nop_vf(const goos::Object& form, const goos::Object& auto args = get_va(form, rest); va_check(form, args, {}, {}); - env->emit_ir(); + env->emit_ir(form); return get_none(); } @@ -283,7 +284,7 @@ Val* Compiler::compile_asm_wait_vf(const goos::Object& form, const goos::Object& auto args = get_va(form, rest); va_check(form, args, {}, {}); - env->emit_ir(); + env->emit_ir(form); return get_none(); } @@ -300,7 +301,7 @@ Val* Compiler::compile_asm_lvf(const goos::Object& form, const goos::Object& res color = get_true_or_false(form, args.named.at("color")); } - auto dest = compile_error_guard(args.unnamed.at(0), env)->to_reg(env); + auto dest = compile_error_guard(args.unnamed.at(0), env)->to_reg(form, env); if (!dest->settable() || dest->ireg().reg_class != RegClass::VECTOR_FLOAT) { throw_compiler_error(form, "Cannot .lvf into this. Got a {}.", dest->print()); } @@ -311,12 +312,12 @@ Val* Compiler::compile_asm_lvf(const goos::Object& form, const goos::Object& res if (as_sv && args.has_named("offset")) { throw_compiler_error(form, "Cannot .lvf from a static value"); } else if (as_sv && !args.has_named("offset")) { - env->emit_ir(dest, as_sv->obj); + env->emit_ir(form, dest, as_sv->obj); return get_none(); } auto as_co = dynamic_cast(src); - RegVal* baseReg = as_co ? as_co->base->to_gpr(env) : src->to_gpr(env); + RegVal* baseReg = as_co ? as_co->base->to_gpr(form, env) : src->to_gpr(form, env); int offset = 0; if (as_co) { @@ -333,7 +334,7 @@ Val* Compiler::compile_asm_lvf(const goos::Object& form, const goos::Object& res info.sign_extend = false; info.size = 16; info.reg = RegClass::VECTOR_FLOAT; - env->emit_ir(dest, offset, baseReg, info, color); + env->emit_ir(form, dest, offset, baseReg, info, color); return get_none(); } @@ -352,14 +353,14 @@ Val* Compiler::compile_asm_svf(const goos::Object& form, const goos::Object& res } auto dest = compile_error_guard(args.unnamed.at(0), env); - auto src = compile_error_guard(args.unnamed.at(1), env)->to_reg(env); + auto src = compile_error_guard(args.unnamed.at(1), env)->to_reg(form, env); if (!src->settable() || src->ireg().reg_class != RegClass::VECTOR_FLOAT) { throw_compiler_error(form, "Cannot .svf from this. Got a {}.", dest->print()); } auto as_co = dynamic_cast(dest); - RegVal* baseReg = as_co ? as_co->base->to_gpr(env) : dest->to_gpr(env); + RegVal* baseReg = as_co ? as_co->base->to_gpr(form, env) : dest->to_gpr(form, env); int offset = 0; if (as_co) { @@ -376,7 +377,7 @@ Val* Compiler::compile_asm_svf(const goos::Object& form, const goos::Object& res info.sign_extend = false; info.size = 16; info.reg = RegClass::VECTOR_FLOAT; - env->emit_ir(src, offset, baseReg, info.size, color); + env->emit_ir(form, src, offset, baseReg, info.size, color); return get_none(); } @@ -401,8 +402,8 @@ Val* Compiler::compile_asm_mov_vf(const goos::Object& form, const goos::Object& color = get_true_or_false(form, args.named.at("color")); } - auto dest = compile_error_guard(args.unnamed.at(0), env)->to_reg(env); - auto src = compile_error_guard(args.unnamed.at(1), env)->to_reg(env); + auto dest = compile_error_guard(args.unnamed.at(0), env)->to_reg(form, env); + auto src = compile_error_guard(args.unnamed.at(1), env)->to_reg(form, env); check_vector_float_regs(form, env, {{"destination", dest}, {"source", src}}); u8 mask = 0b1111; @@ -414,7 +415,7 @@ Val* Compiler::compile_asm_mov_vf(const goos::Object& form, const goos::Object& } } - env->emit_ir(color, dest, dest, src, mask); + env->emit_ir(form, color, dest, dest, src, mask); return get_none(); } @@ -428,9 +429,9 @@ Val* Compiler::compile_asm_blend_vf(const goos::Object& form, const goos::Object color = get_true_or_false(form, args.named.at("color")); } - auto dest = compile_error_guard(args.unnamed.at(0), env)->to_reg(env); - auto src1 = compile_error_guard(args.unnamed.at(1), env)->to_reg(env); - auto src2 = compile_error_guard(args.unnamed.at(2), env)->to_reg(env); + auto dest = compile_error_guard(args.unnamed.at(0), env)->to_reg(form, env); + auto src1 = compile_error_guard(args.unnamed.at(1), env)->to_reg(form, env); + auto src2 = compile_error_guard(args.unnamed.at(2), env)->to_reg(form, env); check_vector_float_regs(form, env, {{"destination", dest}, {"first source", src1}, {"second source", src2}}); @@ -443,7 +444,7 @@ Val* Compiler::compile_asm_blend_vf(const goos::Object& form, const goos::Object } } - env->emit_ir(color, dest, src1, src2, mask); + env->emit_ir(form, color, dest, src1, src2, mask); return get_none(); } @@ -461,9 +462,9 @@ Val* Compiler::compile_asm_vf_math3(const goos::Object& form, color = get_true_or_false(form, args.named.at("color")); } - auto dest = compile_error_guard(args.unnamed.at(0), env)->to_reg(env); - auto src1 = compile_error_guard(args.unnamed.at(1), env)->to_reg(env); - auto src2 = compile_error_guard(args.unnamed.at(2), env)->to_reg(env); + auto dest = compile_error_guard(args.unnamed.at(0), env)->to_reg(form, env); + auto src1 = compile_error_guard(args.unnamed.at(1), env)->to_reg(form, env); + auto src2 = compile_error_guard(args.unnamed.at(2), env)->to_reg(form, env); check_vector_float_regs(form, env, {{"destination", dest}, {"first source", src1}, {"second source", src2}}); @@ -484,27 +485,27 @@ Val* Compiler::compile_asm_vf_math3(const goos::Object& form, // vf10[w] = vf20[w] + vf30[x] if (broadcastElement != emitter::Register::VF_ELEMENT::NONE) { auto temp_reg = env->make_vfr(dest->type()); - env->emit_ir(color, temp_reg, src2, broadcastElement); + env->emit_ir(form, color, temp_reg, src2, broadcastElement); // If the entire destination is to be copied, we can optimize out the blend if (mask == 0b1111) { - env->emit_ir(color, dest, src1, temp_reg, kind); + env->emit_ir(form, color, dest, src1, temp_reg, kind); } else { // Perform the arithmetic operation on the two vectors into a temporary register - env->emit_ir(color, temp_reg, src1, temp_reg, kind); + env->emit_ir(form, color, temp_reg, src1, temp_reg, kind); // Blend the result back into the destination register using the mask - env->emit_ir(color, dest, dest, temp_reg, mask); + env->emit_ir(form, color, dest, dest, temp_reg, mask); } } else { // If the entire destination is to be copied, we can optimize out the blend if (mask == 0b1111) { - env->emit_ir(color, dest, src1, src2, kind); + env->emit_ir(form, color, dest, src1, src2, kind); } else { auto temp_reg = env->make_vfr(dest->type()); // Perform the arithmetic operation on the two vectors into a temporary register - env->emit_ir(color, temp_reg, src1, src2, kind); + env->emit_ir(form, color, temp_reg, src1, src2, kind); // Blend the result back into the destination register using the mask - env->emit_ir(color, dest, dest, temp_reg, mask); + env->emit_ir(form, color, dest, dest, temp_reg, mask); } } @@ -522,14 +523,14 @@ Val* Compiler::compile_asm_int128_math3(const goos::Object& form, color = get_true_or_false(form, args.named.at("color")); } - auto dest = compile_error_guard(args.unnamed.at(0), env)->to_reg(env); - auto src1 = compile_error_guard(args.unnamed.at(1), env)->to_reg(env); - auto src2 = compile_error_guard(args.unnamed.at(2), env)->to_reg(env); + auto dest = compile_error_guard(args.unnamed.at(0), env)->to_reg(form, env); + auto src1 = compile_error_guard(args.unnamed.at(1), env)->to_reg(form, env); + auto src2 = compile_error_guard(args.unnamed.at(2), env)->to_reg(form, env); if (!dest->settable()) { throw_compiler_error(form, "Cannot set destination"); } - env->emit_ir(color, dest, src1, src2, kind); + env->emit_ir(form, color, dest, src1, src2, kind); return get_none(); } @@ -546,8 +547,8 @@ Val* Compiler::compile_asm_vf_math2(const goos::Object& form, color = get_true_or_false(form, args.named.at("color")); } - auto dest = compile_error_guard(args.unnamed.at(0), env)->to_reg(env); - auto src = compile_error_guard(args.unnamed.at(1), env)->to_reg(env); + auto dest = compile_error_guard(args.unnamed.at(0), env)->to_reg(form, env); + auto src = compile_error_guard(args.unnamed.at(1), env)->to_reg(form, env); check_vector_float_regs(form, env, {{"destination", dest}, {"source", src}}); u8 mask = 0b1111; @@ -561,13 +562,13 @@ Val* Compiler::compile_asm_vf_math2(const goos::Object& form, // If the entire destination is to be copied, we can optimize out the blend if (mask == 0b1111) { - env->emit_ir(color, dest, src, kind); + env->emit_ir(form, color, dest, src, kind); } else { auto temp_reg = env->make_vfr(dest->type()); // Perform the arithmetic operation on the two vectors into a temporary register - env->emit_ir(color, temp_reg, src, kind); + env->emit_ir(form, color, temp_reg, src, kind); // Blend the result back into the destination register using the mask - env->emit_ir(color, dest, dest, temp_reg, mask); + env->emit_ir(form, color, dest, dest, temp_reg, mask); } return get_none(); @@ -586,8 +587,8 @@ Val* Compiler::compile_asm_int128_math2_imm_u8(const goos::Object& form, color = get_true_or_false(form, args.named.at("color")); } - auto dest = compile_error_guard(args.unnamed.at(0), env)->to_reg(env); - auto src = compile_error_guard(args.unnamed.at(1), env)->to_reg(env); + auto dest = compile_error_guard(args.unnamed.at(0), env)->to_reg(form, env); + auto src = compile_error_guard(args.unnamed.at(1), env)->to_reg(form, env); s64 imm; if (!try_getting_constant_integer(args.unnamed.at(2), &imm, env)) { throw_compiler_error(form, "Could not evaluate {} as a compile-time integer.", @@ -610,13 +611,13 @@ Val* Compiler::compile_asm_int128_math2_imm_u8(const goos::Object& form, // If the entire destination is to be copied, we can optimize out the blend if (mask == 0b1111) { - env->emit_ir(color, dest, src, kind, imm); + env->emit_ir(form, color, dest, src, kind, imm); } else { auto temp_reg = env->make_vfr(dest->type()); // Perform the arithmetic operation on the two vectors into a temporary register - env->emit_ir(color, temp_reg, src, kind, imm); + env->emit_ir(form, color, temp_reg, src, kind, imm); // Blend the result back into the destination register using the mask - env->emit_ir(color, dest, dest, temp_reg, mask); + env->emit_ir(form, color, dest, dest, temp_reg, mask); } return get_none(); @@ -646,9 +647,9 @@ Val* Compiler::compile_asm_pnor(const goos::Object& form, const goos::Object& re auto args = get_va(form, rest); va_check(form, args, {{}, {}, {}}, {}); - auto dest = compile_error_guard(args.unnamed.at(0), env)->to_reg(env); - auto src1 = compile_error_guard(args.unnamed.at(1), env)->to_reg(env); // rs - auto src2 = compile_error_guard(args.unnamed.at(2), env)->to_reg(env); // rt + auto dest = compile_error_guard(args.unnamed.at(0), env)->to_reg(form, env); + auto src1 = compile_error_guard(args.unnamed.at(1), env)->to_reg(form, env); // rs + auto src2 = compile_error_guard(args.unnamed.at(2), env)->to_reg(form, env); // rt auto temp = env->make_ireg(TypeSpec("uint128"), RegClass::INT_128); if (!ireg_is_128_ok(dest->ireg())) { @@ -671,13 +672,13 @@ Val* Compiler::compile_asm_pnor(const goos::Object& form, const goos::Object& re // Remember - we do not want to mutate the source registers! // How do we create an all-ones-register? Compare it with itself - env->emit_ir(true, temp, temp, temp, IR_Int128Math3Asm::Kind::PCEQW); + env->emit_ir(form, true, temp, temp, temp, IR_Int128Math3Asm::Kind::PCEQW); // Then NOT the first input, store in destination - env->emit_ir(true, dest, temp, src1, IR_Int128Math3Asm::Kind::PXOR); + env->emit_ir(form, true, dest, temp, src1, IR_Int128Math3Asm::Kind::PXOR); // NOT the second input, we not longer require the all-ones-register - env->emit_ir(true, temp, temp, src2, IR_Int128Math3Asm::Kind::PXOR); + env->emit_ir(form, true, temp, temp, src2, IR_Int128Math3Asm::Kind::PXOR); // Preform the AND aka NOR - env->emit_ir(true, dest, dest, temp, IR_Int128Math3Asm::Kind::PAND); + env->emit_ir(form, true, dest, dest, temp, IR_Int128Math3Asm::Kind::PAND); return get_none(); } @@ -750,23 +751,23 @@ Val* Compiler::compile_asm_ppach(const goos::Object& form, const goos::Object& r auto args = get_va(form, rest); va_check(form, args, {{}, {}, {}}, {}); - auto dest = compile_error_guard(args.unnamed.at(0), env)->to_reg(env); - auto src1 = compile_error_guard(args.unnamed.at(1), env)->to_reg(env); // rs - auto src2 = compile_error_guard(args.unnamed.at(2), env)->to_reg(env); // rt + auto dest = compile_error_guard(args.unnamed.at(0), env)->to_reg(form, env); + auto src1 = compile_error_guard(args.unnamed.at(1), env)->to_reg(form, env); // rs + auto src2 = compile_error_guard(args.unnamed.at(2), env)->to_reg(form, env); // rt auto temp = env->make_ireg(TypeSpec("uint128"), RegClass::INT_128); if (!dest->settable()) { throw_compiler_error(form, "Cannot set destination"); } - env->emit_ir(true, temp, src1, IR_Int128Math2Asm::Kind::VPSHUFLW, 0x88); - env->emit_ir(true, dest, src2, IR_Int128Math2Asm::Kind::VPSHUFLW, 0x88); - env->emit_ir(true, temp, temp, IR_Int128Math2Asm::Kind::VPSHUFHW, 0x88); - env->emit_ir(true, dest, dest, IR_Int128Math2Asm::Kind::VPSHUFHW, 0x88); - env->emit_ir(true, temp, temp, IR_Int128Math2Asm::Kind::VPSRLDQ, 4); - env->emit_ir(true, dest, dest, IR_Int128Math2Asm::Kind::VPSRLDQ, 4); + env->emit_ir(form, true, temp, src1, IR_Int128Math2Asm::Kind::VPSHUFLW, 0x88); + env->emit_ir(form, true, dest, src2, IR_Int128Math2Asm::Kind::VPSHUFLW, 0x88); + env->emit_ir(form, true, temp, temp, IR_Int128Math2Asm::Kind::VPSHUFHW, 0x88); + env->emit_ir(form, true, dest, dest, IR_Int128Math2Asm::Kind::VPSHUFHW, 0x88); + env->emit_ir(form, true, temp, temp, IR_Int128Math2Asm::Kind::VPSRLDQ, 4); + env->emit_ir(form, true, dest, dest, IR_Int128Math2Asm::Kind::VPSRLDQ, 4); // is actually a VPUNPCKLQDQ with srcs swapped. - env->emit_ir(true, dest, temp, dest, IR_Int128Math3Asm::Kind::PCPYLD); + env->emit_ir(form, true, dest, temp, dest, IR_Int128Math3Asm::Kind::PCPYLD); return get_none(); } @@ -775,15 +776,15 @@ Val* Compiler::compile_asm_xorp(const goos::Object& form, const goos::Object& re auto args = get_va(form, rest); va_check(form, args, {{}, {}, {}}, {}); - auto dest = compile_error_guard(args.unnamed.at(0), env)->to_reg(env); - auto src1 = compile_error_guard(args.unnamed.at(1), env)->to_reg(env); // rs - auto src2 = compile_error_guard(args.unnamed.at(2), env)->to_reg(env); // rt + auto dest = compile_error_guard(args.unnamed.at(0), env)->to_reg(form, env); + auto src1 = compile_error_guard(args.unnamed.at(1), env)->to_reg(form, env); // rs + auto src2 = compile_error_guard(args.unnamed.at(2), env)->to_reg(form, env); // rt if (!dest->settable()) { throw_compiler_error(form, "Cannot set destination"); } - env->emit_ir(true, dest, src1, src2, IR_VFMath3Asm::Kind::XOR); + env->emit_ir(form, true, dest, src1, src2, IR_VFMath3Asm::Kind::XOR); return get_none(); } @@ -940,16 +941,16 @@ Val* Compiler::compile_asm_vf_math4_two_operation(const goos::Object& form, color = get_true_or_false(form, args.named.at("color")); } - auto dest = compile_error_guard(args.unnamed.at(0), env)->to_reg(env); - auto src1 = compile_error_guard(args.unnamed.at(1), env)->to_reg(env); - auto src2 = compile_error_guard(args.unnamed.at(2), env)->to_reg(env); + auto dest = compile_error_guard(args.unnamed.at(0), env)->to_reg(form, env); + auto src1 = compile_error_guard(args.unnamed.at(1), env)->to_reg(form, env); + auto src2 = compile_error_guard(args.unnamed.at(2), env)->to_reg(form, env); // This third register is intended for the ACC/Q/ETC, and is used to temporarily store the value // that eventually goes into the destination // // For example VMADDA: // > ACC += src1 * src2 // > DEST = ACC - auto src3 = compile_error_guard(args.unnamed.at(3), env)->to_reg(env); + auto src3 = compile_error_guard(args.unnamed.at(3), env)->to_reg(form, env); check_vector_float_regs(form, env, {{"destination", dest}, {"first source", src1}, @@ -975,32 +976,32 @@ Val* Compiler::compile_asm_vf_math4_two_operation(const goos::Object& form, // vf10[z] = vf20[z] + vf30[x] // vf10[w] = vf20[w] + vf30[x] if (broadcastElement != emitter::Register::VF_ELEMENT::NONE) { - env->emit_ir(color, temp_reg, src2, broadcastElement); + env->emit_ir(form, color, temp_reg, src2, broadcastElement); // Perform the first operation - env->emit_ir(color, temp_reg, src1, temp_reg, first_op_kind); + env->emit_ir(form, color, temp_reg, src1, temp_reg, first_op_kind); // If the entire destination is to be copied, we can optimize out the blend if (mask == 0b1111) { - env->emit_ir(color, dest, src3, temp_reg, second_op_kind); + env->emit_ir(form, color, dest, src3, temp_reg, second_op_kind); } else { // Perform the second operation on the two vectors into the temporary register - env->emit_ir(color, temp_reg, src3, temp_reg, second_op_kind); + env->emit_ir(form, color, temp_reg, src3, temp_reg, second_op_kind); // Blend the result back into the destination register using the mask - env->emit_ir(color, dest, dest, temp_reg, mask); + env->emit_ir(form, color, dest, dest, temp_reg, mask); } } else { // Perform the first operation - env->emit_ir(color, temp_reg, src1, src2, first_op_kind); + env->emit_ir(form, color, temp_reg, src1, src2, first_op_kind); // If the entire destination is to be copied, we can optimize out the blend if (mask == 0b1111) { - env->emit_ir(color, dest, src3, temp_reg, second_op_kind); + env->emit_ir(form, color, dest, src3, temp_reg, second_op_kind); } else { // Perform the second operation on the two vectors into the temporary register - env->emit_ir(color, temp_reg, src3, temp_reg, second_op_kind); + env->emit_ir(form, color, temp_reg, src3, temp_reg, second_op_kind); // Blend the result back into the destination register using the mask - env->emit_ir(color, dest, dest, temp_reg, mask); + env->emit_ir(form, color, dest, dest, temp_reg, mask); } } @@ -1097,8 +1098,8 @@ Val* Compiler::compile_asm_abs_vf(const goos::Object& form, const goos::Object& color = get_true_or_false(form, args.named.at("color")); } - auto dest = compile_error_guard(args.unnamed.at(0), env)->to_reg(env); - auto src = compile_error_guard(args.unnamed.at(1), env)->to_reg(env); + auto dest = compile_error_guard(args.unnamed.at(0), env)->to_reg(form, env); + auto src = compile_error_guard(args.unnamed.at(1), env)->to_reg(form, env); check_vector_float_regs(form, env, {{"destination", dest}, {"source", src}}); u8 mask = 0b1111; @@ -1115,21 +1116,21 @@ Val* Compiler::compile_asm_abs_vf(const goos::Object& form, const goos::Object& // First we clear a temporary register, XOR'ing itself auto temp_reg = env->make_vfr(dest->type()); - env->emit_ir(color, temp_reg, temp_reg, temp_reg, IR_VFMath3Asm::Kind::XOR); + env->emit_ir(form, color, temp_reg, temp_reg, temp_reg, IR_VFMath3Asm::Kind::XOR); // Next, find the difference between our source operand and 0, use the same temp register, no need // to use another <0, 0, 0, 0> - <1, -2, -3, 4> = <-1, 2, 3, 4> - env->emit_ir(color, temp_reg, temp_reg, src, IR_VFMath3Asm::Kind::SUB); + env->emit_ir(form, color, temp_reg, temp_reg, src, IR_VFMath3Asm::Kind::SUB); // Finally, find the maximum between our difference, and the original value // MAX_OF(<-1, 2, 3, 4>, <1, -2, -3, 4>) = <1, 2, 3, 4> if (mask == 0b1111) { // If the entire destination is to be copied, we can optimize out the blend - env->emit_ir(color, dest, src, temp_reg, IR_VFMath3Asm::Kind::MAX); + env->emit_ir(form, color, dest, src, temp_reg, IR_VFMath3Asm::Kind::MAX); } else { - env->emit_ir(color, temp_reg, src, temp_reg, IR_VFMath3Asm::Kind::MAX); + env->emit_ir(form, color, temp_reg, src, temp_reg, IR_VFMath3Asm::Kind::MAX); // Blend the result back into the destination register using the mask - env->emit_ir(color, dest, dest, temp_reg, mask); + env->emit_ir(form, color, dest, dest, temp_reg, mask); } return get_none(); @@ -1174,9 +1175,9 @@ Val* Compiler::compile_asm_div_vf(const goos::Object& form, const goos::Object& color = get_true_or_false(form, args.named.at("color")); } - auto dest = compile_error_guard(args.unnamed.at(0), env)->to_reg(env); - auto src1 = compile_error_guard(args.unnamed.at(1), env)->to_reg(env); - auto src2 = compile_error_guard(args.unnamed.at(2), env)->to_reg(env); + auto dest = compile_error_guard(args.unnamed.at(0), env)->to_reg(form, env); + auto src1 = compile_error_guard(args.unnamed.at(1), env)->to_reg(form, env); + auto src2 = compile_error_guard(args.unnamed.at(2), env)->to_reg(form, env); check_vector_float_regs(form, env, {{"destination", dest}, {"first source", src1}, {"second source", src2}}); @@ -1204,12 +1205,12 @@ Val* Compiler::compile_asm_div_vf(const goos::Object& form, const goos::Object& // Splat src1's value into the dest reg, keep it simple, this way no matter which vector component // is accessed from the final result will be the correct answer - env->emit_ir(color, dest, src1, ftf_fsf_to_vector_element(fsf)); + env->emit_ir(form, color, dest, src1, ftf_fsf_to_vector_element(fsf)); // Splat src1's value into the the temp reg - env->emit_ir(color, temp_reg, src2, ftf_fsf_to_vector_element(ftf)); + env->emit_ir(form, color, temp_reg, src2, ftf_fsf_to_vector_element(ftf)); // Perform the Division - env->emit_ir(color, dest, dest, temp_reg, IR_VFMath3Asm::Kind::DIV); + env->emit_ir(form, color, dest, dest, temp_reg, IR_VFMath3Asm::Kind::DIV); return get_none(); } @@ -1223,8 +1224,8 @@ Val* Compiler::compile_asm_sqrt_vf(const goos::Object& form, const goos::Object& color = get_true_or_false(form, args.named.at("color")); } - auto dest = compile_error_guard(args.unnamed.at(0), env)->to_reg(env); - auto src = compile_error_guard(args.unnamed.at(1), env)->to_reg(env); + auto dest = compile_error_guard(args.unnamed.at(0), env)->to_reg(form, env); + auto src = compile_error_guard(args.unnamed.at(1), env)->to_reg(form, env); check_vector_float_regs(form, env, {{"destination", dest}, {"source", src}}); u8 ftf = args.named.at("ftf").as_int(); @@ -1243,9 +1244,9 @@ Val* Compiler::compile_asm_sqrt_vf(const goos::Object& form, const goos::Object& // Splat src's value into the dest reg, keep it simple, this way no matter which vector component // is accessed from the final result will be the correct answer - env->emit_ir(color, dest, src, ftf_fsf_to_vector_element(ftf)); + env->emit_ir(form, color, dest, src, ftf_fsf_to_vector_element(ftf)); - env->emit_ir(color, dest, dest); + env->emit_ir(form, color, dest, dest); return get_none(); } @@ -1264,9 +1265,9 @@ Val* Compiler::compile_asm_inv_sqrt_vf(const goos::Object& form, color = get_true_or_false(form, args.named.at("color")); } - auto dest = compile_error_guard(args.unnamed.at(0), env)->to_reg(env); - auto src1 = compile_error_guard(args.unnamed.at(1), env)->to_reg(env); - auto src2 = compile_error_guard(args.unnamed.at(2), env)->to_reg(env); + auto dest = compile_error_guard(args.unnamed.at(0), env)->to_reg(form, env); + auto src1 = compile_error_guard(args.unnamed.at(1), env)->to_reg(form, env); + auto src2 = compile_error_guard(args.unnamed.at(2), env)->to_reg(form, env); check_vector_float_regs(form, env, {{"destination", dest}, {"first source", src1}, {"second source", src2}}); @@ -1284,14 +1285,14 @@ Val* Compiler::compile_asm_inv_sqrt_vf(const goos::Object& form, // Splat src1's value into the dest reg, keep it simple, this way no matter which vector component // is accessed from the final result will be the correct answer - env->emit_ir(color, dest, src1, ftf_fsf_to_vector_element(fsf)); + env->emit_ir(form, color, dest, src1, ftf_fsf_to_vector_element(fsf)); // Splat src1's value into the the temp reg - env->emit_ir(color, temp_reg, src2, ftf_fsf_to_vector_element(ftf)); + env->emit_ir(form, color, temp_reg, src2, ftf_fsf_to_vector_element(ftf)); // Square Root the temp reg - env->emit_ir(color, temp_reg, temp_reg); + env->emit_ir(form, color, temp_reg, temp_reg); // Perform the Division - env->emit_ir(color, dest, dest, temp_reg, IR_VFMath3Asm::Kind::DIV); + env->emit_ir(form, color, dest, dest, temp_reg, IR_VFMath3Asm::Kind::DIV); return get_none(); } @@ -1305,9 +1306,9 @@ Val* Compiler::compile_asm_outer_product_vf(const goos::Object& form, color = get_true_or_false(form, args.named.at("color")); } - auto dest = compile_error_guard(args.unnamed.at(0), env)->to_reg(env); - auto src1 = compile_error_guard(args.unnamed.at(1), env)->to_reg(env); - auto src2 = compile_error_guard(args.unnamed.at(2), env)->to_reg(env); + auto dest = compile_error_guard(args.unnamed.at(0), env)->to_reg(form, env); + auto src1 = compile_error_guard(args.unnamed.at(1), env)->to_reg(form, env); + auto src2 = compile_error_guard(args.unnamed.at(2), env)->to_reg(form, env); check_vector_float_regs(form, env, {{"destination", dest}, {"first source", src1}, {"second source", src2}}); @@ -1332,28 +1333,28 @@ Val* Compiler::compile_asm_outer_product_vf(const goos::Object& form, // First Portion // - Swizzle src1 appropriately - env->emit_ir(color, temp1, src1, 0b00001001); + env->emit_ir(form, color, temp1, src1, 0b00001001); // - Move it into 'dest' safely (avoid mutating `w`) - env->emit_ir(color, temp_dst, temp_dst, temp1, 0b0111); + env->emit_ir(form, color, temp_dst, temp_dst, temp1, 0b0111); // - Swizzle src2 appropriately - env->emit_ir(color, temp1, src2, 0b00010010); + env->emit_ir(form, color, temp1, src2, 0b00010010); // - Multiply - Result in `dest` - env->emit_ir(color, temp1, temp_dst, temp1, IR_VFMath3Asm::Kind::MUL); + env->emit_ir(form, color, temp1, temp_dst, temp1, IR_VFMath3Asm::Kind::MUL); // - Move it into 'dest' safely (avoid mutating `w`) - env->emit_ir(color, temp_dst, temp_dst, temp1, 0b0111); + env->emit_ir(form, color, temp_dst, temp_dst, temp1, 0b0111); // Second Portion // - Swizzle src2 appropriately - env->emit_ir(color, temp1, src2, 0b00001001); + env->emit_ir(form, color, temp1, src2, 0b00001001); // - Swizzle src1 appropriately - env->emit_ir(color, temp2, src1, 0b00010010); + env->emit_ir(form, color, temp2, src1, 0b00010010); // - Multiply - Result in `temp1` - env->emit_ir(color, temp1, temp1, temp2, IR_VFMath3Asm::Kind::MUL); + env->emit_ir(form, color, temp1, temp1, temp2, IR_VFMath3Asm::Kind::MUL); // Finalize // - Subtract - env->emit_ir(color, temp2, temp_dst, temp1, IR_VFMath3Asm::Kind::SUB); + env->emit_ir(form, color, temp2, temp_dst, temp1, IR_VFMath3Asm::Kind::SUB); // - Blend result, as to avoid not modifying dest's `w` component - env->emit_ir(color, dest, dest, temp2, 0b0111); + env->emit_ir(form, color, dest, dest, temp2, 0b0111); return get_none(); } diff --git a/goalc/compiler/compilation/Atoms.cpp b/goalc/compiler/compilation/Atoms.cpp index 5006faa2e4..b79c168e7c 100644 --- a/goalc/compiler/compilation/Atoms.cpp +++ b/goalc/compiler/compilation/Atoms.cpp @@ -482,7 +482,7 @@ Val* Compiler::compile_pointer_add(const goos::Object& form, const goos::Object& if (args.unnamed.size() < 2 || !args.named.empty()) { throw_compiler_error(form, "&+ must be used with at least two arguments."); } - auto first = compile_error_guard(args.unnamed.at(0), env)->to_gpr(env); + auto first = compile_error_guard(args.unnamed.at(0), env)->to_gpr(form, env); bool ok_type = false; for (auto& type : {"pointer", "structure", "inline-array"}) { @@ -499,12 +499,12 @@ Val* Compiler::compile_pointer_add(const goos::Object& form, const goos::Object& } auto result = env->make_gpr(first->type()); - env->emit(std::make_unique(result, first)); + env->emit_ir(form, result, first); for (size_t i = 1; i < args.unnamed.size(); i++) { - auto second = compile_error_guard(args.unnamed.at(i), env)->to_gpr(env); + auto second = compile_error_guard(args.unnamed.at(i), env)->to_gpr(form, env); typecheck(form, m_ts.make_typespec("integer"), second->type(), "&+ second argument"); - env->emit(std::make_unique(IntegerMathKind::ADD_64, result, second)); + env->emit_ir(form, IntegerMathKind::ADD_64, result, second); } return result; diff --git a/goalc/compiler/compilation/Block.cpp b/goalc/compiler/compilation/Block.cpp index 260ef39e16..d9b7d3d539 100644 --- a/goalc/compiler/compilation/Block.cpp +++ b/goalc/compiler/compilation/Block.cpp @@ -25,7 +25,7 @@ Val* Compiler::compile_begin(const goos::Object& form, const goos::Object& rest, for_each_in_list(rest, [&](const Object& o) { result = compile_error_guard(o, env); if (!dynamic_cast(result)) { - result = result->to_reg(env); + result = result->to_reg(o, env); } }); return result; @@ -65,7 +65,7 @@ Val* Compiler::compile_block(const goos::Object& form, const goos::Object& _rest for_each_in_list(*rest, [&](const Object& o) { result = compile_error_guard(o, block_env); if (!dynamic_cast(result)) { - result = result->to_reg(env); + result = result->to_reg(o, env); } }); @@ -87,12 +87,13 @@ Val* Compiler::compile_block(const goos::Object& form, const goos::Object& _rest if (!dynamic_cast(result)) { // an IR to move the result of the block into the block's return register (if no return-from's // are taken) - auto ir_move_rv = std::make_unique(block_env->return_value, result->to_gpr(fe)); + auto ir_move_rv = + std::make_unique(block_env->return_value, result->to_gpr(form, fe)); // note - one drawback of doing this single pass is that a block always evaluates to a gpr. // so we may have an unneeded xmm -> gpr move that could have been an xmm -> xmm that could have // been eliminated. - env->emit(std::move(ir_move_rv)); + env->emit(form, std::move(ir_move_rv)); } // now we know the end of the block, so we set the label index to be on whatever comes after the @@ -126,16 +127,16 @@ Val* Compiler::compile_return_from(const goos::Object& form, const goos::Object& } // move result into return register - auto ir_move_rv = std::make_unique(block->return_value, result->to_gpr(fe)); + auto ir_move_rv = std::make_unique(block->return_value, result->to_gpr(form, fe)); // inform block of our possible return type block->return_types.push_back(result->type()); - env->emit(std::move(ir_move_rv)); + env->emit(form, std::move(ir_move_rv)); // jump to end of block (by label object) auto ir_jump = std::make_unique(&block->end_label); - env->emit(std::move(ir_jump)); + env->emit(form, std::move(ir_jump)); // In the real GOAL, there is likely a bug here where a non-none value is returned and to_gpr'd // todo, determine if we should replicate this bug and if it can have side effects. @@ -183,13 +184,13 @@ Val* Compiler::compile_goto(const goos::Object& form, const goos::Object& rest, // add this goto to the list of gotos to resolve after the function is done. // it's safe to have this reference, as the FunctionEnv also owns the goto. env->function_env()->unresolved_gotos.push_back({ir_goto.get(), label_name}); - env->emit(std::move(ir_goto)); + env->emit(form, std::move(ir_goto)); return get_none(); } Val* Compiler::compile_nop(const goos::Object& form, const goos::Object& rest, Env* env) { auto args = get_va(form, rest); va_check(form, args, {}, {}); - env->emit_ir(); + env->emit_ir(form); return get_none(); } \ No newline at end of file diff --git a/goalc/compiler/compilation/ControlFlow.cpp b/goalc/compiler/compilation/ControlFlow.cpp index a79cc11eff..81e86cccad 100644 --- a/goalc/compiler/compilation/ControlFlow.cpp +++ b/goalc/compiler/compilation/ControlFlow.cpp @@ -91,12 +91,12 @@ Condition Compiler::compile_condition(const goos::Object& condition, Env* env, b // pick between a floating point and an integer comparison. if (is_float(first_arg->type())) { - gc.a = first_arg->to_fpr(env); - gc.b = second_arg->to_fpr(env); + gc.a = first_arg->to_fpr(condition, env); + gc.b = second_arg->to_fpr(condition, env); gc.is_float = true; } else { - gc.a = first_arg->to_gpr(env); - gc.b = second_arg->to_gpr(env); + gc.a = first_arg->to_gpr(condition, env); + gc.b = second_arg->to_gpr(condition, env); } return gc; @@ -107,8 +107,8 @@ Condition Compiler::compile_condition(const goos::Object& condition, Env* env, b // not something we can process more. Just evaluate as normal and check if we get false. // todo - it's possible to optimize a false comparison because the false offset is zero gc.kind = invert ? ConditionKind::EQUAL : ConditionKind::NOT_EQUAL; - gc.a = compile_error_guard(condition, env)->to_gpr(env); - gc.b = compile_get_sym_obj("#f", env)->to_gpr(env); + gc.a = compile_error_guard(condition, env)->to_gpr(condition, env); + gc.b = compile_get_sym_obj("#f", env)->to_gpr(condition, env); return gc; } @@ -124,15 +124,15 @@ Val* Compiler::compile_condition_as_bool(const goos::Object& form, Env* env) { (void)rest; auto c = compile_condition(form, env, true); - auto result = compile_get_sym_obj("#f", env)->to_gpr(env); // todo - can be optimized. + auto result = compile_get_sym_obj("#f", env)->to_gpr(form, env); // todo - can be optimized. Label label(env->function_env(), -5); auto branch_ir = std::make_unique(c, label); auto branch_ir_ref = branch_ir.get(); - env->emit(std::move(branch_ir)); + env->emit(form, std::move(branch_ir)); // move true - env->emit(std::make_unique( - result, compile_get_sym_obj("#t", env)->to_gpr(env))); // todo, can be optimized + env->emit(form, std::make_unique(result, compile_get_sym_obj("#t", env)->to_gpr( + form, env))); // todo, can be optimized branch_ir_ref->label.idx = branch_ir_ref->label.func->code().size(); branch_ir_ref->mark_as_resolved(); @@ -156,7 +156,7 @@ Val* Compiler::compile_when_goto(const goos::Object& form, const goos::Object& _ auto condition = compile_condition(condition_code, env, false); auto branch = std::make_unique(condition, Label()); env->function_env()->unresolved_cond_gotos.push_back({branch.get(), label}); - env->emit(std::move(branch)); + env->emit(form, std::move(branch)); return get_none(); } @@ -196,7 +196,7 @@ Val* Compiler::compile_cond(const goos::Object& form, const goos::Object& rest, for_each_in_list(clauses, [&](const goos::Object& clause) { case_result = compile_error_guard(clause, env); if (!dynamic_cast(case_result)) { - case_result = case_result->to_reg(env); + case_result = case_result->to_reg(clause, env); } }); @@ -205,7 +205,7 @@ Val* Compiler::compile_cond(const goos::Object& form, const goos::Object& rest, // optimization - if we get junk, don't bother moving it, just leave junk in return. if (!is_none(case_result)) { // todo, what does GOAL do here? does it matter? - env->emit(std::make_unique(result, case_result->to_gpr(env))); + env->emit(o, std::make_unique(result, case_result->to_gpr(o, env))); } } else { @@ -216,26 +216,26 @@ Val* Compiler::compile_cond(const goos::Object& form, const goos::Object& rest, auto branch_ir = std::make_unique(condition, Label()); auto branch_ir_ref = branch_ir.get(); branch_ir->mark_as_resolved(); - env->emit(std::move(branch_ir)); + env->emit(test, std::move(branch_ir)); // CODE Val* case_result = get_none(); for_each_in_list(clauses, [&](const goos::Object& clause) { case_result = compile_error_guard(clause, env); if (!dynamic_cast(case_result)) { - case_result = case_result->to_reg(env); + case_result = case_result->to_reg(clause, env); } }); case_result_types.push_back(case_result->type()); if (!is_none(case_result)) { // todo, what does GOAL do here? - env->emit(std::make_unique(result, case_result->to_gpr(env))); + env->emit(o, std::make_unique(result, case_result->to_gpr(o, env))); } // GO TO END auto ir_goto_end = std::make_unique(end_label); - env->emit(std::move(ir_goto_end)); + env->emit(o, std::move(ir_goto_end)); // PATCH BRANCH FWD branch_ir_ref->label.idx = fenv->code().size(); @@ -245,7 +245,7 @@ Val* Compiler::compile_cond(const goos::Object& form, const goos::Object& rest, if (!got_else) { // if no else, clause, return #f. But don't retype. todo what does goal do here? auto get_false = std::make_unique(result, "#f"); - env->emit(std::move(get_false)); + env->emit(form, std::move(get_false)); } if (case_result_types.empty()) { @@ -289,9 +289,9 @@ Val* Compiler::compile_and_or(const goos::Object& form, const goos::Object& rest int i = 0; for_each_in_list(rest, [&](const goos::Object& o) { // get the result of this case, put it in the main result and remember the type - auto temp = compile_error_guard(o, env)->to_gpr(env); + auto temp = compile_error_guard(o, env)->to_gpr(o, env); case_result_types.push_back(temp->type()); - env->emit_ir(result, temp); + env->emit_ir(o, result, temp); // no need check if we are the last element. if (i != n_elts - 1) { @@ -300,7 +300,7 @@ Val* Compiler::compile_and_or(const goos::Object& form, const goos::Object& rest gc.is_signed = false; gc.is_float = false; gc.a = result; - gc.b = compile_get_sym_obj("#f", env)->to_gpr(env); // todo, optimize + gc.b = compile_get_sym_obj("#f", env)->to_gpr(o, env); // todo, optimize if (is_and) { // for and we abort if we get a false: gc.kind = ConditionKind::EQUAL; @@ -311,7 +311,7 @@ Val* Compiler::compile_and_or(const goos::Object& form, const goos::Object& rest // jump to end auto branch = std::make_unique(gc, Label()); branch_irs.push_back(branch.get()); - env->emit(std::move(branch)); + env->emit(o, std::move(branch)); } i++; }); diff --git a/goalc/compiler/compilation/Define.cpp b/goalc/compiler/compilation/Define.cpp index 10b7405f2f..b7bcd376bd 100644 --- a/goalc/compiler/compilation/Define.cpp +++ b/goalc/compiler/compilation/Define.cpp @@ -44,7 +44,7 @@ Val* Compiler::compile_define(const goos::Object& form, const goos::Object& rest throw_compiler_error(form, "Cannot define {} because it cannot be set.", sym_val->print()); } - auto in_gpr = compiled_val->to_gpr(fe); + auto in_gpr = compiled_val->to_gpr(form, fe); auto existing_type = m_symbol_types.find(sym.as_symbol()->name); if (existing_type == m_symbol_types.end()) { m_symbol_types[sym.as_symbol()->name] = in_gpr->type(); @@ -60,7 +60,7 @@ Val* Compiler::compile_define(const goos::Object& form, const goos::Object& rest m_symbol_info.add_global(symbol_string(sym), form); - fe->emit(std::make_unique(sym_val, in_gpr)); + env->emit(form, std::make_unique(sym_val, in_gpr)); return in_gpr; } @@ -98,7 +98,8 @@ Val* Compiler::compile_define_extern(const goos::Object& form, const goos::Objec /*! * Modify dst by setting the bitfield with give size/offset to the value in src. */ -void Compiler::set_bits_in_bitfield(int size, +void Compiler::set_bits_in_bitfield(const goos::Object& form, + int size, int offset, RegVal* dst, RegVal* src, @@ -108,12 +109,12 @@ void Compiler::set_bits_in_bitfield(int size, auto temp = fe->make_gpr(src->type()); // mask value should be 1's everywhere except for the field so we can AND with it u64 mask_val = ~((((u64)1 << (u64)size) - (u64)1) << (u64)offset); - env->emit(std::make_unique(temp, mask_val)); + env->emit_ir(form, temp, mask_val); // modify the original! - env->emit(std::make_unique(IntegerMathKind::AND_64, dst, temp)); + env->emit_ir(form, IntegerMathKind::AND_64, dst, temp); // put the source in temp - env->emit(std::make_unique(temp, src)); + env->emit_ir(form, temp, src); // to shift us all the way to the left and clear upper bits int left_shift_amnt = 64 - size; @@ -121,14 +122,14 @@ void Compiler::set_bits_in_bitfield(int size, assert(right_shift_amnt >= 0); if (left_shift_amnt > 0) { - env->emit(std::make_unique(IntegerMathKind::SHL_64, temp, left_shift_amnt)); + env->emit_ir(form, IntegerMathKind::SHL_64, temp, left_shift_amnt); } if (right_shift_amnt > 0) { - env->emit(std::make_unique(IntegerMathKind::SHR_64, temp, right_shift_amnt)); + env->emit_ir(form, IntegerMathKind::SHR_64, temp, right_shift_amnt); } - env->emit(std::make_unique(IntegerMathKind::OR_64, dst, temp)); + env->emit_ir(form, IntegerMathKind::OR_64, dst, temp); } void Compiler::set_bitfield(const goos::Object& form, BitFieldVal* dst, RegVal* src, Env* env) { @@ -140,12 +141,12 @@ void Compiler::set_bitfield(const goos::Object& form, BitFieldVal* dst, RegVal* auto fe = env->function_env(); // first, get the value we want to modify: - auto original_original = dst->parent()->to_gpr(env); + auto original_original = dst->parent()->to_gpr(form, env); // let's not directly modify original, and instead create a copy then use do_set on parent. // this way we avoid "cheating" the set system, although it should be safe... auto original = fe->make_gpr(original_original->type()); - env->emit(std::make_unique(original, original_original)); - set_bits_in_bitfield(dst->size(), dst->offset(), original, src, fe, env); + env->emit_ir(form, original, original_original); + set_bits_in_bitfield(form, dst->size(), dst->offset(), original, src, fe, env); do_set(form, dst->parent(), original, original, env); } @@ -157,36 +158,36 @@ void Compiler::set_bitfield_128(const goos::Object& form, BitFieldVal* dst, RegV // first, get the value we want to modify: assert(m_ts.lookup_type(dst->parent()->type())->get_preferred_reg_class() == RegClass::INT_128); - RegVal* original_original = dst->parent()->to_xmm128(env); + RegVal* original_original = dst->parent()->to_xmm128(form, env); // next, get the 64-bit part we want to modify in the lower 64 bits of an XMM RegVal* xmm_temp = fe->make_ireg(original_original->type(), RegClass::INT_128); if (get_top) { - env->emit_ir(true, xmm_temp, original_original, original_original, + env->emit_ir(form, true, xmm_temp, original_original, original_original, IR_Int128Math3Asm::Kind::PCPYUD); } else { - env->emit_ir(xmm_temp, original_original); + env->emit_ir(form, xmm_temp, original_original); } // convert that xmm to a GPR. RegVal* gpr_64_section = fe->make_gpr(original_original->type()); - env->emit_ir(gpr_64_section, xmm_temp); + env->emit_ir(form, gpr_64_section, xmm_temp); // set the bits in the GPR int corrected_offset = get_top ? dst->offset() - 64 : dst->offset(); - set_bits_in_bitfield(dst->size(), corrected_offset, gpr_64_section, src, fe, env); + set_bits_in_bitfield(form, dst->size(), corrected_offset, gpr_64_section, src, fe, env); // back to xmm - env->emit_ir(xmm_temp, gpr_64_section); + env->emit_ir(form, xmm_temp, gpr_64_section); // rebuild the xmm if (get_top) { - env->emit_ir(true, xmm_temp, xmm_temp, original_original, + env->emit_ir(form, true, xmm_temp, xmm_temp, original_original, IR_Int128Math3Asm::Kind::PCPYLD); } else { - env->emit_ir(true, xmm_temp, xmm_temp, xmm_temp, + env->emit_ir(form, true, xmm_temp, xmm_temp, xmm_temp, IR_Int128Math3Asm::Kind::PCPYLD); - env->emit_ir(true, xmm_temp, xmm_temp, original_original, + env->emit_ir(form, true, xmm_temp, xmm_temp, original_original, IR_Int128Math3Asm::Kind::PCPYUD); } @@ -222,7 +223,7 @@ Val* Compiler::do_set(const goos::Object& form, Val* dest, RegVal* src_in_reg, V if (as_mem_deref->info.size == 16) { auto fe = env->function_env(); auto src_128 = fe->make_ireg(src_in_reg->type(), RegClass::INT_128); - env->emit_ir(src_128, src_in_reg); + env->emit_ir(form, src_128, src_in_reg); src_in_reg = src_128; } @@ -231,7 +232,7 @@ Val* Compiler::do_set(const goos::Object& form, Val* dest, RegVal* src_in_reg, V src_in_reg->ireg().reg_class == RegClass::INT_128)) { auto fe = env->function_env(); auto src_gpr = fe->make_ireg(src_in_reg->type(), RegClass::GPR_64); - env->emit_ir(src_gpr, src_in_reg); + env->emit_ir(form, src_gpr, src_in_reg); src_in_reg = src_gpr; } @@ -239,7 +240,7 @@ Val* Compiler::do_set(const goos::Object& form, Val* dest, RegVal* src_in_reg, V if (as_mem_deref->info.size == 8 && src_in_reg->ireg().reg_class == RegClass::FLOAT) { auto fe = env->function_env(); auto src_gpr = fe->make_ireg(src_in_reg->type(), RegClass::GPR_64); - env->emit_ir(src_gpr, src_in_reg); + env->emit_ir(form, src_gpr, src_in_reg); src_in_reg = src_gpr; } @@ -249,27 +250,27 @@ Val* Compiler::do_set(const goos::Object& form, Val* dest, RegVal* src_in_reg, V int load_size = m_ts.get_load_size_allow_partial_def(as_mem_deref->type()); if (base_as_mco) { // if it is a constant offset, we can use a fancy x86-64 addressing mode to simplify - env->emit(std::make_unique(src_in_reg, base_as_mco->offset, - base_as_mco->base->to_gpr(env), load_size)); + env->emit_ir(form, src_in_reg, base_as_mco->offset, + base_as_mco->base->to_gpr(form, env), load_size); return src_in_reg; } else { // nope, the pointer to dereference is some complicated thing. - env->emit(std::make_unique(src_in_reg, 0, base->to_gpr(env), load_size)); + env->emit_ir(form, src_in_reg, 0, base->to_gpr(form, env), load_size); return src_in_reg; } } else if (as_pair) { // this could probably be part of MemoryDerefVal and not a special case here. - env->emit(std::make_unique(src_in_reg, as_pair->is_car ? -2 : 2, - as_pair->base->to_gpr(env), 4)); + env->emit_ir(form, src_in_reg, as_pair->is_car ? -2 : 2, + as_pair->base->to_gpr(form, env), 4); return src_in_reg; } else if (as_reg) { typecheck_reg_type_allow_false(form, as_reg->type(), src, "set! lexical variable"); - env->emit(std::make_unique(as_reg, src_in_reg)); + env->emit_ir(form, as_reg, src_in_reg); return src_in_reg; } else if (as_sym_val) { typecheck_reg_type_allow_false(form, as_sym_val->type(), src, "set! global symbol"); - auto result_in_gpr = src_in_reg->to_gpr(env); - env->emit(std::make_unique(as_sym_val->sym(), result_in_gpr)); + auto result_in_gpr = src_in_reg->to_gpr(form, env); + env->emit_ir(form, as_sym_val->sym(), result_in_gpr); return result_in_gpr; } else if (as_bitfield) { set_bitfield(form, as_bitfield, src_in_reg, env); @@ -292,7 +293,7 @@ Val* Compiler::compile_set(const goos::Object& form, const goos::Object& rest, E // this is the order I'm using in the decompiler and it seems to be right. // see StorePlainDeref::push_to_stack for example auto source = compile_error_guard(args.unnamed.at(1), env); - auto source_reg = source->to_reg(env); + auto source_reg = source->to_reg(form, env); auto dest = compile_error_guard(destination, env); return do_set(form, dest, source_reg, source, env); } \ No newline at end of file diff --git a/goalc/compiler/compilation/Function.cpp b/goalc/compiler/compilation/Function.cpp index b21eff1dec..698695af0b 100644 --- a/goalc/compiler/compilation/Function.cpp +++ b/goalc/compiler/compilation/Function.cpp @@ -173,7 +173,7 @@ Val* Compiler::compile_lambda(const goos::Object& form, const goos::Object& rest if (function_name.empty()) { function_name = obj_env->get_anon_function_name(); } - auto new_func_env = std::make_unique(env, function_name); + auto new_func_env = std::make_unique(env, function_name, &m_goos.reader); new_func_env->set_segment(segment); // set up arguments @@ -230,14 +230,14 @@ Val* Compiler::compile_lambda(const goos::Object& form, const goos::Object& rest auto func_block_env = new_func_env->alloc_env(new_func_env.get(), "#f"); func_block_env->return_value = return_reg; func_block_env->end_label = Label(new_func_env.get()); - func_block_env->emit(std::make_unique(reset_args_for_coloring)); + func_block_env->emit_ir(form, reset_args_for_coloring); for (u32 i = 0; i < lambda.params.size(); i++) { auto ireg = new_func_env->make_ireg( lambda.params.at(i).type, arg_regs.at(i).is_gpr() ? RegClass::GPR_64 : RegClass::INT_128); ireg->mark_as_settable(); new_func_env->params[lambda.params.at(i).name] = ireg; - new_func_env->emit_ir(ireg, reset_args_for_coloring.at(i)); + new_func_env->emit_ir(form, ireg, reset_args_for_coloring.at(i)); } // compile the function, iterating through the body. @@ -246,7 +246,7 @@ Val* Compiler::compile_lambda(const goos::Object& form, const goos::Object& rest for_each_in_list(lambda.body, [&](const goos::Object& o) { result = compile_error_guard(o, func_block_env); if (!dynamic_cast(result)) { - result = result->to_reg(func_block_env); + result = result->to_reg(o, func_block_env); } if (first_thing) { first_thing = false; @@ -268,10 +268,10 @@ Val* Compiler::compile_lambda(const goos::Object& form, const goos::Object& rest if (result->type() != TypeSpec("none") && m_ts.lookup_type(result->type())->get_load_size() == 16) { ret_hw_reg = emitter::gRegInfo.get_xmm_ret_reg(); - final_result = result->to_xmm128(new_func_env.get()); + final_result = result->to_xmm128(form, new_func_env.get()); return_reg->change_class(RegClass::INT_128); } else { - final_result = result->to_gpr(new_func_env.get()); + final_result = result->to_gpr(form, new_func_env.get()); } func_block_env->return_types.push_back(final_result->type()); @@ -283,7 +283,7 @@ Val* Compiler::compile_lambda(const goos::Object& form, const goos::Object& rest } } - new_func_env->emit(std::make_unique(return_reg, final_result, ret_hw_reg)); + new_func_env->emit_ir(form, return_reg, final_result, ret_hw_reg); auto return_type = m_ts.lowest_common_ancestor(func_block_env->return_types); lambda_ts.add_arg(return_type); @@ -293,7 +293,7 @@ Val* Compiler::compile_lambda(const goos::Object& form, const goos::Object& rest } // put null instruction at the end so jumps to the end have somewhere to go. func_block_env->end_label.idx = new_func_env->code().size(); - new_func_env->emit(std::make_unique()); + new_func_env->emit_ir(form); new_func_env->finish(); // save our code for possible inlining @@ -403,14 +403,14 @@ Val* Compiler::compile_function_or_method_call(const goos::Object& form, Env* en // no lambda (not inlining or immediate), and not a method call, so we should actually get // the function pointer. if (!head_as_lambda && !is_method_call) { - head = head->to_gpr(env); + head = head->to_gpr(form, env); } // compile arguments std::vector eval_args; for (uint32_t i = 1; i < args.unnamed.size(); i++) { auto intermediate = compile_error_guard(args.unnamed.at(i), env); - eval_args.push_back(intermediate->to_reg(env)); + eval_args.push_back(intermediate->to_reg(args.unnamed.at(i), env)); } if (head_as_lambda) { @@ -455,7 +455,7 @@ Val* Compiler::compile_function_or_method_call(const goos::Object& form, Env* en // todo, is this right? auto type = eval_args.at(i)->type(); auto copy = env->make_ireg(type, m_ts.lookup_type(type)->get_preferred_reg_class()); - env->emit(std::make_unique(copy, eval_args.at(i))); + env->emit_ir(form, copy, eval_args.at(i)); copy->mark_as_settable(); lexical_env->vars[head_as_lambda->lambda.params.at(i).name] = copy; } @@ -484,7 +484,7 @@ Val* Compiler::compile_function_or_method_call(const goos::Object& form, Env* en for_each_in_list(head_as_lambda->lambda.body, [&](const goos::Object& o) { result = compile_error_guard(o, inlined_compile_env); if (!dynamic_cast(result)) { - result = result->to_reg(inlined_compile_env); + result = result->to_reg(o, inlined_compile_env); } if (first_thing) { first_thing = false; @@ -499,7 +499,7 @@ Val* Compiler::compile_function_or_method_call(const goos::Object& form, Env* en // there were return froms used in the function, so we fall back to using the separate // return gpr. if (!dynamic_cast(result)) { - auto final_result = result->to_reg(inlined_compile_env); + auto final_result = result->to_reg(form, inlined_compile_env); inlined_block_env->return_types.push_back(final_result->type()); for (const auto& possible_type : inlined_block_env->return_types) { @@ -509,8 +509,7 @@ Val* Compiler::compile_function_or_method_call(const goos::Object& form, Env* en } } - inlined_compile_env->emit( - std::make_unique(result_reg_if_return_from, final_result)); + inlined_compile_env->emit_ir(form, result_reg_if_return_from, final_result); auto return_type = m_ts.lowest_common_ancestor(inlined_block_env->return_types); inlined_block_env->return_value->set_type(return_type); @@ -518,12 +517,12 @@ Val* Compiler::compile_function_or_method_call(const goos::Object& form, Env* en inlined_block_env->return_value->set_type(get_none()->type()); } - inlined_compile_env->emit(std::make_unique()); + inlined_compile_env->emit_ir(form); inlined_block_env->end_label.idx = inlined_block_env->end_label.func->code().size(); return inlined_block_env->return_value; } - inlined_compile_env->emit(std::make_unique()); + inlined_compile_env->emit_ir(form); return result; } else { // not an inlined/immediate, it's a real function call. @@ -540,7 +539,7 @@ Val* Compiler::compile_function_or_method_call(const goos::Object& form, Env* en } // convert the head to a GPR (if function, this is already done) - auto head_as_gpr = head->to_gpr(env); + auto head_as_gpr = head->to_gpr(form, env); if (head_as_gpr) { // method calls have special rules for typing _type_ arguments. if (is_method_call) { @@ -625,18 +624,18 @@ Val* Compiler::compile_real_function_call(const goos::Object& form, arg_outs.push_back( env->make_ireg(arg->type(), reg.is_xmm() ? RegClass::INT_128 : RegClass::GPR_64)); arg_outs.back()->mark_as_settable(); - env->emit(std::make_unique(arg_outs.back(), arg)); + env->emit_ir(form, arg_outs.back(), arg); } // todo, there's probably a more efficient way to do this. auto temp_function = fe->make_gpr(function->type()); - env->emit(std::make_unique(temp_function, function)); - env->emit(std::make_unique(temp_function, return_reg, arg_outs, cc.arg_regs, - cc.return_reg)); + env->emit_ir(form, temp_function, function); + env->emit_ir(form, temp_function, return_reg, arg_outs, cc.arg_regs, + cc.return_reg); if (m_settings.emit_move_after_return) { auto result_reg = env->make_ireg(return_reg->type(), ret_reg_class); - env->emit(std::make_unique(result_reg, return_reg)); + env->emit_ir(form, result_reg, return_reg); return result_reg; } else { return return_reg; diff --git a/goalc/compiler/compilation/Macro.cpp b/goalc/compiler/compilation/Macro.cpp index d25624cce4..579923e4de 100644 --- a/goalc/compiler/compilation/Macro.cpp +++ b/goalc/compiler/compilation/Macro.cpp @@ -113,7 +113,7 @@ Val* Compiler::compile_gscond(const goos::Object& form, const goos::Object& rest for_each_in_list(current_case.as_pair()->cdr, [&](const Object& o) { result = compile_error_guard(o, env); if (!dynamic_cast(result)) { - result = result->to_reg(env); + result = result->to_reg(o, env); } }); return result; @@ -230,7 +230,7 @@ Val* Compiler::compile_mlet(const goos::Object& form, const goos::Object& rest, for_each_in_list(body, [&](const goos::Object& o) { result = compile_error_guard(o, menv); if (!dynamic_cast(result)) { - result = result->to_reg(menv); + result = result->to_reg(o, menv); } }); return result; diff --git a/goalc/compiler/compilation/Math.cpp b/goalc/compiler/compilation/Math.cpp index 2e898752c9..cadcad1134 100644 --- a/goalc/compiler/compilation/Math.cpp +++ b/goalc/compiler/compilation/Math.cpp @@ -45,7 +45,7 @@ Val* Compiler::number_to_integer(const goos::Object& form, Val* in, Env* env) { } else if (is_float(ts)) { auto fe = env->function_env(); auto result = fe->make_gpr(m_ts.make_typespec("int")); - env->emit(std::make_unique(result, in->to_fpr(env))); + env->emit_ir(form, result, in->to_fpr(form, env)); return result; } else if (is_integer(ts)) { return in; @@ -63,9 +63,9 @@ Val* Compiler::number_to_binteger(const goos::Object& form, Val* in, Env* env) { throw_compiler_error(form, "Cannot convert {} (a float) to an integer yet.", in->print()); } else if (is_integer(ts)) { auto fe = env->function_env(); - RegVal* input = in->to_reg(env); + RegVal* input = in->to_reg(form, env); auto sa = fe->make_gpr(m_ts.make_typespec("int")); - env->emit(std::make_unique(sa, 3)); + env->emit_ir(form, sa, 3); auto result = compile_variable_shift(form, input, sa, env, IntegerMathKind::SHLV_64); result->set_type(m_ts.make_typespec("binteger")); return result; @@ -84,7 +84,7 @@ Val* Compiler::number_to_float(const goos::Object& form, Val* in, Env* env) { } else if (is_integer(ts)) { auto fe = env->function_env(); auto result = fe->make_fpr(m_ts.make_typespec("float")); - env->emit(std::make_unique(result, in->to_gpr(env))); + env->emit_ir(form, result, in->to_gpr(form, env)); return result; } throw_compiler_error(form, "Cannot convert a {} to a float.", in->type().print()); @@ -119,26 +119,26 @@ Val* Compiler::compile_add(const goos::Object& form, const goos::Object& rest, E case MATH_INT: case MATH_BINT: { auto result = env->make_gpr(first_type); - env->emit(std::make_unique(result, first_val->to_gpr(env))); + env->emit_ir(form, result, first_val->to_gpr(form, env)); for (size_t i = 1; i < args.unnamed.size(); i++) { - env->emit(std::make_unique( - IntegerMathKind::ADD_64, result, + env->emit_ir( + form, IntegerMathKind::ADD_64, result, to_math_type(form, compile_error_guard(args.unnamed.at(i), env), math_type, env) - ->to_gpr(env))); + ->to_gpr(form, env)); } return result; } case MATH_FLOAT: { auto result = env->make_fpr(first_type); - env->emit(std::make_unique(result, first_val->to_fpr(env))); + env->emit_ir(form, result, first_val->to_fpr(form, env)); for (size_t i = 1; i < args.unnamed.size(); i++) { - env->emit(std::make_unique( - FloatMathKind::ADD_SS, result, + env->emit_ir( + form, FloatMathKind::ADD_SS, result, to_math_type(form, compile_error_guard(args.unnamed.at(i), env), math_type, env) - ->to_fpr(env))); + ->to_fpr(form, env)); } return result; } @@ -165,7 +165,7 @@ Val* Compiler::compile_mul(const goos::Object& form, const goos::Object& rest, E switch (math_type) { case MATH_INT: { auto result = env->make_gpr(first_type); - env->emit(std::make_unique(result, first_val->to_gpr(env))); + env->emit_ir(form, result, first_val->to_gpr(form, env)); for (size_t i = 1; i < args.unnamed.size(); i++) { auto val = compile_error_guard(args.unnamed.at(i), env); @@ -179,24 +179,23 @@ Val* Compiler::compile_mul(const goos::Object& form, const goos::Object& rest, E } if (power_of_two >= 0) { - env->emit_ir(IntegerMathKind::SHL_64, result, power_of_two); + env->emit_ir(form, IntegerMathKind::SHL_64, result, power_of_two); } else { - env->emit(std::make_unique( - IntegerMathKind::IMUL_32, result, - to_math_type(form, val, math_type, env)->to_gpr(env))); + env->emit_ir(form, IntegerMathKind::IMUL_32, result, + to_math_type(form, val, math_type, env)->to_gpr(form, env)); } } return result; } case MATH_FLOAT: { auto result = env->make_fpr(first_type); - env->emit(std::make_unique(result, first_val->to_fpr(env))); + env->emit_ir(form, result, first_val->to_fpr(form, env)); for (size_t i = 1; i < args.unnamed.size(); i++) { - env->emit(std::make_unique( - FloatMathKind::MUL_SS, result, + env->emit_ir( + form, FloatMathKind::MUL_SS, result, to_math_type(form, compile_error_guard(args.unnamed.at(i), env), math_type, env) - ->to_fpr(env))); + ->to_fpr(form, env)); } return result; } @@ -222,13 +221,13 @@ Val* Compiler::compile_fmin(const goos::Object& form, const goos::Object& rest, throw_compiler_error(form, "Must use floats in fmin"); } auto result = env->make_fpr(first_val->type()); - env->emit(std::make_unique(result, first_val->to_fpr(env))); + env->emit_ir(form, result, first_val->to_fpr(form, 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_compiler_error(form, "Must use floats in fmin"); } - env->emit(std::make_unique(FloatMathKind::MIN_SS, result, val->to_fpr(env))); + env->emit_ir(form, FloatMathKind::MIN_SS, result, val->to_fpr(form, env)); } return result; } @@ -245,13 +244,13 @@ Val* Compiler::compile_fmax(const goos::Object& form, const goos::Object& rest, throw_compiler_error(form, "Must use floats in fmax"); } auto result = env->make_fpr(first_val->type()); - env->emit(std::make_unique(result, first_val->to_fpr(env))); + env->emit_ir(form, result, first_val->to_fpr(form, 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_compiler_error(form, "Must use floats in fmax"); } - env->emit(std::make_unique(FloatMathKind::MAX_SS, result, val->to_fpr(env))); + env->emit_ir(form, FloatMathKind::MAX_SS, result, val->to_fpr(form, env)); } return result; } @@ -265,7 +264,7 @@ Val* Compiler::compile_sqrtf(const goos::Object& form, const goos::Object& rest, 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)); + env->emit_ir(form, FloatMathKind::SQRT_SS, result, first_val->to_fpr(form, env)); return result; } @@ -282,13 +281,13 @@ Val* Compiler::compile_imul64(const goos::Object& form, const goos::Object& rest switch (math_type) { case MATH_INT: { auto result = env->make_gpr(first_type); - env->emit(std::make_unique(result, first_val->to_gpr(env))); + env->emit_ir(form, result, first_val->to_gpr(form, env)); for (size_t i = 1; i < args.unnamed.size(); i++) { - env->emit(std::make_unique( - IntegerMathKind::IMUL_64, result, + env->emit_ir( + form, IntegerMathKind::IMUL_64, result, to_math_type(form, compile_error_guard(args.unnamed.at(i), env), math_type, env) - ->to_gpr(env))); + ->to_gpr(form, env)); } return result; } @@ -316,46 +315,48 @@ Val* Compiler::compile_sub(const goos::Object& form, const goos::Object& rest, E switch (math_type) { case MATH_INT: if (args.unnamed.size() == 1) { - auto result = compile_integer(0, env)->to_gpr(env); - env->emit(std::make_unique( - IntegerMathKind::SUB_64, result, + auto result = compile_integer(0, env)->to_gpr(form, env); + env->emit_ir( + form, IntegerMathKind::SUB_64, result, to_math_type(form, compile_error_guard(args.unnamed.at(0), env), math_type, env) - ->to_gpr(env))); + ->to_gpr(form, env)); return result; } else { auto result = env->make_gpr(first_type); - env->emit(std::make_unique( - result, to_math_type(form, compile_error_guard(args.unnamed.at(0), env), math_type, env) - ->to_gpr(env))); + env->emit_ir( + form, result, + to_math_type(form, compile_error_guard(args.unnamed.at(0), env), math_type, env) + ->to_gpr(form, env)); for (size_t i = 1; i < args.unnamed.size(); i++) { - env->emit(std::make_unique( - IntegerMathKind::SUB_64, result, + env->emit_ir( + form, IntegerMathKind::SUB_64, result, to_math_type(form, compile_error_guard(args.unnamed.at(i), env), math_type, env) - ->to_gpr(env))); + ->to_gpr(form, env)); } return result; } case MATH_FLOAT: if (args.unnamed.size() == 1) { - auto result = compile_float(0, env, env->function_env()->segment)->to_fpr(env); - env->emit(std::make_unique( - FloatMathKind::SUB_SS, result, + auto result = compile_float(0, env, env->function_env()->segment)->to_fpr(form, env); + env->emit_ir( + form, FloatMathKind::SUB_SS, result, to_math_type(form, compile_error_guard(args.unnamed.at(0), env), math_type, env) - ->to_fpr(env))); + ->to_fpr(form, env)); return result; } else { auto result = env->make_fpr(first_type); - env->emit(std::make_unique( - result, to_math_type(form, compile_error_guard(args.unnamed.at(0), env), math_type, env) - ->to_fpr(env))); + env->emit_ir( + form, result, + to_math_type(form, compile_error_guard(args.unnamed.at(0), env), math_type, env) + ->to_fpr(form, env)); for (size_t i = 1; i < args.unnamed.size(); i++) { - env->emit(std::make_unique( - FloatMathKind::SUB_SS, result, + env->emit_ir( + form, FloatMathKind::SUB_SS, result, to_math_type(form, compile_error_guard(args.unnamed.at(i), env), math_type, env) - ->to_fpr(env))); + ->to_fpr(form, env)); } return result; } @@ -382,9 +383,9 @@ Val* Compiler::compile_div(const goos::Object& form, const goos::Object& rest, E switch (math_type) { case MATH_INT: { auto fe = env->function_env(); - auto first_thing = first_val->to_gpr(env); + auto first_thing = first_val->to_gpr(form, env); auto result = env->make_gpr(first_type); - env->emit(std::make_unique(result, first_thing)); + env->emit_ir(form, result, first_thing); auto val = compile_error_guard(args.unnamed.at(1), env); auto val_as_int = dynamic_cast(val); @@ -398,9 +399,9 @@ Val* Compiler::compile_div(const goos::Object& form, const goos::Object& rest, E if (power_of_two >= 0) { if (is_singed_integer_or_binteger(first_type)) { - env->emit_ir(IntegerMathKind::SAR_64, result, power_of_two); + env->emit_ir(form, IntegerMathKind::SAR_64, result, power_of_two); } else { - env->emit_ir(IntegerMathKind::SHR_64, result, power_of_two); + env->emit_ir(form, IntegerMathKind::SHR_64, result, power_of_two); } } else { IRegConstraint result_rax_constraint; @@ -410,17 +411,15 @@ Val* Compiler::compile_div(const goos::Object& form, const goos::Object& rest, E fe->constrain(result_rax_constraint); if (is_singed_integer_or_binteger(first_type)) { - env->emit(std::make_unique( - IntegerMathKind::IDIV_32, result, - to_math_type(form, val, math_type, env)->to_gpr(env))); + env->emit_ir(form, IntegerMathKind::IDIV_32, result, + to_math_type(form, val, math_type, env)->to_gpr(form, env)); } else { - env->emit(std::make_unique( - IntegerMathKind::UDIV_32, result, - to_math_type(form, val, math_type, env)->to_gpr(env))); + env->emit_ir(form, IntegerMathKind::UDIV_32, result, + to_math_type(form, val, math_type, env)->to_gpr(form, env)); } auto result_moved = env->make_gpr(first_type); - env->emit_ir(result_moved, result); + env->emit_ir(form, result_moved, result); return result_moved; } @@ -429,11 +428,11 @@ Val* Compiler::compile_div(const goos::Object& form, const goos::Object& rest, E case MATH_FLOAT: { auto result = env->make_fpr(first_type); - env->emit(std::make_unique(result, first_val->to_fpr(env))); - env->emit(std::make_unique( - FloatMathKind::DIV_SS, result, + env->emit_ir(form, result, first_val->to_fpr(form, env)); + env->emit_ir( + form, FloatMathKind::DIV_SS, result, to_math_type(form, compile_error_guard(args.unnamed.at(1), env), math_type, env) - ->to_fpr(env))); + ->to_fpr(form, env)); return result; } @@ -455,8 +454,8 @@ Val* Compiler::compile_variable_shift(const goos::Object& form, auto result = env->make_gpr(in->type()); auto sa_in = env->make_gpr(sa->type()); - env->emit(std::make_unique(result, in)); - env->emit(std::make_unique(sa_in, sa)); + env->emit_ir(form, result, in); + env->emit_ir(form, sa_in, sa); auto fenv = env->function_env(); IRegConstraint sa_con; @@ -470,14 +469,14 @@ Val* Compiler::compile_variable_shift(const goos::Object& form, } fenv->constrain(sa_con); - env->emit(std::make_unique(kind, result, sa_in)); + env->emit_ir(form, kind, result, sa_in); return result; } Val* Compiler::compile_shl(const goos::Object& form, const goos::Object& rest, Env* env) { auto args = get_va(form, rest); va_check(form, args, {{}, {}}, {}); - auto first = compile_error_guard(args.unnamed.at(0), env)->to_gpr(env); + auto first = compile_error_guard(args.unnamed.at(0), env)->to_gpr(form, env); int64_t constant_sa = -1; if (try_getting_constant_integer(args.unnamed.at(1), &constant_sa, env)) { if (constant_sa < 0 || constant_sa > 64) { @@ -485,7 +484,7 @@ Val* Compiler::compile_shl(const goos::Object& form, const goos::Object& rest, E } return compile_fixed_shift(form, first, constant_sa, env, IntegerMathKind::SHL_64); } else { - auto second = compile_error_guard(args.unnamed.at(1), env)->to_gpr(env); + auto second = compile_error_guard(args.unnamed.at(1), env)->to_gpr(form, env); return compile_variable_shift(form, first, second, env, IntegerMathKind::SHLV_64); } } @@ -493,7 +492,7 @@ Val* Compiler::compile_shl(const goos::Object& form, const goos::Object& rest, E Val* Compiler::compile_shr(const goos::Object& form, const goos::Object& rest, Env* env) { auto args = get_va(form, rest); va_check(form, args, {{}, {}}, {}); - auto first = compile_error_guard(args.unnamed.at(0), env)->to_gpr(env); + auto first = compile_error_guard(args.unnamed.at(0), env)->to_gpr(form, env); int64_t constant_sa = -1; if (try_getting_constant_integer(args.unnamed.at(1), &constant_sa, env)) { if (constant_sa < 0 || constant_sa > 64) { @@ -501,7 +500,7 @@ Val* Compiler::compile_shr(const goos::Object& form, const goos::Object& rest, E } return compile_fixed_shift(form, first, constant_sa, env, IntegerMathKind::SHR_64); } else { - auto second = compile_error_guard(args.unnamed.at(1), env)->to_gpr(env); + auto second = compile_error_guard(args.unnamed.at(1), env)->to_gpr(form, env); return compile_variable_shift(form, first, second, env, IntegerMathKind::SHRV_64); } } @@ -509,7 +508,7 @@ Val* Compiler::compile_shr(const goos::Object& form, const goos::Object& rest, E Val* Compiler::compile_sar(const goos::Object& form, const goos::Object& rest, Env* env) { auto args = get_va(form, rest); va_check(form, args, {{}, {}}, {}); - auto first = compile_error_guard(args.unnamed.at(0), env)->to_gpr(env); + auto first = compile_error_guard(args.unnamed.at(0), env)->to_gpr(form, env); int64_t constant_sa = -1; if (try_getting_constant_integer(args.unnamed.at(1), &constant_sa, env)) { if (constant_sa < 0 || constant_sa > 64) { @@ -517,7 +516,7 @@ Val* Compiler::compile_sar(const goos::Object& form, const goos::Object& rest, E } return compile_fixed_shift(form, first, constant_sa, env, IntegerMathKind::SAR_64); } else { - auto second = compile_error_guard(args.unnamed.at(1), env)->to_gpr(env); + auto second = compile_error_guard(args.unnamed.at(1), env)->to_gpr(form, env); return compile_variable_shift(form, first, second, env, IntegerMathKind::SARV_64); } } @@ -538,17 +537,17 @@ Val* Compiler::compile_fixed_shift(const goos::Object& form, // copy to result register auto result = env->make_gpr(in->type()); - env->emit(std::make_unique(result, in)); + env->emit_ir(form, result, in); // do the shift - env->emit(std::make_unique(kind, result, sa)); + env->emit_ir(form, kind, result, sa); return result; } Val* Compiler::compile_mod(const goos::Object& form, const goos::Object& rest, Env* env) { auto args = get_va(form, rest); va_check(form, args, {{}, {}}, {}); - auto first = compile_error_guard(args.unnamed.at(0), env)->to_gpr(env); - auto second = compile_error_guard(args.unnamed.at(1), env)->to_gpr(env); + auto first = compile_error_guard(args.unnamed.at(0), env)->to_gpr(form, env); + auto second = compile_error_guard(args.unnamed.at(1), env)->to_gpr(form, env); auto fenv = env->function_env(); if (get_math_mode(first->type()) != MathMode::MATH_INT || @@ -558,7 +557,7 @@ Val* Compiler::compile_mod(const goos::Object& form, const goos::Object& rest, E } auto result = env->make_gpr(first->type()); - env->emit(std::make_unique(result, first)); + env->emit_ir(form, result, first); IRegConstraint con; con.ireg = result->ireg(); @@ -566,15 +565,15 @@ Val* Compiler::compile_mod(const goos::Object& form, const goos::Object& rest, E con.desired_register = emitter::RAX; fenv->constrain(con); - env->emit(std::make_unique(IntegerMathKind::IMOD_32, result, second)); + env->emit_ir(form, IntegerMathKind::IMOD_32, result, second); return result; } Val* Compiler::compile_logand(const goos::Object& form, const goos::Object& rest, Env* env) { auto args = get_va(form, rest); va_check(form, args, {{}, {}}, {}); - auto first = compile_error_guard(args.unnamed.at(0), env)->to_gpr(env); - auto second = compile_error_guard(args.unnamed.at(1), env)->to_gpr(env); + auto first = compile_error_guard(args.unnamed.at(0), env)->to_gpr(form, env); + auto second = compile_error_guard(args.unnamed.at(1), env)->to_gpr(form, env); auto math_1 = get_math_mode(first->type()); auto math_2 = get_math_mode(second->type()); if (!((math_1 == MathMode::MATH_INT && math_2 == MathMode::MATH_INT) || @@ -587,8 +586,8 @@ Val* Compiler::compile_logand(const goos::Object& form, const goos::Object& rest // kind of a hack, but make (logand int pointer) return pointer. auto result = env->make_gpr(m_ts.tc(TypeSpec("pointer"), second->type()) ? second->type() : first->type()); - env->emit(std::make_unique(result, first)); - env->emit(std::make_unique(IntegerMathKind::AND_64, result, second)); + env->emit_ir(form, result, first); + env->emit_ir(form, IntegerMathKind::AND_64, result, second); return result; } @@ -598,10 +597,10 @@ Val* Compiler::compile_logior(const goos::Object& form, const goos::Object& rest throw_compiler_error(form, "Invalid logior form"); } - auto first = compile_error_guard(args.unnamed.at(0), env)->to_gpr(env); + auto first = compile_error_guard(args.unnamed.at(0), env)->to_gpr(form, env); auto result = env->make_gpr(first->type()); - env->emit(std::make_unique(result, first)); + env->emit_ir(form, result, first); for (size_t i = 1; i < args.unnamed.size(); i++) { auto sec = compile_error_guard(args.unnamed.at(i), env); @@ -609,7 +608,7 @@ Val* Compiler::compile_logior(const goos::Object& form, const goos::Object& rest throw_compiler_error(form, "Cannot logior a {} by a {}.", first->type().print(), sec->type().print()); } - env->emit(std::make_unique(IntegerMathKind::OR_64, result, sec->to_gpr(env))); + env->emit_ir(form, IntegerMathKind::OR_64, result, sec->to_gpr(form, env)); } return result; } @@ -617,8 +616,8 @@ Val* Compiler::compile_logior(const goos::Object& form, const goos::Object& rest Val* Compiler::compile_logxor(const goos::Object& form, const goos::Object& rest, Env* env) { auto args = get_va(form, rest); va_check(form, args, {{}, {}}, {}); - auto first = compile_error_guard(args.unnamed.at(0), env)->to_gpr(env); - auto second = compile_error_guard(args.unnamed.at(1), env)->to_gpr(env); + auto first = compile_error_guard(args.unnamed.at(0), env)->to_gpr(form, env); + auto second = compile_error_guard(args.unnamed.at(1), env)->to_gpr(form, env); if (get_math_mode(first->type()) != MathMode::MATH_INT || get_math_mode(second->type()) != MathMode::MATH_INT) { throw_compiler_error(form, "Cannot logxor a {} by a {}.", first->type().print(), @@ -626,21 +625,21 @@ Val* Compiler::compile_logxor(const goos::Object& form, const goos::Object& rest } auto result = env->make_gpr(first->type()); - env->emit(std::make_unique(result, first)); - env->emit(std::make_unique(IntegerMathKind::XOR_64, result, second)); + env->emit_ir(form, result, first); + env->emit_ir(form, IntegerMathKind::XOR_64, result, second); return result; } Val* Compiler::compile_lognot(const goos::Object& form, const goos::Object& rest, Env* env) { auto args = get_va(form, rest); va_check(form, args, {{}}, {}); - auto first = compile_error_guard(args.unnamed.at(0), env)->to_gpr(env); + auto first = compile_error_guard(args.unnamed.at(0), env)->to_gpr(form, env); if (get_math_mode(first->type()) != MathMode::MATH_INT) { throw_compiler_error(form, "Cannot lognot a {}.", first->type().print()); } auto result = env->make_gpr(first->type()); - env->emit(std::make_unique(result, first)); - env->emit(std::make_unique(IntegerMathKind::NOT_64, result, nullptr)); + env->emit_ir(form, result, first); + env->emit_ir(form, IntegerMathKind::NOT_64, result, nullptr); return result; } diff --git a/goalc/compiler/compilation/State.cpp b/goalc/compiler/compilation/State.cpp index b274ba764a..e49c526e68 100644 --- a/goalc/compiler/compilation/State.cpp +++ b/goalc/compiler/compilation/State.cpp @@ -36,7 +36,7 @@ Val* Compiler::compile_define_state_hook(const goos::Object& form, } // get state object - auto state_object = compile_error_guard(args.unnamed.at(2), env)->to_gpr(env); + auto state_object = compile_error_guard(args.unnamed.at(2), env)->to_gpr(form, env); if (state_object->type() != TypeSpec("state")) { throw_compiler_error(form, "define-state-hook got an invalid state object: had type {}", state_object->type().print()); @@ -48,16 +48,16 @@ Val* Compiler::compile_define_state_hook(const goos::Object& form, for (auto name : {"exit", "trans", "post", "event"}) { auto field = get_field_of_structure(state_type_info, state_object, name, env); auto value = compile_error_guard(args.named.at(name), env); - do_set(form, field, value->to_gpr(env), value, env); + do_set(form, field, value->to_gpr(form, env), value, env); } auto enter_field = get_field_of_structure(state_type_info, state_object, "enter", env); auto enter_value = compile_error_guard(args.named.at("enter"), env); - do_set(form, enter_field, enter_value->to_gpr(env), enter_value, env); + do_set(form, enter_field, enter_value->to_gpr(form, env), enter_value, env); auto code_field = get_field_of_structure(state_type_info, state_object, "code", env); auto code_value = compile_error_guard(args.named.at("code"), env); - do_set(form, code_field, code_value->to_gpr(env), code_value, env); + do_set(form, code_field, code_value->to_gpr(form, env), code_value, env); // state name TypeSpec state_type("state"); @@ -74,7 +74,7 @@ Val* Compiler::compile_define_state_hook(const goos::Object& form, } m_symbol_types[state_name] = state_type; auto sym_val = env->function_env()->alloc_val(state_name, state_type); - env->emit(std::make_unique(sym_val, state_object)); + env->emit_ir(form, sym_val, state_object); return get_none(); } @@ -114,7 +114,7 @@ Val* Compiler::compile_define_virtual_state_hook(const goos::Object& form, } // get state object - auto state_object = compile_error_guard(args.unnamed.at(2), env)->to_gpr(env); + auto state_object = compile_error_guard(args.unnamed.at(2), env)->to_gpr(form, env); if (state_object->type() != TypeSpec("state")) { throw_compiler_error(form, "define-state-hook got an invalid state object: had type {}", state_object->type().print()); @@ -126,16 +126,16 @@ Val* Compiler::compile_define_virtual_state_hook(const goos::Object& form, for (auto name : {"exit", "trans", "post", "event"}) { auto field = get_field_of_structure(state_type_info, state_object, name, env); auto value = compile_error_guard(args.named.at(name), env); - do_set(form, field, value->to_gpr(env), value, env); + do_set(form, field, value->to_gpr(form, env), value, env); } auto enter_field = get_field_of_structure(state_type_info, state_object, "enter", env); auto enter_value = compile_error_guard(args.named.at("enter"), env); - do_set(form, enter_field, enter_value->to_gpr(env), enter_value, env); + do_set(form, enter_field, enter_value->to_gpr(form, env), enter_value, env); auto code_field = get_field_of_structure(state_type_info, state_object, "code", env); auto code_value = compile_error_guard(args.named.at("code"), env); - do_set(form, code_field, code_value->to_gpr(env), code_value, env); + do_set(form, code_field, code_value->to_gpr(form, env), code_value, env); // state name TypeSpec state_type("state"); @@ -164,18 +164,19 @@ Val* Compiler::compile_define_virtual_state_hook(const goos::Object& form, auto parent_of_parent_type = m_ts.lookup_type(state_parent)->get_parent(); if (m_ts.try_lookup_method(parent_of_parent_type, state_name, &parent_method_info)) { // need to call inherit state TODO - auto inherit_state_func = compile_get_symbol_value(form, "inherit-state", env)->to_gpr(env); + auto inherit_state_func = + compile_get_symbol_value(form, "inherit-state", env)->to_gpr(form, env); auto parents_state = compile_get_method_of_type(form, TypeSpec(parent_of_parent_type), state_name, env) - ->to_gpr(env); + ->to_gpr(form, env); compile_real_function_call(form, inherit_state_func, {state_object, parents_state}, env); } // call method set. // (method-set! sunken-elevator 22 (the-as function gp-0)) - auto method_set_func = compile_get_symbol_value(form, "method-set!", env)->to_gpr(env); - auto type_obj = compile_get_symbol_value(form, state_parent, env)->to_gpr(env); - auto method_id = compile_integer(child_method_info.id, env)->to_gpr(env); + auto method_set_func = compile_get_symbol_value(form, "method-set!", env)->to_gpr(form, env); + auto type_obj = compile_get_symbol_value(form, state_parent, env)->to_gpr(form, env); + auto method_id = compile_integer(child_method_info.id, env)->to_gpr(form, env); compile_real_function_call(form, method_set_func, {type_obj, method_id, state_object}, env); return get_none(); @@ -199,14 +200,14 @@ Val* Compiler::compile_go_hook(const goos::Object& form, const goos::Object& res } // get the process - auto proc = compile_error_guard(args.unnamed.at(0), env)->to_gpr(env); + auto proc = compile_error_guard(args.unnamed.at(0), env)->to_gpr(form, env); if (!m_ts.tc(TypeSpec("process"), proc->type())) { throw_compiler_error(form, "First argument to go-hook should be a process, got {} instead", proc->type().print()); } // get the state - auto state = compile_error_guard(args.unnamed.at(1), env)->to_gpr(env); + auto state = compile_error_guard(args.unnamed.at(1), env)->to_gpr(form, env); if (!m_ts.tc(TypeSpec("state"), state->type())) { throw_compiler_error(form, "Second argument to go-hook should be a state, got {} instead", state->type().print()); @@ -235,11 +236,11 @@ Val* Compiler::compile_go_hook(const goos::Object& form, const goos::Object& res std::vector function_arguments; for (size_t i = 2; i < args.unnamed.size(); i++) { - function_arguments.push_back(compile_error_guard(args.unnamed.at(i), env)->to_gpr(env)); + function_arguments.push_back(compile_error_guard(args.unnamed.at(i), env)->to_gpr(form, env)); } // typechecking here will make sure the go is possible. - compile_real_function_call(form, enter_state_func->to_gpr(env), function_arguments, env); + compile_real_function_call(form, enter_state_func->to_gpr(form, env), function_arguments, env); return get_none(); } \ No newline at end of file diff --git a/goalc/compiler/compilation/Static.cpp b/goalc/compiler/compilation/Static.cpp index 19de671bda..c1fbd6e7c0 100644 --- a/goalc/compiler/compilation/Static.cpp +++ b/goalc/compiler/compilation/Static.cpp @@ -442,14 +442,14 @@ Val* Compiler::compile_bitfield_definition(const goos::Object& form, assert(allow_dynamic_construction); if (use_128) { - auto integer_lo = compile_integer(constant_integer_part.lo, env)->to_gpr(env); - auto integer_hi = compile_integer(constant_integer_part.hi, env)->to_gpr(env); + auto integer_lo = compile_integer(constant_integer_part.lo, env)->to_gpr(form, env); + auto integer_hi = compile_integer(constant_integer_part.hi, env)->to_gpr(form, env); auto fe = env->function_env(); auto rv = fe->make_ireg(type, RegClass::INT_128); auto xmm_temp = fe->make_ireg(TypeSpec("object"), RegClass::INT_128); for (auto& def : dynamic_defs) { - auto field_val = compile_error_guard(def.definition, env)->to_gpr(env); + auto field_val = compile_error_guard(def.definition, env)->to_gpr(def.definition, env); if (!m_ts.tc(def.expected_type, field_val->type())) { throw_compiler_error(form, "Typecheck failed for bitfield {}! Got a {} but expected a {}", def.field_name, field_val->type().print(), @@ -471,27 +471,25 @@ Val* Compiler::compile_bitfield_definition(const goos::Object& form, assert(right_shift_amnt >= 0); if (left_shift_amnt > 0) { - env->emit(std::make_unique(IntegerMathKind::SHL_64, field_val, - left_shift_amnt)); + env->emit_ir(form, IntegerMathKind::SHL_64, field_val, left_shift_amnt); } if (right_shift_amnt > 0) { - env->emit(std::make_unique(IntegerMathKind::SHR_64, field_val, - right_shift_amnt)); + env->emit_ir(form, IntegerMathKind::SHR_64, field_val, right_shift_amnt); } - env->emit(std::make_unique(IntegerMathKind::OR_64, - start_lo ? integer_lo : integer_hi, field_val)); + env->emit_ir(form, IntegerMathKind::OR_64, + start_lo ? integer_lo : integer_hi, field_val); } - fe->emit_ir(xmm_temp, integer_lo); - fe->emit_ir(rv, integer_hi); - fe->emit_ir(true, rv, rv, xmm_temp, IR_Int128Math3Asm::Kind::PCPYLD); + fe->emit_ir(form, xmm_temp, integer_lo); + fe->emit_ir(form, rv, integer_hi); + fe->emit_ir(form, true, rv, rv, xmm_temp, IR_Int128Math3Asm::Kind::PCPYLD); return rv; } else { - RegVal* integer_reg = integer->to_gpr(env); + RegVal* integer_reg = integer->to_gpr(form, env); for (auto& def : dynamic_defs) { - auto field_val = compile_error_guard(def.definition, env)->to_gpr(env); + auto field_val = compile_error_guard(def.definition, env)->to_gpr(def.definition, env); if (!m_ts.tc(def.expected_type, field_val->type())) { throw_compiler_error(form, "Typecheck failed for bitfield {}! Got a {} but expected a {}", def.field_name, field_val->type().print(), @@ -502,16 +500,14 @@ Val* Compiler::compile_bitfield_definition(const goos::Object& form, assert(right_shift_amnt >= 0); if (left_shift_amnt > 0) { - env->emit(std::make_unique(IntegerMathKind::SHL_64, field_val, - left_shift_amnt)); + env->emit_ir(form, IntegerMathKind::SHL_64, field_val, left_shift_amnt); } if (right_shift_amnt > 0) { - env->emit(std::make_unique(IntegerMathKind::SHR_64, field_val, - right_shift_amnt)); + env->emit_ir(form, IntegerMathKind::SHR_64, field_val, right_shift_amnt); } - env->emit(std::make_unique(IntegerMathKind::OR_64, integer_reg, field_val)); + env->emit_ir(form, IntegerMathKind::OR_64, integer_reg, field_val); } integer_reg->set_type(type); diff --git a/goalc/compiler/compilation/Type.cpp b/goalc/compiler/compilation/Type.cpp index 9186b89406..9faf67ab41 100644 --- a/goalc/compiler/compilation/Type.cpp +++ b/goalc/compiler/compilation/Type.cpp @@ -23,7 +23,7 @@ int get_offset_of_method(int id) { * To do method lookup, the given type must be the same as, or a child of, the given compile time * type. */ -RegVal* Compiler::compile_get_method_of_type(const goos::Object& /*form*/, +RegVal* Compiler::compile_get_method_of_type(const goos::Object& form, const TypeSpec& compile_time_type, RegVal* type, const std::string& method_name, @@ -48,7 +48,7 @@ RegVal* Compiler::compile_get_method_of_type(const goos::Object& /*form*/, assert(di.load_size == 4); auto deref = fe->alloc_val(di.result_type, loc, MemLoadInfo(di)); - return deref->to_reg(env); + return deref->to_reg(form, env); } /*! @@ -60,7 +60,7 @@ RegVal* Compiler::compile_get_method_of_type(const goos::Object& form, const TypeSpec& compile_time_type, const std::string& method_name, Env* env) { - auto typ = compile_get_symbol_value(form, compile_time_type.base_type(), env)->to_gpr(env); + auto typ = compile_get_symbol_value(form, compile_time_type.base_type(), env)->to_gpr(form, env); return compile_get_method_of_type(form, compile_time_type, typ, method_name, env); } @@ -96,10 +96,11 @@ RegVal* Compiler::compile_get_method_of_object(const goos::Object& form, info.size = 4; info.sign_extend = false; info.reg = RegClass::GPR_64; - env->emit(std::make_unique(runtime_type, -4, object, info)); + env->emit_ir(form, runtime_type, -4, object, info); } else { // can't look up at runtime - runtime_type = compile_get_symbol_value(form, compile_time_type.base_type(), env)->to_gpr(env); + runtime_type = + compile_get_symbol_value(form, compile_time_type.base_type(), env)->to_gpr(form, env); } auto offset_of_method = get_offset_of_method(method_info.id); @@ -116,7 +117,7 @@ RegVal* Compiler::compile_get_method_of_object(const goos::Object& form, assert(di.load_size == 4); auto deref = fe->alloc_val(di.result_type, loc, MemLoadInfo(di)); - return deref->to_reg(env); + return deref->to_reg(form, env); } Val* Compiler::compile_format_string(const goos::Object& form, @@ -126,11 +127,11 @@ Val* Compiler::compile_format_string(const goos::Object& form, const std::string& out_stream) { // Add first two format args args.insert(args.begin(), - compile_string(fmt_template, env, env->function_env()->segment)->to_gpr(env)); - args.insert(args.begin(), compile_get_sym_obj(out_stream, env)->to_gpr(env)); + compile_string(fmt_template, env, env->function_env()->segment)->to_gpr(form, env)); + args.insert(args.begin(), compile_get_sym_obj(out_stream, env)->to_gpr(form, env)); // generate code in the method_env - auto format_function = compile_get_symbol_value(form, "_format", env)->to_gpr(env); + auto format_function = compile_get_symbol_value(form, "_format", env)->to_gpr(form, env); return compile_real_function_call(form, format_function, args, env); } @@ -152,50 +153,50 @@ void Compiler::generate_field_description(const goos::Object& form, } else if (f.is_array() && !f.is_dynamic()) { // Arrays str_template += fmt::format("{}{}[{}] @ #x~X~%", tabs, f.name(), f.array_size()); - format_args.push_back(get_field_of_structure(type, reg, f.name(), env)->to_gpr(env)); + format_args.push_back(get_field_of_structure(type, reg, f.name(), env)->to_gpr(form, env)); } else if (f.is_dynamic()) { // Dynamic Field str_template += fmt::format("{}{}[0] @ #x~X~%", tabs, f.name()); - format_args.push_back(get_field_of_structure(type, reg, f.name(), env)->to_gpr(env)); + format_args.push_back(get_field_of_structure(type, reg, f.name(), env)->to_gpr(form, env)); } else if (m_ts.tc(m_ts.make_typespec("basic"), f.type()) || m_ts.tc(m_ts.make_typespec("binteger"), f.type()) || m_ts.tc(m_ts.make_typespec("pair"), f.type())) { // basic, binteger, pair str_template += fmt::format("{}{}: ~A~%", tabs, f.name()); - format_args.push_back(get_field_of_structure(type, reg, f.name(), env)->to_gpr(env)); + format_args.push_back(get_field_of_structure(type, reg, f.name(), env)->to_gpr(form, env)); } else if (m_ts.tc(m_ts.make_typespec("structure"), f.type())) { // Structure str_template += fmt::format("{}{}: #<{} @ #x~X>~%", tabs, f.name(), f.type().print()); - format_args.push_back(get_field_of_structure(type, reg, f.name(), env)->to_gpr(env)); + format_args.push_back(get_field_of_structure(type, reg, f.name(), env)->to_gpr(form, env)); } else if (f.type() == TypeSpec("seconds")) { // seconds str_template += fmt::format("{}{}: (seconds ~e)~%", tabs, f.name()); - format_args.push_back(get_field_of_structure(type, reg, f.name(), env)->to_gpr(env)); + format_args.push_back(get_field_of_structure(type, reg, f.name(), env)->to_gpr(form, env)); } else if (m_ts.tc(m_ts.make_typespec("integer"), f.type())) { // Integer if (m_ts.lookup_type(f.type())->get_load_size() > 8) { str_template += fmt::format("{}: ~%", tabs, f.name()); } else { str_template += fmt::format("{}{}: ~D~%", tabs, f.name()); - format_args.push_back(get_field_of_structure(type, reg, f.name(), env)->to_gpr(env)); + format_args.push_back(get_field_of_structure(type, reg, f.name(), env)->to_gpr(form, env)); } } else if (f.type() == TypeSpec("meters")) { // meters str_template += fmt::format("{}{}: (meters ~m)~%", tabs, f.name()); - format_args.push_back(get_field_of_structure(type, reg, f.name(), env)->to_gpr(env)); + format_args.push_back(get_field_of_structure(type, reg, f.name(), env)->to_gpr(form, env)); } else if (f.type() == TypeSpec("degrees")) { // degrees str_template += fmt::format("{}{}: (degrees ~r)~%", tabs, f.name()); - format_args.push_back(get_field_of_structure(type, reg, f.name(), env)->to_gpr(env)); + format_args.push_back(get_field_of_structure(type, reg, f.name(), env)->to_gpr(form, env)); } else if (m_ts.tc(m_ts.make_typespec("float"), f.type())) { // Float str_template += fmt::format("{}{}: ~f~%", tabs, f.name()); - format_args.push_back(get_field_of_structure(type, reg, f.name(), env)->to_gpr(env)); + format_args.push_back(get_field_of_structure(type, reg, f.name(), env)->to_gpr(form, env)); } else if (m_ts.tc(m_ts.make_typespec("pointer"), f.type())) { // Pointers str_template += fmt::format("{}{}: #x~X~%", tabs, f.name()); - format_args.push_back(get_field_of_structure(type, reg, f.name(), env)->to_gpr(env)); + format_args.push_back(get_field_of_structure(type, reg, f.name(), env)->to_gpr(form, env)); } else { // Otherwise, we havn't implemented it! str_template += fmt::format("{}{}: Undefined!~%", tabs, f.name()); @@ -210,7 +211,7 @@ Val* Compiler::generate_inspector_for_structure_type(const goos::Object& form, // Create a function environment to hold the code for the inspect method. The name is just for // debugging. auto method_env = std::make_unique( - env, "autogenerated-inspect-method-of-" + structure_type->get_name()); + env, "autogenerated-inspect-method-of-" + structure_type->get_name(), &m_goos.reader); // put the method in the debug segment. method_env->set_segment(DEBUG_SEGMENT); @@ -223,10 +224,10 @@ Val* Compiler::generate_inspector_for_structure_type(const goos::Object& form, constraint.desired_register = emitter::gRegInfo.get_gpr_arg_reg(0); // to the first argument method_env->constrain(constraint); // Inform the compiler that `input`'s value will be written to `rdi` (first arg register) - method_env->emit(std::make_unique(std::vector{input_arg})); + method_env->emit_ir(form, std::vector{input_arg}); auto input = method_env->make_gpr(structure_type->get_name()); - method_env->emit_ir(input, input_arg); + method_env->emit_ir(form, input, input_arg); // there's a special case for children of process. if (m_ts.fully_defined_type_exists("process") && @@ -251,10 +252,10 @@ Val* Compiler::generate_inspector_for_structure_type(const goos::Object& form, RegVal* type_name = nullptr; if (dynamic_cast(structure_type)) { type_name = get_field_of_structure(structure_type, input, "type", method_env.get()) - ->to_gpr(method_env.get()); + ->to_gpr(form, method_env.get()); } else { type_name = compile_get_sym_obj(structure_type->get_name(), method_env.get()) - ->to_gpr(method_env.get()); + ->to_gpr(form, method_env.get()); } compile_format_string(form, method_env.get(), "[~8x] ~A~%", {input, type_name}); @@ -263,7 +264,7 @@ Val* Compiler::generate_inspector_for_structure_type(const goos::Object& form, } } - method_env->emit_ir(method_env->make_gpr(input->type()), input, + method_env->emit_ir(form, method_env->make_gpr(input->type()), input, emitter::gRegInfo.get_gpr_ret_reg()); // add this function to the object file @@ -274,12 +275,13 @@ Val* Compiler::generate_inspector_for_structure_type(const goos::Object& form, obj_env_inspect->add_function(std::move(method_env)); // call method-set! - auto type_obj = compile_get_symbol_value(form, structure_type->get_name(), env)->to_gpr(env); + auto type_obj = + compile_get_symbol_value(form, structure_type->get_name(), env)->to_gpr(form, env); auto id_val = compile_integer(m_ts.lookup_method(structure_type->get_name(), "inspect").id, env) - ->to_gpr(env); - auto method_set_val = compile_get_symbol_value(form, "method-set!", env)->to_gpr(env); - return compile_real_function_call(form, method_set_val, {type_obj, id_val, method->to_gpr(env)}, - env); + ->to_gpr(form, env); + auto method_set_val = compile_get_symbol_value(form, "method-set!", env)->to_gpr(form, env); + return compile_real_function_call(form, method_set_val, + {type_obj, id_val, method->to_gpr(form, env)}, env); } Val* Compiler::generate_inspector_for_bitfield_type(const goos::Object& form, @@ -289,7 +291,7 @@ Val* Compiler::generate_inspector_for_bitfield_type(const goos::Object& form, // Create a function environment to hold the code for the inspect method. The name is just for // debugging. auto method_env = std::make_unique( - env, "autogenerated-inspect-method-of-" + bitfield_type->get_name()); + env, "autogenerated-inspect-method-of-" + bitfield_type->get_name(), &m_goos.reader); // put the method in the debug segment. method_env->set_segment(DEBUG_SEGMENT); @@ -307,13 +309,13 @@ Val* Compiler::generate_inspector_for_bitfield_type(const goos::Object& form, method_env->constrain(constraint); // Inform the compiler that `input`'s value will be written to `rdi` (first arg register) - method_env->emit(std::make_unique(std::vector{input_arg})); + method_env->emit_ir(form, std::vector{input_arg}); auto input = method_env->make_gpr(bitfield_type->get_name()); - method_env->emit_ir(input, input_arg); + method_env->emit_ir(form, input, input_arg); - RegVal* type_name = - compile_get_sym_obj(bitfield_type->get_name(), method_env.get())->to_gpr(method_env.get()); + RegVal* type_name = compile_get_sym_obj(bitfield_type->get_name(), method_env.get()) + ->to_gpr(form, method_env.get()); compile_format_string(form, method_env.get(), "[~8x] ~A~%", {input, type_name}); for (const BitField& bf : bitfield_type->fields()) { @@ -321,7 +323,7 @@ Val* Compiler::generate_inspector_for_bitfield_type(const goos::Object& form, std::vector format_args = {}; str_template += fmt::format("~T{}: ~D | 0x~X | 0b~B~%", bf.name()); auto value = get_field_of_bitfield(bitfield_type, input, bf.name(), method_env.get()) - ->to_gpr(method_env.get()); + ->to_gpr(form, method_env.get()); format_args.push_back(value); format_args.push_back(value); format_args.push_back(value); @@ -329,12 +331,11 @@ Val* Compiler::generate_inspector_for_bitfield_type(const goos::Object& form, } if (bitfield_128) { - method_env->emit( - std::make_unique(method_env->make_ireg(input->type(), RegClass::INT_128), input, - emitter::gRegInfo.get_gpr_ret_reg())); + method_env->emit_ir(form, method_env->make_ireg(input->type(), RegClass::INT_128), + input, emitter::gRegInfo.get_gpr_ret_reg()); } else { - method_env->emit(std::make_unique(method_env->make_gpr(input->type()), input, - emitter::gRegInfo.get_gpr_ret_reg())); + method_env->emit_ir(form, method_env->make_gpr(input->type()), input, + emitter::gRegInfo.get_gpr_ret_reg()); } // add this function to the object file @@ -345,12 +346,12 @@ Val* Compiler::generate_inspector_for_bitfield_type(const goos::Object& form, obj_env_inspect->add_function(std::move(method_env)); // call method-set! - auto type_obj = compile_get_symbol_value(form, bitfield_type->get_name(), env)->to_gpr(env); + auto type_obj = compile_get_symbol_value(form, bitfield_type->get_name(), env)->to_gpr(form, env); auto id_val = compile_integer(m_ts.lookup_method(bitfield_type->get_name(), "inspect").id, env) - ->to_gpr(env); - auto method_set_val = compile_get_symbol_value(form, "method-set!", env)->to_gpr(env); - return compile_real_function_call(form, method_set_val, {type_obj, id_val, method->to_gpr(env)}, - env); + ->to_gpr(form, env); + auto method_set_val = compile_get_symbol_value(form, "method-set!", env)->to_gpr(form, env); + return compile_real_function_call(form, method_set_val, + {type_obj, id_val, method->to_gpr(form, env)}, env); } /*! @@ -377,10 +378,10 @@ Val* Compiler::compile_deftype(const goos::Object& form, const goos::Object& res // get the new method of type object. this is new_type in kscheme.cpp auto new_type_method = compile_get_method_of_type(form, m_ts.make_typespec("type"), "new", env); // call (new 'type 'type-name parent-type flags) - auto new_type_symbol = compile_get_sym_obj(result.type.base_type(), env)->to_gpr(env); + auto new_type_symbol = compile_get_sym_obj(result.type.base_type(), env)->to_gpr(form, env); auto parent_type = - compile_get_symbol_value(form, result.type_info->get_parent(), env)->to_gpr(env); - auto flags_int = compile_integer(result.flags.flag, env)->to_gpr(env); + compile_get_symbol_value(form, result.type_info->get_parent(), env)->to_gpr(form, env); + auto flags_int = compile_integer(result.flags.flag, env)->to_gpr(form, env); compile_real_function_call(form, new_type_method, {new_type_symbol, parent_type, flags_int}, env); } @@ -461,7 +462,7 @@ Val* Compiler::compile_defmethod(const goos::Object& form, const goos::Object& _ lambda.body = *body; place->func = nullptr; - auto new_func_env = std::make_unique(env, lambda.debug_name); + auto new_func_env = std::make_unique(env, lambda.debug_name, &m_goos.reader); new_func_env->set_segment(MAIN_SEGMENT); // todo, how do we set debug? new_func_env->method_of_type_name = symbol_string(type_name); @@ -515,14 +516,14 @@ Val* Compiler::compile_defmethod(const goos::Object& form, const goos::Object& _ auto func_block_env = new_func_env->alloc_env(new_func_env.get(), "#f"); func_block_env->return_value = return_reg; func_block_env->end_label = Label(new_func_env.get()); - func_block_env->emit(std::make_unique(reset_args_for_coloring)); + func_block_env->emit_ir(form, reset_args_for_coloring); for (u32 i = 0; i < lambda.params.size(); i++) { auto ireg = new_func_env->make_ireg( lambda.params.at(i).type, arg_regs.at(i).is_gpr() ? RegClass::GPR_64 : RegClass::INT_128); ireg->mark_as_settable(); new_func_env->params[lambda.params.at(i).name] = ireg; - new_func_env->emit_ir(ireg, reset_args_for_coloring.at(i)); + new_func_env->emit_ir(form, ireg, reset_args_for_coloring.at(i)); } // compile the function! @@ -531,7 +532,7 @@ Val* Compiler::compile_defmethod(const goos::Object& form, const goos::Object& _ for_each_in_list(lambda.body, [&](const goos::Object& o) { result = compile_error_guard(o, func_block_env); if (!dynamic_cast(result)) { - result = result->to_reg(func_block_env); + result = result->to_reg(o, func_block_env); } if (first_thing) { first_thing = false; @@ -548,10 +549,10 @@ Val* Compiler::compile_defmethod(const goos::Object& form, const goos::Object& _ emitter::Register ret_hw_reg = emitter::gRegInfo.get_gpr_ret_reg(); if (m_ts.lookup_type(result->type())->get_load_size() == 16) { ret_hw_reg = emitter::gRegInfo.get_xmm_ret_reg(); - final_result = result->to_xmm128(new_func_env.get()); + final_result = result->to_xmm128(form, new_func_env.get()); return_reg->change_class(RegClass::INT_128); } else { - final_result = result->to_gpr(new_func_env.get()); + final_result = result->to_gpr(form, new_func_env.get()); } func_block_env->return_types.push_back(final_result->type()); @@ -564,7 +565,7 @@ Val* Compiler::compile_defmethod(const goos::Object& form, const goos::Object& _ } } - new_func_env->emit(std::make_unique(return_reg, final_result, ret_hw_reg)); + new_func_env->emit_ir(form, return_reg, final_result, ret_hw_reg); auto return_type = m_ts.lowest_common_ancestor(func_block_env->return_types); lambda_ts.add_arg(return_type); @@ -572,7 +573,7 @@ Val* Compiler::compile_defmethod(const goos::Object& form, const goos::Object& _ lambda_ts.add_arg(m_ts.make_typespec("none")); } func_block_env->end_label.idx = new_func_env->code().size(); - new_func_env->emit(std::make_unique()); + new_func_env->emit_ir(form); new_func_env->finish(); auto obj_env = new_func_env->file_env(); @@ -585,10 +586,10 @@ Val* Compiler::compile_defmethod(const goos::Object& form, const goos::Object& _ m_symbol_info.add_method(symbol_string(method_name), symbol_string(type_name), form); auto info = m_ts.define_method(symbol_string(type_name), symbol_string(method_name), lambda_ts); - auto type_obj = compile_get_symbol_value(form, symbol_string(type_name), env)->to_gpr(env); - auto id_val = compile_integer(info.id, env)->to_gpr(env); - auto method_val = place->to_gpr(env); - auto method_set_val = compile_get_symbol_value(form, "method-set!", env)->to_gpr(env); + auto type_obj = compile_get_symbol_value(form, symbol_string(type_name), env)->to_gpr(form, env); + auto id_val = compile_integer(info.id, env)->to_gpr(form, env); + auto method_val = place->to_gpr(form, env); + auto method_set_val = compile_get_symbol_value(form, "method-set!", env)->to_gpr(form, env); return compile_real_function_call(form, method_set_val, {type_obj, id_val, method_val}, env); } @@ -731,7 +732,7 @@ Val* Compiler::compile_deref(const goos::Object& form, const goos::Object& _rest bool has_constant_idx = try_getting_constant_integer(field_obj, &constant_index_value, env); if (!has_constant_idx) { - index_value = compile_error_guard(field_obj, env)->to_gpr(env); + index_value = compile_error_guard(field_obj, env)->to_gpr(form, env); if (!is_integer(index_value->type())) { throw_compiler_error(form, "Cannot use -> with {}.", field_obj.print()); } @@ -747,7 +748,7 @@ Val* Compiler::compile_deref(const goos::Object& form, const goos::Object& _rest } else { // todo - use shifts if possible? RegVal* offset = fe->make_gpr(TypeSpec("int")); - compile_constant_product(offset, index_value, di.stride, env); + compile_constant_product(form, offset, index_value, di.stride, env); result = fe->alloc_val(di.result_type, result, offset); } } else if (result->type().base_type() == "pointer") { @@ -761,7 +762,7 @@ Val* Compiler::compile_deref(const goos::Object& form, const goos::Object& _rest constant_index_value * di.stride); } else { RegVal* offset = fe->make_gpr(TypeSpec("int")); - compile_constant_product(offset, index_value, di.stride, env); + compile_constant_product(form, offset, index_value, di.stride, env); loc = fe->alloc_val(result->type(), result, offset); } result = fe->alloc_val(di.result_type, loc, MemLoadInfo(di)); @@ -788,10 +789,10 @@ Val* Compiler::compile_deref(const goos::Object& form, const goos::Object& _rest loc_type, result, ARRAY_DATA_OFFSET + di.stride * constant_index_value); } else { // the total offset is 12 + stride * idx - auto arr_off = compile_integer(ARRAY_DATA_OFFSET, env)->to_gpr(env); + auto arr_off = compile_integer(ARRAY_DATA_OFFSET, env)->to_gpr(form, env); RegVal* offset = fe->make_gpr(TypeSpec("int")); - compile_constant_product(offset, index_value, di.stride, env); - env->emit_ir(IntegerMathKind::ADD_64, offset, arr_off); + compile_constant_product(form, offset, index_value, di.stride, env); + env->emit_ir(form, IntegerMathKind::ADD_64, offset, arr_off); // create a location to deref (so we can do address-of and get this), with pointer type loc = fe->alloc_val(loc_type, result, offset); @@ -841,7 +842,7 @@ Val* Compiler::compile_addr_of(const goos::Object& form, const goos::Object& res as_reg->force_on_stack(); auto result = env->make_gpr(m_ts.make_pointer_typespec(coerce_to_stack_spill_type(as_reg->type()))); - env->emit_ir(result, as_reg); + env->emit_ir(form, result, as_reg); return result; } @@ -910,7 +911,7 @@ Val* Compiler::compile_the(const goos::Object& form, const goos::Object& rest, E Val* Compiler::compile_print_type(const goos::Object& form, const goos::Object& rest, Env* env) { auto args = get_va(form, rest); va_check(form, args, {{}}, {}); - auto result = compile(args.unnamed.at(0), env)->to_reg(env); + auto result = compile(args.unnamed.at(0), env)->to_reg(form, env); fmt::print("[TYPE] {} {}\n", result->type().print(), result->print()); return result; } @@ -952,17 +953,17 @@ Val* Compiler::compile_heap_new(const goos::Object& form, throw_compiler_error(form, "Cannot make an {} of {}\n", main_type.print(), ts.print()); } - auto malloc_func = compile_get_symbol_value(form, "malloc", env)->to_reg(env); + auto malloc_func = compile_get_symbol_value(form, "malloc", env)->to_reg(form, env); std::vector args; - args.push_back(compile_get_sym_obj(allocation, env)->to_reg(env)); + args.push_back(compile_get_sym_obj(allocation, env)->to_reg(form, env)); if (is_constant_size) { auto array_size = constant_count * info.stride; - args.push_back(compile_integer(array_size, env)->to_reg(env)); + args.push_back(compile_integer(array_size, env)->to_reg(form, env)); } else { - auto array_size = compile_integer(info.stride, env)->to_reg(env); - env->emit(std::make_unique(IntegerMathKind::IMUL_32, array_size, - compile_error_guard(count_obj, env)->to_gpr(env))); + auto array_size = compile_integer(info.stride, env)->to_reg(form, env); + env->emit_ir(form, IntegerMathKind::IMUL_32, array_size, + compile_error_guard(count_obj, env)->to_gpr(form, env)); args.push_back(array_size); } @@ -981,21 +982,21 @@ Val* Compiler::compile_heap_new(const goos::Object& form, } std::vector args; // allocation - args.push_back(compile_get_sym_obj(allocation, env)->to_reg(env)); + args.push_back(compile_get_sym_obj(allocation, env)->to_reg(form, env)); // type - args.push_back(compile_get_symbol_value(form, main_type.base_type(), env)->to_reg(env)); + args.push_back(compile_get_symbol_value(form, main_type.base_type(), env)->to_reg(form, env)); // the other arguments for_each_in_list(*rest, [&](const goos::Object& o) { if (making_boxed_array && !got_content_type) { got_content_type = true; if (o.is_symbol()) { content_type = o.as_symbol()->name; - args.push_back(compile_get_symbol_value(form, content_type, env)->to_reg(env)); + args.push_back(compile_get_symbol_value(form, content_type, env)->to_reg(form, env)); } else { throw_compiler_error(form, "Invalid boxed-array type {}", o.print()); } } else { - args.push_back(compile_error_guard(o, env)->to_reg(env)); + args.push_back(compile_error_guard(o, env)->to_reg(form, env)); } }); @@ -1110,16 +1111,17 @@ Val* Compiler::compile_stack_new(const goos::Object& form, std::vector args; // allocation auto mem = fe->allocate_aligned_stack_variable(type_of_object, ti->get_size_in_memory(), 16) - ->to_gpr(env); + ->to_gpr(form, env); if (call_constructor) { // the new method actual takes a "symbol" according the type system. So we have to cheat it. mem->set_type(TypeSpec("symbol")); args.push_back(mem); // type - args.push_back(compile_get_symbol_value(form, type_of_object.base_type(), env)->to_reg(env)); + args.push_back( + compile_get_symbol_value(form, type_of_object.base_type(), env)->to_reg(form, env)); // the other arguments for_each_in_list(*rest, [&](const goos::Object& o) { - args.push_back(compile_error_guard(o, env)->to_reg(env)); + args.push_back(compile_error_guard(o, env)->to_reg(form, env)); }); auto new_method = compile_get_method_of_type(form, type_of_object, "new", env); @@ -1213,7 +1215,7 @@ Val* Compiler::compile_method_of_type(const goos::Object& form, // that, and do method lookup as if it was a plain object. // this will let you do (method-of-type inspect) and get the inspect // method, with the proper type, from the given type's method table. - auto user_type = compile_error_guard(arg, env)->to_gpr(env); + auto user_type = compile_error_guard(arg, env)->to_gpr(form, env); if (user_type->type() == TypeSpec("type")) { return compile_get_method_of_type(form, TypeSpec("object"), user_type, method_name, env); } @@ -1231,7 +1233,7 @@ Val* Compiler::compile_method_of_object(const goos::Object& form, auto arg = args.unnamed.at(0); auto method_name = symbol_string(args.unnamed.at(1)); - auto obj = compile_error_guard(arg, env)->to_gpr(env); + auto obj = compile_error_guard(arg, env)->to_gpr(form, env); return compile_get_method_of_object(form, obj, method_name, env); } diff --git a/goalc/debugger/DebugInfo.cpp b/goalc/debugger/DebugInfo.cpp index ee38602649..47db9a4bd8 100644 --- a/goalc/debugger/DebugInfo.cpp +++ b/goalc/debugger/DebugInfo.cpp @@ -4,27 +4,30 @@ DebugInfo::DebugInfo(std::string obj_name) : m_obj_name(std::move(obj_name)) {} -std::string FunctionDebugInfo::disassemble_debug_info(bool* had_failure) { +std::string FunctionDebugInfo::disassemble_debug_info(bool* had_failure, + const goos::Reader* reader) { std::string result = fmt::format("[{}]\n", name); - result += disassemble_x86_function(generated_code.data(), generated_code.size(), 0x10000, 0x10000, - instructions, irs, had_failure); + result += disassemble_x86_function(generated_code.data(), generated_code.size(), reader, 0x10000, + 0x10000, instructions, function.get(), had_failure); return result; } -std::string DebugInfo::disassemble_all_functions(bool* had_failure) { +std::string DebugInfo::disassemble_all_functions(bool* had_failure, const goos::Reader* reader) { std::string result; for (auto& kv : m_functions) { - result += kv.second.disassemble_debug_info(had_failure) + "\n\n"; + result += kv.second.disassemble_debug_info(had_failure, reader) + "\n\n"; } return result; } -std::string DebugInfo::disassemble_function_by_name(const std::string& name, bool* had_failure) { +std::string DebugInfo::disassemble_function_by_name(const std::string& name, + bool* had_failure, + const goos::Reader* reader) { std::string result; for (auto& kv : m_functions) { if (kv.second.name == name) { - result += kv.second.disassemble_debug_info(had_failure) + "\n\n"; + result += kv.second.disassemble_debug_info(had_failure, reader) + "\n\n"; } } return result; diff --git a/goalc/debugger/DebugInfo.h b/goalc/debugger/DebugInfo.h index a1d69a3ef4..c1502fa204 100644 --- a/goalc/debugger/DebugInfo.h +++ b/goalc/debugger/DebugInfo.h @@ -3,12 +3,15 @@ #include #include #include +#include #include #include "common/util/assert.h" #include "common/common_types.h" #include "goalc/emitter/Instruction.h" #include "goalc/debugger/disassemble.h" +class FunctionEnv; + /*! * FunctionDebugInfo stores per-function debugging information. * For now, it is pretty basic, but it will eventually contain stuff like stack frame info @@ -21,14 +24,14 @@ struct FunctionDebugInfo { std::string name; std::string obj_name; - std::vector irs; + std::shared_ptr function; std::vector instructions; // contains mapping to IRs // the actual bytes in the object file. std::vector generated_code; std::optional stack_usage; - std::string disassemble_debug_info(bool* had_failure); + std::string disassemble_debug_info(bool* had_failure, const goos::Reader* reader); }; class DebugInfo { @@ -62,8 +65,10 @@ class DebugInfo { void clear() { m_functions.clear(); } - std::string disassemble_all_functions(bool* had_failure); - std::string disassemble_function_by_name(const std::string& name, bool* had_failure); + std::string disassemble_all_functions(bool* had_failure, const goos::Reader* reader); + std::string disassemble_function_by_name(const std::string& name, + bool* had_failure, + const goos::Reader* reader); private: std::string m_obj_name; diff --git a/goalc/debugger/Debugger.cpp b/goalc/debugger/Debugger.cpp index 95c0f2ae2a..41f5256d1e 100644 --- a/goalc/debugger/Debugger.cpp +++ b/goalc/debugger/Debugger.cpp @@ -318,9 +318,9 @@ Disassembly Debugger::disassemble_at_rip(const InstructionPointerInfo& info) { info.map_entry->seg_id, info.map_entry->obj_name, obj_offset, info.function_offset); result.text += disassemble_x86_function( - function_mem.data(), function_mem.size(), + function_mem.data(), function_mem.size(), m_reader, m_debug_context.base + info.map_entry->start_addr + func_info->offset_in_seg, - rip + rip_offset, func_info->instructions, func_info->irs, &result.failed); + rip + rip_offset, func_info->instructions, func_info->function.get(), &result.failed); } } else { result.failed = true; diff --git a/goalc/debugger/Debugger.h b/goalc/debugger/Debugger.h index 169b56ac3c..df90759711 100644 --- a/goalc/debugger/Debugger.h +++ b/goalc/debugger/Debugger.h @@ -58,7 +58,8 @@ struct BacktraceFrame { class Debugger { public: - explicit Debugger(listener::Listener* listener) : m_listener(listener) {} + explicit Debugger(listener::Listener* listener, const goos::Reader* reader) + : m_listener(listener), m_reader(reader) {} ~Debugger(); bool is_halted() const; bool is_valid() const; @@ -206,6 +207,7 @@ class Debugger { InstructionPointerInfo m_break_info; listener::Listener* m_listener = nullptr; + const goos::Reader* m_reader = nullptr; listener::MemoryMap m_memory_map; std::unordered_map m_debug_info; }; diff --git a/goalc/debugger/disassemble.cpp b/goalc/debugger/disassemble.cpp index b3607a07fe..1aabe68241 100644 --- a/goalc/debugger/disassemble.cpp +++ b/goalc/debugger/disassemble.cpp @@ -1,6 +1,10 @@ #include "disassemble.h" #include "Zydis/Zydis.h" #include "third-party/fmt/core.h" +#include "goalc/compiler/Env.h" +#include "goalc/compiler/IR.h" +#include "common/goos/Reader.h" +#include "third-party/fmt/color.h" std::string disassemble_x86(u8* data, int len, u64 base_addr) { std::string result; @@ -60,10 +64,11 @@ std::string disassemble_x86(u8* data, int len, u64 base_addr, u64 highlight_addr std::string disassemble_x86_function(u8* data, int len, + const goos::Reader* reader, u64 base_addr, u64 highlight_addr, const std::vector& x86_instructions, - const std::vector& irs, + const FunctionEnv* fenv, bool* had_failure) { std::string result; ZydisDecoder decoder; @@ -72,6 +77,8 @@ std::string disassemble_x86_function(u8* data, ZydisFormatterInit(&formatter, ZYDIS_FORMATTER_STYLE_INTEL); ZydisDecodedInstruction instr; + const auto& irs = fenv->code(); + constexpr int print_buff_size = 512; char print_buff[print_buff_size]; int offset = 0; @@ -79,6 +86,10 @@ std::string disassemble_x86_function(u8* data, int current_instruction_idx = -1; int current_ir_idx = -1; + std::string current_filename; + int current_file_line = -1; + int current_offset_in_line = -1; + assert(highlight_addr >= base_addr); int mark_offset = int(highlight_addr - base_addr); while (offset < len) { @@ -119,6 +130,25 @@ std::string disassemble_x86_function(u8* data, } } + if (current_ir_idx >= 0 && current_ir_idx < int(irs.size())) { + auto source = reader->db.try_get_short_info(fenv->code_source().at(current_ir_idx)); + if (source) { + if (source->filename != current_filename || + source->line_idx_to_display != current_file_line || + source->pos_in_line != current_offset_in_line) { + current_filename = source->filename; + current_file_line = source->line_idx_to_display; + current_offset_in_line = source->pos_in_line; + result += + fmt::format(fmt::emphasis::bold, "\n{}:{}\n", current_filename, current_file_line); + result += fmt::format(fg(fmt::color::orange), "-> {}\n", source->line_text); + std::string pointer(current_offset_in_line + 3, ' '); + pointer += "^\n"; + result += fmt::format(fmt::emphasis::bold | fg(fmt::color::lime_green), "{}", pointer); + } + } + } + std::string line; line += fmt::format("{:c} [0x{:X}] ", prefix, base_addr); @@ -130,7 +160,7 @@ std::string disassemble_x86_function(u8* data, line.append(50 - line.size(), ' '); } line += " "; - line += irs.at(current_ir_idx); + line += irs.at(current_ir_idx)->print(); } if (warn_messed_up) { diff --git a/goalc/debugger/disassemble.h b/goalc/debugger/disassemble.h index d03c5a81b8..ebbffbbf91 100644 --- a/goalc/debugger/disassemble.h +++ b/goalc/debugger/disassemble.h @@ -5,6 +5,12 @@ #include "common/common_types.h" #include "goalc/emitter/Instruction.h" +class FunctionEnv; + +namespace goos { +class Reader; +} + struct InstructionInfo { emitter::Instruction instruction; //! the actual x86 instruction enum class Kind { PROLOGUE, IR, EPILOGUE } kind; @@ -23,8 +29,9 @@ std::string disassemble_x86(u8* data, int len, u64 base_addr, u64 highlight_addr std::string disassemble_x86_function(u8* data, int len, + const goos::Reader* reader, u64 base_addr, u64 highlight_addr, const std::vector& x86_instructions, - const std::vector& irs, + const FunctionEnv* fenv, bool* had_failure); \ No newline at end of file diff --git a/goalc/emitter/ObjectGenerator.cpp b/goalc/emitter/ObjectGenerator.cpp index 3133345cda..4bb2a83198 100644 --- a/goalc/emitter/ObjectGenerator.cpp +++ b/goalc/emitter/ObjectGenerator.cpp @@ -143,15 +143,13 @@ FunctionRecord ObjectGenerator::get_existing_function_record(int f_idx) { * actual Instructions. These Instructions can be added with add_instruction. The IR_Record * can be used as a label for jump targets. */ -IR_Record ObjectGenerator::add_ir(const FunctionRecord& func, const std::string& debug_print) { +IR_Record ObjectGenerator::add_ir(const FunctionRecord& func) { IR_Record rec; rec.seg = func.seg; rec.func_id = func.func_id; auto& func_data = m_function_data_by_seg.at(rec.seg).at(rec.func_id); rec.ir_id = int(func_data.ir_to_instruction.size()); func_data.ir_to_instruction.push_back(int(func_data.instructions.size())); - assert(int(func.debug->irs.size()) == rec.ir_id); - func.debug->irs.push_back(debug_print); return rec; } diff --git a/goalc/emitter/ObjectGenerator.h b/goalc/emitter/ObjectGenerator.h index 819e1dc7de..e9d03f596f 100644 --- a/goalc/emitter/ObjectGenerator.h +++ b/goalc/emitter/ObjectGenerator.h @@ -66,7 +66,7 @@ class ObjectGenerator { FunctionDebugInfo* debug, int min_align = 16); // should align and insert function tag FunctionRecord get_existing_function_record(int f_idx); - IR_Record add_ir(const FunctionRecord& func, const std::string& debug_print); + IR_Record add_ir(const FunctionRecord& func); IR_Record get_future_ir_record(const FunctionRecord& func, int ir_id); IR_Record get_future_ir_record_in_same_func(const IR_Record& irec, int ir_id); InstructionRecord add_instr(Instruction inst, IR_Record ir); diff --git a/test/goalc/test_with_game.cpp b/test/goalc/test_with_game.cpp index 90cecd70fa..29d7aa4ea2 100644 --- a/test/goalc/test_with_game.cpp +++ b/test/goalc/test_with_game.cpp @@ -354,7 +354,7 @@ TEST_F(WithGameTests, DebuggerMemoryMap) { TEST_F(WithGameTests, DebuggerDisassemble) { auto di = shared_compiler->compiler.get_debugger().get_debug_info_for_object("gcommon"); bool fail = false; - auto result = di.disassemble_all_functions(&fail); + auto result = di.disassemble_all_functions(&fail, &shared_compiler->compiler.get_goos().reader); // printf("Got\n%s\n", result.c_str()); EXPECT_FALSE(fail); } diff --git a/test/test_emitter.cpp b/test/test_emitter.cpp index fe816078d2..ac335512df 100644 --- a/test/test_emitter.cpp +++ b/test/test_emitter.cpp @@ -3898,4 +3898,4 @@ TEST(EmitterXMM, SqrtS) { 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 +}