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 (...) {
|
||||
|
||||
@@ -3,12 +3,25 @@
|
||||
|
||||
#include "furlang/ir/block.hpp"
|
||||
|
||||
#include <cstdint>
|
||||
#include <memory>
|
||||
#include <type_traits>
|
||||
#include <vector>
|
||||
|
||||
namespace furlang {
|
||||
namespace ir {
|
||||
|
||||
enum class function_t : std::uint8_t {
|
||||
Normal = 0,
|
||||
Import,
|
||||
Native,
|
||||
};
|
||||
|
||||
enum class function_access_t : std::uint8_t {
|
||||
Public = 0,
|
||||
Private,
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief IR function.
|
||||
*
|
||||
@@ -22,18 +35,11 @@ public:
|
||||
/**
|
||||
* @brief Construct a new IR function.
|
||||
*
|
||||
* @param name Name to copy.
|
||||
* @param name Name to forward.
|
||||
*/
|
||||
function(const std::string& name)
|
||||
: m_name(name) {}
|
||||
|
||||
/**
|
||||
* @brief Construct a new IR function.
|
||||
*
|
||||
* @param name Name to move.
|
||||
*/
|
||||
function(std::string&& name)
|
||||
: m_name(std::move(name)) {}
|
||||
template <typename StringFwd, typename = std::enable_if_t<std::is_constructible_v<std::string, StringFwd>>>
|
||||
function(StringFwd&& name, function_access_t access, std::uint32_t paramCount, function_t type = function_t::Normal)
|
||||
: m_name(std::forward<StringFwd>(name)), m_access(access), m_paramCount(paramCount), m_type(type) {}
|
||||
public:
|
||||
/**
|
||||
* @brief Returns this function's name.
|
||||
@@ -42,6 +48,27 @@ public:
|
||||
*/
|
||||
const std::string& name() const { return m_name; }
|
||||
|
||||
/**
|
||||
* @brief Returns the function's access.
|
||||
*
|
||||
* @return The access.
|
||||
*/
|
||||
function_access_t access() const { return m_access; }
|
||||
|
||||
/**
|
||||
* @brief Returns this function's parameter count.
|
||||
*
|
||||
* @return The parameter count.
|
||||
*/
|
||||
std::uint32_t param_count() const { return m_paramCount; }
|
||||
|
||||
/**
|
||||
* @brief Returns this function's type.
|
||||
*
|
||||
* @return The type.
|
||||
*/
|
||||
function_t type() const { return m_type; }
|
||||
|
||||
/**
|
||||
* @brief Pushes and returns a new IR block.
|
||||
*
|
||||
@@ -57,10 +84,13 @@ public:
|
||||
const std::vector<value_type>& blocks() const { return m_blocks; }
|
||||
private:
|
||||
std::string m_name;
|
||||
function_access_t m_access;
|
||||
function_t m_type;
|
||||
std::uint32_t m_paramCount;
|
||||
std::vector<value_type> m_blocks;
|
||||
};
|
||||
|
||||
} // namespace ir
|
||||
} // namespace furlang
|
||||
|
||||
#endif // FURLANG_IR_FUNCTION_HPP
|
||||
#endif // FURLANG_IR_FUNCTION_HPP
|
||||
|
||||
Reference in New Issue
Block a user