/* 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