From d296a9215e3d26030f47f199574a655fa838bdc1 Mon Sep 17 00:00:00 2001 From: chentianya Date: Fri, 21 Aug 2026 11:30:43 +0800 Subject: [PATCH] =?UTF-8?q?=E8=A7=84=E5=88=92=2012.8=20=E5=AF=84=E5=AD=98?= =?UTF-8?q?=E5=99=A8=E7=A0=81=EF=BC=9A=E5=AD=98=E5=82=A8=E5=B8=83=E5=B1=80?= =?UTF-8?q?=E3=80=81=E6=8C=87=E4=BB=A4=E6=A8=A1=E5=BC=8F=E3=80=818=20?= =?UTF-8?q?=E7=89=87=E6=89=A7=E8=A1=8C=E8=AE=A1=E5=88=92=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 寄存器码.md:帧/数据区布局(FB 实例块持久化)、短路编跳转、函数帧约定(结果 r0) - 用户 FB 调用内联展开定案;内建 CAL_TON/TOF/CTU - 8 片计划:骨架→I/Q/M→短路→IF→WHILE→算术→CALL→FB+line1 全链路 - 索引.md 登记 --- Doc/compiler/寄存器码.md | 121 +++++++++++++++++++++++++++++++++++++++ Doc/索引.md | 2 + 2 files changed, 123 insertions(+) create mode 100644 Doc/compiler/寄存器码.md diff --git a/Doc/compiler/寄存器码.md b/Doc/compiler/寄存器码.md new file mode 100644 index 0000000..7e9cb80 --- /dev/null +++ b/Doc/compiler/寄存器码.md @@ -0,0 +1,121 @@ +# 寄存器码(12.8) + +compiler 模块的代码生成。输入:`Project` + `Unit`(AST)+ `LinkResult`;输出:`.stb` 映像字节(`std::vector`)。全工程定案见 [`初步计划.md`](../初步计划.md) 12.8,指令/映像布局见 [`指令与映像.md`](../isa/指令与映像.md)。 + +## 做 / 不做 + +**做** + +- 寄存器分配:局部/变量固定寄存器,表达式临时值往后编号,`nregs` 写进函数头 +- 跳转先留洞、后回填;`AND` / `OR` **必须编成跳转**(短路),禁止两边都算 +- 常量表(`LOADK`)、全局/实例槽(`LOAD_GLOBAL` / `STORE_GLOBAL` 等) +- `CALL fn_id` 有界帧;用户 FB 调用**内联展开**;内建 `CAL_TON` / `CAL_TOF` / `CAL_CTU` +- 拼装映像:函数表 / 常量表 / 数据段 / 头(`cycle_limit`、`dt_ms`、工程哈希、入口) + +**不做(第一版)** + +- 图染色、SSA、生命周期分析、优化、异常表、闭包 +- 函数指针、间接跳转、`REAL` + +## 存储布局(v1 定案) + +| 数据 | 放哪 | 说明 | +|---|---|---| +| PROGRAM / FUNCTION 标量变量与临时 | **寄存器**(函数帧) | 每周期帧保留由 VM 负责(12.9) | +| FB 实例(任意 POU 内声明) | **数据区实例块**(绝对地址) | 状态跨周期持久 | +| 全局(含 I/Q/M) | 数据区(声明序) | 12.6 已定槽号 | + +- **数据区** = 全局块(声明序,按对齐规则:BOOL 1B / INT 2B / TIME 8B,起点对齐自身宽度)→ FB 实例块(按实例声明序,各块按类型布局大小、8 字节对齐) +- **指令 slot = 数据区字节偏移**(u16);符号表 `address` 保持逻辑槽号(12.6 冻结),编译时做 槽号 → 偏移 映射 +- 字段访问 `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 起按声明序 + +## 寄存器分配 + +- 局部变量固定占用前段(0..k-1) +- 表达式临时从 k 起,**语句内递增、语句结束复用基址**(不分析生命周期) +- `nregs` = 全函数临时峰值 + 1 + +## 表达式与语句的指令模式 + +```text +字面量 LOADK rd, const_id +变量读 LOAD_GLOBAL/LOAD_I/LOAD_M rd, slot (或帧内 MOVE) +字段读 LOAD_GLOBAL rd, <基址+偏移> +函数调用 <实参求值 → 参数寄存器> CALL fn_id MOVE rd, r0 + +NOT NOT rd, t +AND/OR 短路(必须跳转): + JF(AND)/JT(OR) rd, L_end + MOVE rd, t + L_end: +比较 CMP_xx rd, t1, t2 +算术 ADD/SUB/MUL/DIV rd, t1, t2 +负号 SUB rd, r0, t (0 - t,r0 恒 0) + +IF JF t, L_else + JMP L_end + L_else: (ELSIF 逐级) JF t, L_next ... + L_end: +WHILE L_loop: JF t, L_end JMP L_loop L_end: + +FB 调用(用户,内联展开): + <每个实参求值 → 临时> STORE_GLOBAL <实例基址+字段偏移>, 临时 + <内联体:读输入字段、算输出、写输出字段> +内建 实参同左 → CAL_TON/CAL_TOF/CAL_CTU <实例偏移> +``` + +- 常量统一进常量表(BOOL / INT / TIME),`const_id` = 首次出现序 +- 空条件寄存器约定:`r0` 恒 0(`enc_jmp` 用),`SUB rd, r0, t` 实现取负 + +## 用户 FB 调用内联(v1 定案) + +FB 体共享会与「绝对字段地址」冲突(不同实例基址不同),v1 选择**调用点内联展开**: + +- 调用点:实参写入该实例字段 → 内联该 FB 的函数体(字段地址按本实例基址算死)→ 字段读取自然可用 +- 代价:字节码随调用点数膨胀;v1 规模可接受;以后可升级为「基址寄存器寻址」指令 +- FB 无递归、无动态实例,内联安全 + +## 映像拼装 + +```text +函数表:收集序 fn_id → { nregs, code_offset(相对字节码段), code_len } +常量表:const_id → { tag, value } +数据段:全局 + 实例块(见上) +头:cycle_limit / dt_ms / 工程哈希(12.3)/ entry=MAIN fn_id / n_globals / n_i=n_q=n_m=0 +``` + +- 用 `isa` 的 `enc_*` 编码指令、`ImageView` 校验回读 +- 工程哈希用 12.3 的 `compute_project_hash` + +## 错误 + +稳定前缀 `codegen error`: + +```text +codegen error: register overflow (>256) in function 'f' +codegen error: constant table overflow +codegen error: slot out of range +``` + +## 完成标准 + +1. `line1` 能写出映像(函数字节码 + 全局/FB 槽 + 工程哈希),`ImageView` 校验通过 +2. 跳转回填无悬空(disasm 抽查) +3. 用例 1~9、13、15、17、18、20 编译出映像;负例(10/11/12/14/16/19)仍在前层被拒 +4. 全部构建 + `ctest` 无回归 + +--- + +## 执行计划(8 片,每片验证编译产物) + +1. **`Codegen.h`(新建)+ `Codegen.cpp` 骨架**:帧/槽/常量表/指令缓冲/回填基础设施;`MOVE` `LOADK` `RET` → 用例 1、2 出映像 +2. **全局与 I/Q/M**:`LOAD_I` / `STORE_Q` / `LOAD_M` / `STORE_M` / `LOAD_GLOBAL` / `STORE_GLOBAL`(用例 9) +3. **`NOT` + 短路 `AND` / `OR`**(用例 3,断言产物含跳转) +4. **`CMP_*` + `JMP` / `JT` / `JF` → `IF`**(用例 4) +5. **`WHILE`**(用例 5;`cycle_limit` 进映像头) +6. **`ADD/SUB/MUL/DIV` + TIME 常量**(用例 7、8) +7. **`CALL fn_id` + 有界帧**(用例 13) +8. **FB 实例块 + 字段偏移;内联用户 FB;`CAL_TON` / `CAL_TOF` / `CAL_CTU`**(用例 15、17、18、20 line1 全链路) + +每片配 `codegen_test` 断言(nregs / 指令序列 disasm / 回填 / 常量表 / 数据区);最终 `ctest` 9/9。 diff --git a/Doc/索引.md b/Doc/索引.md index 4eaf3af..44cd671 100644 --- a/Doc/索引.md +++ b/Doc/索引.md @@ -12,6 +12,7 @@ doc/ compiler/语法.md compiler/符号表与链接.md compiler/类型检查.md + compiler/寄存器码.md vm/扫描周期.md executor/执行器入口.md ``` @@ -25,6 +26,7 @@ doc/ | [`compiler/语法.md`](compiler/语法.md) | 12.5 语法:AST 结构、文法、拒绝清单 | | [`compiler/符号表与链接.md`](compiler/符号表与链接.md) | 12.6 符号表与链接:数据区定址、FB 布局、错误类别 | | [`compiler/类型检查.md`](compiler/类型检查.md) | 12.7 类型检查:表达式类型、语句规则、错误类别 | +| [`compiler/寄存器码.md`](compiler/寄存器码.md) | 12.8 寄存器码:布局、指令模式、内联 FB、8 片计划 | | [`vm/扫描周期.md`](vm/扫描周期.md) | 扫描周期与 VM 边界 | | [`executor/执行器入口.md`](executor/执行器入口.md) | 可执行入口:加载 `.stb` + sidecar,跑扫描周期 |