mirror of
https://github.com/open-goal/jak-project
synced 2026-07-11 07:25:37 -04:00
working return integer tests as part of gtest
This commit is contained in:
+14
-13
@@ -6,12 +6,13 @@ set(CMAKE_CXX_STANDARD 14)
|
||||
|
||||
# Set default compile flags for GCC
|
||||
# optimization level can be set here. Note that game/ overwrites this for building game C++ code.
|
||||
if(CMAKE_COMPILER_IS_GNUCXX)
|
||||
if (CMAKE_COMPILER_IS_GNUCXX)
|
||||
message(STATUS "GCC detected, adding compile flags")
|
||||
set(CMAKE_CXX_FLAGS
|
||||
"${CMAKE_CXX_FLAGS} \
|
||||
set(CMAKE_CXX_FLAGS
|
||||
"${CMAKE_CXX_FLAGS} \
|
||||
-Wall \
|
||||
-Winit-self \
|
||||
-ggdb \
|
||||
-Wextra \
|
||||
-Wcast-align \
|
||||
-Wcast-qual \
|
||||
@@ -22,16 +23,16 @@ if(CMAKE_COMPILER_IS_GNUCXX)
|
||||
-Wredundant-decls \
|
||||
-Wshadow \
|
||||
-Wsign-promo")
|
||||
else()
|
||||
set(CMAKE_CXX_FLAGS "/EHsc")
|
||||
endif(CMAKE_COMPILER_IS_GNUCXX)
|
||||
else ()
|
||||
set(CMAKE_CXX_FLAGS "/EHsc")
|
||||
endif (CMAKE_COMPILER_IS_GNUCXX)
|
||||
|
||||
IF (WIN32)
|
||||
set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON)
|
||||
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib)
|
||||
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib)
|
||||
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)
|
||||
ENDIF()
|
||||
set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON)
|
||||
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib)
|
||||
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib)
|
||||
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)
|
||||
ENDIF ()
|
||||
|
||||
# includes relative to top level jak-project folder
|
||||
include_directories(./)
|
||||
@@ -65,5 +66,5 @@ add_subdirectory(third-party/fmt)
|
||||
|
||||
# windows memory management lib
|
||||
IF (WIN32)
|
||||
add_subdirectory(third-party/mman)
|
||||
ENDIF()
|
||||
add_subdirectory(third-party/mman)
|
||||
ENDIF ()
|
||||
|
||||
+11
-15
@@ -16,7 +16,7 @@ class BinaryWriter {
|
||||
public:
|
||||
BinaryWriter() = default;
|
||||
|
||||
template<typename T>
|
||||
template <typename T>
|
||||
BinaryWriterRef add(const T& obj) {
|
||||
auto orig_size = data.size();
|
||||
data.resize(orig_size + sizeof(T));
|
||||
@@ -24,26 +24,24 @@ class BinaryWriter {
|
||||
return {orig_size, sizeof(T)};
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
template <typename T>
|
||||
void add_at_ref(const T& obj, const BinaryWriterRef& ref) {
|
||||
assert(ref.write_size == sizeof(T));
|
||||
assert(ref.offset + ref.write_size < get_size());
|
||||
memcpy(data.data() + ref.offset, &obj, sizeof(T));
|
||||
}
|
||||
|
||||
void add_str_len(const std::string& str, size_t len) {
|
||||
add_cstr_len(str.c_str(), len);
|
||||
}
|
||||
void add_str_len(const std::string& str, size_t len) { add_cstr_len(str.c_str(), len); }
|
||||
|
||||
void add_cstr_len(const char* str, size_t len) {
|
||||
size_t i = 0;
|
||||
while(*str) {
|
||||
while (*str) {
|
||||
data.push_back(*str);
|
||||
str++;
|
||||
i++;
|
||||
}
|
||||
|
||||
while(i < len) {
|
||||
while (i < len) {
|
||||
data.push_back(0);
|
||||
i++;
|
||||
}
|
||||
@@ -56,18 +54,16 @@ class BinaryWriter {
|
||||
return {orig_size, len};
|
||||
}
|
||||
|
||||
size_t get_size() {
|
||||
return data.size();
|
||||
}
|
||||
size_t get_size() { return data.size(); }
|
||||
|
||||
void* get_data() {
|
||||
return data.data();
|
||||
}
|
||||
void* get_data() { return data.data(); }
|
||||
|
||||
void write_to_file(const std::string& filename) {
|
||||
auto fp = fopen(filename.c_str(), "wb");
|
||||
if(!fp) throw std::runtime_error("failed to open " + filename);
|
||||
if(fwrite(get_data(), get_size(), 1, fp) != 1) throw std::runtime_error("failed to write " + filename);
|
||||
if (!fp)
|
||||
throw std::runtime_error("failed to open " + filename);
|
||||
if (fwrite(get_data(), get_size(), 1, fp) != 1)
|
||||
throw std::runtime_error("failed to write " + filename);
|
||||
fclose(fp);
|
||||
}
|
||||
|
||||
|
||||
@@ -138,8 +138,8 @@ u32 InitRPC() {
|
||||
*/
|
||||
void StopIOP() {
|
||||
x[2] = 0x14; // todo - this type and message
|
||||
RpcSync(PLAYER_RPC_CHANNEL);
|
||||
RpcCall(PLAYER_RPC_CHANNEL, 0, false, x, 0x50, nullptr, 0);
|
||||
// RpcSync(PLAYER_RPC_CHANNEL);
|
||||
// RpcCall(PLAYER_RPC_CHANNEL, 0, false, x, 0x50, nullptr, 0);
|
||||
printf("IOP shut down\n");
|
||||
// sceDmaSync(0x10009000, 0, 0);
|
||||
printf("DMA shut down\n");
|
||||
|
||||
@@ -141,6 +141,9 @@ void ProcessListenerMessage(Ptr<char> msg) {
|
||||
break;
|
||||
case LTT_MSG_RESET:
|
||||
MasterExit = 1;
|
||||
if (protoBlock.msg_id == UINT64_MAX) {
|
||||
MasterExit = 2;
|
||||
}
|
||||
break;
|
||||
case LTT_MSG_CODE: {
|
||||
auto buffer = kmalloc(kdebugheap, MessCount, 0, "listener-link-block");
|
||||
|
||||
+3
-1
@@ -10,7 +10,9 @@ int main(int argc, char** argv) {
|
||||
while (true) {
|
||||
// run the runtime in a loop so we can reset the game and have it restart cleanly
|
||||
printf("gk %d.%d\n", versions::GOAL_VERSION_MAJOR, versions::GOAL_VERSION_MINOR);
|
||||
exec_runtime(argc, argv);
|
||||
if (exec_runtime(argc, argv) == 2) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
+3
-2
@@ -229,7 +229,7 @@ void iop_runner(SystemThreadInterface& iface) {
|
||||
* Main function to launch the runtime.
|
||||
* Arguments are currently ignored.
|
||||
*/
|
||||
void exec_runtime(int argc, char** argv) {
|
||||
u32 exec_runtime(int argc, char** argv) {
|
||||
(void)argc;
|
||||
(void)argv;
|
||||
|
||||
@@ -262,5 +262,6 @@ void exec_runtime(int argc, char** argv) {
|
||||
|
||||
// join and exit
|
||||
tm.join();
|
||||
printf("GOAL Runtime Shutdown\n");
|
||||
printf("GOAL Runtime Shutdown (code %d)\n", MasterExit);
|
||||
return MasterExit;
|
||||
}
|
||||
|
||||
+1
-1
@@ -9,6 +9,6 @@
|
||||
#include "common/common_types.h"
|
||||
|
||||
extern u8* g_ee_main_mem;
|
||||
void exec_runtime(int argc, char** argv);
|
||||
u32 exec_runtime(int argc, char** argv);
|
||||
|
||||
#endif // JAK1_RUNTIME_H
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
; simply return an integer
|
||||
#x123456789
|
||||
@@ -0,0 +1 @@
|
||||
#x17
|
||||
@@ -0,0 +1 @@
|
||||
-17
|
||||
@@ -0,0 +1 @@
|
||||
-2147483648
|
||||
@@ -0,0 +1 @@
|
||||
-2147483649
|
||||
@@ -0,0 +1 @@
|
||||
0
|
||||
@@ -0,0 +1 @@
|
||||
-123
|
||||
@@ -1,3 +1,117 @@
|
||||
|
||||
|
||||
#include "CodeGenerator.h"
|
||||
#include "goalc/emitter/IGen.h"
|
||||
#include "IR.h"
|
||||
|
||||
using namespace emitter;
|
||||
constexpr int GPR_SIZE = 8;
|
||||
constexpr int XMM_SIZE = 16;
|
||||
|
||||
CodeGenerator::CodeGenerator(FileEnv* env) : m_fe(env) {}
|
||||
|
||||
std::vector<u8> CodeGenerator::run() {
|
||||
// todo, static objects
|
||||
|
||||
for (auto& f : m_fe->functions()) {
|
||||
do_function(f.get());
|
||||
}
|
||||
|
||||
return m_gen.generate_data_v3().to_vector();
|
||||
}
|
||||
|
||||
void CodeGenerator::do_function(FunctionEnv* env) {
|
||||
auto f_rec = m_gen.add_function_to_seg(env->segment); // todo, extra alignment settings
|
||||
auto& ri = emitter::gRegInfo;
|
||||
const auto& allocs = env->alloc_result();
|
||||
|
||||
// compute how much stack we will use
|
||||
int stack_offset = 0;
|
||||
|
||||
// back up xmms
|
||||
for (auto& saved_reg : allocs.used_saved_regs) {
|
||||
if (saved_reg.is_xmm()) {
|
||||
m_gen.add_instr_no_ir(f_rec, IGen::sub_gpr64_imm8s(RSP, XMM_SIZE));
|
||||
m_gen.add_instr_no_ir(f_rec, IGen::store128_gpr64_xmm128(RSP, saved_reg));
|
||||
stack_offset += XMM_SIZE;
|
||||
}
|
||||
}
|
||||
|
||||
// back up gprs
|
||||
for (auto& saved_reg : allocs.used_saved_regs) {
|
||||
if (saved_reg.is_gpr()) {
|
||||
m_gen.add_instr_no_ir(f_rec, IGen::push_gpr64(saved_reg));
|
||||
stack_offset += GPR_SIZE;
|
||||
}
|
||||
}
|
||||
|
||||
bool bonus_push = false;
|
||||
int manually_added_stack_offset = GPR_SIZE * allocs.stack_slots;
|
||||
stack_offset += manually_added_stack_offset;
|
||||
|
||||
if (manually_added_stack_offset || allocs.needs_aligned_stack_for_spills ||
|
||||
env->needs_aligned_stack()) {
|
||||
if (!(stack_offset & 15)) {
|
||||
if (manually_added_stack_offset) {
|
||||
manually_added_stack_offset += 8;
|
||||
} else {
|
||||
bonus_push = true;
|
||||
m_gen.add_instr_no_ir(f_rec, IGen::push_gpr64(ri.get_saved_gpr(0)));
|
||||
}
|
||||
stack_offset += 8;
|
||||
}
|
||||
|
||||
assert(stack_offset & 15);
|
||||
|
||||
if (manually_added_stack_offset) {
|
||||
m_gen.add_instr_no_ir(f_rec, IGen::sub_gpr64_imm(RSP, manually_added_stack_offset));
|
||||
}
|
||||
}
|
||||
|
||||
// TODO EMIT FUNCTIONS
|
||||
for (int ir_idx = 0; ir_idx < int(env->code().size()); ir_idx++) {
|
||||
auto& ir = env->code().at(ir_idx);
|
||||
auto i_rec = m_gen.add_ir(f_rec);
|
||||
|
||||
auto& bonus = allocs.stack_ops.at(ir_idx);
|
||||
for (auto& op : bonus.ops) {
|
||||
if (op.load) {
|
||||
assert(false);
|
||||
}
|
||||
}
|
||||
ir->do_codegen(&m_gen, allocs, i_rec);
|
||||
for (auto& op : bonus.ops) {
|
||||
if (op.store) {
|
||||
assert(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// EPILOGUE
|
||||
if (manually_added_stack_offset || allocs.needs_aligned_stack_for_spills ||
|
||||
env->needs_aligned_stack()) {
|
||||
if (manually_added_stack_offset) {
|
||||
m_gen.add_instr_no_ir(f_rec, IGen::add_gpr64_imm(RSP, manually_added_stack_offset));
|
||||
}
|
||||
|
||||
if (bonus_push) {
|
||||
assert(!manually_added_stack_offset);
|
||||
m_gen.add_instr_no_ir(f_rec, IGen::pop_gpr64(ri.get_saved_gpr(0)));
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = int(allocs.used_saved_regs.size()); i-- > 0;) {
|
||||
auto& saved_reg = allocs.used_saved_regs.at(i);
|
||||
if (saved_reg.is_gpr()) {
|
||||
m_gen.add_instr_no_ir(f_rec, IGen::pop_gpr64(saved_reg));
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = int(allocs.used_saved_regs.size()); i-- > 0;) {
|
||||
auto& saved_reg = allocs.used_saved_regs.at(i);
|
||||
if (saved_reg.is_xmm()) {
|
||||
m_gen.add_instr_no_ir(f_rec, IGen::load128_xmm128_gpr64(saved_reg, RSP));
|
||||
m_gen.add_instr_no_ir(f_rec, IGen::add_gpr64_imm8s(RSP, XMM_SIZE));
|
||||
}
|
||||
}
|
||||
|
||||
m_gen.add_instr_no_ir(f_rec, IGen::ret());
|
||||
}
|
||||
@@ -3,6 +3,18 @@
|
||||
#ifndef JAK_CODEGENERATOR_H
|
||||
#define JAK_CODEGENERATOR_H
|
||||
|
||||
class CodeGenerator {};
|
||||
#include "Env.h"
|
||||
#include "goalc/emitter/ObjectGenerator.h"
|
||||
|
||||
class CodeGenerator {
|
||||
public:
|
||||
CodeGenerator(FileEnv* env);
|
||||
std::vector<u8> run();
|
||||
|
||||
private:
|
||||
void do_function(FunctionEnv* env);
|
||||
emitter::ObjectGenerator m_gen;
|
||||
FileEnv* m_fe;
|
||||
};
|
||||
|
||||
#endif // JAK_CODEGENERATOR_H
|
||||
|
||||
+73
-13
@@ -1,6 +1,9 @@
|
||||
#include "Compiler.h"
|
||||
#include "goalc/logger/Logger.h"
|
||||
#include "common/link_types.h"
|
||||
#include "IR.h"
|
||||
#include "goalc/regalloc/allocate.h"
|
||||
#include "unistd.h"
|
||||
|
||||
using namespace goos;
|
||||
|
||||
@@ -14,6 +17,7 @@ Compiler::Compiler() {
|
||||
}
|
||||
|
||||
void Compiler::execute_repl() {
|
||||
m_listener.connect_to_target();
|
||||
while (!m_want_exit) {
|
||||
try {
|
||||
// 1). get a line from the user (READ)
|
||||
@@ -29,19 +33,19 @@ void Compiler::execute_repl() {
|
||||
auto obj_file = compile_object_file("repl", code, m_listener.is_connected());
|
||||
obj_file->debug_print_tl();
|
||||
|
||||
// // 3). color
|
||||
// color_object_file(obj_file);
|
||||
//
|
||||
// // 4). codegen
|
||||
// auto data = codegen_object_file(obj_file);
|
||||
//
|
||||
// // 4). send!
|
||||
// if(m_listener.is_connected()) {
|
||||
// m_listener.send_code(data);
|
||||
// if(!m_listener.most_recent_send_was_acked()) {
|
||||
// gLogger.log(MSG_ERR, "Runtime is not responding. Did it crash?\n");
|
||||
// }
|
||||
// }
|
||||
// 3). color
|
||||
color_object_file(obj_file);
|
||||
|
||||
// 4). codegen
|
||||
auto data = codegen_object_file(obj_file);
|
||||
|
||||
// 4). send!
|
||||
if (m_listener.is_connected()) {
|
||||
m_listener.send_code(data);
|
||||
if (!m_listener.most_recent_send_was_acked()) {
|
||||
gLogger.log(MSG_ERR, "Runtime is not responding. Did it crash?\n");
|
||||
}
|
||||
}
|
||||
|
||||
} catch (std::exception& e) {
|
||||
gLogger.log(MSG_WARN, "REPL Error: %s\n", e.what());
|
||||
@@ -126,3 +130,59 @@ void Compiler::ice(const std::string& error) {
|
||||
gLogger.log(MSG_ICE, "[ICE] %s\n", error.c_str());
|
||||
throw std::runtime_error("ICE");
|
||||
}
|
||||
|
||||
void Compiler::color_object_file(FileEnv* env) {
|
||||
for (auto& f : env->functions()) {
|
||||
AllocationInput input;
|
||||
for (auto& i : f->code()) {
|
||||
input.instructions.push_back(i->to_rai());
|
||||
input.debug_instruction_names.push_back(i->print());
|
||||
}
|
||||
input.max_vars = f->max_vars();
|
||||
input.constraints = f->constraints();
|
||||
|
||||
// for now...
|
||||
input.debug_settings.print_input = true;
|
||||
input.debug_settings.print_result = true;
|
||||
input.debug_settings.print_analysis = true;
|
||||
|
||||
f->set_allocations(allocate_registers(input));
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<u8> Compiler::codegen_object_file(FileEnv* env) {
|
||||
CodeGenerator gen(env);
|
||||
return gen.run();
|
||||
}
|
||||
|
||||
std::vector<std::string> Compiler::run_test(const std::string& source_code) {
|
||||
if (!m_listener.is_connected()) {
|
||||
for (int i = 0; i < 1000; i++) {
|
||||
m_listener.connect_to_target();
|
||||
usleep(10000);
|
||||
if (m_listener.is_connected()) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!m_listener.is_connected()) {
|
||||
throw std::runtime_error("Compiler::run_test couldn't connect!");
|
||||
}
|
||||
}
|
||||
|
||||
auto code = m_goos.reader.read_from_file(source_code);
|
||||
auto compiled = compile_object_file("test-code", code, true);
|
||||
color_object_file(compiled);
|
||||
auto data = codegen_object_file(compiled);
|
||||
m_listener.record_messages(ListenerMessageKind::MSG_PRINT);
|
||||
m_listener.send_code(data);
|
||||
if (!m_listener.most_recent_send_was_acked()) {
|
||||
gLogger.log(MSG_ERR, "Runtime is not responding after sending test code. Did it crash?\n");
|
||||
}
|
||||
return m_listener.stop_recording_messages();
|
||||
}
|
||||
|
||||
void Compiler::shutdown_target() {
|
||||
if (m_listener.is_connected()) {
|
||||
m_listener.send_reset(true);
|
||||
}
|
||||
}
|
||||
@@ -5,6 +5,7 @@
|
||||
#include "Env.h"
|
||||
#include "goalc/listener/Listener.h"
|
||||
#include "goalc/goos/Interpreter.h"
|
||||
#include "goalc/compiler/IR.h"
|
||||
|
||||
class Compiler {
|
||||
public:
|
||||
@@ -21,14 +22,19 @@ class Compiler {
|
||||
void ice(const std::string& err);
|
||||
None* get_none() { return m_none.get(); }
|
||||
|
||||
std::vector<std::string> run_test(const std::string& source_code);
|
||||
void shutdown_target();
|
||||
|
||||
private:
|
||||
void init_logger();
|
||||
Val* compile_pair(const goos::Object& code, Env* env);
|
||||
Val* compile_integer(const goos::Object& code, Env* env);
|
||||
Val* compile_integer(s64 value, Env* env);
|
||||
void color_object_file(FileEnv* env);
|
||||
std::vector<u8> codegen_object_file(FileEnv* env);
|
||||
|
||||
void for_each_in_list(const goos::Object& list, const std::function<void (const goos::Object&)>& f);
|
||||
|
||||
void for_each_in_list(const goos::Object& list,
|
||||
const std::function<void(const goos::Object&)>& f);
|
||||
|
||||
goos::Arguments get_va(const goos::Object& form, const goos::Object& rest);
|
||||
void va_check(
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#include <stdexcept>
|
||||
#include "Env.h"
|
||||
#include "IR.h"
|
||||
|
||||
///////////////////
|
||||
// Env
|
||||
@@ -93,12 +94,12 @@ Val* GlobalEnv::lexical_lookup(goos::Object sym) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
BlockEnv * GlobalEnv::find_block(const std::string& name) {
|
||||
BlockEnv* GlobalEnv::find_block(const std::string& name) {
|
||||
(void)name;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
FileEnv * GlobalEnv::add_file(std::string name) {
|
||||
FileEnv* GlobalEnv::add_file(std::string name) {
|
||||
m_files.push_back(std::make_unique<FileEnv>(this, std::move(name)));
|
||||
return m_files.back().get();
|
||||
}
|
||||
@@ -142,15 +143,15 @@ 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() {
|
||||
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()) {
|
||||
if (m_top_level_func) {
|
||||
for (auto& code : m_top_level_func->code()) {
|
||||
fmt::print("{}\n", code->print());
|
||||
}
|
||||
} else {
|
||||
@@ -162,7 +163,8 @@ void FileEnv::debug_print_tl() {
|
||||
// FunctionEnv
|
||||
///////////////////
|
||||
|
||||
FunctionEnv::FunctionEnv(Env* parent, std::string name) : DeclareEnv(parent), m_name(std::move(name)){}
|
||||
FunctionEnv::FunctionEnv(Env* parent, std::string name)
|
||||
: DeclareEnv(parent), m_name(std::move(name)) {}
|
||||
|
||||
std::string FunctionEnv::print() {
|
||||
return "function-" + m_name;
|
||||
@@ -176,7 +178,7 @@ void FunctionEnv::finish() {
|
||||
// todo resolve gotos
|
||||
}
|
||||
|
||||
RegVal * FunctionEnv::make_ireg(TypeSpec ts, emitter::RegKind kind) {
|
||||
RegVal* FunctionEnv::make_ireg(TypeSpec ts, emitter::RegKind kind) {
|
||||
IRegister ireg;
|
||||
ireg.kind = kind;
|
||||
ireg.id = m_iregs.size();
|
||||
|
||||
+21
-14
@@ -11,13 +11,15 @@
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
#include "common/type_system/TypeSpec.h"
|
||||
#include "goalc/regalloc/allocate.h"
|
||||
#include "goalc/goos/Object.h"
|
||||
#include "IR.h"
|
||||
//#include "IR.h"
|
||||
#include "Label.h"
|
||||
#include "Val.h"
|
||||
|
||||
class FileEnv;
|
||||
class BlockEnv;
|
||||
class IR;
|
||||
|
||||
/*!
|
||||
* Parent class for Env's
|
||||
@@ -84,6 +86,7 @@ class FileEnv : public Env {
|
||||
void add_top_level_function(std::unique_ptr<FunctionEnv> fe);
|
||||
NoEmitEnv* add_no_emit_env();
|
||||
void debug_print_tl();
|
||||
const std::vector<std::unique_ptr<FunctionEnv>>& functions() { return m_functions; }
|
||||
|
||||
// todo - is_empty
|
||||
~FileEnv() = default;
|
||||
@@ -118,11 +121,18 @@ class FunctionEnv : public DeclareEnv {
|
||||
public:
|
||||
FunctionEnv(Env* parent, std::string name);
|
||||
std::string print() override;
|
||||
void set_segment(int seg) { m_segment = seg; }
|
||||
void set_segment(int seg) { segment = seg; }
|
||||
void emit(std::unique_ptr<IR> ir) override;
|
||||
void finish();
|
||||
RegVal* make_ireg(TypeSpec ts, emitter::RegKind kind) override;
|
||||
const std::vector<std::unique_ptr<IR>>& code() { return m_code; }
|
||||
int max_vars() const { return m_iregs.size(); }
|
||||
const std::vector<IRegConstraint>& constraints() { return m_constraints; }
|
||||
void set_allocations(const AllocationResult& result) { m_regalloc_result = result; }
|
||||
|
||||
const AllocationResult& alloc_result() { return m_regalloc_result; }
|
||||
|
||||
bool needs_aligned_stack() const { return m_aligned_stack_required; }
|
||||
|
||||
template <typename T, class... Args>
|
||||
T* alloc_val(Args&&... args) {
|
||||
@@ -130,7 +140,7 @@ class FunctionEnv : public DeclareEnv {
|
||||
m_vals.push_back(std::move(new_obj));
|
||||
return (T*)m_vals.back().get();
|
||||
}
|
||||
|
||||
int segment = -1;
|
||||
|
||||
protected:
|
||||
std::string m_name;
|
||||
@@ -144,7 +154,6 @@ class FunctionEnv : public DeclareEnv {
|
||||
|
||||
std::string m_method_of_type_name = "#f";
|
||||
bool m_aligned_stack_required = false;
|
||||
int m_segment = -1;
|
||||
|
||||
std::unordered_map<std::string, Env*> m_params;
|
||||
};
|
||||
@@ -154,6 +163,7 @@ class BlockEnv : public Env {
|
||||
BlockEnv(Env* parent, std::string name);
|
||||
std::string print() override;
|
||||
BlockEnv* find_block(const std::string& name) override;
|
||||
|
||||
protected:
|
||||
std::string m_name;
|
||||
Label* m_end_label = nullptr;
|
||||
@@ -173,20 +183,17 @@ class LabelEnv : public Env {
|
||||
std::unordered_map<std::string, Label> m_labels;
|
||||
};
|
||||
|
||||
class WithInlineEnv : public Env {
|
||||
class WithInlineEnv : public Env {};
|
||||
|
||||
};
|
||||
class SymbolMacroEnv : public Env {};
|
||||
|
||||
class SymbolMacroEnv : public Env {
|
||||
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
template <typename T>
|
||||
T* get_parent_env_of_type(Env* in) {
|
||||
for(;;) {
|
||||
for (;;) {
|
||||
auto attempt = dynamic_cast<T*>(in);
|
||||
if(attempt) return attempt;
|
||||
if(dynamic_cast<GlobalEnv*>(in)) {
|
||||
if (attempt)
|
||||
return attempt;
|
||||
if (dynamic_cast<GlobalEnv*>(in)) {
|
||||
return nullptr;
|
||||
}
|
||||
in = in->parent();
|
||||
|
||||
+36
-5
@@ -1,6 +1,18 @@
|
||||
#include "IR.h"
|
||||
#include "goalc/emitter/IGen.h"
|
||||
|
||||
IR_Return::IR_Return(const RegVal* return_reg, const RegVal* value) : m_return_reg(return_reg), m_value(value) {}
|
||||
using namespace emitter;
|
||||
|
||||
namespace {
|
||||
Register get_reg(const RegVal* rv, const AllocationResult& allocs, emitter::IR_Record irec) {
|
||||
auto& ass = allocs.ass_as_ranges.at(rv->ireg().id).get(irec.ir_id);
|
||||
assert(ass.kind == Assignment::Kind::REGISTER);
|
||||
return ass.reg;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
IR_Return::IR_Return(const RegVal* return_reg, const RegVal* value)
|
||||
: m_return_reg(return_reg), m_value(value) {}
|
||||
std::string IR_Return::print() {
|
||||
return fmt::format("ret {} {}", m_return_reg->print(), m_value->print());
|
||||
}
|
||||
@@ -9,15 +21,15 @@ RegAllocInstr IR_Return::to_rai() {
|
||||
RegAllocInstr rai;
|
||||
rai.write.push_back(m_return_reg->ireg());
|
||||
rai.read.push_back(m_value->ireg());
|
||||
if(m_value->ireg().kind == m_return_reg->ireg().kind) {
|
||||
rai.is_move = true; // only true if we aren't moving from register kind to register kind
|
||||
if (m_value->ireg().kind == m_return_reg->ireg().kind) {
|
||||
rai.is_move = true; // only true if we aren't moving from register kind to register kind
|
||||
}
|
||||
return rai;
|
||||
}
|
||||
|
||||
void IR_Return::add_constraints(std::vector<IRegConstraint>* constraints, int my_id) {
|
||||
IRegConstraint c;
|
||||
if(dynamic_cast<const None*>(m_return_reg)){
|
||||
if (dynamic_cast<const None*>(m_return_reg)) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -27,10 +39,22 @@ void IR_Return::add_constraints(std::vector<IRegConstraint>* constraints, int my
|
||||
constraints->push_back(c);
|
||||
}
|
||||
|
||||
IR_LoadConstant64::IR_LoadConstant64(const RegVal* dest, u64 value) : m_dest(dest), m_value(value) {
|
||||
void IR_Return::do_codegen(emitter::ObjectGenerator* gen,
|
||||
const AllocationResult& allocs,
|
||||
emitter::IR_Record irec) {
|
||||
auto val_reg = get_reg(m_value, allocs, irec);
|
||||
auto dest_reg = get_reg(m_return_reg, allocs, irec);
|
||||
|
||||
if (val_reg == dest_reg) {
|
||||
gen->add_instr(IGen::null(), irec);
|
||||
} else {
|
||||
gen->add_instr(IGen::mov_gpr64_gpr64(dest_reg, val_reg), irec);
|
||||
}
|
||||
}
|
||||
|
||||
IR_LoadConstant64::IR_LoadConstant64(const RegVal* dest, u64 value)
|
||||
: m_dest(dest), m_value(value) {}
|
||||
|
||||
std::string IR_LoadConstant64::print() {
|
||||
return fmt::format("mov-ic {}, {}", m_dest->print(), m_value);
|
||||
}
|
||||
@@ -39,4 +63,11 @@ RegAllocInstr IR_LoadConstant64::to_rai() {
|
||||
RegAllocInstr rai;
|
||||
rai.write.push_back(m_dest->ireg());
|
||||
return rai;
|
||||
}
|
||||
|
||||
void IR_LoadConstant64::do_codegen(emitter::ObjectGenerator* gen,
|
||||
const AllocationResult& allocs,
|
||||
emitter::IR_Record irec) {
|
||||
auto dest_reg = get_reg(m_dest, allocs, irec);
|
||||
gen->add_instr(IGen::mov_gpr64_u64(dest_reg, m_value), irec);
|
||||
}
|
||||
+10
-3
@@ -5,12 +5,15 @@
|
||||
#include "CodeGenerator.h"
|
||||
#include "goalc/regalloc/allocate.h"
|
||||
#include "Val.h"
|
||||
#include "goalc/emitter/ObjectGenerator.h"
|
||||
|
||||
class IR {
|
||||
public:
|
||||
virtual std::string print() = 0;
|
||||
virtual RegAllocInstr to_rai() = 0;
|
||||
// virtual void do_codegen(CodeGenerator* gen) = 0;
|
||||
virtual void do_codegen(emitter::ObjectGenerator* gen,
|
||||
const AllocationResult& allocs,
|
||||
emitter::IR_Record irec) = 0;
|
||||
virtual void add_constraints(std::vector<IRegConstraint>* constraints, int my_id) {
|
||||
(void)constraints;
|
||||
(void)my_id;
|
||||
@@ -29,7 +32,9 @@ class IR_Return : public IR {
|
||||
std::string print() override;
|
||||
RegAllocInstr to_rai() override;
|
||||
void add_constraints(std::vector<IRegConstraint>* constraints, int my_id) override;
|
||||
// void do_codegen(CodeGenerator* gen) override;
|
||||
void do_codegen(emitter::ObjectGenerator* gen,
|
||||
const AllocationResult& allocs,
|
||||
emitter::IR_Record irec) override;
|
||||
const RegVal* value() { return m_value; }
|
||||
|
||||
protected:
|
||||
@@ -42,7 +47,9 @@ class IR_LoadConstant64 : public IR {
|
||||
IR_LoadConstant64(const RegVal* dest, u64 value);
|
||||
std::string print() override;
|
||||
RegAllocInstr to_rai() override;
|
||||
// void do_codegen(CodeGenerator* gen) override;
|
||||
void do_codegen(emitter::ObjectGenerator* gen,
|
||||
const AllocationResult& allocs,
|
||||
emitter::IR_Record irec) override;
|
||||
|
||||
protected:
|
||||
const RegVal* m_dest = nullptr;
|
||||
|
||||
@@ -3,8 +3,6 @@
|
||||
#ifndef JAK_LABEL_H
|
||||
#define JAK_LABEL_H
|
||||
|
||||
struct Label {
|
||||
|
||||
};
|
||||
struct Label {};
|
||||
|
||||
#endif // JAK_LABEL_H
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
#include "goalc/compiler/Compiler.h"
|
||||
#include "goalc/compiler/IR.h"
|
||||
|
||||
goos::Arguments Compiler::get_va(const goos::Object& form, const goos::Object& rest) {
|
||||
goos::Arguments args;
|
||||
@@ -82,15 +83,16 @@ void Compiler::va_check(
|
||||
}
|
||||
}
|
||||
|
||||
void Compiler::for_each_in_list(const goos::Object& list, const std::function<void(const goos::Object&)>& f) {
|
||||
void Compiler::for_each_in_list(const goos::Object& list,
|
||||
const std::function<void(const goos::Object&)>& f) {
|
||||
const goos::Object* iter = &list;
|
||||
while(iter->is_pair()) {
|
||||
while (iter->is_pair()) {
|
||||
auto lap = iter->as_pair();
|
||||
f(lap->car);
|
||||
iter = &lap->cdr;
|
||||
}
|
||||
|
||||
if(!iter->is_empty_list()) {
|
||||
if (!iter->is_empty_list()) {
|
||||
throw_compile_error(list, "invalid list in for_each_in_list");
|
||||
}
|
||||
}
|
||||
@@ -1,12 +1,13 @@
|
||||
#include "Val.h"
|
||||
#include "Env.h"
|
||||
#include "IR.h"
|
||||
|
||||
/*!
|
||||
* Fallback to_gpr if a more optimized one is not provided.
|
||||
*/
|
||||
const RegVal* Val::to_gpr(FunctionEnv* fe) const {
|
||||
auto rv = to_reg(fe);
|
||||
if(rv->ireg().kind == emitter::RegKind::GPR) {
|
||||
if (rv->ireg().kind == emitter::RegKind::GPR) {
|
||||
return rv;
|
||||
} else {
|
||||
throw std::runtime_error("Val::to_gpr NYI"); // todo
|
||||
@@ -21,31 +22,30 @@ const RegVal* Val::to_xmm(FunctionEnv* fe) const {
|
||||
throw std::runtime_error("Val::to_xmm NYI"); // todo
|
||||
}
|
||||
|
||||
|
||||
const RegVal* RegVal::to_reg(FunctionEnv* fe) const {
|
||||
(void)fe;
|
||||
return this;
|
||||
}
|
||||
|
||||
const RegVal * RegVal::to_gpr(FunctionEnv* fe) const {
|
||||
const RegVal* RegVal::to_gpr(FunctionEnv* fe) const {
|
||||
(void)fe;
|
||||
if(m_ireg.kind == emitter::RegKind::GPR) {
|
||||
if (m_ireg.kind == emitter::RegKind::GPR) {
|
||||
return this;
|
||||
} else {
|
||||
throw std::runtime_error("RegVal::to_gpr NYI"); // todo
|
||||
throw std::runtime_error("RegVal::to_gpr NYI"); // todo
|
||||
}
|
||||
}
|
||||
|
||||
const RegVal * RegVal::to_xmm(FunctionEnv* fe) const {
|
||||
const RegVal* RegVal::to_xmm(FunctionEnv* fe) const {
|
||||
(void)fe;
|
||||
if(m_ireg.kind == emitter::RegKind::XMM) {
|
||||
if (m_ireg.kind == emitter::RegKind::XMM) {
|
||||
return this;
|
||||
} else {
|
||||
throw std::runtime_error("RegVal::to_xmm NYI"); // todo
|
||||
throw std::runtime_error("RegVal::to_xmm NYI"); // todo
|
||||
}
|
||||
}
|
||||
|
||||
const RegVal * IntegerConstantVal::to_reg(FunctionEnv* fe) const {
|
||||
const RegVal* IntegerConstantVal::to_reg(FunctionEnv* fe) const {
|
||||
auto rv = fe->make_gpr(m_ts);
|
||||
fe->emit(std::make_unique<IR_LoadConstant64>(rv, m_value));
|
||||
return rv;
|
||||
|
||||
@@ -1,139 +1,141 @@
|
||||
#include "goalc/compiler/Compiler.h"
|
||||
#include "goalc/compiler/IR.h"
|
||||
|
||||
/*!
|
||||
* Main table for compiler forms
|
||||
*/
|
||||
static const std::unordered_map<std::string,
|
||||
Val* (Compiler::*)(const goos::Object& form, const goos::Object& rest, Env* env)> goal_forms =
|
||||
{
|
||||
// // inline asm
|
||||
// {".ret", &Compiler::compile_asm},
|
||||
// {".push", &Compiler::compile_asm},
|
||||
// {".pop", &Compiler::compile_asm},
|
||||
// {".jmp", &Compiler::compile_asm},
|
||||
// {".sub", &Compiler::compile_asm},
|
||||
// {".ret-reg", &Compiler::compile_asm},
|
||||
//
|
||||
// // BLOCK FORMS
|
||||
static const std::unordered_map<
|
||||
std::string,
|
||||
Val* (Compiler::*)(const goos::Object& form, const goos::Object& rest, Env* env)>
|
||||
goal_forms = {
|
||||
// // inline asm
|
||||
// {".ret", &Compiler::compile_asm},
|
||||
// {".push", &Compiler::compile_asm},
|
||||
// {".pop", &Compiler::compile_asm},
|
||||
// {".jmp", &Compiler::compile_asm},
|
||||
// {".sub", &Compiler::compile_asm},
|
||||
// {".ret-reg", &Compiler::compile_asm},
|
||||
//
|
||||
// // BLOCK FORMS
|
||||
{"top-level", &Compiler::compile_top_level},
|
||||
{"begin", &Compiler::compile_begin},
|
||||
// {"block", &Compiler::compile_block},
|
||||
// {"return-from", &Compiler::compile_return_from},
|
||||
// {"label", &Compiler::compile_label},
|
||||
// {"goto", &Compiler::compile_goto},
|
||||
//
|
||||
// // COMPILER CONTROL
|
||||
// {"gs", &Compiler::compile_gs},
|
||||
// {"block", &Compiler::compile_block},
|
||||
// {"return-from", &Compiler::compile_return_from},
|
||||
// {"label", &Compiler::compile_label},
|
||||
// {"goto", &Compiler::compile_goto},
|
||||
//
|
||||
// // COMPILER CONTROL
|
||||
// {"gs", &Compiler::compile_gs},
|
||||
{":exit", &Compiler::compile_exit}
|
||||
// {"asm-file", &Compiler::compile_asm_file},
|
||||
// {"test", &Compiler::compile_test},
|
||||
// {"in-package", &Compiler::compile_in_package},
|
||||
//
|
||||
// // CONDITIONAL COMPILATION
|
||||
// {"#cond", &Compiler::compile_gscond},
|
||||
// {"defglobalconstant", &Compiler::compile_defglobalconstant},
|
||||
// {"seval", &Compiler::compile_seval},
|
||||
//
|
||||
// // CONTROL FLOW
|
||||
// {"cond", &Compiler::compile_cond},
|
||||
// {"when-goto", &Compiler::compile_when_goto},
|
||||
//
|
||||
// // DEFINITION
|
||||
// {"define", &Compiler::compile_define},
|
||||
// {"define-extern", &Compiler::compile_define_extern},
|
||||
// {"set!", &Compiler::compile_set},
|
||||
// {"defun-extern", &Compiler::compile_defun_extern},
|
||||
// {"declare-method", &Compiler::compile_declare_method},
|
||||
//
|
||||
// // DEFTYPE
|
||||
// {"deftype", &Compiler::compile_deftype},
|
||||
//
|
||||
// // ENUM
|
||||
// {"defenum", &Compiler::compile_defenum},
|
||||
//
|
||||
// // Field Access
|
||||
// {"->", &Compiler::compile_deref},
|
||||
// {"&", &Compiler::compile_addr_of},
|
||||
//
|
||||
//
|
||||
// // LAMBDA
|
||||
// {"lambda", &Compiler::compile_lambda},
|
||||
// {"inline", &Compiler::compile_inline},
|
||||
// {"with-inline", &Compiler::compile_with_inline},
|
||||
// {"rlet", &Compiler::compile_rlet},
|
||||
// {"mlet", &Compiler::compile_mlet},
|
||||
// {"get-ra-ptr", &Compiler::compile_get_ra_ptr},
|
||||
//
|
||||
//
|
||||
//
|
||||
// // MACRO
|
||||
// {"print-type", &Compiler::compile_print_type},
|
||||
// {"quote", &Compiler::compile_quote},
|
||||
// {"defconstant", &Compiler::compile_defconstant},
|
||||
//
|
||||
// {"declare", &Compiler::compile_declare},
|
||||
//
|
||||
//
|
||||
//
|
||||
//
|
||||
// // OBJECT
|
||||
//
|
||||
// {"the", &Compiler::compile_the},
|
||||
// {"the-as", &Compiler::compile_the_as},
|
||||
//
|
||||
// {"defmethod", &Compiler::compile_defmethod},
|
||||
//
|
||||
// {"current-method-type", &Compiler::compile_current_method_type},
|
||||
// {"new", &Compiler::compile_new},
|
||||
// {"method", &Compiler::compile_method},
|
||||
//
|
||||
// // PAIR
|
||||
// {"car", &Compiler::compile_car},
|
||||
// {"cdr", &Compiler::compile_cdr},
|
||||
//
|
||||
// // IT IS MATH
|
||||
// {"+", &Compiler::compile_add},
|
||||
// {"-", &Compiler::compile_sub},
|
||||
// {"*", &Compiler::compile_mult},
|
||||
// {"/", &Compiler::compile_divide},
|
||||
// {"shlv", &Compiler::compile_shlv},
|
||||
// {"shrv", &Compiler::compile_shrv},
|
||||
// {"sarv", &Compiler::compile_sarv},
|
||||
// {"shl", &Compiler::compile_shl},
|
||||
// {"shr", &Compiler::compile_shr},
|
||||
// {"sar", &Compiler::compile_sar},
|
||||
// {"mod", &Compiler::compile_mod},
|
||||
// {"logior", &Compiler::compile_logior},
|
||||
// {"logxor", &Compiler::compile_logxor},
|
||||
// {"logand", &Compiler::compile_logand},
|
||||
// {"lognot", &Compiler::compile_lognot},
|
||||
// {"=", &Compiler::compile_condition_as_bool},
|
||||
// {"!=", &Compiler::compile_condition_as_bool},
|
||||
// {"eq?", &Compiler::compile_condition_as_bool},
|
||||
// {"not", &Compiler::compile_condition_as_bool},
|
||||
// {"<=", &Compiler::compile_condition_as_bool},
|
||||
// {">=", &Compiler::compile_condition_as_bool},
|
||||
// {"<", &Compiler::compile_condition_as_bool},
|
||||
// {">", &Compiler::compile_condition_as_bool},
|
||||
//
|
||||
// // BUILDER
|
||||
// {"builder", &Compiler::compile_builder},
|
||||
//
|
||||
// // UTIL
|
||||
// {"set-config!", &Compiler::compile_set_config},
|
||||
//
|
||||
//
|
||||
//
|
||||
// {"listen-to-target", &Compiler::compile_listen_to_target},
|
||||
// {"reset-target", &Compiler::compile_reset_target},
|
||||
// {":status", &Compiler::compile_poke},
|
||||
//
|
||||
// // temporary testing hacks...
|
||||
// {"send-test", &Compiler::compile_send_test_data},
|
||||
};
|
||||
// {"asm-file", &Compiler::compile_asm_file},
|
||||
// {"test", &Compiler::compile_test},
|
||||
// {"in-package", &Compiler::compile_in_package},
|
||||
//
|
||||
// // CONDITIONAL COMPILATION
|
||||
// {"#cond", &Compiler::compile_gscond},
|
||||
// {"defglobalconstant", &Compiler::compile_defglobalconstant},
|
||||
// {"seval", &Compiler::compile_seval},
|
||||
//
|
||||
// // CONTROL FLOW
|
||||
// {"cond", &Compiler::compile_cond},
|
||||
// {"when-goto", &Compiler::compile_when_goto},
|
||||
//
|
||||
// // DEFINITION
|
||||
// {"define", &Compiler::compile_define},
|
||||
// {"define-extern", &Compiler::compile_define_extern},
|
||||
// {"set!", &Compiler::compile_set},
|
||||
// {"defun-extern", &Compiler::compile_defun_extern},
|
||||
// {"declare-method", &Compiler::compile_declare_method},
|
||||
//
|
||||
// // DEFTYPE
|
||||
// {"deftype", &Compiler::compile_deftype},
|
||||
//
|
||||
// // ENUM
|
||||
// {"defenum", &Compiler::compile_defenum},
|
||||
//
|
||||
// // Field Access
|
||||
// {"->", &Compiler::compile_deref},
|
||||
// {"&", &Compiler::compile_addr_of},
|
||||
//
|
||||
//
|
||||
// // LAMBDA
|
||||
// {"lambda", &Compiler::compile_lambda},
|
||||
// {"inline", &Compiler::compile_inline},
|
||||
// {"with-inline", &Compiler::compile_with_inline},
|
||||
// {"rlet", &Compiler::compile_rlet},
|
||||
// {"mlet", &Compiler::compile_mlet},
|
||||
// {"get-ra-ptr", &Compiler::compile_get_ra_ptr},
|
||||
//
|
||||
//
|
||||
//
|
||||
// // MACRO
|
||||
// {"print-type", &Compiler::compile_print_type},
|
||||
// {"quote", &Compiler::compile_quote},
|
||||
// {"defconstant", &Compiler::compile_defconstant},
|
||||
//
|
||||
// {"declare", &Compiler::compile_declare},
|
||||
//
|
||||
//
|
||||
//
|
||||
//
|
||||
// // OBJECT
|
||||
//
|
||||
// {"the", &Compiler::compile_the},
|
||||
// {"the-as", &Compiler::compile_the_as},
|
||||
//
|
||||
// {"defmethod", &Compiler::compile_defmethod},
|
||||
//
|
||||
// {"current-method-type", &Compiler::compile_current_method_type},
|
||||
// {"new", &Compiler::compile_new},
|
||||
// {"method", &Compiler::compile_method},
|
||||
//
|
||||
// // PAIR
|
||||
// {"car", &Compiler::compile_car},
|
||||
// {"cdr", &Compiler::compile_cdr},
|
||||
//
|
||||
// // IT IS MATH
|
||||
// {"+", &Compiler::compile_add},
|
||||
// {"-", &Compiler::compile_sub},
|
||||
// {"*", &Compiler::compile_mult},
|
||||
// {"/", &Compiler::compile_divide},
|
||||
// {"shlv", &Compiler::compile_shlv},
|
||||
// {"shrv", &Compiler::compile_shrv},
|
||||
// {"sarv", &Compiler::compile_sarv},
|
||||
// {"shl", &Compiler::compile_shl},
|
||||
// {"shr", &Compiler::compile_shr},
|
||||
// {"sar", &Compiler::compile_sar},
|
||||
// {"mod", &Compiler::compile_mod},
|
||||
// {"logior", &Compiler::compile_logior},
|
||||
// {"logxor", &Compiler::compile_logxor},
|
||||
// {"logand", &Compiler::compile_logand},
|
||||
// {"lognot", &Compiler::compile_lognot},
|
||||
// {"=", &Compiler::compile_condition_as_bool},
|
||||
// {"!=", &Compiler::compile_condition_as_bool},
|
||||
// {"eq?", &Compiler::compile_condition_as_bool},
|
||||
// {"not", &Compiler::compile_condition_as_bool},
|
||||
// {"<=", &Compiler::compile_condition_as_bool},
|
||||
// {">=", &Compiler::compile_condition_as_bool},
|
||||
// {"<", &Compiler::compile_condition_as_bool},
|
||||
// {">", &Compiler::compile_condition_as_bool},
|
||||
//
|
||||
// // BUILDER
|
||||
// {"builder", &Compiler::compile_builder},
|
||||
//
|
||||
// // UTIL
|
||||
// {"set-config!", &Compiler::compile_set_config},
|
||||
//
|
||||
//
|
||||
//
|
||||
// {"listen-to-target", &Compiler::compile_listen_to_target},
|
||||
// {"reset-target", &Compiler::compile_reset_target},
|
||||
// {":status", &Compiler::compile_poke},
|
||||
//
|
||||
// // temporary testing hacks...
|
||||
// {"send-test", &Compiler::compile_send_test_data},
|
||||
};
|
||||
|
||||
Val * Compiler::compile(const goos::Object& code, Env* env) {
|
||||
switch(code.type) {
|
||||
Val* Compiler::compile(const goos::Object& code, Env* env) {
|
||||
switch (code.type) {
|
||||
case goos::ObjectType::PAIR:
|
||||
return compile_pair(code, env);
|
||||
case goos::ObjectType::INTEGER:
|
||||
@@ -144,34 +146,33 @@ Val * Compiler::compile(const goos::Object& code, Env* env) {
|
||||
return get_none();
|
||||
}
|
||||
|
||||
Val * Compiler::compile_pair(const goos::Object& code, Env* env) {
|
||||
Val* Compiler::compile_pair(const goos::Object& code, Env* env) {
|
||||
auto pair = code.as_pair();
|
||||
auto head = pair->car;
|
||||
auto rest = pair->cdr;
|
||||
|
||||
if(head.is_symbol()) {
|
||||
|
||||
if (head.is_symbol()) {
|
||||
auto head_sym = head.as_symbol();
|
||||
// first try as a goal compiler form
|
||||
auto kv_gfs = goal_forms.find(head_sym->name);
|
||||
if(kv_gfs != goal_forms.end()) {
|
||||
if (kv_gfs != goal_forms.end()) {
|
||||
return ((*this).*(kv_gfs->second))(code, rest, env);
|
||||
}
|
||||
|
||||
// todo macro
|
||||
// todo enum
|
||||
}
|
||||
|
||||
|
||||
// todo function or method call
|
||||
ice("unhandled compile_pair on " + code.print());
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Val * Compiler::compile_integer(const goos::Object& code, Env* env) {
|
||||
Val* Compiler::compile_integer(const goos::Object& code, Env* env) {
|
||||
return compile_integer(code.integer_obj.value, env);
|
||||
}
|
||||
|
||||
Val * Compiler::compile_integer(s64 value, Env* env) {
|
||||
Val* Compiler::compile_integer(s64 value, Env* env) {
|
||||
auto fe = get_parent_env_of_type<FunctionEnv>(env);
|
||||
return fe->alloc_val<IntegerConstantVal>(m_ts.make_typespec("int"), value);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,16 +1,15 @@
|
||||
#include "goalc/compiler/Compiler.h"
|
||||
#include "goalc/compiler/IR.h"
|
||||
|
||||
using namespace goos;
|
||||
|
||||
Val * Compiler::compile_top_level(const goos::Object& form, const goos::Object& rest, Env* env) {
|
||||
Val* Compiler::compile_top_level(const goos::Object& form, const goos::Object& rest, Env* env) {
|
||||
return compile_begin(form, rest, env);
|
||||
}
|
||||
|
||||
Val * Compiler::compile_begin(const goos::Object& form, const goos::Object& rest, Env* env) {
|
||||
Val* Compiler::compile_begin(const goos::Object& form, const goos::Object& rest, Env* env) {
|
||||
(void)form;
|
||||
Val* result = get_none();
|
||||
for_each_in_list(rest, [&](const Object& o){
|
||||
result = compile_error_guard(o, env);
|
||||
});
|
||||
for_each_in_list(rest, [&](const Object& o) { result = compile_error_guard(o, env); });
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
#include "goalc/compiler/Compiler.h"
|
||||
#include "goalc/compiler/IR.h"
|
||||
|
||||
Val * Compiler::compile_exit(const goos::Object& form, const goos::Object& rest, Env* env) {
|
||||
Val* Compiler::compile_exit(const goos::Object& form, const goos::Object& rest, Env* env) {
|
||||
(void)env;
|
||||
auto args = get_va(form, rest);
|
||||
va_check(form, args, {}, {});
|
||||
if(m_listener.is_connected()) {
|
||||
m_listener.send_reset();
|
||||
if (m_listener.is_connected()) {
|
||||
m_listener.send_reset(false);
|
||||
}
|
||||
m_want_exit = true;
|
||||
return get_none();
|
||||
|
||||
@@ -156,6 +156,11 @@ InstructionRecord ObjectGenerator::add_instr(Instruction inst, IR_Record ir) {
|
||||
return rec;
|
||||
}
|
||||
|
||||
void ObjectGenerator::add_instr_no_ir(FunctionRecord func, Instruction inst) {
|
||||
assert(func.func_id == int(m_function_data_by_seg.at(func.seg).size()) - 1);
|
||||
m_function_data_by_seg.at(func.seg).at(func.func_id).instructions.push_back(inst);
|
||||
}
|
||||
|
||||
/*!
|
||||
* Create a new static object in the given segment.
|
||||
*/
|
||||
@@ -461,7 +466,7 @@ std::vector<u8> ObjectGenerator::generate_header_v3() {
|
||||
offset += push_data<u32>(N_SEG, result);
|
||||
|
||||
offset += sizeof(u32) * N_SEG * 4; // 4 u32's per segment
|
||||
|
||||
offset += 4;
|
||||
struct SizeOffset {
|
||||
uint32_t offset, size;
|
||||
};
|
||||
|
||||
@@ -44,6 +44,7 @@ class ObjectGenerator {
|
||||
IR_Record add_ir(const FunctionRecord& func);
|
||||
IR_Record get_future_ir_record(const FunctionRecord& func, int ir_id);
|
||||
InstructionRecord add_instr(Instruction inst, IR_Record ir);
|
||||
void add_instr_no_ir(FunctionRecord func, Instruction inst);
|
||||
StaticRecord add_static_to_seg(int seg, int min_align = 16);
|
||||
void link_instruction_jump(InstructionRecord jump_instr, IR_Record destination);
|
||||
void link_static_type_ptr(StaticRecord rec, int offset, const std::string& type_name);
|
||||
|
||||
+31
-17
@@ -18,7 +18,7 @@
|
||||
#include "common/versions.h"
|
||||
|
||||
using namespace versions;
|
||||
constexpr bool debug_listener = true;
|
||||
constexpr bool debug_listener = false;
|
||||
|
||||
namespace listener {
|
||||
Listener::Listener() {
|
||||
@@ -245,10 +245,24 @@ void Listener::receive_func() {
|
||||
}
|
||||
}
|
||||
|
||||
void Listener::send_code(std::vector<uint8_t> &code) {
|
||||
void Listener::record_messages(ListenerMessageKind kind) {
|
||||
if (filter != ListenerMessageKind::MSG_INVALID) {
|
||||
printf("[Listener] Already recording!\n");
|
||||
}
|
||||
filter = kind;
|
||||
}
|
||||
|
||||
std::vector<std::string> Listener::stop_recording_messages() {
|
||||
filter = ListenerMessageKind::MSG_INVALID;
|
||||
auto result = message_record;
|
||||
message_record.clear();
|
||||
return result;
|
||||
}
|
||||
|
||||
void Listener::send_code(std::vector<uint8_t>& code) {
|
||||
got_ack = false;
|
||||
int total_size = code.size() + sizeof(ListenerMessageHeader);
|
||||
if(total_size > BUFFER_SIZE) {
|
||||
if (total_size > BUFFER_SIZE) {
|
||||
printf("[ERROR] Listener send_code got too big of a message\n");
|
||||
return;
|
||||
}
|
||||
@@ -257,7 +271,7 @@ void Listener::send_code(std::vector<uint8_t> &code) {
|
||||
auto* buffer_data = (char*)(header + 1);
|
||||
header->deci2_header.rsvd = 0;
|
||||
header->deci2_header.len = total_size;
|
||||
header->deci2_header.proto = 0xe042; // todo don't hardcode
|
||||
header->deci2_header.proto = 0xe042; // todo don't hardcode
|
||||
header->deci2_header.src = 'H';
|
||||
header->deci2_header.dst = 'E';
|
||||
header->msg_size = code.size();
|
||||
@@ -268,21 +282,21 @@ void Listener::send_code(std::vector<uint8_t> &code) {
|
||||
send_buffer(total_size);
|
||||
}
|
||||
|
||||
void Listener::send_reset() {
|
||||
if(!m_connected) {
|
||||
void Listener::send_reset(bool shutdown) {
|
||||
if (!m_connected) {
|
||||
printf("Not connected, so cannot reset target.\n");
|
||||
return;
|
||||
}
|
||||
auto* header = (ListenerMessageHeader*)m_buffer;
|
||||
header->deci2_header.rsvd = 0;
|
||||
header->deci2_header.len = sizeof(ListenerMessageHeader);
|
||||
header->deci2_header.proto = 0xe042; // todo don't hardcode
|
||||
header->deci2_header.proto = 0xe042; // todo don't hardcode
|
||||
header->deci2_header.src = 'H';
|
||||
header->deci2_header.dst = 'E';
|
||||
header->msg_size = 0;
|
||||
header->ltt_msg_kind = LTT_MSG_RESET;
|
||||
header->u6 = 0;
|
||||
header->u8 = 0;
|
||||
header->u8 = shutdown ? UINT64_MAX : 0;
|
||||
send_buffer(sizeof(ListenerMessageHeader));
|
||||
disconnect();
|
||||
close(socket_fd);
|
||||
@@ -292,25 +306,24 @@ void Listener::send_reset() {
|
||||
void Listener::send_buffer(int sz) {
|
||||
int wrote = 0;
|
||||
|
||||
if(debug_listener) {
|
||||
if (debug_listener) {
|
||||
printf("[L -> T] sending %d bytes...\n", sz);
|
||||
}
|
||||
|
||||
got_ack = false;
|
||||
waiting_for_ack = true;
|
||||
while(wrote < sz) {
|
||||
while (wrote < sz) {
|
||||
auto to_send = std::min(512, sz - wrote);
|
||||
auto x = write(socket_fd, m_buffer + wrote, to_send);
|
||||
wrote += x;
|
||||
}
|
||||
|
||||
if(debug_listener) {
|
||||
if (debug_listener) {
|
||||
printf(" waiting for ack...\n");
|
||||
}
|
||||
|
||||
|
||||
if(wait_for_ack()) {
|
||||
if(debug_listener) {
|
||||
if (wait_for_ack()) {
|
||||
if (debug_listener) {
|
||||
printf("ack buff:\n");
|
||||
printf("%s\n", ack_recv_buff);
|
||||
printf(" OK\n");
|
||||
@@ -321,13 +334,14 @@ void Listener::send_buffer(int sz) {
|
||||
}
|
||||
|
||||
bool Listener::wait_for_ack() {
|
||||
if(!m_connected) {
|
||||
if (!m_connected) {
|
||||
printf("wait_for_ack called when not connected!\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
for(int i = 0; i < 2000; i++) {
|
||||
if(got_ack) return true;
|
||||
for (int i = 0; i < 2000; i++) {
|
||||
if (got_ack)
|
||||
return true;
|
||||
usleep(1000);
|
||||
}
|
||||
|
||||
|
||||
@@ -21,20 +21,17 @@ class Listener {
|
||||
~Listener();
|
||||
bool connect_to_target(const std::string& ip = "127.0.0.1", int port = DECI2_PORT);
|
||||
void record_messages(ListenerMessageKind kind);
|
||||
void stop_recording_messages();
|
||||
std::vector<std::string> stop_recording_messages();
|
||||
bool is_connected() const;
|
||||
void send_reset();
|
||||
void send_reset(bool shutdown);
|
||||
void disconnect();
|
||||
void send_code(std::vector<uint8_t> &code);
|
||||
bool most_recent_send_was_acked() {
|
||||
return got_ack;
|
||||
}
|
||||
void send_code(std::vector<uint8_t>& code);
|
||||
bool most_recent_send_was_acked() { return got_ack; }
|
||||
|
||||
private:
|
||||
void send_buffer(int sz);
|
||||
bool wait_for_ack();
|
||||
|
||||
|
||||
char* m_buffer = nullptr; //! buffer for incoming messages
|
||||
bool m_connected = false; //! do we think we are connected?
|
||||
bool receive_thread_running = false; //! is the receive thread unjoined?
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
void Logger::close() {
|
||||
if (fp) {
|
||||
fclose(fp);
|
||||
fp = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -12,10 +12,12 @@ namespace {
|
||||
* Print out the input data for debugging.
|
||||
*/
|
||||
void print_allocate_input(const AllocationInput& in) {
|
||||
fmt::print("[RegAlloc] Debug Input:\n");
|
||||
fmt::print("[RegAlloc] Debug Input Program:\n");
|
||||
if (in.instructions.size() == in.debug_instruction_names.size()) {
|
||||
for (size_t i = 0; i < in.instructions.size(); i++) {
|
||||
fmt::print(" [{:3d}] {:30} -> {:30}\n", in.debug_instruction_names.at(i),
|
||||
// fmt::print(" [{}] {} -> {}\n", in.debug_instruction_names.at(i),
|
||||
// in.instructions.at(i).print());
|
||||
fmt::print(" [{:3d}] {:30} -> {:30}\n", i, in.debug_instruction_names.at(i),
|
||||
in.instructions.at(i).print());
|
||||
}
|
||||
} else {
|
||||
@@ -23,6 +25,7 @@ void print_allocate_input(const AllocationInput& in) {
|
||||
fmt::print(" [{:3d}] {}\n", instruction.print());
|
||||
}
|
||||
}
|
||||
fmt::print("[RegAlloc] Debug Input Constraints:\n");
|
||||
for (const auto& c : in.constraints) {
|
||||
fmt::print(" {}\n", c.to_string());
|
||||
}
|
||||
|
||||
@@ -14,6 +14,7 @@ add_executable(goalc-test
|
||||
test_emitter_loads_and_store.cpp
|
||||
test_emitter_xmm32.cpp
|
||||
test_emitter_integer_math.cpp
|
||||
test_compiler_and_runtime.cpp
|
||||
)
|
||||
|
||||
IF (WIN32)
|
||||
|
||||
@@ -0,0 +1,109 @@
|
||||
#include <thread>
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
#include "game/runtime.h"
|
||||
#include "goalc/listener/Listener.h"
|
||||
#include "goalc/compiler/Compiler.h"
|
||||
|
||||
TEST(CompilerAndRuntime, ConstructCompiler) {
|
||||
Compiler compiler;
|
||||
}
|
||||
|
||||
TEST(CompilerAndRuntime, StartRuntime) {
|
||||
std::thread runtime_thread([]() { exec_runtime(0, nullptr); });
|
||||
|
||||
listener::Listener listener;
|
||||
while (!listener.is_connected()) {
|
||||
listener.connect_to_target();
|
||||
usleep(1000);
|
||||
}
|
||||
|
||||
listener.send_reset(true);
|
||||
runtime_thread.join();
|
||||
}
|
||||
|
||||
TEST(CompilerAndRuntime, SendProgram) {
|
||||
std::thread runtime_thread([]() { exec_runtime(0, nullptr); });
|
||||
Compiler compiler;
|
||||
compiler.run_test("goal_src/test/test-return-integer-1.gc");
|
||||
compiler.shutdown_target();
|
||||
runtime_thread.join();
|
||||
}
|
||||
|
||||
namespace {
|
||||
std::string escaped_string(const std::string& in) {
|
||||
std::string result;
|
||||
for (auto x : in) {
|
||||
switch (x) {
|
||||
case '\n':
|
||||
result.append("\\n");
|
||||
break;
|
||||
case '\t':
|
||||
result.append("\\t");
|
||||
break;
|
||||
default:
|
||||
result.push_back(x);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
struct CompilerTestRunner {
|
||||
Compiler* c = nullptr;
|
||||
|
||||
struct Test {
|
||||
std::vector<std::string> expected, actual;
|
||||
std::string test_name;
|
||||
};
|
||||
|
||||
std::vector<Test> tests;
|
||||
|
||||
void run_test(const std::string& test_file, const std::vector<std::string>& expected) {
|
||||
auto result = c->run_test("goal_src/test/" + test_file);
|
||||
EXPECT_EQ(result, expected);
|
||||
tests.push_back({expected, result, test_file});
|
||||
}
|
||||
|
||||
void print_summary() {
|
||||
fmt::print("~~ Compiler Test Summary for {} tests... ~~\n", tests.size());
|
||||
int passed = 0;
|
||||
for (auto& test : tests) {
|
||||
if (test.expected == test.actual) {
|
||||
fmt::print("[{:30}] PASS!\n", test.test_name);
|
||||
passed++;
|
||||
} else {
|
||||
fmt::print("[{:30}] FAIL!\n", test.test_name);
|
||||
fmt::print("expected:\n");
|
||||
for (auto& x : test.expected) {
|
||||
fmt::print(" \"{}\"\n", escaped_string(x));
|
||||
}
|
||||
fmt::print("result:\n");
|
||||
for (auto& x : test.actual) {
|
||||
fmt::print(" \"{}\"\n", escaped_string(x));
|
||||
}
|
||||
}
|
||||
}
|
||||
fmt::print("Total: passed {}/{} tests\n", passed, tests.size());
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
TEST(CompilerAndRuntime, CompilerTests) {
|
||||
std::thread runtime_thread([]() { exec_runtime(0, nullptr); });
|
||||
Compiler compiler;
|
||||
CompilerTestRunner runner;
|
||||
runner.c = &compiler;
|
||||
|
||||
runner.run_test("test-return-integer-1.gc", {"4886718345\n"});
|
||||
runner.run_test("test-return-integer-2.gc", {"23\n"});
|
||||
runner.run_test("test-return-integer-3.gc", {"-17\n"});
|
||||
runner.run_test("test-return-integer-4.gc", {"-2147483648\n"});
|
||||
runner.run_test("test-return-integer-5.gc", {"-2147483649\n"});
|
||||
runner.run_test("test-return-integer-6.gc", {"0\n"});
|
||||
runner.run_test("test-return-integer-7.gc", {"-123\n"});
|
||||
|
||||
compiler.shutdown_target();
|
||||
runtime_thread.join();
|
||||
runner.print_summary();
|
||||
}
|
||||
Reference in New Issue
Block a user