From 0a36e36b16fd3bdcdd0b34281840ababc52415c9 Mon Sep 17 00:00:00 2001 From: chentianya Date: Fri, 21 Aug 2026 11:48:33 +0800 Subject: [PATCH] =?UTF-8?q?12.8=20=E5=88=87=E7=89=87=206=EF=BC=9AFUNCTION?= =?UTF-8?q?=20=E4=B8=8E=20CALL=EF=BC=8C=E5=86=BB=E7=BB=93=E8=B0=83?= =?UTF-8?q?=E7=94=A8=E7=BA=A6=E5=AE=9A=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 调用约定(冻结进 isa 规格与 12.8 文档):结果 r0、参数 r1..r7(最多 7 输入、函数内只读)、 变量与临时全部从 r8 起;CALL/RET 时 VM 复制 r0..r7(12.9 实现) - 调用点:实参求值到 r8+ 临时 → MOVE r(1+i) → CALL fn_id → MOVE rd, r0 - 函数名赋值 = 写 r0(结果);写函数输入 → codegen error - codegen_test:134 断言(用例 13 两函数 CALL 序列;既有用例帧基址迁移 r8 起),ctest 9/9 --- Doc/compiler/寄存器码.md | 14 ++++ Doc/isa/指令与映像.md | 8 ++ compiler/src/Codegen.cpp | 104 +++++++++++++++++++----- tests/src/codegen_test.cpp | 159 ++++++++++++++++++++++++------------- 4 files changed, 213 insertions(+), 72 deletions(-) diff --git a/Doc/compiler/寄存器码.md b/Doc/compiler/寄存器码.md index 7e9cb80..a50d4ed 100644 --- a/Doc/compiler/寄存器码.md +++ b/Doc/compiler/寄存器码.md @@ -30,6 +30,20 @@ compiler 模块的代码生成。输入:`Project` + `Unit`(AST)+ `LinkResu - 字段访问 `fb.Q`:`LOAD_GLOBAL rd, <实例基址+字段偏移>`(编译期算死);I/Q/M 用 `LOAD_I` / `STORE_Q` / `LOAD_M` / `STORE_M` 同槽号 - 函数帧寄存器:`FUNCTION` 结果固定 **r0**,`VAR_INPUT` 从 r1 起按声明序,`VAR` 续后;PROGRAM / FB 变量从 r0 起按声明序 +### 调用约定(v1 冻结,VM 12.9 按此实现) + +| 项 | 约定 | +|---|---| +| 结果寄存器 | **r0**(FUNCTION 结果写入处) | +| 参数寄存器 | **r1..r7**(最多 7 个输入,按声明序) | +| 变量 / 临时 | **全部从 r8 起**(调用约定区不受覆盖) | +| `CALL` | VM 复制当前帧 **r0..r7 → 新帧 r0..r7** | +| `RET` | VM 复制当前帧 **r0..r7 → 调用方帧 r0..r7**(r0=结果,r1..r7 原样返回) | +| 函数输入 | 函数体内**只读**(写输入 → codegen error) | + +- 调用点:实参求值到 r8+ 临时 → `MOVE r(1+i), t` → `CALL fn_id` → `MOVE rd, r0` +- 所有 POU 的变量/临时统一 r8 起,故 r1..r7 在调用点可安全覆盖 + ## 寄存器分配 - 局部变量固定占用前段(0..k-1) diff --git a/Doc/isa/指令与映像.md b/Doc/isa/指令与映像.md index 2256c8a..082d43f 100644 --- a/Doc/isa/指令与映像.md +++ b/Doc/isa/指令与映像.md @@ -47,6 +47,14 @@ CMake 目标:`isa`(`STATIC`),无依赖。公开头:`isa/include/isa/` | 寄存器 | 下标 0..255;每函数实际个数写在函数头 `nregs` | | 跳转 | 相对 offset,单位是**指令条数**,不是字节 | | `CALL` | 立即数 `fn_id`(u16),无函数指针 | + +### 调用约定(冻结,compiler 12.8 与 VM 12.9 共同遵守) + +- 结果寄存器 **r0**;参数寄存器 **r1..r7**(最多 7 个输入,按声明序) +- 变量与表达式临时**全部从 r8 起**(调用约定区 r0..r7 不受用户数据占用) +- `CALL`:VM 复制当前帧 r0..r7 到新帧 r0..r7 +- `RET`:VM 复制当前帧 r0..r7 回调用方帧 r0..r7(r0 = 结果;r1..r7 原样返回) +- 函数输入在函数体内只读(compiler 拒绝写入) | 映像魔数 | `STSC`,版本 `1` | | 工程哈希 | 源文件路径排序后对内容做 FNV-1a 64(非密码学) | | I/O 绑定 | **不进映像**;编译期把 `var` 收成槽号,channel/bit 由 STCompiler 写进 sidecar(`.runtime.toml`),BytecodeExecutor 读 sidecar 采样 | diff --git a/compiler/src/Codegen.cpp b/compiler/src/Codegen.cpp index 796e036..8aed05f 100644 --- a/compiler/src/Codegen.cpp +++ b/compiler/src/Codegen.cpp @@ -1,15 +1,15 @@ /** * @file Codegen.cpp - * @brief 寄存器码生成(12.8,切片 5:+ WHILE、四则运算) + * @brief 寄存器码生成(12.8,切片 6:+ FUNCTION 与 CALL) * @author * @date 2026-08-21 * * @details 设计说明(详见 Doc/compiler/寄存器码.md): - * - 切片 1~4:帧/字面量/MOVE/RET;全局数据区;NOT 与短路 AND/OR;CMP 与 IF。 - * - 切片 5:WHILE 编成 - * L_loop: JF t, L_end JMP L_loop L_end: - * (用例 5 循环体含自增,四则 ADD/SUB/MUL/DIV 同模式一并实现,用例 7 可测) - * - 跳转偏移相对下一条指令(目标 = 当前 + 1 + off,见 Doc/isa/指令与映像.md) + * - 切片 1~5:帧/字面量/MOVE/RET;全局数据区;NOT 与短路 AND/OR;CMP 与 IF;WHILE 与四则。 + * - 切片 6:调用约定(冻结)——结果 r0、参数 r1..r7(最多 7 输入、函数内只读)、 + * 变量与临时全部从 r8 起(调用约定区不受覆盖); + * CALL 时 VM 复制 r0..r7 到新帧、RET 复制回调用方(r0=结果); + * 调用点:实参求值到 r8+ 临时 → MOVE r(1+i) → CALL fn_id → MOVE rd, r0 * - 其余构造报 codegen error(后续切片展开) * * 函数清单: @@ -19,13 +19,14 @@ * - Builder::run 布局数据区 → 逐 POU 建函数 → 拼映像 * - Builder::fail 组装 "codegen error: " 返回 false * - find_pou 按名查 POU AST - * - build_function 编译一个 POU 的语句体(帧寄存器分配) + * - find_fn_id 按名查 fn_id(POU 收集序) + * - build_function 编译一个 POU(PROGRAM/FUNCTION;帧约定分配) * - begin_stmt / alloc_temp 临时寄存器:语句内递增、语句结束复用基址 - * - compile_stmt 语句编译(切片 5:赋值 / IF / WHILE) + * - compile_stmt 语句编译(赋值 / IF / WHILE;函数输入只读) * - compile_if IF/ELSIF/ELSE:条件链 + 分支尾部 JMP,JF/JMP 回填 * - compile_while WHILE:L_loop + 条件 JF + 体 + JMP 回环 * - store_target 赋值左值:STORE_* 到全局槽 - * - compile_expr 表达式编译到寄存器(含 CMP/算术/NOT/短路 AND/OR) + * - compile_expr 表达式编译到寄存器(含 CMP/算术/NOT/短路/CALL) * - cmp_op / arith_op 比较符/算术符 → 操作码 * - load_op / store_op 按 io 绑定选读取/写入操作码 * - global_offset 逻辑槽号 → 数据区字节偏移 @@ -176,9 +177,11 @@ namespace { std::string name; std::vector code; // 字节码(函数表 code_offset 相对此段) std::map regs; // 变量名 → 帧寄存器 - uint8_t nlocals = 0; // 变量数 = 临时寄存器起始 + uint8_t nlocals = 0; // 变量区终点 = 临时寄存器起始 uint8_t nregs = 0; // 峰值(变量 + 临时) uint8_t temp_used = 0; // 本语句已用临时数(语句结束清零) + bool is_function = false; // FUNCTION(结果 r0 / 输入只读) + std::string result_name; // FUNCTION 名(结果寄存器映射) }; /** @@ -203,31 +206,53 @@ namespace { /** * @brief 编译一个 POU - * @details 切片 1:仅 PROGRAM + 标量变量(FB 实例/函数留后续切片) + * @details 切片 6:支持 PROGRAM 与 FUNCTION(FB 留切片 8) + * 帧约定(见 Doc/compiler/寄存器码.md):结果 r0、输入 r1..r7(只读)、 + * 变量与临时全部从 r8 起 * @param pou POU AST * @param f 输出函数编译态 * @return true 成功;false(err 已写) */ bool build_function(const POU& pou, FuncCtx* f) { - if (pou.kind != PouKind::Program) { - return fail("only PROGRAM supported in slice 1 ('" + pou.name + "')"); + if (pou.kind == PouKind::FunctionBlock) { + return fail("FB not supported in slice 6 ('" + pou.name + "')"); } + f->is_function = pou.kind == PouKind::Function; + f->result_name = pou.name; + if (f->is_function) { + f->regs[pou.name] = 0; // 结果寄存器 r0 + 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++; // 输入 r1..r7 + } + } + } + uint8_t r = 8; // 变量/临时基址(调用约定区 r0..r7 不占用) for (const VarBlock& b : pou.blocks) { // External / Global 走数据区槽,不占帧寄存器 if (b.section == VarSection::External || b.section == VarSection::Global) { continue; } + // FUNCTION 输入已分配(r1..r7) + 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) { - return fail("FB instance not supported in slice 1 ('" + d.name + "')"); + return fail("FB instance not supported in slice 6 ('" + d.name + "')"); } - if (f->regs.size() > 255) { + if (r > 255) { return fail("register overflow in function '" + pou.name + "'"); } - f->regs[d.name] = f->nregs++; + f->regs[d.name] = r++; } } - f->nlocals = f->nregs; + f->nlocals = r; + f->nregs = r; for (const Stmt& st : pou.body) { begin_stmt(*f); if (!compile_stmt(*f, st)) { @@ -259,6 +284,10 @@ namespace { // 全局 / 外部左值 → STORE_* 到数据区 return store_target(f, st.target, *st.value); } + // 函数输入只读(调用约定,见 Doc/compiler/寄存器码.md) + if (f.is_function && it->second >= 1 && it->second <= 7) { + return fail("cannot write function input '" + st.target + "'"); + } const uint8_t rd = it->second; return compile_expr(f, *st.value, rd); } @@ -452,7 +481,46 @@ namespace { patch_jump(f, jmp_idx, f.code.size()); return true; } - return fail("expression not supported in slice 3"); + if (e.kind == ExprKind::Call) { + // 调用约定:实参求值到 r8+ 临时 → MOVE 到 r1..r7 → CALL → 结果 r0 + 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) { + f.code.push_back( + isa::enc_rr(isa::Op::MOVE, static_cast(1 + i), args[i])); + } + f.code.push_back(isa::enc_call(static_cast(fn_id))); + f.code.push_back(isa::enc_rr(isa::Op::MOVE, rd, 0)); + return true; + } + return fail("expression not supported in slice 6"); + } + + /** + * @brief 按名查 fn_id(POU 收集序下标) + * @param name POU 名(小写) + * @return fn_id;未找到返回 -1 + */ + 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; } /** diff --git a/tests/src/codegen_test.cpp b/tests/src/codegen_test.cpp index 8dac32a..2418128 100644 --- a/tests/src/codegen_test.cpp +++ b/tests/src/codegen_test.cpp @@ -121,7 +121,7 @@ static bool test_case01() { CHECK(v.header().project_hash != isa::kFnvBasis); const isa::FuncRow r = v.func_row(0); - CHECK(r.nregs == 0); + CHECK(r.nregs == 8); // 帧基址(调用约定区) CHECK(r.code_len == 1); char buf[32]; @@ -143,16 +143,16 @@ static bool test_case02() { CHECK(v.header().n_consts == 2); // TRUE 与 FALSE const isa::FuncRow r = v.func_row(0); - CHECK(r.nregs == 2); // a, b + CHECK(r.nregs == 10); // a, b(r8 起) CHECK(r.code_len == 3); // 从字节码段取指令(按函数行 code_offset 定位) const uint8_t* base = v.code_bytes(); char buf[64]; isa::disasm(reinterpret_cast(base)[0], buf, sizeof buf); - CHECK(std::strcmp(buf, "LOADK r0, 0") == 0); // a := TRUE(常量 0) + CHECK(std::strcmp(buf, "LOADK r8, 0") == 0); // a := TRUE(常量 0) isa::disasm(reinterpret_cast(base)[1], buf, sizeof buf); - CHECK(std::strcmp(buf, "LOADK r1, 1") == 0); // b := FALSE(常量 1) + CHECK(std::strcmp(buf, "LOADK r9, 1") == 0); // b := FALSE(常量 1) isa::disasm(reinterpret_cast(base)[2], buf, sizeof buf); CHECK(std::strcmp(buf, "RET") == 0); @@ -179,13 +179,13 @@ static bool test_case09() { CHECK(v.data_bytes()[1] == 0); const isa::FuncRow r = v.func_row(0); - CHECK(r.nregs == 1); // 仅局部 x + CHECK(r.nregs == 9); // r8 起:仅局部 x CHECK(r.code_len == 2); char buf[64]; const uint8_t* base = v.code_bytes(); isa::disasm(reinterpret_cast(base)[0], buf, sizeof buf); - CHECK(std::strcmp(buf, "LOAD_GLOBAL r0, 0") == 0); // x := G1(槽 0 偏移 0) + CHECK(std::strcmp(buf, "LOAD_GLOBAL r8, 0") == 0); // x := G1(槽 0 偏移 0) isa::disasm(reinterpret_cast(base)[1], buf, sizeof buf); CHECK(std::strcmp(buf, "RET") == 0); return true; @@ -213,16 +213,16 @@ static bool test_io_ops() { CHECK(v.header().n_globals == 2); const isa::FuncRow r = v.func_row(0); - CHECK(r.nregs == 2); // q + 1 临时 + CHECK(r.nregs == 10); // r8 起:q + 1 临时 char buf[64]; const uint8_t* base = v.code_bytes(); isa::disasm(reinterpret_cast(base)[0], buf, sizeof buf); - CHECK(std::strcmp(buf, "LOAD_I r0, 0") == 0); // q := I0_0(io.input → LOAD_I) + CHECK(std::strcmp(buf, "LOAD_I r8, 0") == 0); // q := I0_0(io.input → LOAD_I) isa::disasm(reinterpret_cast(base)[1], buf, sizeof buf); - CHECK(std::strcmp(buf, "MOVE r1, r0") == 0); // 临时 ← q + CHECK(std::strcmp(buf, "MOVE r9, r8") == 0); // 临时 ← q isa::disasm(reinterpret_cast(base)[2], buf, sizeof buf); - CHECK(std::strcmp(buf, "STORE_Q r1, 1") == 0); // Q0_0 := 临时(io.output → STORE_Q) + CHECK(std::strcmp(buf, "STORE_Q r9, 1") == 0); // Q0_0 := 临时(io.output → STORE_Q) isa::disasm(reinterpret_cast(base)[3], buf, sizeof buf); CHECK(std::strcmp(buf, "RET") == 0); return true; @@ -255,7 +255,7 @@ static bool test_layout() { char buf[64]; isa::disasm(reinterpret_cast(v.code_bytes())[0], buf, sizeof buf); - CHECK(std::strcmp(buf, "LOAD_GLOBAL r0, 2") == 0); // x := I(INT 偏移 2) + CHECK(std::strcmp(buf, "LOAD_GLOBAL r8, 2") == 0); // x := I(INT 偏移 2) return true; } @@ -289,7 +289,7 @@ static bool test_case03() { const isa::ImageView v = isa::ImageView::from(img); CHECK(v.ok()); const isa::FuncRow r = v.func_row(0); - CHECK(r.nregs == 4); // a b x + 1 临时 + CHECK(r.nregs == 12); // r8 起:a b x + 1 临时 CHECK(r.code_len == 9); char buf[64]; @@ -297,22 +297,22 @@ static bool test_case03() { const uint32_t* ins = reinterpret_cast(base); // x := a AND b:MOVE r2,r0 / JF r2,+2 / MOVE r3,r1 / MOVE r2,r3 isa::disasm(ins[0], buf, sizeof buf); - CHECK(std::strcmp(buf, "MOVE r2, r0") == 0); + CHECK(std::strcmp(buf, "MOVE r10, r8") == 0); isa::disasm(ins[1], buf, sizeof buf); - CHECK(std::strcmp(buf, "JF r2, +2") == 0); + CHECK(std::strcmp(buf, "JF r10, +2") == 0); isa::disasm(ins[2], buf, sizeof buf); - CHECK(std::strcmp(buf, "MOVE r3, r1") == 0); + CHECK(std::strcmp(buf, "MOVE r11, r9") == 0); isa::disasm(ins[3], buf, sizeof buf); - CHECK(std::strcmp(buf, "MOVE r2, r3") == 0); + CHECK(std::strcmp(buf, "MOVE r10, r11") == 0); // x := a OR b:MOVE r2,r0 / JT r2,+2 / MOVE r3,r1 / MOVE r2,r3 isa::disasm(ins[4], buf, sizeof buf); - CHECK(std::strcmp(buf, "MOVE r2, r0") == 0); + CHECK(std::strcmp(buf, "MOVE r10, r8") == 0); isa::disasm(ins[5], buf, sizeof buf); - CHECK(std::strcmp(buf, "JT r2, +2") == 0); + CHECK(std::strcmp(buf, "JT r10, +2") == 0); isa::disasm(ins[6], buf, sizeof buf); - CHECK(std::strcmp(buf, "MOVE r3, r1") == 0); + CHECK(std::strcmp(buf, "MOVE r11, r9") == 0); isa::disasm(ins[7], buf, sizeof buf); - CHECK(std::strcmp(buf, "MOVE r2, r3") == 0); + CHECK(std::strcmp(buf, "MOVE r10, r11") == 0); isa::disasm(ins[8], buf, sizeof buf); CHECK(std::strcmp(buf, "RET") == 0); return true; @@ -332,16 +332,16 @@ static bool test_not() { const isa::ImageView v = isa::ImageView::from(img); CHECK(v.ok()); const isa::FuncRow r = v.func_row(0); - CHECK(r.nregs == 3); // a x + 1 临时 + CHECK(r.nregs == 11); // r8 起:a x + 1 临时 CHECK(r.code_len == 3); char buf[64]; const uint8_t* base = v.code_bytes(); const uint32_t* ins = reinterpret_cast(base); isa::disasm(ins[0], buf, sizeof buf); - CHECK(std::strcmp(buf, "MOVE r2, r0") == 0); // 临时 ← a + CHECK(std::strcmp(buf, "MOVE r10, r8") == 0); // 临时 ← a isa::disasm(ins[1], buf, sizeof buf); - CHECK(std::strcmp(buf, "NOT r1, r2") == 0); // x := NOT 临时 + CHECK(std::strcmp(buf, "NOT r9, r10") == 0); // x := NOT 临时 isa::disasm(ins[2], buf, sizeof buf); CHECK(std::strcmp(buf, "RET") == 0); return true; @@ -357,7 +357,7 @@ static bool test_case04() { const isa::ImageView v = isa::ImageView::from(img); CHECK(v.ok()); const isa::FuncRow r = v.func_row(0); - CHECK(r.nregs == 5); // sel out + 3 临时(CMP 目的 + 两操作数) + CHECK(r.nregs == 13); // r8 起:sel out + 3 临时 CHECK(r.code_len == 14); char buf[64]; @@ -365,33 +365,33 @@ static bool test_case04() { const uint32_t* ins = reinterpret_cast(base); // IF sel = 0 THEN:sel→r3、0→r4、CMP_EQ r2(常量序:0、10、1、20、30) isa::disasm(ins[0], buf, sizeof buf); - CHECK(std::strcmp(buf, "MOVE r3, r0") == 0); + CHECK(std::strcmp(buf, "MOVE r11, r8") == 0); isa::disasm(ins[1], buf, sizeof buf); - CHECK(std::strcmp(buf, "LOADK r4, 0") == 0); + CHECK(std::strcmp(buf, "LOADK r12, 0") == 0); isa::disasm(ins[2], buf, sizeof buf); - CHECK(std::strcmp(buf, "CMP_EQ r2, r3, r4") == 0); + CHECK(std::strcmp(buf, "CMP_EQ r10, r11, r12") == 0); isa::disasm(ins[3], buf, sizeof buf); - CHECK(std::strcmp(buf, "JF r2, +2") == 0); // 假 → elsif([6]) + CHECK(std::strcmp(buf, "JF r10, +2") == 0); // 假 → elsif([6]) isa::disasm(ins[4], buf, sizeof buf); - CHECK(std::strcmp(buf, "LOADK r1, 1") == 0); // out := 10(常量 1) + CHECK(std::strcmp(buf, "LOADK r9, 1") == 0); // out := 10(常量 1) isa::disasm(ins[5], buf, sizeof buf); CHECK(std::strcmp(buf, "JMP +7") == 0); // → end([13]) // ELSIF sel = 1 isa::disasm(ins[6], buf, sizeof buf); - CHECK(std::strcmp(buf, "MOVE r3, r0") == 0); + CHECK(std::strcmp(buf, "MOVE r11, r8") == 0); isa::disasm(ins[7], buf, sizeof buf); - CHECK(std::strcmp(buf, "LOADK r4, 2") == 0); + CHECK(std::strcmp(buf, "LOADK r12, 2") == 0); isa::disasm(ins[8], buf, sizeof buf); - CHECK(std::strcmp(buf, "CMP_EQ r2, r3, r4") == 0); + CHECK(std::strcmp(buf, "CMP_EQ r10, r11, r12") == 0); isa::disasm(ins[9], buf, sizeof buf); - CHECK(std::strcmp(buf, "JF r2, +2") == 0); // 假 → else([12]) + CHECK(std::strcmp(buf, "JF r10, +2") == 0); // 假 → else([12]) isa::disasm(ins[10], buf, sizeof buf); - CHECK(std::strcmp(buf, "LOADK r1, 3") == 0); + CHECK(std::strcmp(buf, "LOADK r9, 3") == 0); isa::disasm(ins[11], buf, sizeof buf); CHECK(std::strcmp(buf, "JMP +1") == 0); // → end([13]) // ELSE isa::disasm(ins[12], buf, sizeof buf); - CHECK(std::strcmp(buf, "LOADK r1, 4") == 0); + CHECK(std::strcmp(buf, "LOADK r9, 4") == 0); isa::disasm(ins[13], buf, sizeof buf); CHECK(std::strcmp(buf, "RET") == 0); return true; @@ -407,30 +407,30 @@ static bool test_case05() { const isa::ImageView v = isa::ImageView::from(img); CHECK(v.ok()); const isa::FuncRow r = v.func_row(0); - CHECK(r.nregs == 4); // n + 3 临时(CMP 目的 + 两操作数) + CHECK(r.nregs == 12); // r8 起:n + 3 临时(条件结果 r9 + 两操作数) CHECK(r.code_len == 10); char buf[64]; const uint8_t* base = v.code_bytes(); const uint32_t* ins = reinterpret_cast(base); isa::disasm(ins[0], buf, sizeof buf); - CHECK(std::strcmp(buf, "LOADK r0, 0") == 0); // n := 0 - // L_loop [1]:n < 10 → r1 + CHECK(std::strcmp(buf, "LOADK r8, 0") == 0); // n := 0 + // L_loop [1]:n < 10 → r9 isa::disasm(ins[1], buf, sizeof buf); - CHECK(std::strcmp(buf, "MOVE r2, r0") == 0); + CHECK(std::strcmp(buf, "MOVE r10, r8") == 0); isa::disasm(ins[2], buf, sizeof buf); - CHECK(std::strcmp(buf, "LOADK r3, 1") == 0); // 常量 1 = 10 + CHECK(std::strcmp(buf, "LOADK r11, 1") == 0); // 常量 1 = 10 isa::disasm(ins[3], buf, sizeof buf); - CHECK(std::strcmp(buf, "CMP_LT r1, r2, r3") == 0); + CHECK(std::strcmp(buf, "CMP_LT r9, r10, r11") == 0); isa::disasm(ins[4], buf, sizeof buf); - CHECK(std::strcmp(buf, "JF r1, +4") == 0); // 假 → RET([9]) - // n := n + 1(体语句临时复用 r1/r2) + CHECK(std::strcmp(buf, "JF r9, +4") == 0); // 假 → RET([9]) + // n := n + 1(体语句临时复用 r9/r10) isa::disasm(ins[5], buf, sizeof buf); - CHECK(std::strcmp(buf, "MOVE r1, r0") == 0); + CHECK(std::strcmp(buf, "MOVE r9, r8") == 0); isa::disasm(ins[6], buf, sizeof buf); - CHECK(std::strcmp(buf, "LOADK r2, 2") == 0); // 常量 2 = 1 + CHECK(std::strcmp(buf, "LOADK r10, 2") == 0); // 常量 2 = 1 isa::disasm(ins[7], buf, sizeof buf); - CHECK(std::strcmp(buf, "ADD r0, r1, r2") == 0); + CHECK(std::strcmp(buf, "ADD r8, r9, r10") == 0); isa::disasm(ins[8], buf, sizeof buf); CHECK(std::strcmp(buf, "JMP -8") == 0); // 回 L_loop([1]) isa::disasm(ins[9], buf, sizeof buf); @@ -448,7 +448,7 @@ static bool test_case07() { const isa::ImageView v = isa::ImageView::from(img); CHECK(v.ok()); const isa::FuncRow r = v.func_row(0); - CHECK(r.nregs == 6); // a b c eq + 2 临时(语句间复用) + CHECK(r.nregs == 14); // r8 起:a b c eq + 2 临时 char buf[64]; const uint8_t* base = v.code_bytes(); @@ -456,10 +456,10 @@ static bool test_case07() { bool saw_mul = false, saw_div = false, saw_sub = false, saw_gt = false; for (uint32_t i = 0; i < r.code_len; ++i) { isa::disasm(ins[i], buf, sizeof buf); - if (std::strstr(buf, "MUL r0, ")) saw_mul = true; - if (std::strstr(buf, "DIV r1, ")) saw_div = true; - if (std::strstr(buf, "SUB r2, ")) saw_sub = true; - if (std::strstr(buf, "CMP_GT r3, ")) saw_gt = true; + if (std::strstr(buf, "MUL r8, ")) saw_mul = true; + if (std::strstr(buf, "DIV r9, ")) saw_div = true; + if (std::strstr(buf, "SUB r10, ")) saw_sub = true; + if (std::strstr(buf, "CMP_GT r11, ")) saw_gt = true; } CHECK(saw_mul && saw_div && saw_sub && saw_gt); return true; @@ -481,13 +481,63 @@ static bool test_case08() { CHECK(c1.tag == isa::types::Time && c1.value == 1250); // T#1s250ms const isa::FuncRow r = v.func_row(0); - CHECK(r.nregs == 2); + CHECK(r.nregs == 10); // r8 起 char buf[64]; const uint32_t* ins = reinterpret_cast(v.code_bytes()); isa::disasm(ins[0], buf, sizeof buf); - CHECK(std::strcmp(buf, "LOADK r0, 0") == 0); + CHECK(std::strcmp(buf, "LOADK r8, 0") == 0); isa::disasm(ins[1], buf, sizeof buf); - CHECK(std::strcmp(buf, "LOADK r1, 1") == 0); + CHECK(std::strcmp(buf, "LOADK r9, 1") == 0); + return true; +} + +// ---- 13. 用例 13:FUNCTION + CALL(调用约定 r0 结果 / r1.. 参数)---- + +static bool test_case13() { + std::vector img; + std::string err; + CHECK(compile_case("13_function_call", &img, &err)); + + const isa::ImageView v = isa::ImageView::from(img); + CHECK(v.ok()); + CHECK(v.header().n_funcs == 2); + CHECK(v.header().entry_fn_id == 1); // MAIN 是第二个 POU + + char buf[64]; + const uint8_t* base = v.code_bytes(); + // Add(fn_id 0):结果 r0、输入 r1(a) r2(b)、临时 r8/r9 + const isa::FuncRow fa = v.func_row(0); + CHECK(fa.nregs == 10); + CHECK(fa.code_len == 4); + const uint32_t* ia = reinterpret_cast(base); + isa::disasm(ia[0], buf, sizeof buf); + CHECK(std::strcmp(buf, "MOVE r8, r1") == 0); // t ← a + isa::disasm(ia[1], buf, sizeof buf); + CHECK(std::strcmp(buf, "MOVE r9, r2") == 0); // t ← b + isa::disasm(ia[2], buf, sizeof buf); + CHECK(std::strcmp(buf, "ADD r0, r8, r9") == 0); // 结果 r0 + isa::disasm(ia[3], buf, sizeof buf); + CHECK(std::strcmp(buf, "RET") == 0); + + // MAIN(fn_id 1):x 在 r8,实参临时 r9/r10 + const isa::FuncRow fm = v.func_row(1); + CHECK(fm.nregs == 11); + CHECK(fm.code_len == 7); + const uint32_t* im = reinterpret_cast(base) + fm.code_offset / 4; + isa::disasm(im[0], buf, sizeof buf); + CHECK(std::strcmp(buf, "LOADK r9, 0") == 0); // 3 + isa::disasm(im[1], buf, sizeof buf); + CHECK(std::strcmp(buf, "LOADK r10, 1") == 0); // 4 + isa::disasm(im[2], buf, sizeof buf); + CHECK(std::strcmp(buf, "MOVE r1, r9") == 0); // 参数 1 ← 3 + isa::disasm(im[3], buf, sizeof buf); + CHECK(std::strcmp(buf, "MOVE r2, r10") == 0); // 参数 2 ← 4 + isa::disasm(im[4], buf, sizeof buf); + CHECK(std::strcmp(buf, "CALL 0") == 0); + isa::disasm(im[5], buf, sizeof buf); + CHECK(std::strcmp(buf, "MOVE r8, r0") == 0); // x ← 结果 + isa::disasm(im[6], buf, sizeof buf); + CHECK(std::strcmp(buf, "RET") == 0); return true; } @@ -504,6 +554,7 @@ int main() { if (!test_case05()) return 1; if (!test_case07()) return 1; if (!test_case08()) return 1; + if (!test_case13()) return 1; std::printf("codegen_test: %d checks passed\n", g_checks); return 0; }