From 8466902281592a047654e4c433ebae145d89bf76 Mon Sep 17 00:00:00 2001 From: CHatingPython Date: Sun, 28 Jun 2026 13:16:31 +0200 Subject: [PATCH] feat(IR): improve IR functions Add access specifiers and parameter counts to furlang's IR functions. --- furc/src/back/furvm.cpp | 45 +++++++++++++++------ furc/src/front/ir_generator.cpp | 38 +++++++++++++---- furc/src/front/post_process.cpp | 4 ++ furc/src/main.cpp | 28 ++++++++++++- furlang/include/furlang/ir/function.hpp | 54 +++++++++++++++++++------ 5 files changed, 135 insertions(+), 34 deletions(-) diff --git a/furc/src/back/furvm.cpp b/furc/src/back/furvm.cpp index 67871c5..cd26e13 100644 --- a/furc/src/back/furvm.cpp +++ b/furc/src/back/furvm.cpp @@ -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 #include @@ -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; } } diff --git a/furc/src/front/ir_generator.cpp b/furc/src/front/ir_generator.cpp index c37cb43..9c40260 100644 --- a/furc/src/front/ir_generator.cpp +++ b/furc/src/front/ir_generator.cpp @@ -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 #include +#include +#include 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(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(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(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(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::operand::new_reg(rhs), ir::operand::new_reg(reg)); } + + if (auto it = m_variables.find(lhs->get_name()); it != m_variables.end()) { + push(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) { diff --git a/furc/src/front/post_process.cpp b/furc/src/front/post_process.cpp index 31281b2..2717e78 100644 --- a/furc/src/front/post_process.cpp +++ b/furc/src/front/post_process.cpp @@ -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(); diff --git a/furc/src/main.cpp b/furc/src/main.cpp index abaac39..ce50a28 100644 --- a/furc/src/main.cpp +++ b/furc/src/main.cpp @@ -8,12 +8,13 @@ #include "furlang/arena.hpp" #include +#include #include 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(); + 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 (...) { diff --git a/furlang/include/furlang/ir/function.hpp b/furlang/include/furlang/ir/function.hpp index 4835c18..9a434fe 100644 --- a/furlang/include/furlang/ir/function.hpp +++ b/furlang/include/furlang/ir/function.hpp @@ -3,12 +3,25 @@ #include "furlang/ir/block.hpp" +#include #include +#include #include 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 >> + function(StringFwd&& name, function_access_t access, std::uint32_t paramCount, function_t type = function_t::Normal) + : m_name(std::forward(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& 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 m_blocks; }; } // namespace ir } // namespace furlang -#endif // FURLANG_IR_FUNCTION_HPP \ No newline at end of file +#endif // FURLANG_IR_FUNCTION_HPP