Files
Interpreter/Doc/compiler/寄存器码.md
T
Admin d296a9215e 规划 12.8 寄存器码:存储布局、指令模式、8 片执行计划。
- 寄存器码.md:帧/数据区布局(FB 实例块持久化)、短路编跳转、函数帧约定(结果 r0)
- 用户 FB 调用内联展开定案;内建 CAL_TON/TOF/CTU
- 8 片计划:骨架→I/Q/M→短路→IF→WHILE→算术→CALL→FB+line1 全链路
- 索引.md 登记
2026-08-21 11:30:43 +08:00

122 lines
5.7 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 寄存器码(12.8
compiler 模块的代码生成。输入:`Project` + `Unit`AST+ `LinkResult`;输出:`.stb` 映像字节(`std::vector<uint8_t>`)。全工程定案见 [`初步计划.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 <operand → t> NOT rd, t
AND/OR 短路(必须跳转):
<lhs → rd> JF(AND)/JT(OR) rd, L_end
<rhs → t> MOVE rd, t
L_end:
比较 <l→t1> <r→t2> CMP_xx rd, t1, t2
算术 <l→t1> <r→t2> ADD/SUB/MUL/DIV rd, t1, t2
负号 <operand → t> SUB rd, r0, t 0 - tr0 恒 0
IF <cond → t> JF t, L_else
<then body> JMP L_end
L_else: (ELSIF 逐级) <elsif cond → t> JF t, L_next ...
L_end:
WHILE L_loop: <cond → t> JF t, L_end <body> 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. 用例 19、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。