Files
Interpreter/Doc/compiler/编译器优化.md
T
Admin 6869624f09 U10 定案:寄存器/调用约定维持 + 栈方案 C(预分配栈区 + max_stack 编译期算 + 双检查 + 递归编译期报错)
- §2.2 修正:256 = 寻址上限(非每帧分配数);帧按 nregs 动态分配
- 新增调用栈设计:max_stack@116(调用图最坏路径)、预分配零分配、
  字节/深度双检查、MAIN 帧常驻
- 递归 = 链接层环检测编译期报错(link error: recursive call)
- 编译器优化.md:max_stack 计算职责 + Linker 环检测
- §9.2 U10 闭合;影响面/决策历史同步
2026-08-24 16:00:45 +08:00

6.7 KiB
Raw Blame History

编译器优化(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;上限 256register overflow (>256)
  • 调用约定:r0 结果、r1..r7 参数(≤7)、r8+ 变量/临时;调用点实参求值到 r8+ → MOVE r(1+i), tCALLMOVE rd, r0
  • 跳转留洞回填patch_jump(相对下一条:目标 = 当前 + 1 + off)
  • 常量统一进常量表const_id = 首次出现序,去重
  • 空条件寄存器r0 恒 0enc_jmp 用);一元负号 = SUB rd, r0, t
  • IF/WHILE 模式JF 跳 else、JMP 连 end、WHILE 回跳循环头

3. V2 编译器侧变更(对应指令集优化)

3.1 FB 共享体(基址寻址)——消除内联膨胀

  • 现状问题:FB 每调用一次复制一份体,字节码膨胀
  • V2 定案LOAD/STORE rd, slot, off3216B 长度组,SLOT+off 形态)即基址寻址——结构体字段与 FB 共享体字段同一指令LOADF 已取消);FB 体编译一次,运行时按实例槽 + 编译期算死的字段偏移定位
  • 收益:字节码不再随调用点膨胀;代价:每次字段访问多一个偏移操作数

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.3b 调用栈与递归(U10 方案 C)

  • 递归 = 编译期错误:链接层对 FUNCTION 调用图做环检测(自调用/循环调用)→ link error: recursive call(V1 用例 19 已是负例,V2 明确为编译期错误)
  • max_stack 计算(链接层/Codegen 职责):无环调用图 → 最坏调用路径 Σ(帧头 12B + 各函数 nregs×8),写入映像头 @116
  • VM 按 max_stack 预分配栈区(运行期零分配);溢出双检查(字节 + 深度 64)

3.4 变长指令对 codegen 的影响

  • 跳转回填改字节单位patch_jump 按字节(off32,相对下一条),pc/code_offset/code_len 全字节化
  • 发射器(E_*)按前缀分区决定长度组(4/8/16B),指令缓冲按字节追加
  • 取指/对齐:code 段 16 字节对齐

3.5 类型系统扩展(ST 层)

  • 19 个 IEC 基础类型BOOL + 位串 4 + 有符号 4 + 无符号 4 + TIME + REAL/LREAL + DATE/TOD/DT)全量进关键字(声明即可用)
  • 进制前缀2#/8#/16# 字面量 + 浮点十进制字面量(1.5-2.5e3
  • 类型检查:禁止隐式变量转换(赋值/比较/算术类型严格一致,编译期报错);字面量按上下文适配5 可赋 INT/REAL/DINT,编译期解释);显式转换函数 v1 不做
  • 进制字面量默认类型归属与适配细则 → 指令集优化.md §4 项 A9

4. 已定案(编译器相关)

定案
I/Q/M 六条合并为 LOAD/STORE 两条(单一值区,语义标签交给 sidecar)
结构体 v1 只留编码(LOAD/STORE 16B 变体 + 元数据段),语法不实现
ST 层类型 19 类型名全量进关键字
类型转换 禁止隐式变量转换;字面量按上下文适配
字面量 进制前缀 2#/8#/16# + 浮点十进制
FB 共享体 实施(16B 变体 = 基址寻址)

仍待闭合的细节见指令集优化.md §4(A1..A10,编译器相关:A5 算术语义 / A6 sidecar / A8 machine.toml schema / A9 字面量类型推断)。

5. 影响面(编译器侧)

子模块 改动
Lexer 类型关键字扩展(19)、进制前缀 + 浮点字面量
Parser 类型引用、字面量 AST
Typecheck 禁隐式转换(严格一致)+ 字面量上下文适配、19 类型元数据
Linker 槽表条目分配(addr:u32)、FB 实例字段偏移、调用图环检测(递归报错)+ max_stack 计算
Codegen E_* 变长发射、字节化回填、槽表+值区 layout、FB 共享体(16B 变体)
MachineConfig / machine.toml type 表 19 条(base/width/signed/tag)、前缀分区/func 位段校验

6. 实施阶段(合并进指令集优化.md §6)

  • 阶段 2isa)后接阶段 3compiler 侧)machine.toml V2 → MachineConfig → Codec → Codegen(槽表/值区/变长发射)→ Stb → 对应测试
  • FB 共享体(§3.1 已定案)并入阶段 3 的 Codegen 子步骤

7. 决策历史

  • V1 定案(12.8):用户 FB 内联 / FUNCTION CALL / 内建 FB CAL_*;短路必须跳转;固定寄存器分配
  • V2 讨论:用户确认 V1 内联现状;提出 V2 用基址寻址消除内联膨胀(已定案)
  • 类型扩展:19 IEC 基础类型(type:5);禁隐式转换 + 字面量适配;进制前缀定案