/** * @file Codegen.cpp * @brief 寄存器码生成(V2:配置驱动 + 变长指令;compiler 不依赖 isa) * @author * @date 2026-08-21 * * @details 设计说明(详见 Doc/compiler/寄存器码.md 与 Doc/isa/指令与映像.md V2): * - 指令 prefix/op/func 全部来自 machine.toml(MachineConfig);发射经 Codec 位号 * - 数据模型:槽表(8B 引用 {addr,预留})→ 值段(变宽紧凑,1/2/4/8 对齐) * - 常量表 8B 原始值(无 tag),LOADK 按 func 解释,位模式去重 * - 跳转回填字节单位(off32 相对下一条:目标 = 当前指令起点 + 指令长 + off) * - 用户 FB 调用点内联展开(字段访问 = LOAD_OFF/STORE_OFF 实例槽 + 字段偏移) * - 内建 FB → CAL fb_id, 实例槽(fb_id 查 [[fb]] 表) * - max_stack:MAIN + FUNCTION 调用图 DAG 最坏路径 Σ(12 + nregs×8);递归 = 编译期报错 * * 函数清单: * - Builder::Builder 构造;run 布局 → 逐 POU 建函数 → 拼映像 * - emit / emit0 指令发射(查 ConfigOp,Codec 位号写字节) * - E_rr/E_rrr/E_imm/E_slot/E_jmp/E_jc/E_call/E_cal/E_ret/E_slot_off * - func_of_name 语言类型名 → func 位段值 * - compile_stmt/if/while/fb_call/fb_inline/store_target/compile_expr(V1 语义保留) * - patch_jump 字节化回填 * - layout_slots_values 槽表 + 值段布局(全局 + FB 实例,对齐 1/2/4/8) * - compute_max_stack 调用图 DAG 最长路径 + 环检测 * - assemble_image V2 头 128B + 段序拼装 */ #include "compiler/Codegen.h" #include #include #include #include #include #include #include #include "compiler/Codec.h" #include "compiler/MachineConfig.h" #include "compiler/Stb.h" #include "compiler/TypeInfo.h" namespace compiler { namespace { /** * @brief 代码生成器(V2 寄存器码)。 * @details 流程:布局槽表/值段 → 逐 POU 建函数 → 计算 max_stack → 拼映像。 * 寄存器分配:r0 结果、r1..r7 参数(调用约定区,输入只读)、r8+ 变量/临时; * 跳转偏移字节单位相对下一条。失败统一经 fail() 写 err(前缀 "codegen error")。 */ class Builder { public: Builder(const Project& proj, const std::vector& units, const LinkResult& link, const MachineConfig& cfg, std::vector* image, std::string* err, CodegenMap* map) : proj_(proj), units_(units), link_(link), cfg_(cfg), image_(image), err_(err), map_(map) { for (const IoBinding& b : proj_.io) { std::string key = b.var; for (char& ch : key) { ch = static_cast(std::tolower(static_cast(ch))); } if (b.is_input) { io_input_[key] = true; } else { io_output_[key] = true; } } } bool run() { if (!layout_slots_values()) { return false; } for (const LinkResult::PouScope& sc : link_.scopes) { const POU* pou = find_pou(sc.name); if (pou == nullptr) { continue; } FuncCtx f; f.name = sc.name; f.pou_name = sc.name; if (!build_function(*pou, &f)) { return false; } funcs_.push_back(std::move(f)); } if (!compute_max_stack()) { return false; } return assemble_image(); } private: bool fail(const std::string& msg) { if (err_) { *err_ = "codegen error: " + msg; } return false; } /** * @brief 查指令行(MachineConfig 强校验保证存在)。 * @param name 指令名(大写,如 "ADD") * @return 配置行指针(找不到返回 nullptr,不应发生) */ const ConfigOp* opc(const char* name) const { return cfg_.find_op(name); } // ---- 指令发射(V2:Codec 位号写字节)---- /** * @brief 单个函数的编译状态(V2)。 */ struct FuncCtx { std::string name; ///< 函数名 std::string pou_name; ///< 所属 POU 名(实例查找键) std::vector code; ///< 字节码(变长指令,字节流) std::map regs; ///< 变量名 → 帧寄存器 std::map reg_func; ///< 变量名 → func(类型) uint8_t nlocals = 0; ///< 变量区终点 = 临时寄存器起始 uint8_t nregs = 0; ///< 寄存器峰值 uint8_t temp_used = 0; ///< 本语句已用临时数 bool is_function = false; ///< FUNCTION(结果 r0 / 输入只读) std::string result_name; ///< FUNCTION 名(结果寄存器映射) std::vector calls; ///< 本函数 CALL 的 fn_id 列表(max_stack 用) }; /// 发射一条指令:追加 instr_len 字节到函数码流,返回起始字节偏移。 size_t emit(FuncCtx& f, const ConfigOp* op) { const size_t start = f.code.size(); f.code.resize(start + kMaxInstrLen, 0); set_byte0(f.code.data() + start, op->prefix, op->op); if (op->func_mode == "none" || op->func_mode == "width" || op->func_mode == "uint") { set_func(f.code.data() + start, 0); } f.code.resize(start + instr_len(f.code.data() + start)); return start; } /// 双寄存器指令(rd, rs)。 size_t E_rr(FuncCtx& f, const char* name, uint8_t rd, uint8_t rs) { const size_t s = emit(f, opc(name)); set_rd(f.code.data() + s, rd); set_rs1(f.code.data() + s, rs); return s; } /// 三寄存器指令(rd, ra, rb)。 size_t E_rrr(FuncCtx& f, const char* name, uint8_t rd, uint8_t ra, uint8_t rb) { const size_t s = emit(f, opc(name)); set_rd(f.code.data() + s, rd); set_rs1(f.code.data() + s, ra); set_rs2(f.code.data() + s, rb); return s; } /// 立即数指令(rd, imm32)。 size_t E_imm(FuncCtx& f, const char* name, uint8_t rd, uint32_t imm) { const size_t s = emit(f, opc(name)); set_rd(f.code.data() + s, rd); set_imm32(f.code.data() + s, imm); return s; } /// 槽号指令(rd, slot32)。 size_t E_slot(FuncCtx& f, const char* name, uint8_t rd, uint32_t slot) { const size_t s = emit(f, opc(name)); set_rd(f.code.data() + s, rd); set_slot32(f.code.data() + s, slot); return s; } /// 无条件跳转(off 字节相对下一条)。 size_t E_jmp(FuncCtx& f, int32_t off) { const size_t s = emit(f, opc("JMP")); set_off32(f.code.data() + s, off); return s; } /// 条件跳转(r 为真则跳;off 字节相对下一条,JC 形态 off@55..24)。 size_t E_jc(FuncCtx& f, const char* name, uint8_t r, int32_t off) { const size_t s = emit(f, opc(name)); set_rd(f.code.data() + s, r); set_off32_jc(f.code.data() + s, off); return s; } /// CALL 指令(fn_id32)。 size_t E_call(FuncCtx& f, uint32_t fn_id) { const size_t s = emit(f, opc("CALL")); set_fn_id32(f.code.data() + s, fn_id); return s; } /// RET 指令。 size_t E_ret(FuncCtx& f) { const size_t s = emit(f, opc("RET")); return s; } /// 字段访问(实例槽 + 字段偏移,16B SLOT+off)。 size_t E_slot_off(FuncCtx& f, const char* name, uint8_t rd, uint32_t slot, int32_t off) { const size_t s = emit(f, opc(name)); set_rd(f.code.data() + s, rd); set_slot32(f.code.data() + s, slot); set_off32_hi(f.code.data() + s, off); return s; } /// 内建 FB 调用(fb_id16 + 实例槽32)。 size_t E_cal(FuncCtx& f, uint16_t fb_id, uint32_t slot) { const size_t s = emit(f, opc("CAL")); set_fb_id16(f.code.data() + s, fb_id); set_cal_slot32(f.code.data() + s, slot); return s; } /// 语言类型名 → func 位段值(大小写不敏感:符号表存小写,type 表存大写)。 uint8_t func_of_name(const std::string& type_name) const { std::string key = type_name; for (char& ch : key) { ch = static_cast(std::toupper(static_cast(ch))); } const ConfigType* t = cfg_.find_type(key); return t ? static_cast(t->func) : 0; } const POU* find_pou(const std::string& name) const { for (const SourceUnit& u : units_) { for (const POU& p : u.ast.pous) { if (p.name == name) { return &p; } } } return nullptr; } /** * @brief FB 实例布局(V2:槽表条目 + 值区偏移 + 字段偏移)。 */ struct InstFields { std::map field_off; ///< 字段名 → 值区内偏移 std::map field_func; ///< 字段名 → func(类型) uint32_t slot = 0; ///< 实例槽号(槽表条目) std::string type_name; ///< 实例的 FB 类型名 }; void begin_stmt(FuncCtx& f) { f.temp_used = 0; } uint8_t alloc_temp(FuncCtx& f) { const uint8_t r = f.nlocals + f.temp_used; ++f.temp_used; if (static_cast(f.nlocals) + f.temp_used > f.nregs) { f.nregs = f.nlocals + f.temp_used; } return r; } /// 变量名 → 语言类型名(局部声明;标量 = d.type.name 小写)。 std::string type_name_of_var(const POU& pou, const std::string& name) const { for (const VarBlock& b : pou.blocks) { for (const VarDecl& d : b.vars) { if (d.name == name) { return d.type.kind == TypeKind::Scalar ? d.type.name : "int"; } } } return "int"; } bool build_function(const POU& pou, FuncCtx* f) { if (pou.kind == PouKind::FunctionBlock) { f->nlocals = 8; f->nregs = 8; E_ret(*f); return true; } f->is_function = pou.kind == PouKind::Function; f->result_name = pou.name; if (f->is_function) { f->regs[pou.name] = 0; f->reg_func[pou.name] = func_of_name("INT"); uint8_t idx = 1; for (const VarBlock& b : pou.blocks) { if (b.section != VarSection::Input) { continue; } for (const VarDecl& d : b.vars) { f->regs[d.name] = idx++; f->reg_func[d.name] = func_of_name(type_name_of_var(pou, d.name)); } } } uint8_t r = 8; for (const VarBlock& b : pou.blocks) { if (b.section == VarSection::External || b.section == VarSection::Global) { continue; } if (f->is_function && b.section == VarSection::Input) { continue; } for (const VarDecl& d : b.vars) { if (d.type.kind == TypeKind::FbUser || d.type.kind == TypeKind::FbBuiltin) { continue; } f->regs[d.name] = r; f->reg_func[d.name] = func_of_name(type_name_of_var(pou, d.name)); ++r; } } f->nlocals = r; f->nregs = r; if (map_ != nullptr) { std::map vars; for (const auto& kv : f->regs) { std::string tn = "int"; const auto tf = f->reg_func.find(kv.first); if (tf != f->reg_func.end()) { tn = std::to_string(tf->second); } vars[kv.first] = "r" + std::to_string(kv.second) + " (func " + tn + ")"; } map_->funcs.emplace_back(f->name, vars); } for (const Stmt& st : pou.body) { begin_stmt(*f); if (!compile_stmt(*f, st)) { return false; } } E_ret(*f); return true; } bool compile_stmt(FuncCtx& f, const Stmt& st) { if (st.kind == StmtKind::If) { return compile_if(f, st); } if (st.kind == StmtKind::While) { return compile_while(f, st); } if (st.kind == StmtKind::FbCall) { return compile_fb_call(f, st); } if (st.kind != StmtKind::Assign) { return fail("statement not supported"); } if (inline_fields_) { const auto fit = inline_fields_->field_off.find(st.target); if (fit != inline_fields_->field_off.end()) { const uint8_t t = alloc_temp(f); if (!compile_expr(f, *st.value, t)) { return false; } const size_t so = E_slot_off(f, "STORE_OFF", t, inline_fields_->slot, fit->second); const auto ff = inline_fields_->field_func.find(st.target); if (ff != inline_fields_->field_func.end()) { set_func(f.code.data() + so, ff->second); } return true; } } const auto it = f.regs.find(st.target); if (it == f.regs.end()) { return store_target(f, st.target, *st.value); } if (f.is_function && it->second >= 1 && it->second <= 7) { return fail("cannot write function input '" + st.target + "'"); } return compile_expr(f, *st.value, it->second); } bool compile_fb_call(FuncCtx& f, const Stmt& st) { const InstFields* inst = instance_of(f.pou_name, st.instance); if (inst == nullptr) { return fail("no instance '" + st.instance + "' in '" + f.pou_name + "'"); } for (const FbArg& a : st.args) { const auto it = inst->field_off.find(a.name); if (it == inst->field_off.end()) { return fail("unknown input '" + a.name + "' for '" + st.instance + "'"); } const uint8_t t = alloc_temp(f); if (!compile_expr(f, *a.value, t)) { return false; } const size_t so = E_slot_off(f, "STORE_OFF", t, inst->slot, it->second); const auto ff = inst->field_func.find(a.name); if (ff != inst->field_func.end()) { set_func(f.code.data() + so, ff->second); } } // 内建 FB:fb 表查 id const ConfigFb* fb = cfg_.find_fb(uppercase_of(inst->type_name)); if (fb != nullptr) { E_cal(f, static_cast(fb->fb_id), inst->slot); return true; } const POU* user_fb = find_pou(inst->type_name); if (user_fb == nullptr) { return fail("no FB type '" + inst->type_name + "'"); } return compile_fb_inline(f, *user_fb, *inst); } static std::string uppercase_of(const std::string& s) { std::string out = s; for (char& ch : out) { ch = static_cast(std::toupper(static_cast(ch))); } return out; } bool compile_fb_inline(FuncCtx& f, const POU& fb, const InstFields& inst) { const InstFields* saved = inline_fields_; inline_fields_ = &inst; for (const Stmt& s : fb.body) { begin_stmt(f); if (!compile_stmt(f, s)) { return false; } } inline_fields_ = saved; return true; } bool compile_while(FuncCtx& f, const Stmt& st) { const size_t loop = f.code.size(); const uint8_t t = alloc_temp(f); if (!compile_expr(f, *st.cond, t)) { return false; } const size_t jf_idx = E_jc(f, "JF", t, 0); for (const Stmt& s : st.body) { begin_stmt(f); if (!compile_stmt(f, s)) { return false; } } const size_t jmp_idx = E_jmp(f, 0); patch_jump(f, jmp_idx, loop); patch_jump(f, jf_idx, f.code.size()); return true; } bool compile_if(FuncCtx& f, const Stmt& st) { std::vector*>> branches; branches.push_back({st.cond.get(), &st.body}); for (const IfBranch& b : st.elsifs) { branches.push_back({b.cond.get(), &b.body}); } const bool has_else = !st.else_body.empty(); std::vector end_jmps; for (size_t i = 0; i < branches.size(); ++i) { const uint8_t t = alloc_temp(f); if (!compile_expr(f, *branches[i].first, t)) { return false; } const size_t jf_idx = E_jc(f, "JF", t, 0); for (const Stmt& s : *branches[i].second) { begin_stmt(f); if (!compile_stmt(f, s)) { return false; } } if (i + 1 < branches.size() || has_else) { end_jmps.push_back(E_jmp(f, 0)); } patch_jump(f, jf_idx, f.code.size()); } if (has_else) { for (const Stmt& s : st.else_body) { begin_stmt(f); if (!compile_stmt(f, s)) { return false; } } } const size_t end = f.code.size(); for (const size_t j : end_jmps) { patch_jump(f, j, end); } return true; } bool store_target(FuncCtx& f, const std::string& target, const Expr& value) { const auto git = link_.global_index.find(target); if (git == link_.global_index.end()) { return fail("no storage for '" + target + "'"); } if (io_input_.count(target)) { return fail("cannot write to input '" + target + "'"); } const uint8_t tmp = alloc_temp(f); if (!compile_expr(f, value, tmp)) { return false; } E_slot(f, "STORE", tmp, git->second); return true; } bool compile_expr(FuncCtx& f, const Expr& e, uint8_t rd) { if (e.kind == ExprKind::LitBool || e.kind == ExprKind::LitInt || e.kind == ExprKind::LitTime || e.kind == ExprKind::LitReal || e.kind == ExprKind::LitDate || e.kind == ExprKind::LitTod || e.kind == ExprKind::LitDt) { const char* type_name = "INT"; int64_t value = e.int_value; switch (e.kind) { case ExprKind::LitBool: type_name = "BOOL"; break; case ExprKind::LitInt: type_name = "INT"; break; case ExprKind::LitTime: type_name = "TIME"; break; case ExprKind::LitReal: { // TODO(V2): 浮点字面量按目标类型装载(REAL/LREAL 位模式不同), // 需 compile_expr 携带目标 func;当前按 REAL(float32)装载 type_name = "REAL"; float fv = static_cast(e.double_value); std::memcpy(&value, &fv, sizeof fv); break; } case ExprKind::LitDate: type_name = "DATE"; break; case ExprKind::LitTod: type_name = "TOD"; break; case ExprKind::LitDt: type_name = "DT"; break; default: break; } const size_t s = E_imm(f, "LOADK", rd, const_id(value)); set_func(f.code.data() + s, func_of_name(type_name)); return true; } if (e.kind == ExprKind::VarRef) { if (inline_fields_) { const auto fit = inline_fields_->field_off.find(e.name); if (fit != inline_fields_->field_off.end()) { const size_t lo = E_slot_off(f, "LOAD_OFF", rd, inline_fields_->slot, fit->second); const auto ff = inline_fields_->field_func.find(e.name); if (ff != inline_fields_->field_func.end()) { set_func(f.code.data() + lo, ff->second); } return true; } } const auto sit = f.regs.find(e.name); if (sit != f.regs.end()) { const size_t s = E_rr(f, "MOVE", rd, sit->second); const auto tf = f.reg_func.find(e.name); set_func(f.code.data() + s, tf != f.reg_func.end() ? tf->second : func_of_name("INT")); return true; } const auto git = link_.global_index.find(e.name); if (git != link_.global_index.end()) { const size_t s = E_slot(f, "LOAD", rd, git->second); set_func(f.code.data() + s, func_of_global(e.name)); return true; } return fail("no register or slot for '" + e.name + "'"); } if (e.kind == ExprKind::Field) { const InstFields* inst = instance_of(f.pou_name, e.name); if (inst == nullptr) { return fail("no instance '" + e.name + "' in '" + f.pou_name + "'"); } const auto fit = inst->field_off.find(e.field); if (fit == inst->field_off.end()) { return fail("unknown field '" + e.field + "' for '" + e.name + "'"); } const size_t lo = E_slot_off(f, "LOAD_OFF", rd, inst->slot, fit->second); const auto ff = inst->field_func.find(e.field); if (ff != inst->field_func.end()) { set_func(f.code.data() + lo, ff->second); } return true; } if (e.kind == ExprKind::Add || e.kind == ExprKind::Sub || e.kind == ExprKind::Mul || e.kind == ExprKind::Div) { const uint8_t l = alloc_temp(f); if (!compile_expr(f, *e.lhs, l)) { return false; } const uint8_t r = alloc_temp(f); if (!compile_expr(f, *e.rhs, r)) { return false; } const size_t s = E_rrr(f, arith_name(e.kind), rd, l, r); set_func(f.code.data() + s, expr_func(f, *e.lhs, *e.rhs)); return true; } if (e.kind == ExprKind::Cmp) { const uint8_t l = alloc_temp(f); if (!compile_expr(f, *e.lhs, l)) { return false; } const uint8_t r = alloc_temp(f); if (!compile_expr(f, *e.rhs, r)) { return false; } const size_t s = E_rrr(f, cmp_name(e.op), rd, l, r); set_func(f.code.data() + s, expr_func(f, *e.lhs, *e.rhs)); return true; } if (e.kind == ExprKind::Not) { const uint8_t t = alloc_temp(f); if (!compile_expr(f, *e.operand, t)) { return false; } E_rr(f, "NOT", rd, t); return true; } if (e.kind == ExprKind::Neg) { const uint8_t t = alloc_temp(f); if (!compile_expr(f, *e.operand, t)) { return false; } const size_t s = E_rr(f, "NEG", rd, t); set_func(f.code.data() + s, expr_func(f, *e.operand, *e.operand)); return true; } if (e.kind == ExprKind::And || e.kind == ExprKind::Or) { if (!compile_expr(f, *e.lhs, rd)) { return false; } const char* jname = (e.kind == ExprKind::And) ? "JF" : "JT"; const size_t jmp_idx = E_jc(f, jname, rd, 0); const uint8_t t = alloc_temp(f); if (!compile_expr(f, *e.rhs, t)) { return false; } E_rr(f, "MOVE", rd, t); patch_jump(f, jmp_idx, f.code.size()); return true; } if (e.kind == ExprKind::Call) { if (e.args.size() > 7) { return fail("too many arguments (max 7)"); } std::vector args; for (const auto& a : e.args) { const uint8_t t = alloc_temp(f); if (!compile_expr(f, *a, t)) { return false; } args.push_back(t); } const int fn_id = find_fn_id(e.name); if (fn_id < 0) { return fail("no fn_id for '" + e.name + "'"); } for (size_t i = 0; i < args.size(); ++i) { E_rr(f, "MOVE", static_cast(1 + i), args[i]); } f.calls.push_back(static_cast(fn_id)); E_call(f, static_cast(fn_id)); E_rr(f, "MOVE", rd, 0); return true; } return fail("expression not supported"); } /// 表达式类型 func(算术/比较用):VarRef 取 reg_func/全局; /// 嵌套表达式左右递归;字面量按装载类型(LitInt→INT、LitReal→REAL 等)。 uint8_t expr_func(const FuncCtx& f, const Expr& l, const Expr& r) const { if (l.kind == ExprKind::VarRef) { const auto tf = f.reg_func.find(l.name); if (tf != f.reg_func.end()) { return tf->second; } return func_of_global(l.name); } if (l.kind == ExprKind::LitBool || l.kind == ExprKind::LitInt || l.kind == ExprKind::LitTime || l.kind == ExprKind::LitReal || l.kind == ExprKind::LitDate || l.kind == ExprKind::LitTod || l.kind == ExprKind::LitDt) { // 左是字面量 → 取右操作数(Typecheck 已定型同型) if (r.kind == ExprKind::VarRef) { const auto tf = f.reg_func.find(r.name); if (tf != f.reg_func.end()) { return tf->second; } return func_of_global(r.name); } } return func_of_name("INT"); } /// 全局变量 → func(查链接符号类型)。 uint8_t func_of_global(const std::string& name) const { for (const Symbol& s : link_.globals) { if (s.name == name) { return func_of_name(s.type_name); } } return func_of_name("INT"); } int find_fn_id(const std::string& name) const { for (size_t i = 0; i < link_.scopes.size(); ++i) { if (link_.scopes[i].name == name) { return static_cast(i); } } return -1; } /** * @brief 回填跳转偏移(字节单位)。 * @param f 函数编译态 * @param idx 跳转指令起始字节偏移 * @param target_off 目标字节偏移 * @details off 相对下一条:目标 = 当前起点 + 指令长 + off。 */ void patch_jump(FuncCtx& f, size_t idx, size_t target_off) { const int32_t off = static_cast( static_cast(target_off) - (static_cast(idx) + static_cast(instr_len(f.code.data() + idx)))); // 按前缀选偏移字段:JMP(010010)off@47..16;JT/JF(010011)off@55..24 const std::string prefix = prefix_of(f.code.data() + idx); if (prefix == "010010") { set_off32(f.code.data() + idx, off); } else { set_off32_jc(f.code.data() + idx, off); } } static const char* arith_name(ExprKind k) { switch (k) { case ExprKind::Add: return "ADD"; case ExprKind::Sub: return "SUB"; case ExprKind::Mul: return "MUL"; case ExprKind::Div: return "DIV"; default: return "ADD"; } } static const char* cmp_name(BinOp op) { switch (op) { case BinOp::Eq: return "CMP_EQ"; case BinOp::Ne: return "CMP_NE"; case BinOp::Lt: return "CMP_LT"; case BinOp::Le: return "CMP_LE"; case BinOp::Gt: return "CMP_GT"; case BinOp::Ge: return "CMP_GE"; default: return "CMP_EQ"; } } // ---- V2 布局:槽表 → 值段 ---- /** * @brief 布局槽表与值段。 * @details 槽表条目:全局(声明序,每变量 1 条)+ FB 实例(每实例 1 条, * 指向值区块起点)。值段:全局按类型 1/2/4/8 对齐 + 实例字段按 * 字段类型对齐连续排。初值写值段(实例字段 0)。 */ bool layout_slots_values() { uint32_t cur_addr = 0; // 值段当前偏移 for (const Symbol& s : link_.globals) { const TypeMeta tm = type_meta(cfg_, s.type_name); if (!tm) { return fail("no type in machine.toml for '" + s.type_name + "'"); } cur_addr = align_up(cur_addr, tm.width()); slots_.push_back(cur_addr); values_.resize(cur_addr + tm.width(), 0); bool has_init = false; int64_t init = 0; init_of(s.name, &has_init, &init); const int64_t v = has_init ? init : 0; write_value(values_, cur_addr, v, tm.width()); global_slot_[s.name] = static_cast(slots_.size() - 1); if (map_ != nullptr) { map_->globals[s.name] = "slot=" + std::to_string(slots_.size() - 1) + " off=" + std::to_string(cur_addr) + " type=" + s.type_name + " func=" + std::to_string(tm.func()); } cur_addr += tm.width(); } for (const LinkResult::PouScope& sc : link_.scopes) { for (const Symbol& s : sc.syms) { if (s.kind != SymbolKind::FbInstance) { continue; } const auto lay = sc.fb_instances.find(s.name); if (lay == sc.fb_instances.end()) { return fail("no layout for instance '" + s.name + "'"); } InstFields inst; inst.slot = static_cast(slots_.size()); inst.type_name = s.type_name; int32_t off = 0; for (const FbField& fd : lay->second.fields) { const TypeMeta tm = type_meta(cfg_, fd.type_name); if (!tm) { return fail("no type for fb field '" + fd.type_name + "'"); } off = static_cast(align_up(off, tm.width())); inst.field_off[fd.name] = off; inst.field_func[fd.name] = static_cast(tm.func()); off += static_cast(tm.width()); } // 实例块对齐到 max(字段对齐) uint32_t max_align = 1; for (const FbField& fd : lay->second.fields) { const TypeMeta tm = type_meta(cfg_, fd.type_name); max_align = max_align > tm.width() ? max_align : tm.width(); } cur_addr = align_up(cur_addr, max_align); slots_.push_back(cur_addr); values_.resize(cur_addr + static_cast(off), 0); instances_[sc.name + "/" + s.name] = inst; if (map_ != nullptr) { std::string desc = "slot=" + std::to_string(inst.slot) + " off=" + std::to_string(cur_addr) + " fb=" + inst.type_name + " size=" + std::to_string(off) + " "; for (const auto& fo : inst.field_off) { desc += fo.first + "@" + std::to_string(fo.second) + " "; } map_->instances[sc.name + "/" + s.name] = desc; } cur_addr += static_cast(off); } } return true; } static uint32_t align_up(uint32_t v, uint32_t a) { if (a <= 1) { return v; } return (v + a - 1) / a * a; } /// 按宽度写小端值(1/2/4/8 字节)。 static void write_value(std::vector& buf, size_t off, int64_t v, uint32_t width) { for (uint32_t i = 0; i < width; ++i) { buf[off + i] = static_cast((static_cast(v) >> (8 * i)) & 0xFFu); } } const InstFields* instance_of(const std::string& pou, const std::string& name) const { const auto it = instances_.find(pou + "/" + name); return it == instances_.end() ? nullptr : &it->second; } void init_of(const std::string& name, bool* has_init, int64_t* init) const { for (const SourceUnit& u : units_) { for (const VarBlock& b : u.ast.globals) { for (const VarDecl& d : b.vars) { if (d.name == name) { *has_init = d.has_init; *init = d.init_value; return; } } } } *has_init = false; *init = 0; } /// 常量表:8B 原始值位模式去重(无 tag;LOADK 按 func 解释)。 uint16_t const_id(int64_t value) { const uint64_t v = static_cast(value); for (size_t i = 0; i < consts_.size(); ++i) { if (consts_[i] == v) { return static_cast(i); } } consts_.push_back(v); return static_cast(consts_.size() - 1); } /** * @brief max_stack:MAIN + FUNCTION 调用图 DAG 最坏路径 Σ(12 + nregs×8)。 * @return true 成功;false(调用图有环 → "recursive call") */ bool compute_max_stack() { const size_t n = funcs_.size(); // 邻接表:fn_id → 被调 fn_id 列表(权重 = 帧需求) std::vector> edges(n); for (size_t i = 0; i < n; ++i) { for (const uint32_t c : funcs_[i].calls) { if (c < n) { edges[i].push_back(c); } } } // 环检测(DFS 三色)——防御(链接层已拒递归) std::vector color(n, 0); std::vector in_stack(n, false); std::function dfs_cycle = [&](size_t u) -> bool { color[u] = 1; in_stack[u] = true; for (const uint32_t v : edges[u]) { if (color[v] == 0) { if (dfs_cycle(v)) return true; } else if (in_stack[v]) { return true; } } in_stack[u] = false; return false; }; for (size_t i = 0; i < n; ++i) { if (color[i] == 0 && dfs_cycle(i)) { return fail("recursive call detected"); } } // 最长路径(按字节权重)——DAG 上记忆化 std::vector memo(n, -1); std::function best = [&](size_t u) -> int64_t { if (memo[u] >= 0) { return memo[u]; } int64_t b = 0; for (const uint32_t v : edges[u]) { const int64_t cand = 12 + static_cast(funcs_[v].nregs) * 8 + best(v); if (cand > b) { b = cand; } } memo[u] = b; return b; }; int64_t total = 0; for (size_t i = 0; i < n; ++i) { const int64_t need = 12 + static_cast(funcs_[i].nregs) * 8 + best(i); if (need > total) { total = need; } } max_stack_ = static_cast(total); return true; } bool assemble_image() { // 段布局(V2 头 128B + 常量表 8B + 函数表 12B + 字节码 + 槽表 + 值段 + SHA) const uint32_t off_const = static_cast(kHeaderSize); const uint32_t off_funcs = off_const + static_cast(consts_.size()) * kConstEntrySize; uint32_t off_code = off_funcs + static_cast(funcs_.size()) * kFuncRowSize; uint32_t code_total = 0; for (const FuncCtx& f : funcs_) { code_total += static_cast(f.code.size()); } const uint32_t off_slots = align_up(off_code + code_total, 16); const uint32_t off_values = off_slots + static_cast(slots_.size()) * kSlotRowSize; const uint32_t off_end = off_values + static_cast(values_.size()) + static_cast(kSha256Size); std::vector& b = *image_; b.assign(off_end, 0); put_le32(b, kOffMagic, kMagic); put_le32(b, kOffVersion, kVersion); put_le32(b, kOffCycleLimit, proj_.cycle_limit); put_le32(b, kOffDtMs, proj_.dt_ms); uint64_t hash = kFnvBasis; if (!compute_project_hash(proj_, &hash, err_)) { return false; } put_le64(b, kOffProjectHash, hash); uint32_t entry = 0; for (size_t i = 0; i < funcs_.size(); ++i) { if (funcs_[i].name == "main") { entry = static_cast(i); } } put_le32(b, kOffEntryFnId, entry); put_le32(b, kOffNGlobals, static_cast(link_.globals.size())); put_le32(b, kOffNI, 0); put_le32(b, kOffNQ, 0); put_le32(b, kOffNM, 0); put_le32(b, kOffNConsts, static_cast(consts_.size())); put_le32(b, kOffNFuncs, static_cast(funcs_.size())); put_le32(b, kOffConst, off_const); put_le32(b, kOffFuncs, off_funcs); put_le32(b, kOffCode, off_code); put_le32(b, kOffSlots, off_slots); put_le32(b, kOffValues, off_values); put_le32(b, kOffNSlots, static_cast(slots_.size())); put_le32(b, kOffValuesSize, static_cast(values_.size())); put_le32(b, kOffMeta, 0); put_le32(b, kOffMaxStack, max_stack_); char mid[kModelIdSize]; fill_model_id(cfg_.model_name(), cfg_.version(), mid); for (size_t i = 0; i < kModelIdSize; ++i) { b[kOffModelId + i] = static_cast(mid[i]); } // 常量表(8B 原始值) for (size_t i = 0; i < consts_.size(); ++i) { put_le64(b, off_const + i * kConstEntrySize, consts_[i]); } // 函数表(nregs/code_offset/code_len 字节)+ 字节码 uint32_t acc = 0; for (size_t i = 0; i < funcs_.size(); ++i) { const size_t o = off_funcs + i * kFuncRowSize; put_le32(b, o + kFuncNregsOff, funcs_[i].nregs); put_le32(b, o + kFuncCodeOff, acc); put_le32(b, o + kFuncLenOff, static_cast(funcs_[i].code.size())); for (size_t j = 0; j < funcs_[i].code.size(); ++j) { b[off_code + acc + j] = funcs_[i].code[j]; } acc += static_cast(funcs_[i].code.size()); } // 槽表(addr:u32 + 预留:u32) for (size_t i = 0; i < slots_.size(); ++i) { put_le32(b, off_slots + i * kSlotRowSize + kSlotAddrOff, slots_[i]); put_le32(b, off_slots + i * kSlotRowSize + kSlotPadOff, 0); } // 值段 for (size_t i = 0; i < values_.size(); ++i) { b[off_values + i] = values_[i]; } // SHA-256 文件尾(对文件尾之前全部内容) const size_t content_len = off_values + values_.size(); uint8_t digest[kSha256Size]; sha256(&b[0], content_len, digest); for (size_t i = 0; i < kSha256Size; ++i) { b[content_len + i] = digest[i]; } return true; } static void put_le32(std::vector& b, size_t off, uint32_t v) { b[off + 0] = static_cast(v & 0xFFu); b[off + 1] = static_cast((v >> 8) & 0xFFu); b[off + 2] = static_cast((v >> 16) & 0xFFu); b[off + 3] = static_cast((v >> 24) & 0xFFu); } static void put_le64(std::vector& b, size_t off, uint64_t v) { for (int i = 0; i < 8; ++i) { b[off + i] = static_cast((v >> (8 * i)) & 0xFFu); } } // ---- 成员 ---- const Project& proj_; const std::vector& units_; const LinkResult& link_; const MachineConfig& cfg_; std::vector* image_; std::string* err_; std::vector funcs_; std::vector consts_; ///< 常量表(8B 原始值,位模式去重) std::map io_input_; std::map io_output_; std::vector slots_; ///< 槽表 addr 列表 std::vector values_; ///< 值段字节 std::map global_slot_; ///< 全局名 → 槽号 std::map instances_; ///< "POU名/实例名" → 实例布局 const InstFields* inline_fields_ = nullptr; ///< 内联 FB 字段表 uint32_t max_stack_ = 0; ///< 栈区字节数 CodegenMap* map_ = nullptr; ///< 变量/槽映射输出(可空) }; } // namespace /** * @brief 编译工程为 .stb 映像字节(对外入口,V2)。 * @param proj 工程定义 * @param units 全部源文件的 AST * @param link 链接结果 * @param cfg 机器定义(machine.toml V2) * @param image 输出映像字节 * @param err 错误输出;可为 nullptr * @return true 成功;false(err 前缀 "codegen error") */ bool codegen_project(const Project& proj, const std::vector& units, const LinkResult& link, const MachineConfig& cfg, std::vector* image, std::string* err, CodegenMap* map) { Builder b(proj, units, link, cfg, image, err, map); return b.run(); } } // namespace compiler