/* Source code for RCC-Legacy.
Copyright (C) 2026 Richard Qin
This file is part of RCC.
RCC is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free
Software Foundation; either version 3, or (at your option) any later
version.
RCC is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with RCC; see the file LICENSE. If not see
. */
#pragma once
/// @file irgen.h
/// @brief AST -> SSA IR (Braun Algorithm)
///
/// Produces Fn/Blk/Ins/Phi structures defined in all.h.
/// Memory is managed via the injected Ctx (SubPool-backed).
#include "rcc/all.h"
#include "rcc/ast.h"
#include "rcc/symtab.h"
#include
#include
#include
#include
namespace rcc {
/// Global variable data (for data segment emission)
struct GlobalData {
std::string name;
int elem_cls = Kw; // Kw / Ks
size_t total_elems = 0;
bool is_const = false;
bool is_zeroinit = false;
std::vector> init_vals;
};
/// IRGen output
struct IROutput {
std::vector functions;
std::vector globals;
};
/// Export global variables list as data segment syntax.
void print_globals(const std::vector& globals, FILE* f);
class IRGen {
public:
explicit IRGen(Ctx* ctx) : ctx_(ctx) {}
/// Translate AST to IR
IROutput generate(CompUnitNode* root);
private:
Ctx* ctx_;
IROutput output_;
Fn* cur_fn_ = nullptr;
Blk* cur_blk_ = nullptr;
SymbolTable sym_;
// Current function's return K class: Kw / Ks (Kx=-1 for void).
// Do not reuse Fn::retty.
int cur_fn_ret_cls_ = Kx;
// Fn/Blk constructors
/// Create new function
Fn* new_fn(const char* name);
/// Create new basic block
Blk* new_blk(const char* name);
/// Get basic block (by id)
Blk* get_blk(uint id);
/// All blocks in current function (indexed by id)
std::vector blk_vec_;
// constant/Ref constructors
/// Create int constant Ref
Ref make_int_ref(int32_t val);
/// Create float constant Ref
Ref make_float_ref(float val);
/// Create global symbol RCon (CAddr).
/// For call target use only; data access should uniformly go through make_global_addr_ref.
Ref make_global_ref(const char* name);
/// Materialize global symbol into a Tmp (Oaddr Kl).
Ref make_global_addr_ref(const char* name);
/// Create new temporary
Ref new_tmp_ref(int cls);
// Braun SSA algorithm
//
// Index using Symbol::uid rather than variable name to prevent scope shadowing bugs.
std::unordered_map> current_def_;
struct IncompletePhi {
int var_uid;
Phi* phi;
uint block_id;
int cls;
};
std::vector incomplete_phis_;
void write_variable(int uid, Blk* blk, Ref val);
Ref read_variable(int uid, Blk* blk, int cls);
Ref read_variable_recursive(int uid, Blk* blk, int cls);
void seal_block(Blk* blk);
void add_phi_operands(int uid, Blk* blk, Phi* phi, int cls);
Ref try_remove_trivial_phi(Phi* phi);
// Block sealing
std::unordered_map sealed_;
bool is_sealed(Blk* b) const;
// Loop context
struct LoopCtx {
Blk* cond_block;
Blk* exit_block;
};
std::vector loop_stack_;
// AST traversal
void visit_comp_unit(CompUnitNode* node);
void visit_func_def(FuncDefNode* node);
void visit_global_decl(VarDeclNode* node);
void visit_local_decl(VarDeclNode* node);
void visit_stmt(ASTNode* node);
void visit_block(BlockNode* node);
void visit_if(IfStmtNode* node);
void visit_while(WhileStmtNode* node);
void visit_assign(AssignStmtNode* node);
void visit_return(ReturnStmtNode* node);
Ref visit_expr(ASTNode* node);
void visit_cond(ASTNode* cond, Blk* true_bb, Blk* false_bb);
void visit_cond_and(BinaryExprNode* node, Blk* true_bb, Blk* false_bb);
void visit_cond_or(BinaryExprNode* node, Blk* true_bb, Blk* false_bb);
// Instruction emission
Ref emit_ins(int op, int cls, Ref a0, Ref a1);
void emit_store(Ref val, Ref addr, int cls);
Ref emit_load(Ref addr, int cls);
/// IR-level zero-fill loop. Clears [addr, addr+size_bytes) entirely.
void emit_bulk_zero(Ref addr, int size_bytes);
void emit_jmp(Blk* target);
void emit_jnz(Ref cond, Blk* true_bb, Blk* false_bb);
void emit_ret(Ref val, int cls);
void emit_ret_void();
void push_ins(Ins i);
bool cur_blk_terminated() const;
void add_edge(Blk* from, Blk* to);
// Helpers
Ref compute_array_addr(LValNode* node);
Ref get_var_addr_ref(Symbol* sym);
int32_t eval_const_int(ASTNode* node);
float eval_const_float(ASTNode* node);
void flatten_init(const std::vector& dims, ASTNode* init, std::vector& out);
/// BType -> K class (Kw / Ks)
static int btype_to_cls(BType t);
/// Infer actual K class of a Ref.
static int ref_cls_of(Ref r, Fn* fn);
/// Type coercion: Emit Oswtof/Ostosi when Ref's current cls differs from target.
Ref coerce(Ref v, int target_cls);
};
} // namespace rcc