Files
Interpreter/Doc/compiler/寄存器码.md
T

7.1 KiB
Raw Blame History

寄存器码(V2

compiler 模块的代码生成。输入:Project + UnitAST+ LinkResult;输出:.stb 映像字节(std::vector<uint8_t>)。全工程定案见 初步计划.md 12.8,指令/映像布局见 指令与映像.md,槽表/值段格式见 stb文件格式.md

做 / 不做

  • 寄存器分配:局部/变量固定寄存器,表达式临时值往后编号,nregs 写进函数头
  • 跳转先留洞、后回填(字节单位,相对下一条);AND / OR 必须编成跳转(短路),禁止两边都算
  • 常量表(LOADK8B 原始值无 tag,按 func 解释)、全局/实例槽(LOAD / STORE / LOAD_OFF / STORE_OFF)、FB 共享体基址访问(LOAD_PTR / STORE_PTR
  • CALL fn_id 有界帧;用户 FB 共享体函数化r1 = 实例指针);内建 CAL fb_id, 实例槽
  • 拼装映像:V2 头 128B / 函数表 / 常量表 / 字节码 / 槽表 / 值段 + SHA-256 尾部
  • max_stackMAIN + FUNCTION 调用图 DAG 最坏路径 Σ(12 + nregs×8);递归 = 编译期报错

不做(第一版)

  • 图染色、SSA、生命周期分析、优化、异常表、闭包
  • 函数指针、间接跳转、动态实例

存储布局(V2 定案)

数据 放哪 说明
PROGRAM / FUNCTION 标量变量与临时 寄存器(函数帧) 每周期帧保留由 VM 负责(12.9
全局(含 I/Q/M)与 FB 实例 值区(紧凑变宽,1/2/4/8 对齐) 槽表条目(8B:addr:u32 + 预留)指到值区偏移;状态跨周期持久
  • 槽表两级:指令操作数 = 槽号(u32)→ 槽表条目 → 值区字节偏移;slot_addr(slot) 由 VM/Image 提供
  • 全局按 GVL 声明序编槽;FB 实例 = 1 个槽表条目,字段在实例基址上按偏移访问(字段偏移编译期按 1/2/4/8 对齐计算,字段类型 = machine.toml [[fb]] 表)
  • 字段访问 fb.QLOAD_OFF rd, <实例槽>, <偏移> / STORE_OFF <实例槽>, <偏移>, rs16B SLOT+off 指令,调用点/输出读用);FB 共享体函数体内:LOAD_PTR / STORE_PTR rd, r1, <偏移>16B RS+off,基址寄存器 r1 = 实例指针);I/Q/M 同普通槽(LOAD / STORE
  • 函数帧寄存器:FUNCTION 结果固定 r0VAR_INPUT 从 r1 起按声明序,VAR 续后;PROGRAM / FB 变量从 r0 起按声明序

调用约定(v1 冻结,VM 12.9 按此实现)

约定
结果寄存器 r0FUNCTION 结果写入处)
参数寄存器 r1..r7(最多 7 个输入,按声明序)
变量 / 临时 全部从 r8 起(调用约定区不受覆盖)
CALL VM 复制当前帧 r0..r7 → 新帧 r0..r7(全宽)
RET VM 复制当前帧 r0..r7 → 调用方帧 r0..r7r0=结果,r1..r7 原样返回)
函数输入 函数体内只读(写输入 → codegen error
  • 调用点:实参求值到 r8+ 临时 → MOVE r(1+i), tCALL fn_idMOVE rd, r0
  • 所有 POU 的变量/临时统一 r8 起,故 r1..r7 在调用点可安全覆盖

寄存器分配

  • 局部变量固定占用前段(0..k-1
  • 表达式临时从 k 起,语句内递增、语句结束复用基址(不分析生命周期)
  • nregs = 全函数临时峰值 + 1

表达式与语句的指令模式

字面量     LOADK rd, const_id                 func = 语言类型;REAL/LREAL 位模式按目标类型装载)
变量读     LOAD rd, slot                      (帧内直接 MOVE
字段读     LOAD_OFF 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>  NEG rd, t

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_OFF <实例槽>, <字段偏移>, 临时
          LOADK r1, <实例值区地址>  CALL <fb_fn_id>
          FB 函数体内:字段访问 = LOAD_PTR/STORE_PTR rd, r1, <字段偏移>
内建      实参同左 → CAL <fb_id>, <实例槽>
  • 常量统一进常量表(8B 原始值,位模式去重;BOOL / 整数 / 时间 / 浮点 / 日期),const_id = 首次出现序;LOADK 按 func 解释位模式
  • 指令 func 位段 = 语言类型对应(func_of_name:宽度 × 符号 + F32/F64

用户 FB 共享体(函数化,2026-08-26 实施)

FB 体共享会与「绝对字段地址」冲突(不同实例基址不同),V1 内联;V2 改为共享体函数化

  • FB 编译为独立共享函数fn_id 收集序):r1 = 实例指针(值区地址,隐藏参数/this),字段访问 LOAD_PTR/STORE_PTR rd, r1, 字段偏移
  • 调用点:实参 STORE_OFF(绝对槽)→ LOADK r1, c(实例addr)CALL fb_fn_id2 条指令替代整个展开体)
  • 嵌套(FB 函数内调 FUNCTION):实参区 r1..r7 会覆盖实例指针 → 调用点自动 MOVE t, r1 / 调用后 MOVE r1, t 保护
  • VAR_TEMP 落 FB 帧寄存器,帧每周期重建 → 天然每次调用重置(内联期的寄存器隔离 hack 退役)
  • 多实例共享同一函数体,状态经 r1 指针隔离(countVAR 仍在实例字段)
  • FB 无递归、无动态实例(链接层保证),函数化安全

映像拼装(V2

头 128Bmagic / version=2 / model=STATOR2 / cycle_limit / dt_ms / 工程哈希 /
        entry_fn_id / n_globals / n_consts / n_funcs / 各段偏移 /
        n_slots / values_size / meta / max_stack
函数表:收集序 fn_id → { nregs, code_offset(相对字节码段), code_len }
常量表:const_id → { value:u64 }(无 tag)
字节码:各函数指令连续
槽表:每条目 8B(addr:u32 + 预留:u32
值段:全局 + FB 实例紧凑变宽
尾部:SHA-256(覆盖头部到值段末尾)
  • isaenc_* 编码指令(变长 4/8/16/32B,前缀分区)
  • 工程哈希用 12.3 的 compute_project_hashFNV-1a 64
  • --dump-map 可打印变量/槽映射(对照源码 ↔ 反汇编)

错误

稳定前缀 codegen error

codegen error: register overflow (>256) in function 'f'
codegen error: constant table overflow
codegen error: no storage for 'x'
codegen error: no instance 't' in 'MAIN'
codegen error: recursive CALL/FB nesting too deep

完成标准

  1. line1 能写出映像(函数字节码 + 槽表/值段 + 工程哈希 + SHA-256),StbView 校验通过
  2. 跳转回填无悬空(--disasm 抽查)
  3. 用例 19、13、15、17、18、20 编译出映像;负例(10/11/12/14/16/19)仍在前层被拒
  4. 全部构建 + ctest 无回归(14/14