feat(IR): improve IR functions
Add access specifiers and parameter counts to furlang's IR functions.
This commit is contained in:
+32
-13
@@ -1,6 +1,9 @@
|
||||
#include "furc/back/furvm.hpp"
|
||||
|
||||
#include "furlang/ir/function.hpp"
|
||||
#include "furlang/ir/instruction.hpp"
|
||||
#include "furvm/function.hpp"
|
||||
#include "furvm/fwd.hpp"
|
||||
|
||||
#include <furvm/instruction.hpp>
|
||||
#include <stdexcept>
|
||||
@@ -18,22 +21,38 @@ furvm::mod furvm_generator::generate(furlang::ir::mod& mod) {
|
||||
}
|
||||
|
||||
void furvm_generator::generate_function(furvm::mod& mod, const furlang::ir::function& function) {
|
||||
auto func = mod.emplace_function(function.name(), mod.bytecode().size());
|
||||
func.dispatch();
|
||||
switch (function.type()) {
|
||||
case furlang::ir::function_t::Normal: {
|
||||
if (function.access() == furlang::ir::function_access_t::Public)
|
||||
mod.emplace_function(function.name(), function.param_count(), mod.bytecode().size()).dispatch();
|
||||
else
|
||||
mod.emplace_function_private(function.name(), function.param_count(), mod.bytecode().size()).dispatch();
|
||||
|
||||
function_context ctx;
|
||||
for (furlang::ir::block_index idx = 0; idx < function.blocks().size(); ++idx) {
|
||||
if (auto it = ctx.incompleteJumps.find(idx); it != ctx.incompleteJumps.end()) {
|
||||
for (std::size_t offset : it->second) {
|
||||
mod.bytecode()[offset] = mod.bytecode().size() - offset - 1;
|
||||
function_context ctx;
|
||||
for (furlang::ir::block_index idx = 0; idx < function.blocks().size(); ++idx) {
|
||||
if (auto it = ctx.incompleteJumps.find(idx); it != ctx.incompleteJumps.end()) {
|
||||
for (std::size_t offset : it->second) {
|
||||
mod.bytecode()[offset] = mod.bytecode().size() - offset - 1;
|
||||
}
|
||||
ctx.incompleteJumps.erase(it);
|
||||
}
|
||||
ctx.incompleteJumps.erase(it);
|
||||
}
|
||||
|
||||
ctx.blockOffsets[idx] = mod.bytecode().size();
|
||||
for (const auto& instr : function.blocks()[idx]->instructions())
|
||||
generate_instruction(mod, ctx, *instr);
|
||||
generate_instruction(mod, ctx, *function.blocks()[idx]->exit());
|
||||
ctx.blockOffsets[idx] = mod.bytecode().size();
|
||||
for (const auto& instr : function.blocks()[idx]->instructions())
|
||||
generate_instruction(mod, ctx, *instr);
|
||||
generate_instruction(mod, ctx, *function.blocks()[idx]->exit());
|
||||
}
|
||||
} break;
|
||||
case furlang::ir::function_t::Import: {
|
||||
throw std::runtime_error("unimplemented");
|
||||
// mod.emplace_function_private(function.name(), function.param_count(), mod.bytecode().size()).dispatch();
|
||||
} break;
|
||||
case furlang::ir::function_t::Native: {
|
||||
if (function.access() == furlang::ir::function_access_t::Public)
|
||||
mod.emplace_function(function.name(), function.param_count(), function.name()).dispatch();
|
||||
else
|
||||
mod.emplace_function_private(function.name(), function.param_count(), function.name()).dispatch();
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -4,10 +4,14 @@
|
||||
#include "furc/ast/expression.hpp" // IWYU pragma: keep
|
||||
#include "furc/ast/literal.hpp" // IWYU pragma: keep
|
||||
#include "furc/ast/statement.hpp" // IWYU pragma: keep
|
||||
#include "furlang/ir/function.hpp"
|
||||
#include "furlang/ir/instruction.hpp"
|
||||
#include "furlang/ir/operand.hpp"
|
||||
|
||||
#include <cassert>
|
||||
#include <memory>
|
||||
#include <stdexcept>
|
||||
#include <vector>
|
||||
|
||||
namespace furc::front {
|
||||
|
||||
@@ -16,7 +20,11 @@ namespace ir = furlang::ir;
|
||||
}
|
||||
|
||||
void ir_generator::visit(const ast::function_definition_node& funcDef) {
|
||||
m_currentFunction = std::make_unique<furlang::ir::function>(std::string(funcDef.name()));
|
||||
furlang::ir::function_access_t access = (funcDef.access() == ast::declaration_access_t::Public)
|
||||
? furlang::ir::function_access_t::Public
|
||||
: furlang::ir::function_access_t::Private;
|
||||
|
||||
m_currentFunction = std::make_unique<furlang::ir::function>(std::string(funcDef.name()), access, 0);
|
||||
|
||||
push_block();
|
||||
for (const auto& stmt : funcDef.body().statements) {
|
||||
@@ -28,6 +36,21 @@ void ir_generator::visit(const ast::function_definition_node& funcDef) {
|
||||
m_module.push(std::move(m_currentFunction));
|
||||
}
|
||||
|
||||
void ir_generator::visit(const ast::function_declaration_node& funcDecl) {
|
||||
if (funcDecl.type() == ast::function_declaration_node_t::Normal) return;
|
||||
|
||||
furlang::ir::function_t type = funcDecl.type() == ast::function_declaration_node_t::Import
|
||||
? furlang::ir::function_t::Import
|
||||
: furlang::ir::function_t::Native;
|
||||
|
||||
furlang::ir::function_access_t access = (funcDecl.access() == ast::declaration_access_t::Public)
|
||||
? furlang::ir::function_access_t::Public
|
||||
: furlang::ir::function_access_t::Private;
|
||||
|
||||
m_module.push(
|
||||
std::make_unique<furlang::ir::function>(std::string(funcDecl.name()), access, funcDecl.params().size(), type));
|
||||
}
|
||||
|
||||
void ir_generator::visit(const ast::return_statement_node& returnStmt) {
|
||||
if (returnStmt.value().has_value()) {
|
||||
returnStmt.value().value()->accept(*this);
|
||||
@@ -149,12 +172,7 @@ void ir_generator::visit(const ast::var_assign_expression_node& node) {
|
||||
assert(node.lhs()->expression_type() == ast::expression_node_t::VarRead);
|
||||
auto lhs = std::dynamic_pointer_cast<ast::var_read_expression_node>(node.lhs());
|
||||
|
||||
ir_register reg = 0;
|
||||
if (auto it = m_variables.find(lhs->get_name()); it != m_variables.end()) {
|
||||
reg = it->second;
|
||||
} else {
|
||||
m_variables[lhs->get_name()] = reg = m_registerCounter++;
|
||||
}
|
||||
ir_register reg = m_registerCounter++;
|
||||
|
||||
auto compound = node.compound();
|
||||
if (compound != ast::binop_expression_node_t::None) {
|
||||
@@ -165,6 +183,12 @@ void ir_generator::visit(const ast::var_assign_expression_node& node) {
|
||||
} else {
|
||||
push<ir::assign_instruction>(ir::operand::new_reg(rhs), ir::operand::new_reg(reg));
|
||||
}
|
||||
|
||||
if (auto it = m_variables.find(lhs->get_name()); it != m_variables.end()) {
|
||||
push<ir::assign_instruction>(ir::operand::new_reg(reg), ir::operand::new_reg(it->second));
|
||||
} else {
|
||||
m_variables[lhs->get_name()] = reg;
|
||||
}
|
||||
}
|
||||
|
||||
void ir_generator::visit(const ast::function_call_expression_node& node) {
|
||||
|
||||
@@ -546,6 +546,10 @@ static void adce_stage(function_context& ctx) {
|
||||
if (instr->has_destination() && instr->destination().type() == furlang::ir::operand_t::Register) {
|
||||
defMap[instr->destination().reg()] = instr.get();
|
||||
}
|
||||
if (instr->type() == furlang::ir::instruction_t::Call) {
|
||||
// TODO: Check if the function has side effects
|
||||
if (alive.insert(instr.get()).second) worklist.push(instr.get());
|
||||
}
|
||||
}
|
||||
|
||||
auto* exit = block->exit().get();
|
||||
|
||||
+26
-2
@@ -8,12 +8,13 @@
|
||||
#include "furlang/arena.hpp"
|
||||
|
||||
#include <fstream>
|
||||
#include <furvm/furvm.hpp>
|
||||
#include <iostream>
|
||||
|
||||
int main(void) {
|
||||
try {
|
||||
std::string programStr = R"(
|
||||
native func print(value: int32);
|
||||
private native func print(value: int32);
|
||||
|
||||
func main() -> int32 {
|
||||
x = 0;
|
||||
@@ -22,6 +23,7 @@ int main(void) {
|
||||
while (x < y) {
|
||||
x = x + z;
|
||||
}
|
||||
print(x);
|
||||
}
|
||||
)";
|
||||
furlang::arena arena{};
|
||||
@@ -58,8 +60,30 @@ int main(void) {
|
||||
}
|
||||
}
|
||||
|
||||
auto context = std::make_shared<furvm::context>();
|
||||
auto furvmMod = context->emplace_module("main", furc::back::furvm_generator::generate(mod));
|
||||
|
||||
std::ofstream file("./a.fmod", std::ios::binary);
|
||||
furc::back::furvm_generator::generate(mod).serialize(file);
|
||||
furvmMod->serialize(file);
|
||||
file.close();
|
||||
|
||||
furvmMod->set_native_function("print", [](furvm::executor& executor) {
|
||||
furvm::thing_h thing = executor.load_thing(0);
|
||||
switch (thing->type()) {
|
||||
case furvm::thing_t::Int32: {
|
||||
std::cout << thing->int32() << '\n';
|
||||
} break;
|
||||
}
|
||||
});
|
||||
|
||||
furvm::executor_h executor = context->emplace_executor(context);
|
||||
executor->push_frame(furvmMod, *furvmMod->function_at("main"));
|
||||
|
||||
std::cout << "--- Interpreting:\n";
|
||||
|
||||
while ((executor->flags() & furvm::executor_flags::Done) != furvm::executor_flags::Done) {
|
||||
executor->step();
|
||||
}
|
||||
|
||||
return 0;
|
||||
} catch (...) {
|
||||
|
||||
Reference in New Issue
Block a user