增加注释

This commit is contained in:
Luke 2025-05-11 22:58:49 +08:00
parent 089e629187
commit 48b7418b03
3 changed files with 170 additions and 85 deletions

View File

@ -6,31 +6,29 @@ import java.util.EnumMap;
import java.util.Map;
/**
* IROpCodeMapper IR 操作码IROpCode VM 虚拟机操作码字符串形式的映射器
* 提供 IR 操作码{@link IROpCode}到虚拟机指令名{@code String}的一一映射工具类
* <p>
* 本类用于编译器后端阶段将中间表示中的操作类型 ADD_I32转换为
* 虚拟机指令集中的具体指令 "I_ADD"用于代码生成输出
* 本类在编译器后端负责将中间表示中的操作码转换为对应的 VM 指令用于最终的代码生成
* 不负责操作数或参数传递的逻辑仅做纯映射处理
* </p>
* <p>
* 注意该类只做一一映射不处理操作数或参数传递逻辑
* 若未来有更多数据类型或扩展语义可在此处集中管理
* 如需扩展更多操作码或新增指令语义可在此集中管理映射关系
* </p>
*/
public final class IROpCodeMapper {
/** 存储映射关系的枚举映射表(使用 EnumMap 提高性能) */
/**
* IR 操作码到 VM 指令名的映射表基于 {@code EnumMap} 实现以提升性能
*/
private static final Map<IROpCode, String> opcodeMap = new EnumMap<>(IROpCode.class);
// 初始化静态映射表
static {
// 算术运算
opcodeMap.put(IROpCode.ADD_I32, "I_ADD");
opcodeMap.put(IROpCode.SUB_I32, "I_SUB");
opcodeMap.put(IROpCode.MUL_I32, "I_MUL");
opcodeMap.put(IROpCode.DIV_I32, "I_DIV");
opcodeMap.put(IROpCode.NEG_I32, "I_NEG");
// 逻辑比较运算
opcodeMap.put(IROpCode.CMP_EQ, "IC_EQ");
opcodeMap.put(IROpCode.CMP_NE, "IC_NE");
opcodeMap.put(IROpCode.CMP_LT, "IC_L");
@ -38,33 +36,35 @@ public final class IROpCodeMapper {
opcodeMap.put(IROpCode.CMP_LE, "IC_LE");
opcodeMap.put(IROpCode.CMP_GE, "IC_GE");
// 数据操作
opcodeMap.put(IROpCode.LOAD, "I_LOAD");
opcodeMap.put(IROpCode.STORE, "I_STORE");
opcodeMap.put(IROpCode.CONST, "I_PUSH");
// 控制流
opcodeMap.put(IROpCode.JUMP, "JMP");
opcodeMap.put(IROpCode.JUMP_IF_ZERO, "JZ");
opcodeMap.put(IROpCode.LABEL, "LABEL");
// 函数调用
opcodeMap.put(IROpCode.CALL, "CALL");
opcodeMap.put(IROpCode.RET, "RET");
}
/**
* 将给定的 IR 操作码转换为对应的 VM 指令名字符串
* 将给定的 IR 操作码转换为对应的 VM 指令名
*
* @param irOp IROpCode 中的操作码
* @return 对应的 VM opcode 字符串
* @throws IllegalArgumentException 操作码未被映射
* @param irOp 需转换的 IR 操作码
* @return IR 操作码对应的 VM 指令名称
* @throws IllegalArgumentException {@code irOp} 未在映射表中定义
*/
public static String toVMOp(IROpCode irOp) {
String code = opcodeMap.get(irOp);
if (code == null) {
String vmCode = opcodeMap.get(irOp);
if (vmCode == null) {
throw new IllegalArgumentException("未映射的 IR 操作码: " + irOp);
}
return code;
return vmCode;
}
// 私有构造函数防止实例化
private IROpCodeMapper() {
// 不允许实例化
}
}

View File

@ -1,52 +1,55 @@
package org.jcnc.snow.compiler.backend;
import org.jcnc.snow.compiler.ir.core.*;
import org.jcnc.snow.compiler.ir.core.IRFunction;
import org.jcnc.snow.compiler.ir.core.IRInstruction;
import org.jcnc.snow.compiler.ir.core.IRValue;
import org.jcnc.snow.compiler.ir.value.IRVirtualRegister;
import java.util.HashMap;
import java.util.Map;
/**
* A <em>very</em> simple linear-scan register allocator.
*
* <p>Strategy:</p>
* 线性扫描寄存器分配器
* <p>
* 分配策略
* <ol>
* <li>Assign <strong>formal parameters</strong> to slots
* 0&nbsp;..&nbsp;n-1 (in declaration order).</li>
* <li>Scan the instruction list; every unseen virtual register
* gets the next free slot number.</li>
* <li>将函数的形式参数按照声明顺序分配到槽编号 0 n-1</li>
* <li>随后扫描函数体中的指令列表每遇到尚未分配槽号的虚拟寄存器
* 即为其分配下一个可用的槽编号</li>
* </ol>
* <p>No liveness analysis, no spilling demo-grade only.</p>
*/
public final class RegisterAllocator {
/**
* 存储虚拟寄存器到物理槽的映射表
* 键为虚拟寄存器值为分配的槽编号
*/
private final Map<IRVirtualRegister, Integer> map = new HashMap<>();
/**
* Computes a registerslot mapping for the given function.
* 为指定的 IR 函数计算寄存器到槽的映射关系
* <p>
* 先为函数的形式参数分配槽号再为函数体中出现的其他虚拟寄存器依次分配
* </p>
*
* @param fn IRFunction to allocate
* @return mapping table (immutable)
* @param fn 需要进行寄存器分配的中间表示函数
* @return 一个不可变的映射表表示每个虚拟寄存器对应的槽编号
*/
public Map<IRVirtualRegister, Integer> allocate(IRFunction fn) {
int next = 0;
/* ---------- 1) parameters first ---------- */
// 1. 为形式参数分配槽编号
for (IRVirtualRegister param : fn.parameters()) {
map.put(param, next++);
}
/* ---------- 2) then all remaining VRegs ---------- */
// 2. 扫描函数体分配其他虚拟寄存器的槽编号
for (IRInstruction inst : fn.body()) {
if (inst.dest() != null && !map.containsKey(inst.dest())) {
map.put(inst.dest(), next++);
}
for (IRValue v : inst.operands()) {
if (v instanceof IRVirtualRegister vr &&
!map.containsKey(vr)) {
for (IRValue operand : inst.operands()) {
if (operand instanceof IRVirtualRegister vr && !map.containsKey(vr)) {
map.put(vr, next++);
}
}

View File

@ -1,33 +1,68 @@
package org.jcnc.snow.compiler.backend;
import org.jcnc.snow.compiler.ir.core.*;
import org.jcnc.snow.compiler.ir.instruction.*;
import org.jcnc.snow.compiler.ir.value.*;
import org.jcnc.snow.compiler.ir.core.IRFunction;
import org.jcnc.snow.compiler.ir.core.IRInstruction;
import org.jcnc.snow.compiler.ir.core.IRValue;
import org.jcnc.snow.compiler.ir.instruction.BinaryOperationInstruction;
import org.jcnc.snow.compiler.ir.instruction.CallInstruction;
import org.jcnc.snow.compiler.ir.instruction.LoadConstInstruction;
import org.jcnc.snow.compiler.ir.instruction.ReturnInstruction;
import org.jcnc.snow.compiler.ir.instruction.UnaryOperationInstruction;
import org.jcnc.snow.compiler.ir.value.IRVirtualRegister;
import org.jcnc.snow.compiler.ir.value.IRConstant;
import org.jcnc.snow.vm.engine.VMOpCode;
import java.lang.reflect.Field;
import java.util.Map;
/**
* Generates VM code for a single IRFunction.
* 为单个 {@link IRFunction} 生成对应的虚拟机指令序列
* <p>
* 本类依据中间表示函数的指令列表调用 {@link VMProgramBuilder} 输出相应的 VM 操作码
* 包括常量加载算术运算函数调用和返回等指令生成逻辑
* </p>
*/
public final class VMCodeGenerator {
/**
* 虚拟寄存器到槽编号的映射表用于确定加载和存储的目标槽
*/
private final Map<IRVirtualRegister, Integer> slotMap;
/**
* VM 指令输出器用于构建最终的指令流
*/
private final VMProgramBuilder out;
/**
* 当前正在生成代码的函数名称用于在返回指令处区分主函数与其他函数
*/
private String currentFn;
/**
* 构造 VMCodeGenerator 实例
*
* @param slotMap 虚拟寄存器与槽编号的映射表
* @param out 用于输出 VM 指令的构建器
*/
public VMCodeGenerator(Map<IRVirtualRegister, Integer> slotMap,
VMProgramBuilder out) {
this.slotMap = slotMap;
this.out = out;
}
/**
* 为指定的 IR 函数生成完整的 VM 指令流
*
* @param fn 目标 IRFunction 实例
* @throws IllegalStateException 若遇到不支持的 IR 指令类型
*/
public void generate(IRFunction fn) {
currentFn = fn.name();
out.beginFunction(currentFn);
for (IRInstruction inst : fn.body()) switch (inst) {
for (IRInstruction inst : fn.body()) {
switch (inst) {
case LoadConstInstruction c -> genLoadConst(c);
case BinaryOperationInstruction b -> genBinOp(b);
case UnaryOperationInstruction u -> genUnary(u);
@ -36,15 +71,25 @@ public final class VMCodeGenerator {
default -> throw new IllegalStateException("Unsupported IR: " + inst);
}
}
}
/* ---------- helpers ---------- */
/**
* 生成常量加载指令序列将常量推入栈并存入目标寄存器槽
*
* @param c 常量加载指令
*/
private void genLoadConst(LoadConstInstruction c) {
IRConstant k = (IRConstant) c.operands().getFirst();
emit(op("I_PUSH"), k.value().toString());
IRConstant constant = (IRConstant) c.operands().getFirst();
emit(op("I_PUSH"), constant.value().toString());
emit(op("I_STORE"), slot(c.dest()));
}
/**
* 生成二元算术或比较运算指令序列
* 依次加载两个操作数执行运算并存回目标寄存器槽
*
* @param b 二元操作指令
*/
private void genBinOp(BinaryOperationInstruction b) {
emit(op("I_LOAD"), slot((IRVirtualRegister) b.operands().get(0)));
emit(op("I_LOAD"), slot((IRVirtualRegister) b.operands().get(1)));
@ -52,15 +97,24 @@ public final class VMCodeGenerator {
emit(op("I_STORE"), slot(b.dest()));
}
/**
* 生成一元运算指令序列加载操作数执行运算并存回目标寄存器槽
*
* @param u 一元操作指令
*/
private void genUnary(UnaryOperationInstruction u) {
emit(op("I_LOAD"), slot((IRVirtualRegister) u.operands().getFirst()));
emit(op(IROpCodeMapper.toVMOp(u.op())));
emit(op("I_STORE"), slot(u.dest()));
}
/** Generates CALL addr nArgs */
/**
* 生成函数调用指令序列
* 按参数顺序加载每个参数执行调用并将返回值存入目标寄存器槽
*
* @param c 调用指令
*/
private void genCall(CallInstruction c) {
/* push arguments in IR order (already left-to-right) */
for (IRValue arg : c.getArguments()) {
emit(op("I_LOAD"), slot((IRVirtualRegister) arg));
}
@ -69,26 +123,54 @@ public final class VMCodeGenerator {
emit(op("I_STORE"), slot(c.getDest()));
}
/**
* 生成返回指令序列可选地加载返回值然后根据是否为主函数选择 HALT RET
*
* @param r 返回指令
*/
private void genRet(ReturnInstruction r) {
if (r.value() != null)
if (r.value() != null) {
emit(op("I_LOAD"), slot(r.value()));
emit("main".equals(currentFn) ? op("HALT") : op("RET"));
}
String opcode = "main".equals(currentFn) ? op("HALT") : op("RET");
out.emit(opcode);
}
/**
* 构造并输出一条 VM 指令
*
* @param opcode 操作码字符串
* @param args 可选的操作数字符串列表
*/
private void emit(String opcode, String... args) {
StringBuilder sb = new StringBuilder(opcode);
for (String a : args) sb.append(' ').append(a);
for (String a : args) {
sb.append(' ').append(a);
}
out.emit(sb.toString());
}
/**
* 将虚拟寄存器映射为对应的槽编号字符串
*
* @param r 虚拟寄存器
* @return 目标槽编号的字符串形式
*/
private String slot(IRVirtualRegister r) {
return slotMap.get(r).toString();
}
/**
* 根据 VMOpCode 常量名反射获取对应的操作码字符串
*
* @param name VMOpCode 常量字段名
* @return 对应的操作码字符串
* @throws RuntimeException 若未找到指定操作码字段
*/
private String op(String name) {
try {
Field f = VMOpCode.class.getField(name);
return f.get(null).toString();
Field field = VMOpCode.class.getField(name);
return field.get(null).toString();
} catch (Exception e) {
throw new RuntimeException("Unknown opcode: " + name, e);
}