IR generation #3

Merged
CHatingPython merged 15 commits from irgen into master 2026-06-01 21:27:39 +00:00
5 changed files with 45 additions and 11 deletions
Showing only changes of commit 62619cd0bc - Show all commits
+7
View File
@@ -35,6 +35,13 @@ public:
void visit(const ast::binop_expression_node& node) override;
void visit(const ast::var_assign_expression_node& node) override;
private:
template <typename T, typename... Args>
void push(Args&&... args) {
if (!m_currentBlock->emplace<T>(std::forward<Args>(args)...)) {
throw std::runtime_error("block exited too soon");
}
}
furlang::ir::block_index push_block();
private:
furlang::ir::module m_module;
+14 -9
View File
@@ -24,6 +24,7 @@ void ir_generator::visit(const ast::function_definition_node& funcDef) {
for (const auto& stmt : funcDef.body()->statements) {
stmt->accept(*this);
}
m_currentBlock->emplace<ir::return_instruction>();
m_module.push(std::move(m_currentFunction));
}
@@ -35,16 +36,16 @@ void ir_generator::visit(const ast::return_statement_node& returnStmt) {
if (returnStmt.value().present()) {
returnStmt.value()->accept(*this);
m_currentBlock->emplace<ir::return_instruction>(ir::operand::new_reg(m_registerCounter - 1));
push<ir::return_instruction>(ir::operand::new_reg(m_registerCounter - 1));
} else {
m_currentBlock->emplace<ir::return_instruction>();
push<ir::return_instruction>();
}
}
void ir_generator::visit(const ast::if_statement_node& node) {
node.cond()->accept(*this);
ir_register cond = m_registerCounter - 1;
m_currentBlock->emplace<ir::branch_cond_instruction>(ir::operand::new_reg(cond),
push<ir::branch_cond_instruction>(ir::operand::new_reg(cond),
m_currentFunction->blocks().size(),
m_currentFunction->blocks().size() + 1);
@@ -68,18 +69,18 @@ void ir_generator::visit(const ast::compound_statement_node& node) {
}
void ir_generator::visit(const ast::string_literal_node& node) {
m_currentBlock->emplace<furlang::ir::assign_instruction>(ir::operand::new_string(std::string(*node.value())),
push<furlang::ir::assign_instruction>(ir::operand::new_string(std::string(*node.value())),
ir::operand::new_reg(m_registerCounter++));
}
void ir_generator::visit(const ast::integer_literal_node& node) {
m_currentBlock->emplace<furlang::ir::assign_instruction>(ir::operand::new_integer(*node.value()),
push<furlang::ir::assign_instruction>(ir::operand::new_integer(*node.value()),
ir::operand::new_reg(m_registerCounter++));
}
void ir_generator::visit(const ast::var_read_expression_node& node) {
if (auto it = m_variables.find(*node.get_name()); it != m_variables.end()) {
m_currentBlock->emplace<furlang::ir::assign_instruction>(ir::operand::new_reg(it->second),
push<furlang::ir::assign_instruction>(ir::operand::new_reg(it->second),
ir::operand::new_reg(m_registerCounter++));
} else {
throw std::runtime_error("unknown variable");
@@ -114,7 +115,7 @@ void ir_generator::visit(const ast::binop_expression_node& node) {
node.rhs()->accept(*this);
ir_register rhs = m_registerCounter - 1;
ir_register dst = m_registerCounter++;
m_currentBlock->emplace<furlang::ir::binary_op_instruction>(binary_op_instruction_t(node.type()),
push<furlang::ir::binary_op_instruction>(binary_op_instruction_t(node.type()),
ir::operand::new_reg(lhs),
ir::operand::new_reg(rhs),
ir::operand::new_reg(dst));
@@ -135,16 +136,20 @@ void ir_generator::visit(const ast::var_assign_expression_node& node) {
auto compound = node.compound();
if (compound != ast::binop_expression_node_t::None) {
m_currentBlock->emplace<ir::binary_op_instruction>(binary_op_instruction_t(compound),
push<ir::binary_op_instruction>(binary_op_instruction_t(compound),
ir::operand::new_reg(reg),
ir::operand::new_reg(rhs),
ir::operand::new_reg(reg));
} else {
m_currentBlock->emplace<ir::assign_instruction>(ir::operand::new_reg(rhs), ir::operand::new_reg(reg));
push<ir::assign_instruction>(ir::operand::new_reg(rhs), ir::operand::new_reg(reg));
}
}
furlang::ir::block_index ir_generator::push_block() {
if (!m_currentFunction->blocks().empty() && !m_currentFunction->blocks().back()->has_exit()) {
throw std::runtime_error(
"block " + std::to_string(m_currentFunction->blocks().size() - 1) + " is lacking an exit");
}
ir::block_index index = m_currentFunction->blocks().size();
m_currentBlock = m_currentFunction->push();
return index;
+1
View File
@@ -39,6 +39,7 @@ int main(void) {
for (const auto& instruction : block->instructions()) {
std::cout << " " << *instruction << '\n';
}
std::cout << " " << *block->exit() << '\n';
}
}
+14 -2
View File
@@ -18,14 +18,26 @@ public:
block() = default;
public:
template <typename T, typename... Args, typename = std::enable_if_t<std::is_base_of_v<instruction, T>>>
void emplace(Args&&... args) {
m_instructions.emplace_back(std::make_unique<T>(std::forward<Args>(args)...));
bool emplace(Args&&... args) {
if (has_exit()) return false;
auto instr = std::make_unique<T>(std::forward<Args>(args)...);
if (is_exit_instruction(instr->type())) {
m_exit = std::move(instr);
} else {
m_instructions.emplace_back(std::move(instr));
}
return true;
}
std::vector<value_type>& instructions() { return m_instructions; }
const std::vector<value_type>& instructions() const { return m_instructions; }
bool has_exit() const { return m_exit != nullptr; }
value_type& exit() { return m_exit; }
const value_type& exit() const { return m_exit; }
private:
std::vector<value_type> m_instructions;
value_type m_exit;
};
} // namespace ir
@@ -20,6 +20,15 @@ enum class instruction_t {
Return,
};
static inline bool is_exit_instruction(instruction_t type) {
switch (type) {
case instruction_t::Branch:
case instruction_t::BranchCond:
case instruction_t::Return: return true;
default: return false;
}
}
class instruction {
public:
instruction() = default;