增加注释
This commit is contained in:
parent
089e629187
commit
48b7418b03
@ -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() {
|
||||
// 不允许实例化
|
||||
}
|
||||
}
|
||||
|
||||
@ -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 .. 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<>();
|
||||
/**
|
||||
* 存储虚拟寄存器到物理槽的映射表。
|
||||
* 键为虚拟寄存器,值为分配的槽编号。
|
||||
*/
|
||||
private final Map<IRVirtualRegister, Integer> map = new HashMap<>();
|
||||
|
||||
/**
|
||||
* Computes a register→slot 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) {
|
||||
|
||||
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++);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,50 +1,95 @@
|
||||
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;
|
||||
/**
|
||||
* 虚拟寄存器到槽编号的映射表,用于确定加载和存储的目标槽。
|
||||
*/
|
||||
private final Map<IRVirtualRegister, Integer> slotMap;
|
||||
|
||||
/**
|
||||
* VM 指令输出器,用于构建最终的指令流。
|
||||
*/
|
||||
private final VMProgramBuilder out;
|
||||
|
||||
/**
|
||||
* 当前正在生成代码的函数名称,用于在返回指令处区分主函数与其他函数。
|
||||
*/
|
||||
private String currentFn;
|
||||
|
||||
public VMCodeGenerator(Map<IRVirtualRegister,Integer> slotMap,
|
||||
/**
|
||||
* 构造 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);
|
||||
case CallInstruction c -> genCall(c);
|
||||
case ReturnInstruction r -> genRet(r);
|
||||
default -> throw new IllegalStateException("Unsupported IR: "+inst);
|
||||
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,28 +123,56 @@ 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);
|
||||
throw new RuntimeException("Unknown opcode: " + name, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user