阶段一:骨架与基础数据结构
- 新增文件/类: Backend.java (实现 GenerateMips()、GetMipsModule()),MipsModule.java,MipsBuilder.java,Register.java,MipsType.java,MipsAssembly.java。
- 指令最小子集(先实现以便能插入并打印): MipsLabel、MipsAlu(只保留 ADD/SUB/ADDI)、MipsLsu(LW/SW)、MipsJump(J/JAL/JR)、MipsBranch(BEQ/BNE)。
- 初步方法: Backend.GenerateMips()中构造 MipsModule、调用中端 IrModule.toMips()(暂留TODO或空实现)、MipsModule.toString()输出。
- 数据结构完成后可手工插入几条指令验证打印。
阶段二:函数级代码生成
- 增量修改: 为 IR 函数遍历增加回调:在中端模块调用 IrModule.toMips()时插入 MipsBuilder.SetCurrentFunction(irFunction)。
- 新增/扩展方法: 在 MipsBuilder 中添加栈偏移管理接口(AllocateStackSpace、AllocateStackForValue、GetStackValueOffset)。
- 在生成函数起始处插入:MipsLabel(函数名)、建立栈帧(
addiu $sp, $sp, -frameSize/ 保存$ra/ 保存需要的$s寄存器),结束处:恢复栈帧、jr $ra。 - 若暂缺 IR 函数结构,可建立占位适配器类或在函数生成处留 TODO 注释。
阶段三:表达式与控制流
- 扩展指令使用: 根据 IR 基本块遍历生成算术:
add/sub→MipsAlu;赋值/变量访问:寄存器直接用,内存用lw/sw。 - 加载常数:若小常数用
addiu/ 若需要可临时增加伪指令支持(可后放)。 - 控制流: 基本块起始插入
MipsLabel;终结指令br/条件跳转→beq/bne+ 目标标签;无条件跳转 →j label;return→ 写返回值到$v0后栈帧恢复 +jr $ra。 - 修改: 在中端 IR 到 MIPS 的转换流程中加分支与跳转映射逻辑。
阶段四:全局与数据段
- 新增数据指令类: MipsWord、MipsAsciiz(可不先实现 MipsSpace / MipsSpaceOptimize,留后期)。
- 在 Backend.GenerateMips() 或 IrModule.toMips() 前扫描 IR 全局: 整数常量→
.word;字符串常量→.asciiz。 - 若有全局数组:简单策略分配
.space size*4(后期再做优化空间压缩)。 - 修改 MipsModule.toString() 已支持 data 段打印(阶段一已具备)。
阶段五:调用约定与返回值处理
- 扩展 MipsBuilder:增加参数寄存器分配方法 AllocateRegForParam(IrParameter, Register)。
- 在函数入口:加载超出前四的参数(从调用者栈)到局部栈或寄存器。
- 在函数调用点生成:
- 传参:前四参数放
$a0-$a3,额外参数按逆序入栈。 - 保存调用者活跃的
$s寄存器与$ra(如多级调用)。 - 发起调用:
jal funcLabel;弹栈/恢复$s寄存器。 - 获取返回值:用
$v0映射到 IR 目的值的寄存器或存栈。
- 传参:前四参数放
- 若需:简单活跃分析可暂用“所有用到的 S 寄存器都保存”策略(后续阶段优化)。
阶段六:比较、逻辑、乘除扩展
- 新增指令类: MipsCompare(支持 SLT/SGT/SEQ/SNE 等,或用组合
slt+ 逻辑指令)与 MipsMdu(mult/div/mflo/mfhi)。 - 表达式扩展:
<, <=, >, >=, ==, !=映射:- 直接用 MipsCompare 或
slt+ 取反/交换操作;结果落到临时寄存器作为布尔值 (0/1)。
- 直接用 MipsCompare 或
- 逻辑与或:短路实现(生成分支跳转)或直接用布尔值与/或(需要
and/or指令)。 - 乘除: mult rs rt 后 mflo rd;除法同理(若需余数用
mfhi)。 - 更新中端到后端的指令选择表。
阶段七:窥孔优化与指令合并
- 在 Peephole.java 实现:把参考的 PeepHole.PeepContinueSW() 迁移为 remove 连续写同地址前条指令。
- 结构: 持有 MipsModule、遍历 textSegment,循环直到稳定。
- 可扩展新增规则(可分层 TODO 注释):
- 连续
lw同地址后未使用前值删除前一次。 addiu $sp, $sp, k紧接addiu $sp, $sp, m合并。move消除(若引入)。
- 连续
- 在 Backend.GenerateMips() 末尾:如果 Setting.FINE_TUNING 为真则调用 Peephole.Peep()。
阶段八:测试验证与迭代优化
- 编写或复用简单驱动:调用前端+中端+后端,打印 MIPS。
- 用
test/Code-test中多个样例运行,人工或脚本比对预期(检查是否有main:、系统调用、栈帧平衡)。 - 验证点:寄存器重用冲突(临时值覆盖问题)、栈偏移正确性、调用嵌套返回值正确性。
- 添加更多 peephole:
- 删除死标签(无跳转目标的标签)。
- 合并
li+move。 - 简化分支:
beq $zero,$zero label→ j label。
- 若出现溢出:实现简单线性扫描分配策略(活跃期冲突时把旧值 spill 到栈)。
整体文件/类时间线概览(按阶段逐步出现)
- 阶段一: Backend, MipsModule, MipsBuilder, Register, MipsType, MipsAssembly, (指令子集: MipsLabel, MipsAlu, MipsLsu, MipsJump, MipsBranch)。
- 阶段二: 扩展 MipsBuilder(栈接口)、函数 prologue/epilogue 逻辑(可能内嵌于 IR→MIPS 代码生成文件中)。
- 阶段三: 在 IR 转换代码中添加表达式与基本块控制流生成(不一定新文件,主要新逻辑)。
- 阶段四: MipsWord, MipsAsciiz(可选后续 MipsSpace)。
- 阶段五: 参数传递逻辑(调用点与被调用点),可能新增辅助类(若需要)或只在生成逻辑中。
- 阶段六: MipsCompare, MipsMdu + 对应表达式映射扩展。
- 阶段七: Peephole(替换原空类实现),新增或扩展优化规则。
- 阶段八: 测试脚本或小驱动(若当前仓库无主入口,可在顶层 Compiler.java 串联调用 Backend.GenerateMips() 并输出),附加优化与冲突处理。
如果你希望,我可以直接开始阶段一的文件创建与最小指令迁移。是否继续执行阶段一代码实现?告诉我即可。