feat(IR): improve IR functions

Add access specifiers and parameter counts to furlang's IR functions.
This commit is contained in:
2026-06-28 13:16:31 +02:00
parent 7b609f87c9
commit 8466902281
5 changed files with 135 additions and 34 deletions
+21 -2
View File
@@ -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,8 +21,12 @@ 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) {
@@ -35,6 +42,18 @@ void furvm_generator::generate_function(furvm::mod& mod, const furlang::ir::func
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;
}
}
static inline furvm::instruction_t binary_op_type(furlang::ir::binary_op_instruction_t type) {
+31 -7
View File
@@ -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) {
+4
View File
@@ -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
View File
@@ -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 (...) {
+41 -11
View File
@@ -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,6 +84,9 @@ 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;
};