[goalc] Address-to-line (#783)

* refactor debug info stuff before adding form to emit

* source mapping working for non-macro sourced forms

* support macros
This commit is contained in:
water111
2021-08-26 20:33:00 -04:00
committed by GitHub
parent 7a5562106e
commit 24fe2c78c0
32 changed files with 772 additions and 677 deletions
+66 -24
View File
@@ -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<int, int> 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<int, int> 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<SourceText>& frag) {
fragments.push_back(frag);
m_fragments.push_back(frag);
}
/*!
@@ -108,7 +108,7 @@ void TextDb::link(const Object& o, std::shared_ptr<SourceText> 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<SourceText> 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<SourceText>& frag, int of
return result + pointer;
}
std::optional<TextDb::ShortInfo> 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<SourceText>& 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<const Object*> 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);
}
+16 -6
View File
@@ -18,6 +18,7 @@
#include <stdexcept>
#include <unordered_map>
#include <memory>
#include <optional>
#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<int> offset_by_line;
std::string m_text;
std::vector<int> m_offset_by_line;
std::pair<int, int> 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<SourceText>& frag);
void link(const Object& o, std::shared_ptr<SourceText> 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<SourceText>& frag, int offset) const;
std::optional<ShortInfo> 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<std::shared_ptr<SourceText>> fragments;
std::unordered_map<std::shared_ptr<goos::HeapObject>, TextRef> map;
std::vector<std::shared_ptr<SourceText>> m_fragments;
std::unordered_map<std::shared_ptr<goos::HeapObject>, TextRef> m_map;
};
} // namespace goos
+11 -7
View File
@@ -32,7 +32,9 @@ std::vector<u8> 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<u8> 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<FunctionEnv>& 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<FunctionEnv>& 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<FunctionEnv>& 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()) {
+3 -3
View File
@@ -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<FunctionEnv>& env, int f_idx);
void do_goal_function(const std::shared_ptr<FunctionEnv>& env, int f_idx);
void do_asm_function(const std::shared_ptr<FunctionEnv>& env, int f_idx, bool allow_saved_regs);
emitter::ObjectGenerator m_gen;
FileEnv* m_fe = nullptr;
DebugInfo* m_debug_info = nullptr;
+11 -10
View File
@@ -12,7 +12,7 @@
using namespace goos;
Compiler::Compiler(std::unique_ptr<ReplWrapper> 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<GlobalEnv>();
@@ -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<FunctionEnv> Compiler::compile_top_level_function(const std::string& name,
const goos::Object& code,
Env* env) {
auto fe = std::make_unique<FunctionEnv>(env, name);
auto fe = std::make_unique<FunctionEnv>(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<const None*>(result)) {
fe->emit(std::make_unique<IR_Return>(fe->make_gpr(result->type()), result->to_gpr(fe.get()),
emitter::gRegInfo.get_gpr_ret_reg()));
fe->emit_ir<IR_Return>(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<IR_Null>();
fe->emit_ir<IR_Null>(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<u8> 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;
}
+8 -3
View File
@@ -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<std::string, TypeSpec> m_symbol_types;
std::unordered_map<goos::HeapObject*, goos::Object> m_global_constants;
std::unordered_map<goos::HeapObject*, LambdaVal*> 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<std::pair<std::string, RegVal*>> args);
+35 -45
View File
@@ -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> 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<std::string, Label>& Env::get_label_map() {
return parent()->get_label_map();
}
void Env::emit(const goos::Object& form, std::unique_ptr<IR> 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> 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> 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<FunctionEnv> 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<NoEmitEnv>(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> ir) {
void FunctionEnv::emit(const goos::Object& form, std::unique_ptr<IR> 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();
}
+12 -23
View File
@@ -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> ir);
void emit(const goos::Object& form, std::unique_ptr<IR> 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 <typename IR_Type, typename... Args>
void emit_ir(Args&&... args) {
emit(std::make_unique<IR_Type>(std::forward<Args>(args)...));
void emit_ir(const goos::Object& form, Args&&... args) {
emit(form, std::make_unique<IR_Type>(std::forward<Args>(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> 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<std::unique_ptr<FileEnv>> 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> 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<FunctionEnv> fe);
void add_top_level_function(std::unique_ptr<FunctionEnv> fe);
void add_static(std::unique_ptr<StaticObject> s);
NoEmitEnv* add_no_emit_env();
void debug_print_tl();
const std::vector<std::unique_ptr<FunctionEnv>>& functions() { return m_functions; }
const std::vector<std::shared_ptr<FunctionEnv>>& functions() { return m_functions; }
const std::vector<std::unique_ptr<StaticObject>>& 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<std::unique_ptr<FunctionEnv>> m_functions;
std::vector<std::shared_ptr<FunctionEnv>> m_functions;
std::vector<std::unique_ptr<StaticObject>> m_statics;
std::unique_ptr<NoEmitEnv> m_no_emit_env = nullptr;
int m_anon_func_counter = 0;
std::vector<std::unique_ptr<Val>> 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<std::string, Label>& get_label_map() override;
void set_segment(int seg) { segment = seg; }
void emit(std::unique_ptr<IR> ir) override;
void emit(const goos::Object& form, std::unique_ptr<IR> ir, Env* lowest_env);
void finish();
RegVal* make_ireg(const TypeSpec& ts, RegClass reg_class) override;
const std::vector<std::unique_ptr<IR>>& code() const { return m_code; }
const std::vector<goos::Object>& code_source() const { return m_code_debug_source; }
int max_vars() const { return m_iregs.size(); }
const std::vector<IRegConstraint>& constraints() { return m_constraints; }
void constrain(const IRegConstraint& c) { m_constraints.push_back(c); }
@@ -239,17 +225,20 @@ class FunctionEnv : public DeclareEnv {
void resolve_gotos();
std::string m_name;
std::vector<std::unique_ptr<IR>> m_code;
std::vector<goos::Object> m_code_debug_source;
std::vector<std::unique_ptr<RegVal>> m_iregs;
std::vector<std::unique_ptr<Val>> m_vals;
std::vector<std::unique_ptr<Env>> m_envs;
std::vector<IRegConstraint> 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<std::string, Label> m_labels;
std::vector<std::unique_ptr<Label>> m_unnamed_labels;
const goos::Reader* m_reader = nullptr;
};
class BlockEnv : public Env {
+10 -6
View File
@@ -278,25 +278,29 @@ std::vector<goos::Object> 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<IR_RegSet>(dest, src);
env->emit_ir<IR_RegSet>(form, dest, src);
} else if (is_power_of_two) {
for (int i = 0; i < 16; i++) {
if (stride == (1 << i)) {
env->emit_ir<IR_RegSet>(dest, src);
env->emit_ir<IR_IntegerMath>(IntegerMathKind::SHL_64, dest, i);
env->emit_ir<IR_RegSet>(form, dest, src);
env->emit_ir<IR_IntegerMath>(form, IntegerMathKind::SHL_64, dest, i);
return;
}
}
assert(false);
} else {
// get the multiplier
env->emit_ir<IR_LoadConstant64>(dest, stride);
env->emit_ir<IR_IntegerMath>(IntegerMathKind::IMUL_32, dest, src);
env->emit_ir<IR_LoadConstant64>(form, dest, stride);
env->emit_ir<IR_IntegerMath>(form, IntegerMathKind::IMUL_32, dest, src);
}
}
+71 -66
View File
@@ -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<IR_RegSet>(re, rv));
fe->emit(form, std::make_unique<IR_RegSet>(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<IR_RegSet>(re, rv));
fe->emit(form, std::make_unique<IR_RegSet>(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<IR_RegSet>(re, rv));
fe->emit(form, std::make_unique<IR_RegSet>(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<IR_RegSet>(re, this));
fe->emit(form, std::make_unique<IR_RegSet>(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<IR_RegSet>(re, this));
fe->emit(form, std::make_unique<IR_RegSet>(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<IR_RegSet>(re, this));
fe->emit(form, std::make_unique<IR_RegSet>(re, this));
return re;
}
}
@@ -88,59 +88,59 @@ const std::optional<emitter::Register>& 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<IR_LoadConstant64>(rv, m_value.value_64()));
fe->emit(form, std::make_unique<IR_LoadConstant64>(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<IR_LoadConstant64>(gpr, m_value.value_128_lo());
fe->emit_ir<IR_RegSet>(xmm_temp, gpr);
fe->emit_ir<IR_LoadConstant64>(gpr, m_value.value_128_hi());
fe->emit_ir<IR_RegSet>(rv, gpr);
fe->emit_ir<IR_Int128Math3Asm>(true, rv, rv, xmm_temp, IR_Int128Math3Asm::Kind::PCPYLD);
fe->emit_ir<IR_LoadConstant64>(form, gpr, m_value.value_128_lo());
fe->emit_ir<IR_RegSet>(form, xmm_temp, gpr);
fe->emit_ir<IR_LoadConstant64>(form, gpr, m_value.value_128_hi());
fe->emit_ir<IR_RegSet>(form, rv, gpr);
fe->emit_ir<IR_Int128Math3Asm>(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<IR_LoadSymbolPointer>(re, m_name));
fe->emit(form, std::make_unique<IR_LoadSymbolPointer>(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<IR_GetSymbolValue>(re, m_sym, m_sext));
fe->emit(form, std::make_unique<IR_GetSymbolValue>(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<IR_StaticVarAddr>(re, obj));
fe->emit(form, std::make_unique<IR_StaticVarAddr>(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<IR_FunctionAddr>(re, func));
fe->emit(form, std::make_unique<IR_FunctionAddr>(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<IR_StaticVarLoad>(re, m_value));
fe->emit(form, std::make_unique<IR_StaticVarLoad>(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<IR_RegSet>(re, final_base->to_gpr(fe));
fe->emit_ir<IR_RegSet>(form, re, final_base->to_gpr(form, fe));
} else {
fe->emit(std::make_unique<IR_LoadConstant64>(re, int64_t(final_offset)));
fe->emit(std::make_unique<IR_IntegerMath>(IntegerMathKind::ADD_64, re, final_base->to_gpr(fe)));
fe->emit(form, std::make_unique<IR_LoadConstant64>(re, int64_t(final_offset)));
fe->emit(form, std::make_unique<IR_IntegerMath>(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<IR_RegSet>(re, offset->to_gpr(fe)));
fe->emit(std::make_unique<IR_IntegerMath>(IntegerMathKind::ADD_64, re, base->to_gpr(fe)));
fe->emit(form, std::make_unique<IR_RegSet>(re, offset->to_gpr(form, fe)));
fe->emit(form,
std::make_unique<IR_IntegerMath>(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<MemoryOffsetConstantVal*>(base);
if (base_as_co) {
s64 offset;
auto final_base = get_constant_offset_and_base(base_as_co, &offset);
fe->emit_ir<IR_LoadConstOffset>(re, (int)offset, final_base->to_gpr(fe), info);
fe->emit_ir<IR_LoadConstOffset>(form, re, (int)offset, final_base->to_gpr(form, fe), info);
} else {
auto addr = base->to_gpr(fe);
fe->emit(std::make_unique<IR_LoadConstOffset>(re, 0, addr, info));
auto addr = base->to_gpr(form, fe);
fe->emit(form, std::make_unique<IR_LoadConstOffset>(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<MemoryOffsetConstantVal*>(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<IR_LoadConstOffset>(re, offset, final_base->to_gpr(fe), info);
fe->emit_ir<IR_LoadConstOffset>(form, re, offset, final_base->to_gpr(form, fe), info);
} else {
auto addr = base->to_gpr(fe);
fe->emit(std::make_unique<IR_LoadConstOffset>(re, 0, addr, info));
auto addr = base->to_gpr(form, fe);
fe->emit(form, std::make_unique<IR_LoadConstOffset>(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<IR_RegSet>(result, as_old_type));
fe->emit(form, std::make_unique<IR_RegSet>(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<IR_LoadConstOffset>(re, offset, base->to_gpr(fe), info));
fe->emit(form, std::make_unique<IR_LoadConstOffset>(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<IR_GetStackAddr>(re, m_slot));
fe->emit(form, std::make_unique<IR_GetStackAddr>(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<IR_RegSet>(result, gpr));
RegVal* gpr = m_parent->to_gpr(form, env);
env->emit(form, std::make_unique<IR_RegSet>(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<IR_Int128Math3Asm>(true, xmm_temp, xmm, xmm, IR_Int128Math3Asm::Kind::PCPYUD);
env->emit_ir<IR_RegSet>(result, xmm_temp);
env->emit_ir<IR_Int128Math3Asm>(form, true, xmm_temp, xmm, xmm,
IR_Int128Math3Asm::Kind::PCPYUD);
env->emit_ir<IR_RegSet>(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<IR_IntegerMath>(IntegerMathKind::SHL_64, result, epad));
env->emit(form, std::make_unique<IR_IntegerMath>(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<IR_IntegerMath>(IntegerMathKind::SAR_64, result, next_shift));
env->emit(form,
std::make_unique<IR_IntegerMath>(IntegerMathKind::SAR_64, result, next_shift));
} else {
env->emit(std::make_unique<IR_IntegerMath>(IntegerMathKind::SHR_64, result, next_shift));
env->emit(form,
std::make_unique<IR_IntegerMath>(IntegerMathKind::SHR_64, result, next_shift));
}
}
+23 -23
View File
@@ -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<emitter::Register>& 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; }
+131 -130
View File
@@ -123,7 +123,7 @@ Val* Compiler::compile_rlet(const goos::Object& form, const goos::Object& rest,
});
if (!reset_regs.empty()) {
lenv->emit_ir<IR_ValueReset>(reset_regs);
lenv->emit_ir<IR_ValueReset>(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<None*>(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<IR_AsmRet>(color);
env->emit_ir<IR_AsmRet>(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<IR_AsmPop>(color, pop_dest);
env->emit_ir<IR_AsmPop>(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<IR_AsmPush>(color, compile_error_guard(args.unnamed.at(0), env)->to_gpr(env));
env->emit_ir<IR_AsmPush>(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<IR_AsmSub>(color, dest, src);
auto src = compile_error_guard(args.unnamed.at(1), env)->to_gpr(form, env);
env->emit_ir<IR_AsmSub>(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<IR_AsmAdd>(color, dest, src);
auto src = compile_error_guard(args.unnamed.at(1), env)->to_gpr(form, env);
env->emit_ir<IR_AsmAdd>(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<IR_GetSymbolValueAsm>(color, dest, sym_name, sext);
env->emit_ir<IR_GetSymbolValueAsm>(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<IR_JumpReg>(color, src);
auto src = compile_error_guard(args.unnamed.at(0), env)->to_gpr(form, env);
env->emit_ir<IR_JumpReg>(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<IR_RegSetAsm>(color, dest, src);
auto src = compile_error_guard(args.unnamed.at(1), env)->to_reg(form, env);
env->emit_ir<IR_RegSetAsm>(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<IR_AsmFNop>();
env->emit_ir<IR_AsmFNop>(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<IR_AsmFWait>();
env->emit_ir<IR_AsmFWait>(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<IR_StaticVarLoad>(dest, as_sv->obj);
env->emit_ir<IR_StaticVarLoad>(form, dest, as_sv->obj);
return get_none();
}
auto as_co = dynamic_cast<MemoryOffsetConstantVal*>(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<IR_LoadConstOffset>(dest, offset, baseReg, info, color);
env->emit_ir<IR_LoadConstOffset>(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<MemoryOffsetConstantVal*>(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<IR_StoreConstOffset>(src, offset, baseReg, info.size, color);
env->emit_ir<IR_StoreConstOffset>(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<IR_BlendVF>(color, dest, dest, src, mask);
env->emit_ir<IR_BlendVF>(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<IR_BlendVF>(color, dest, src1, src2, mask);
env->emit_ir<IR_BlendVF>(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<IR_SplatVF>(color, temp_reg, src2, broadcastElement);
env->emit_ir<IR_SplatVF>(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<IR_VFMath3Asm>(color, dest, src1, temp_reg, kind);
env->emit_ir<IR_VFMath3Asm>(form, color, dest, src1, temp_reg, kind);
} else {
// Perform the arithmetic operation on the two vectors into a temporary register
env->emit_ir<IR_VFMath3Asm>(color, temp_reg, src1, temp_reg, kind);
env->emit_ir<IR_VFMath3Asm>(form, color, temp_reg, src1, temp_reg, kind);
// Blend the result back into the destination register using the mask
env->emit_ir<IR_BlendVF>(color, dest, dest, temp_reg, mask);
env->emit_ir<IR_BlendVF>(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<IR_VFMath3Asm>(color, dest, src1, src2, kind);
env->emit_ir<IR_VFMath3Asm>(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<IR_VFMath3Asm>(color, temp_reg, src1, src2, kind);
env->emit_ir<IR_VFMath3Asm>(form, color, temp_reg, src1, src2, kind);
// Blend the result back into the destination register using the mask
env->emit_ir<IR_BlendVF>(color, dest, dest, temp_reg, mask);
env->emit_ir<IR_BlendVF>(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<IR_Int128Math3Asm>(color, dest, src1, src2, kind);
env->emit_ir<IR_Int128Math3Asm>(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<IR_VFMath2Asm>(color, dest, src, kind);
env->emit_ir<IR_VFMath2Asm>(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<IR_VFMath2Asm>(color, temp_reg, src, kind);
env->emit_ir<IR_VFMath2Asm>(form, color, temp_reg, src, kind);
// Blend the result back into the destination register using the mask
env->emit_ir<IR_BlendVF>(color, dest, dest, temp_reg, mask);
env->emit_ir<IR_BlendVF>(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<IR_Int128Math2Asm>(color, dest, src, kind, imm);
env->emit_ir<IR_Int128Math2Asm>(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<IR_Int128Math2Asm>(color, temp_reg, src, kind, imm);
env->emit_ir<IR_Int128Math2Asm>(form, color, temp_reg, src, kind, imm);
// Blend the result back into the destination register using the mask
env->emit_ir<IR_BlendVF>(color, dest, dest, temp_reg, mask);
env->emit_ir<IR_BlendVF>(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<IR_Int128Math3Asm>(true, temp, temp, temp, IR_Int128Math3Asm::Kind::PCEQW);
env->emit_ir<IR_Int128Math3Asm>(form, true, temp, temp, temp, IR_Int128Math3Asm::Kind::PCEQW);
// Then NOT the first input, store in destination
env->emit_ir<IR_Int128Math3Asm>(true, dest, temp, src1, IR_Int128Math3Asm::Kind::PXOR);
env->emit_ir<IR_Int128Math3Asm>(form, true, dest, temp, src1, IR_Int128Math3Asm::Kind::PXOR);
// NOT the second input, we not longer require the all-ones-register
env->emit_ir<IR_Int128Math3Asm>(true, temp, temp, src2, IR_Int128Math3Asm::Kind::PXOR);
env->emit_ir<IR_Int128Math3Asm>(form, true, temp, temp, src2, IR_Int128Math3Asm::Kind::PXOR);
// Preform the AND aka NOR
env->emit_ir<IR_Int128Math3Asm>(true, dest, dest, temp, IR_Int128Math3Asm::Kind::PAND);
env->emit_ir<IR_Int128Math3Asm>(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<IR_Int128Math2Asm>(true, temp, src1, IR_Int128Math2Asm::Kind::VPSHUFLW, 0x88);
env->emit_ir<IR_Int128Math2Asm>(true, dest, src2, IR_Int128Math2Asm::Kind::VPSHUFLW, 0x88);
env->emit_ir<IR_Int128Math2Asm>(true, temp, temp, IR_Int128Math2Asm::Kind::VPSHUFHW, 0x88);
env->emit_ir<IR_Int128Math2Asm>(true, dest, dest, IR_Int128Math2Asm::Kind::VPSHUFHW, 0x88);
env->emit_ir<IR_Int128Math2Asm>(true, temp, temp, IR_Int128Math2Asm::Kind::VPSRLDQ, 4);
env->emit_ir<IR_Int128Math2Asm>(true, dest, dest, IR_Int128Math2Asm::Kind::VPSRLDQ, 4);
env->emit_ir<IR_Int128Math2Asm>(form, true, temp, src1, IR_Int128Math2Asm::Kind::VPSHUFLW, 0x88);
env->emit_ir<IR_Int128Math2Asm>(form, true, dest, src2, IR_Int128Math2Asm::Kind::VPSHUFLW, 0x88);
env->emit_ir<IR_Int128Math2Asm>(form, true, temp, temp, IR_Int128Math2Asm::Kind::VPSHUFHW, 0x88);
env->emit_ir<IR_Int128Math2Asm>(form, true, dest, dest, IR_Int128Math2Asm::Kind::VPSHUFHW, 0x88);
env->emit_ir<IR_Int128Math2Asm>(form, true, temp, temp, IR_Int128Math2Asm::Kind::VPSRLDQ, 4);
env->emit_ir<IR_Int128Math2Asm>(form, true, dest, dest, IR_Int128Math2Asm::Kind::VPSRLDQ, 4);
// is actually a VPUNPCKLQDQ with srcs swapped.
env->emit_ir<IR_Int128Math3Asm>(true, dest, temp, dest, IR_Int128Math3Asm::Kind::PCPYLD);
env->emit_ir<IR_Int128Math3Asm>(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<IR_VFMath3Asm>(true, dest, src1, src2, IR_VFMath3Asm::Kind::XOR);
env->emit_ir<IR_VFMath3Asm>(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<IR_SplatVF>(color, temp_reg, src2, broadcastElement);
env->emit_ir<IR_SplatVF>(form, color, temp_reg, src2, broadcastElement);
// Perform the first operation
env->emit_ir<IR_VFMath3Asm>(color, temp_reg, src1, temp_reg, first_op_kind);
env->emit_ir<IR_VFMath3Asm>(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<IR_VFMath3Asm>(color, dest, src3, temp_reg, second_op_kind);
env->emit_ir<IR_VFMath3Asm>(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<IR_VFMath3Asm>(color, temp_reg, src3, temp_reg, second_op_kind);
env->emit_ir<IR_VFMath3Asm>(form, color, temp_reg, src3, temp_reg, second_op_kind);
// Blend the result back into the destination register using the mask
env->emit_ir<IR_BlendVF>(color, dest, dest, temp_reg, mask);
env->emit_ir<IR_BlendVF>(form, color, dest, dest, temp_reg, mask);
}
} else {
// Perform the first operation
env->emit_ir<IR_VFMath3Asm>(color, temp_reg, src1, src2, first_op_kind);
env->emit_ir<IR_VFMath3Asm>(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<IR_VFMath3Asm>(color, dest, src3, temp_reg, second_op_kind);
env->emit_ir<IR_VFMath3Asm>(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<IR_VFMath3Asm>(color, temp_reg, src3, temp_reg, second_op_kind);
env->emit_ir<IR_VFMath3Asm>(form, color, temp_reg, src3, temp_reg, second_op_kind);
// Blend the result back into the destination register using the mask
env->emit_ir<IR_BlendVF>(color, dest, dest, temp_reg, mask);
env->emit_ir<IR_BlendVF>(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<IR_VFMath3Asm>(color, temp_reg, temp_reg, temp_reg, IR_VFMath3Asm::Kind::XOR);
env->emit_ir<IR_VFMath3Asm>(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<IR_VFMath3Asm>(color, temp_reg, temp_reg, src, IR_VFMath3Asm::Kind::SUB);
env->emit_ir<IR_VFMath3Asm>(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<IR_VFMath3Asm>(color, dest, src, temp_reg, IR_VFMath3Asm::Kind::MAX);
env->emit_ir<IR_VFMath3Asm>(form, color, dest, src, temp_reg, IR_VFMath3Asm::Kind::MAX);
} else {
env->emit_ir<IR_VFMath3Asm>(color, temp_reg, src, temp_reg, IR_VFMath3Asm::Kind::MAX);
env->emit_ir<IR_VFMath3Asm>(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<IR_BlendVF>(color, dest, dest, temp_reg, mask);
env->emit_ir<IR_BlendVF>(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<IR_SplatVF>(color, dest, src1, ftf_fsf_to_vector_element(fsf));
env->emit_ir<IR_SplatVF>(form, color, dest, src1, ftf_fsf_to_vector_element(fsf));
// Splat src1's value into the the temp reg
env->emit_ir<IR_SplatVF>(color, temp_reg, src2, ftf_fsf_to_vector_element(ftf));
env->emit_ir<IR_SplatVF>(form, color, temp_reg, src2, ftf_fsf_to_vector_element(ftf));
// Perform the Division
env->emit_ir<IR_VFMath3Asm>(color, dest, dest, temp_reg, IR_VFMath3Asm::Kind::DIV);
env->emit_ir<IR_VFMath3Asm>(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<IR_SplatVF>(color, dest, src, ftf_fsf_to_vector_element(ftf));
env->emit_ir<IR_SplatVF>(form, color, dest, src, ftf_fsf_to_vector_element(ftf));
env->emit_ir<IR_SqrtVF>(color, dest, dest);
env->emit_ir<IR_SqrtVF>(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<IR_SplatVF>(color, dest, src1, ftf_fsf_to_vector_element(fsf));
env->emit_ir<IR_SplatVF>(form, color, dest, src1, ftf_fsf_to_vector_element(fsf));
// Splat src1's value into the the temp reg
env->emit_ir<IR_SplatVF>(color, temp_reg, src2, ftf_fsf_to_vector_element(ftf));
env->emit_ir<IR_SplatVF>(form, color, temp_reg, src2, ftf_fsf_to_vector_element(ftf));
// Square Root the temp reg
env->emit_ir<IR_SqrtVF>(color, temp_reg, temp_reg);
env->emit_ir<IR_SqrtVF>(form, color, temp_reg, temp_reg);
// Perform the Division
env->emit_ir<IR_VFMath3Asm>(color, dest, dest, temp_reg, IR_VFMath3Asm::Kind::DIV);
env->emit_ir<IR_VFMath3Asm>(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<IR_SwizzleVF>(color, temp1, src1, 0b00001001);
env->emit_ir<IR_SwizzleVF>(form, color, temp1, src1, 0b00001001);
// - Move it into 'dest' safely (avoid mutating `w`)
env->emit_ir<IR_BlendVF>(color, temp_dst, temp_dst, temp1, 0b0111);
env->emit_ir<IR_BlendVF>(form, color, temp_dst, temp_dst, temp1, 0b0111);
// - Swizzle src2 appropriately
env->emit_ir<IR_SwizzleVF>(color, temp1, src2, 0b00010010);
env->emit_ir<IR_SwizzleVF>(form, color, temp1, src2, 0b00010010);
// - Multiply - Result in `dest`
env->emit_ir<IR_VFMath3Asm>(color, temp1, temp_dst, temp1, IR_VFMath3Asm::Kind::MUL);
env->emit_ir<IR_VFMath3Asm>(form, color, temp1, temp_dst, temp1, IR_VFMath3Asm::Kind::MUL);
// - Move it into 'dest' safely (avoid mutating `w`)
env->emit_ir<IR_BlendVF>(color, temp_dst, temp_dst, temp1, 0b0111);
env->emit_ir<IR_BlendVF>(form, color, temp_dst, temp_dst, temp1, 0b0111);
// Second Portion
// - Swizzle src2 appropriately
env->emit_ir<IR_SwizzleVF>(color, temp1, src2, 0b00001001);
env->emit_ir<IR_SwizzleVF>(form, color, temp1, src2, 0b00001001);
// - Swizzle src1 appropriately
env->emit_ir<IR_SwizzleVF>(color, temp2, src1, 0b00010010);
env->emit_ir<IR_SwizzleVF>(form, color, temp2, src1, 0b00010010);
// - Multiply - Result in `temp1`
env->emit_ir<IR_VFMath3Asm>(color, temp1, temp1, temp2, IR_VFMath3Asm::Kind::MUL);
env->emit_ir<IR_VFMath3Asm>(form, color, temp1, temp1, temp2, IR_VFMath3Asm::Kind::MUL);
// Finalize
// - Subtract
env->emit_ir<IR_VFMath3Asm>(color, temp2, temp_dst, temp1, IR_VFMath3Asm::Kind::SUB);
env->emit_ir<IR_VFMath3Asm>(form, color, temp2, temp_dst, temp1, IR_VFMath3Asm::Kind::SUB);
// - Blend result, as to avoid not modifying dest's `w` component
env->emit_ir<IR_BlendVF>(color, dest, dest, temp2, 0b0111);
env->emit_ir<IR_BlendVF>(form, color, dest, dest, temp2, 0b0111);
return get_none();
}
+4 -4
View File
@@ -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<IR_RegSet>(result, first));
env->emit_ir<IR_RegSet>(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<IR_IntegerMath>(IntegerMathKind::ADD_64, result, second));
env->emit_ir<IR_IntegerMath>(form, IntegerMathKind::ADD_64, result, second);
}
return result;
+10 -9
View File
@@ -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<None*>(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<None*>(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<None*>(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<IR_RegSet>(block_env->return_value, result->to_gpr(fe));
auto ir_move_rv =
std::make_unique<IR_RegSet>(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<IR_RegSet>(block->return_value, result->to_gpr(fe));
auto ir_move_rv = std::make_unique<IR_RegSet>(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<IR_GotoLabel>(&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<IR_Nop>();
env->emit_ir<IR_Nop>(form);
return get_none();
}
+22 -22
View File
@@ -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<IR_ConditionalBranch>(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<IR_RegSet>(
result, compile_get_sym_obj("#t", env)->to_gpr(env))); // todo, can be optimized
env->emit(form, std::make_unique<IR_RegSet>(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<IR_ConditionalBranch>(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<None*>(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<IR_RegSet>(result, case_result->to_gpr(env)));
env->emit(o, std::make_unique<IR_RegSet>(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<IR_ConditionalBranch>(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<None*>(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<IR_RegSet>(result, case_result->to_gpr(env)));
env->emit(o, std::make_unique<IR_RegSet>(result, case_result->to_gpr(o, env)));
}
// GO TO END
auto ir_goto_end = std::make_unique<IR_GotoLabel>(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<IR_LoadSymbolPointer>(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<IR_RegSet>(result, temp);
env->emit_ir<IR_RegSet>(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<IR_ConditionalBranch>(gc, Label());
branch_irs.push_back(branch.get());
env->emit(std::move(branch));
env->emit(o, std::move(branch));
}
i++;
});
+34 -33
View File
@@ -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<IR_SetSymbolValue>(sym_val, in_gpr));
env->emit(form, std::make_unique<IR_SetSymbolValue>(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<IR_LoadConstant64>(temp, mask_val));
env->emit_ir<IR_LoadConstant64>(form, temp, mask_val);
// modify the original!
env->emit(std::make_unique<IR_IntegerMath>(IntegerMathKind::AND_64, dst, temp));
env->emit_ir<IR_IntegerMath>(form, IntegerMathKind::AND_64, dst, temp);
// put the source in temp
env->emit(std::make_unique<IR_RegSet>(temp, src));
env->emit_ir<IR_RegSet>(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<IR_IntegerMath>(IntegerMathKind::SHL_64, temp, left_shift_amnt));
env->emit_ir<IR_IntegerMath>(form, IntegerMathKind::SHL_64, temp, left_shift_amnt);
}
if (right_shift_amnt > 0) {
env->emit(std::make_unique<IR_IntegerMath>(IntegerMathKind::SHR_64, temp, right_shift_amnt));
env->emit_ir<IR_IntegerMath>(form, IntegerMathKind::SHR_64, temp, right_shift_amnt);
}
env->emit(std::make_unique<IR_IntegerMath>(IntegerMathKind::OR_64, dst, temp));
env->emit_ir<IR_IntegerMath>(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<IR_RegSet>(original, original_original));
set_bits_in_bitfield(dst->size(), dst->offset(), original, src, fe, env);
env->emit_ir<IR_RegSet>(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<IR_Int128Math3Asm>(true, xmm_temp, original_original, original_original,
env->emit_ir<IR_Int128Math3Asm>(form, true, xmm_temp, original_original, original_original,
IR_Int128Math3Asm::Kind::PCPYUD);
} else {
env->emit_ir<IR_RegSet>(xmm_temp, original_original);
env->emit_ir<IR_RegSet>(form, xmm_temp, original_original);
}
// convert that xmm to a GPR.
RegVal* gpr_64_section = fe->make_gpr(original_original->type());
env->emit_ir<IR_RegSet>(gpr_64_section, xmm_temp);
env->emit_ir<IR_RegSet>(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<IR_RegSet>(xmm_temp, gpr_64_section);
env->emit_ir<IR_RegSet>(form, xmm_temp, gpr_64_section);
// rebuild the xmm
if (get_top) {
env->emit_ir<IR_Int128Math3Asm>(true, xmm_temp, xmm_temp, original_original,
env->emit_ir<IR_Int128Math3Asm>(form, true, xmm_temp, xmm_temp, original_original,
IR_Int128Math3Asm::Kind::PCPYLD);
} else {
env->emit_ir<IR_Int128Math3Asm>(true, xmm_temp, xmm_temp, xmm_temp,
env->emit_ir<IR_Int128Math3Asm>(form, true, xmm_temp, xmm_temp, xmm_temp,
IR_Int128Math3Asm::Kind::PCPYLD);
env->emit_ir<IR_Int128Math3Asm>(true, xmm_temp, xmm_temp, original_original,
env->emit_ir<IR_Int128Math3Asm>(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<IR_RegSet>(src_128, src_in_reg);
env->emit_ir<IR_RegSet>(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<IR_RegSet>(src_gpr, src_in_reg);
env->emit_ir<IR_RegSet>(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<IR_RegSet>(src_gpr, src_in_reg);
env->emit_ir<IR_RegSet>(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<IR_StoreConstOffset>(src_in_reg, base_as_mco->offset,
base_as_mco->base->to_gpr(env), load_size));
env->emit_ir<IR_StoreConstOffset>(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<IR_StoreConstOffset>(src_in_reg, 0, base->to_gpr(env), load_size));
env->emit_ir<IR_StoreConstOffset>(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<IR_StoreConstOffset>(src_in_reg, as_pair->is_car ? -2 : 2,
as_pair->base->to_gpr(env), 4));
env->emit_ir<IR_StoreConstOffset>(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<IR_RegSet>(as_reg, src_in_reg));
env->emit_ir<IR_RegSet>(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<IR_SetSymbolValue>(as_sym_val->sym(), result_in_gpr));
auto result_in_gpr = src_in_reg->to_gpr(form, env);
env->emit_ir<IR_SetSymbolValue>(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);
}
+22 -23
View File
@@ -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<FunctionEnv>(env, function_name);
auto new_func_env = std::make_unique<FunctionEnv>(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<BlockEnv>(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<IR_ValueReset>(reset_args_for_coloring));
func_block_env->emit_ir<IR_ValueReset>(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<IR_RegSet>(ireg, reset_args_for_coloring.at(i));
new_func_env->emit_ir<IR_RegSet>(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<None*>(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<IR_Return>(return_reg, final_result, ret_hw_reg));
new_func_env->emit_ir<IR_Return>(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<IR_Null>());
new_func_env->emit_ir<IR_Null>(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<RegVal*> 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<IR_RegSet>(copy, eval_args.at(i)));
env->emit_ir<IR_RegSet>(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<None*>(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<None*>(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<IR_RegSet>(result_reg_if_return_from, final_result));
inlined_compile_env->emit_ir<IR_RegSet>(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<IR_Null>());
inlined_compile_env->emit_ir<IR_Null>(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<IR_Null>());
inlined_compile_env->emit_ir<IR_Null>(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<IR_RegSet>(arg_outs.back(), arg));
env->emit_ir<IR_RegSet>(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<IR_RegSet>(temp_function, function));
env->emit(std::make_unique<IR_FunctionCall>(temp_function, return_reg, arg_outs, cc.arg_regs,
cc.return_reg));
env->emit_ir<IR_RegSet>(form, temp_function, function);
env->emit_ir<IR_FunctionCall>(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<IR_RegSet>(result_reg, return_reg));
env->emit_ir<IR_RegSet>(form, result_reg, return_reg);
return result_reg;
} else {
return return_reg;
+2 -2
View File
@@ -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<None*>(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<None*>(result)) {
result = result->to_reg(menv);
result = result->to_reg(o, menv);
}
});
return result;
+93 -94
View File
@@ -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<IR_FloatToInt>(result, in->to_fpr(env)));
env->emit_ir<IR_FloatToInt>(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<IR_LoadConstant64>(sa, 3));
env->emit_ir<IR_LoadConstant64>(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<IR_IntToFloat>(result, in->to_gpr(env)));
env->emit_ir<IR_IntToFloat>(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<IR_RegSet>(result, first_val->to_gpr(env)));
env->emit_ir<IR_RegSet>(form, result, first_val->to_gpr(form, env));
for (size_t i = 1; i < args.unnamed.size(); i++) {
env->emit(std::make_unique<IR_IntegerMath>(
IntegerMathKind::ADD_64, result,
env->emit_ir<IR_IntegerMath>(
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<IR_RegSet>(result, first_val->to_fpr(env)));
env->emit_ir<IR_RegSet>(form, result, first_val->to_fpr(form, env));
for (size_t i = 1; i < args.unnamed.size(); i++) {
env->emit(std::make_unique<IR_FloatMath>(
FloatMathKind::ADD_SS, result,
env->emit_ir<IR_FloatMath>(
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<IR_RegSet>(result, first_val->to_gpr(env)));
env->emit_ir<IR_RegSet>(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<IR_IntegerMath>(IntegerMathKind::SHL_64, result, power_of_two);
env->emit_ir<IR_IntegerMath>(form, IntegerMathKind::SHL_64, result, power_of_two);
} else {
env->emit(std::make_unique<IR_IntegerMath>(
IntegerMathKind::IMUL_32, result,
to_math_type(form, val, math_type, env)->to_gpr(env)));
env->emit_ir<IR_IntegerMath>(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<IR_RegSet>(result, first_val->to_fpr(env)));
env->emit_ir<IR_RegSet>(form, result, first_val->to_fpr(form, env));
for (size_t i = 1; i < args.unnamed.size(); i++) {
env->emit(std::make_unique<IR_FloatMath>(
FloatMathKind::MUL_SS, result,
env->emit_ir<IR_FloatMath>(
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<IR_RegSet>(result, first_val->to_fpr(env)));
env->emit_ir<IR_RegSet>(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<IR_FloatMath>(FloatMathKind::MIN_SS, result, val->to_fpr(env)));
env->emit_ir<IR_FloatMath>(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<IR_RegSet>(result, first_val->to_fpr(env)));
env->emit_ir<IR_RegSet>(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<IR_FloatMath>(FloatMathKind::MAX_SS, result, val->to_fpr(env)));
env->emit_ir<IR_FloatMath>(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<IR_FloatMath>(FloatMathKind::SQRT_SS, result, first_val->to_fpr(env));
env->emit_ir<IR_FloatMath>(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<IR_RegSet>(result, first_val->to_gpr(env)));
env->emit_ir<IR_RegSet>(form, result, first_val->to_gpr(form, env));
for (size_t i = 1; i < args.unnamed.size(); i++) {
env->emit(std::make_unique<IR_IntegerMath>(
IntegerMathKind::IMUL_64, result,
env->emit_ir<IR_IntegerMath>(
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<IR_IntegerMath>(
IntegerMathKind::SUB_64, result,
auto result = compile_integer(0, env)->to_gpr(form, env);
env->emit_ir<IR_IntegerMath>(
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<IR_RegSet>(
result, to_math_type(form, compile_error_guard(args.unnamed.at(0), env), math_type, env)
->to_gpr(env)));
env->emit_ir<IR_RegSet>(
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<IR_IntegerMath>(
IntegerMathKind::SUB_64, result,
env->emit_ir<IR_IntegerMath>(
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<IR_FloatMath>(
FloatMathKind::SUB_SS, result,
auto result = compile_float(0, env, env->function_env()->segment)->to_fpr(form, env);
env->emit_ir<IR_FloatMath>(
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<IR_RegSet>(
result, to_math_type(form, compile_error_guard(args.unnamed.at(0), env), math_type, env)
->to_fpr(env)));
env->emit_ir<IR_RegSet>(
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<IR_FloatMath>(
FloatMathKind::SUB_SS, result,
env->emit_ir<IR_FloatMath>(
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<IR_RegSet>(result, first_thing));
env->emit_ir<IR_RegSet>(form, result, first_thing);
auto val = compile_error_guard(args.unnamed.at(1), env);
auto val_as_int = dynamic_cast<IntegerConstantVal*>(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<IR_IntegerMath>(IntegerMathKind::SAR_64, result, power_of_two);
env->emit_ir<IR_IntegerMath>(form, IntegerMathKind::SAR_64, result, power_of_two);
} else {
env->emit_ir<IR_IntegerMath>(IntegerMathKind::SHR_64, result, power_of_two);
env->emit_ir<IR_IntegerMath>(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<IR_IntegerMath>(
IntegerMathKind::IDIV_32, result,
to_math_type(form, val, math_type, env)->to_gpr(env)));
env->emit_ir<IR_IntegerMath>(form, IntegerMathKind::IDIV_32, result,
to_math_type(form, val, math_type, env)->to_gpr(form, env));
} else {
env->emit(std::make_unique<IR_IntegerMath>(
IntegerMathKind::UDIV_32, result,
to_math_type(form, val, math_type, env)->to_gpr(env)));
env->emit_ir<IR_IntegerMath>(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<IR_RegSet>(result_moved, result);
env->emit_ir<IR_RegSet>(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<IR_RegSet>(result, first_val->to_fpr(env)));
env->emit(std::make_unique<IR_FloatMath>(
FloatMathKind::DIV_SS, result,
env->emit_ir<IR_RegSet>(form, result, first_val->to_fpr(form, env));
env->emit_ir<IR_FloatMath>(
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<IR_RegSet>(result, in));
env->emit(std::make_unique<IR_RegSet>(sa_in, sa));
env->emit_ir<IR_RegSet>(form, result, in);
env->emit_ir<IR_RegSet>(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<IR_IntegerMath>(kind, result, sa_in));
env->emit_ir<IR_IntegerMath>(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<IR_RegSet>(result, in));
env->emit_ir<IR_RegSet>(form, result, in);
// do the shift
env->emit(std::make_unique<IR_IntegerMath>(kind, result, sa));
env->emit_ir<IR_IntegerMath>(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<IR_RegSet>(result, first));
env->emit_ir<IR_RegSet>(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<IR_IntegerMath>(IntegerMathKind::IMOD_32, result, second));
env->emit_ir<IR_IntegerMath>(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<IR_RegSet>(result, first));
env->emit(std::make_unique<IR_IntegerMath>(IntegerMathKind::AND_64, result, second));
env->emit_ir<IR_RegSet>(form, result, first);
env->emit_ir<IR_IntegerMath>(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<IR_RegSet>(result, first));
env->emit_ir<IR_RegSet>(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<IR_IntegerMath>(IntegerMathKind::OR_64, result, sec->to_gpr(env)));
env->emit_ir<IR_IntegerMath>(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<IR_RegSet>(result, first));
env->emit(std::make_unique<IR_IntegerMath>(IntegerMathKind::XOR_64, result, second));
env->emit_ir<IR_RegSet>(form, result, first);
env->emit_ir<IR_IntegerMath>(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<IR_RegSet>(result, first));
env->emit(std::make_unique<IR_IntegerMath>(IntegerMathKind::NOT_64, result, nullptr));
env->emit_ir<IR_RegSet>(form, result, first);
env->emit_ir<IR_IntegerMath>(form, IntegerMathKind::NOT_64, result, nullptr);
return result;
}
+19 -18
View File
@@ -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<SymbolVal>(state_name, state_type);
env->emit(std::make_unique<IR_SetSymbolValue>(sym_val, state_object));
env->emit_ir<IR_SetSymbolValue>(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<RegVal*> 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();
}
+15 -19
View File
@@ -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<IR_IntegerMath>(IntegerMathKind::SHL_64, field_val,
left_shift_amnt));
env->emit_ir<IR_IntegerMath>(form, IntegerMathKind::SHL_64, field_val, left_shift_amnt);
}
if (right_shift_amnt > 0) {
env->emit(std::make_unique<IR_IntegerMath>(IntegerMathKind::SHR_64, field_val,
right_shift_amnt));
env->emit_ir<IR_IntegerMath>(form, IntegerMathKind::SHR_64, field_val, right_shift_amnt);
}
env->emit(std::make_unique<IR_IntegerMath>(IntegerMathKind::OR_64,
start_lo ? integer_lo : integer_hi, field_val));
env->emit_ir<IR_IntegerMath>(form, IntegerMathKind::OR_64,
start_lo ? integer_lo : integer_hi, field_val);
}
fe->emit_ir<IR_RegSet>(xmm_temp, integer_lo);
fe->emit_ir<IR_RegSet>(rv, integer_hi);
fe->emit_ir<IR_Int128Math3Asm>(true, rv, rv, xmm_temp, IR_Int128Math3Asm::Kind::PCPYLD);
fe->emit_ir<IR_RegSet>(form, xmm_temp, integer_lo);
fe->emit_ir<IR_RegSet>(form, rv, integer_hi);
fe->emit_ir<IR_Int128Math3Asm>(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<IR_IntegerMath>(IntegerMathKind::SHL_64, field_val,
left_shift_amnt));
env->emit_ir<IR_IntegerMath>(form, IntegerMathKind::SHL_64, field_val, left_shift_amnt);
}
if (right_shift_amnt > 0) {
env->emit(std::make_unique<IR_IntegerMath>(IntegerMathKind::SHR_64, field_val,
right_shift_amnt));
env->emit_ir<IR_IntegerMath>(form, IntegerMathKind::SHR_64, field_val, right_shift_amnt);
}
env->emit(std::make_unique<IR_IntegerMath>(IntegerMathKind::OR_64, integer_reg, field_val));
env->emit_ir<IR_IntegerMath>(form, IntegerMathKind::OR_64, integer_reg, field_val);
}
integer_reg->set_type(type);
+86 -84
View File
@@ -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<MemoryDerefVal>(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<IR_LoadConstOffset>(runtime_type, -4, object, info));
env->emit_ir<IR_LoadConstOffset>(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<MemoryDerefVal>(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("{}: <cannot-print>~%", 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<FunctionEnv>(
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<IR_ValueReset>(std::vector<RegVal*>{input_arg}));
method_env->emit_ir<IR_ValueReset>(form, std::vector<RegVal*>{input_arg});
auto input = method_env->make_gpr(structure_type->get_name());
method_env->emit_ir<IR_RegSet>(input, input_arg);
method_env->emit_ir<IR_RegSet>(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<BasicType*>(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<IR_Return>(method_env->make_gpr(input->type()), input,
method_env->emit_ir<IR_Return>(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<FunctionEnv>(
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<IR_ValueReset>(std::vector<RegVal*>{input_arg}));
method_env->emit_ir<IR_ValueReset>(form, std::vector<RegVal*>{input_arg});
auto input = method_env->make_gpr(bitfield_type->get_name());
method_env->emit_ir<IR_RegSet>(input, input_arg);
method_env->emit_ir<IR_RegSet>(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<RegVal*> 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<IR_Return>(method_env->make_ireg(input->type(), RegClass::INT_128), input,
emitter::gRegInfo.get_gpr_ret_reg()));
method_env->emit_ir<IR_Return>(form, method_env->make_ireg(input->type(), RegClass::INT_128),
input, emitter::gRegInfo.get_gpr_ret_reg());
} else {
method_env->emit(std::make_unique<IR_Return>(method_env->make_gpr(input->type()), input,
emitter::gRegInfo.get_gpr_ret_reg()));
method_env->emit_ir<IR_Return>(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<FunctionEnv>(env, lambda.debug_name);
auto new_func_env = std::make_unique<FunctionEnv>(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<BlockEnv>(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<IR_ValueReset>(reset_args_for_coloring));
func_block_env->emit_ir<IR_ValueReset>(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<IR_RegSet>(ireg, reset_args_for_coloring.at(i));
new_func_env->emit_ir<IR_RegSet>(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<None*>(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<IR_Return>(return_reg, final_result, ret_hw_reg));
new_func_env->emit_ir<IR_Return>(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<IR_Null>());
new_func_env->emit_ir<IR_Null>(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<MemoryOffsetVal>(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<MemoryOffsetVal>(result->type(), result, offset);
}
result = fe->alloc_val<MemoryDerefVal>(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<IR_IntegerMath>(IntegerMathKind::ADD_64, offset, arr_off);
compile_constant_product(form, offset, index_value, di.stride, env);
env->emit_ir<IR_IntegerMath>(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<MemoryOffsetVal>(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<IR_RegValAddr>(result, as_reg);
env->emit_ir<IR_RegValAddr>(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<RegVal*> 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<IR_IntegerMath>(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<IR_IntegerMath>(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<RegVal*> 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<RegVal*> 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 <something-complicated> 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);
}
+10 -7
View File
@@ -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;
+9 -4
View File
@@ -3,12 +3,15 @@
#include <vector>
#include <string>
#include <optional>
#include <memory>
#include <unordered_map>
#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<std::string> irs;
std::shared_ptr<FunctionEnv> function;
std::vector<InstructionInfo> instructions; // contains mapping to IRs
// the actual bytes in the object file.
std::vector<u8> generated_code;
std::optional<int> 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;
+2 -2
View File
@@ -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;
+3 -1
View File
@@ -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<std::string, DebugInfo> m_debug_info;
};
+32 -2
View File
@@ -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<InstructionInfo>& x86_instructions,
const std::vector<std::string>& 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) {
+8 -1
View File
@@ -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<InstructionInfo>& x86_instructions,
const std::vector<std::string>& irs,
const FunctionEnv* fenv,
bool* had_failure);
+1 -3
View File
@@ -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;
}
+1 -1
View File
@@ -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);
+1 -1
View File
@@ -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);
}
+1 -1
View File
@@ -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");
}
}