编译器优化(V2 草案)
状态:设计中。本文聚焦编译器(codegen/优化策略)侧的现状与 V2 变更;
指令集/映像层(指令格式、槽表/值区、类型位段)见 isa/指令集优化.md。
全部内容为草案,未进入实现。
1. 定位
| 文档 |
覆盖层 |
内容 |
isa/指令集优化.md |
ISA/映像层 |
变长指令、槽表/值区、type 位段、映像格式 |
| 本文(compiler) |
编译策略层 |
代码生成策略、POU 调用方式、寄存器分配、优化方向 |
2. V1 现状(已实现的编译策略)
2.1 POU 调用方式(三种)
| 对象 |
V1 处理 |
理由 |
代价 |
| 用户 FB |
调用点内联展开 |
FB 体访问绝对字段地址(LOAD_GLOBAL rd, 基槽+字段序),不同实例基址不同,共享体无法复用;无递归、无动态实例 → 内联安全(12.8 定案) |
字节码随调用点数膨胀 |
| FUNCTION |
独立函数 + CALL fn_id 帧栈 |
无状态、寄存器约定(r1..r7 实参 / r0 结果)无地址冲突 |
帧压栈 |
| 内建 FB |
CAL_* 指令(VM 原语) |
定时器/计数器在 VM 侧 |
无 |
2.2 其他编译策略(V1 冻结)
- 短路求值必须编跳转:
AND/OR 禁止两边都算(JF(AND)/JT(OR) rd, L_end)
- 寄存器分配:变量固定前段(r0..k-1)、表达式临时从 k 起、语句结束复用基址(不分析生命周期);
nregs = 峰值 + 1;上限 256(register overflow (>256))
- 调用约定:r0 结果、r1..r7 参数(≤7)、r8+ 变量/临时;调用点实参求值到 r8+ →
MOVE r(1+i), t → CALL → MOVE rd, r0
- 跳转留洞回填:
patch_jump(相对下一条:目标 = 当前 + 1 + off)
- 常量统一进常量表:
const_id = 首次出现序,去重
- 空条件寄存器:r0 恒 0(
enc_jmp 用);一元负号 = SUB rd, r0, t
- IF/WHILE 模式:
JF 跳 else、JMP 连 end、WHILE 回跳循环头
3. V2 编译器侧变更(对应指令集优化)
3.1 FB 共享体(基址寻址)——消除内联膨胀
- 现状问题:FB 每调用一次复制一份体,字节码膨胀
- V2 方案:槽表模型下引入基址寻址指令(
LOAD/STORE rd, base_slot, field_off,base 槽取自寄存器/立即数,16B 长度组已预留)→ FB 体编译一次,运行时按实例基址定位字段
- 收益:字节码不再随调用点膨胀;代价:每次字段访问多一个基址操作数
- 待确认:见指令集优化.md §4 项 9(推荐实施)
3.2 类型驱动语义(type 位段红利)
- CMP/算术按
type 位段自动选择语义:无符号无符号比较、整数饱和到类型宽度(模板化)、浮点 IEEE 754(无饱和,溢出→±inf)
- 读取按宽度 + 符号/零扩展(
slot_read(addr, width, signed))
- 常量表 tag = type 位段值(0..15),REAL=14 / LREAL=15 存位模式
3.3 槽表/值区布局(codegen 职责)
- 槽表段:每槽 {addr:u32},编译器为每个变量分配槽 + 值区地址(编译期算死)
- 值段:紧凑变宽布局,对齐规则 1/2/8 字节(BOOL 1 / INT 2 / TIME·LREAL·LWORD·ULINT·LINT 8 / REAL·DWORD·UDINT·DINT 4),对齐由编译器保证,VM 从 type 位段已知宽度
- 初值写值段(编译期 layout);结构体 = 值区连续字段块(元数据段字段表,v1 预留)
3.4 变长指令对 codegen 的影响
- 跳转回填改字节单位:
patch_jump 按字节(off32,相对下一条),pc/code_offset/code_len 全字节化
- 发射器(E_*)按 fmt 决定长度组(4/8/16B),指令缓冲按字节追加
- 取指/对齐:code 段 16 字节对齐
3.5 类型系统扩展(ST 层)
- 12 个 IEC 整数类型 + REAL/LREAL 进关键字(全量支持:声明即可用)
- 类型检查:隐式升宽允许(SINT→INT→DINT→LINT、BYTE→WORD→…)、降宽禁止
- 浮点字面量(
1.5、-2.5e3)v1 是否支持——待确认
4. 待确认(引用指令集优化.md §4 中编译器相关项)
| 项 |
问题 |
推荐 |
| 4 |
I/Q/M 六条 LOAD/STORE 合并为两条 |
合并 |
| 5 |
结构体 v1 只留编码不实现语法 |
预留 |
| 6 |
ST 层类型全量支持(12 类型名进关键字) |
全量 |
| 7 |
隐式升宽允许、降宽禁止 |
按此 |
| 8 |
字面量:十进制 only(含浮点字面量) |
十进制 |
| 9 |
FB 共享体:基址寻址指令实施 |
实施 |
| 10 |
REAL/LREAL 引入后 type:4 满编 |
满编(结构体走元数据) |
5. 影响面(编译器侧)
| 子模块 |
改动 |
| Lexer |
类型关键字扩展(14 → 16+)、浮点字面量(若确认) |
| Parser |
类型引用、字面量 AST |
| Typecheck |
隐式升宽规则、16 类型元数据 |
| Linker |
槽表条目分配(addr:u32)、FB 实例字段偏移 |
| Codegen |
E_* 变长发射、字节化回填、槽表+值区 layout、FB 共享体(若实施)、基址寻址 |
| MachineConfig / machine.toml |
type 表 16 条(base/width/signed/tag)、fmt/type 位段互锁校验 |
6. 实施阶段(合并进指令集优化.md §6)
- 阶段 2(isa)后接阶段 3(compiler 侧):machine.toml V2 → MachineConfig → Codec → Codegen(槽表/值区/变长发射)→ Stb → 对应测试
- FB 共享体(§3.1)若确认实施,并入阶段 3 的 Codegen 子步骤
7. 决策历史
- V1 定案(12.8):用户 FB 内联 / FUNCTION CALL / 内建 FB CAL_*;短路必须跳转;固定寄存器分配
- V2 讨论:用户确认 V1 内联现状;提出 V2 用基址寻址消除内联膨胀(写入 §2.7/§4 项 9)