From f29e6eccb5483c5dc49f25f621f5a627eeeb76d0 Mon Sep 17 00:00:00 2001 From: Luke Date: Fri, 9 May 2025 09:54:31 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BC=98=E5=8C=96=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../snow/compiler/backend/IROpCodeMapper.java | 70 ++++++++++++ .../compiler/backend/RegisterAllocator.java | 46 ++++++-- .../compiler/backend/VMCodeGenerator.java | 103 ++++++++++++------ 3 files changed, 175 insertions(+), 44 deletions(-) create mode 100644 src/main/java/org/jcnc/snow/compiler/backend/IROpCodeMapper.java diff --git a/src/main/java/org/jcnc/snow/compiler/backend/IROpCodeMapper.java b/src/main/java/org/jcnc/snow/compiler/backend/IROpCodeMapper.java new file mode 100644 index 0000000..c6cb9e4 --- /dev/null +++ b/src/main/java/org/jcnc/snow/compiler/backend/IROpCodeMapper.java @@ -0,0 +1,70 @@ +package org.jcnc.snow.compiler.backend; + +import org.jcnc.snow.compiler.ir.core.IROpCode; + +import java.util.EnumMap; +import java.util.Map; + +/** + * IROpCodeMapper —— IR 操作码(IROpCode)到 VM 虚拟机操作码(字符串形式)的映射器。 + *

+ * 本类用于编译器后端阶段,将中间表示中的操作类型(如 ADD_I32)转换为 + * 虚拟机指令集中的具体指令(如 "I_ADD"),用于代码生成输出。 + *

+ *

+ * 注意:该类只做一一映射,不处理操作数或参数传递逻辑。 + * 若未来有更多数据类型或扩展语义,可在此处集中管理。 + *

+ */ +public final class IROpCodeMapper { + + /** 存储映射关系的枚举映射表(使用 EnumMap 提高性能) */ + private static final Map 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"); + opcodeMap.put(IROpCode.CMP_GT, "IC_G"); + 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 指令名(字符串)。 + * + * @param irOp IROpCode 中的操作码 + * @return 对应的 VM opcode 字符串 + * @throws IllegalArgumentException 若操作码未被映射 + */ + public static String toVMOp(IROpCode irOp) { + String code = opcodeMap.get(irOp); + if (code == null) { + throw new IllegalArgumentException("未映射的 IR 操作码: " + irOp); + } + return code; + } +} diff --git a/src/main/java/org/jcnc/snow/compiler/backend/RegisterAllocator.java b/src/main/java/org/jcnc/snow/compiler/backend/RegisterAllocator.java index 970ea1e..4bd906c 100644 --- a/src/main/java/org/jcnc/snow/compiler/backend/RegisterAllocator.java +++ b/src/main/java/org/jcnc/snow/compiler/backend/RegisterAllocator.java @@ -1,5 +1,3 @@ -// ────────────────────────────────────────── -// file: compiler/backend/RegisterAllocator.java package org.jcnc.snow.compiler.backend; import org.jcnc.snow.compiler.ir.core.IRFunction; @@ -10,17 +8,45 @@ import org.jcnc.snow.compiler.ir.value.IRVirtualRegister; import java.util.HashMap; import java.util.Map; -/** 线性扫描寄存器分配(演示级) */ +/** + * RegisterAllocator —— 简单的线性扫描寄存器分配器(演示级实现)。 + *

+ * 该类用于为 IRFunction 中出现的所有虚拟寄存器(IRVirtualRegister)分配槽位编号。 + * 每个槽位编号对应虚拟机中的局部变量位置或栈槽。 + *

+ *

+ * 算法策略:顺序扫描所有 IR 指令,每遇到一个新的虚拟寄存器就分配一个递增编号。 + * 不考虑寄存器生存期重叠、重用或优化,仅做简单映射。 + *

+ */ public final class RegisterAllocator { - private final Map map = new HashMap<>(); - public Map allocate(IRFunction fn){ - int next = 0; - for (IRInstruction i : fn.body()){ - if(i.dest()!=null && !map.containsKey(i.dest())) map.put(i.dest(), next++); - for(IRValue v : i.operands()) - if(v instanceof IRVirtualRegister r && !map.containsKey(r)) map.put(r, next++); + /** 虚拟寄存器 → 槽位编号 的映射表 */ + private final Map map = new HashMap<>(); + + /** + * 执行寄存器分配:将函数中所有虚拟寄存器映射为连续的整型槽位编号。 + * + * @param fn 中间表示形式的函数(IRFunction) + * @return 映射表(IRVirtualRegister → 槽位编号) + */ + public Map allocate(IRFunction fn) { + int next = 0; // 当前可分配的下一个槽位编号 + + for (IRInstruction i : fn.body()) { + // 若该指令有目标寄存器(dest),且尚未分配槽位 → 分配一个 + if (i.dest() != null && !map.containsKey(i.dest())) { + map.put(i.dest(), next++); + } + + // 遍历指令的所有操作数(operand),若是寄存器也进行分配 + for (IRValue v : i.operands()) { + if (v instanceof IRVirtualRegister r && !map.containsKey(r)) { + map.put(r, next++); + } + } } + return map; } } diff --git a/src/main/java/org/jcnc/snow/compiler/backend/VMCodeGenerator.java b/src/main/java/org/jcnc/snow/compiler/backend/VMCodeGenerator.java index 7ec94c8..6864c59 100644 --- a/src/main/java/org/jcnc/snow/compiler/backend/VMCodeGenerator.java +++ b/src/main/java/org/jcnc/snow/compiler/backend/VMCodeGenerator.java @@ -8,7 +8,6 @@ import org.jcnc.snow.compiler.ir.instruction.ReturnInstruction; import org.jcnc.snow.compiler.ir.instruction.UnaryOperationInstruction; import org.jcnc.snow.compiler.ir.value.IRConstant; import org.jcnc.snow.compiler.ir.value.IRVirtualRegister; -import org.jcnc.snow.vm.engine.VMOpCode; import java.lang.reflect.Field; import java.util.ArrayList; @@ -16,107 +15,143 @@ import java.util.List; import java.util.Map; /** - * 将 IRFunction 转译为 SVM 指令文本。 - * 目前支持:int32 常量、+ - * /、一元 -、return。 + * VMCodeGenerator —— 虚拟机代码生成器。 + *

+ * 该类负责将中间表示(IRFunction)翻译为 SVM 虚拟机可执行的文本指令。 + * 当前支持: + * - int32 类型的常量加载 + * - 加减乘除(+ - * /)的二元表达式 + * - 取负(一元 -) + * - 函数返回(含 main 函数终止) + *

+ *

+ * 每个虚拟寄存器通过 slotMap 分配一个槽位(int 索引),用于定位变量。 + * 生成的代码是一系列字符串,格式为汇编式:OPCODE 参数... + *

*/ public final class VMCodeGenerator { + /** 虚拟寄存器 → 栈槽编号的映射表(由编译器分配) */ private final Map slotMap; + + /** 存储生成的指令 */ private final List code = new ArrayList<>(); - private String currentFnName; // ← 当前正在生成的函数名 + /** 当前正在生成代码的函数名称 */ + private String currentFnName; public VMCodeGenerator(Map slotMap) { this.slotMap = slotMap; } /** - * 主入口:IR → 指令序列 + * 主入口:接收一个中间表示函数(IRFunction),输出对应的 VM 指令文本序列 + * + * @param fn IRFunction,包含该函数的所有 IRInstruction + * @return 指令字符串列表 */ public List generate(IRFunction fn) { - currentFnName = fn.name(); // ← 保存函数名 + currentFnName = fn.name(); for (IRInstruction inst : fn.body()) { switch (inst) { - case LoadConstInstruction c -> genLoadConst(c); - case BinaryOperationInstruction b -> genBinOp(b); - case UnaryOperationInstruction u -> genUnary(u); - case ReturnInstruction r -> genRet(r); - default -> throw new IllegalStateException("Unsupported IR: " + inst); + case LoadConstInstruction c -> genLoadConst(c); // 常量加载 + case BinaryOperationInstruction b -> genBinOp(b); // 二元操作 + case UnaryOperationInstruction u -> genUnary(u); // 一元操作 + case ReturnInstruction r -> genRet(r); // 返回语句 + default -> throw new IllegalStateException("不支持的 IR 指令类型: " + inst); } } - /* 注意:不再额外添加 HALT,结束行为由 genRet 决定 */ + return code; } - /* ───────────── 指令生成 ───────────── */ - + /** + * 生成常量加载指令:I_PUSH 常量 → I_STORE 寄存器槽位 + */ private void genLoadConst(LoadConstInstruction c) { - IRConstant k = (IRConstant) c.operands().get(0); + IRConstant k = (IRConstant) c.operands().getFirst(); emit(op("I_PUSH"), k.value().toString()); emit(op("I_STORE"), slot(c.dest()) + ""); } + /** + * 生成二元运算(+ - * /) + */ 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)) + ""); - String opcode = switch (b.op()) { - case ADD_I32 -> "I_ADD"; - case SUB_I32 -> "I_SUB"; - case MUL_I32 -> "I_MUL"; - case DIV_I32 -> "I_DIV"; - default -> throw new IllegalStateException("Unsupported bin op " + b.op()); - }; + // 通过 IROpCode → VM 指令映射表获取实际指令 + String opcode = IROpCodeMapper.toVMOp(b.op()); emit(op(opcode)); emit(op("I_STORE"), slot(b.dest()) + ""); } + /** + * 生成一元运算(如取负) + */ private void genUnary(UnaryOperationInstruction u) { emit(op("I_LOAD"), slot((IRVirtualRegister) u.operands().get(0)) + ""); - String opcode = switch (u.op()) { - case NEG_I32 -> "I_NEG"; - default -> throw new IllegalStateException("Unsupported unary op " + u.op()); - }; + String opcode = IROpCodeMapper.toVMOp(u.op()); emit(op(opcode)); emit(op("I_STORE"), slot(u.dest()) + ""); } + /** + * 生成返回语句: + * - 对于 main 函数,使用 HALT 表示程序终止 + * - 其他函数使用 RET 指令返回调用者 + */ private void genRet(ReturnInstruction r) { - /* — 主函数:加载返回值(若有) → HALT — */ if ("main".equals(currentFnName)) { if (r.value() != null) { emit(op("I_LOAD"), slot(r.value()) + ""); } - emit(op("HALT")); // 结束整个程序 + emit(op("HALT")); return; } - /* — 普通函数:LOAD (可选) → RET — */ if (r.value() != null) { emit(op("I_LOAD"), slot(r.value()) + ""); } emit(op("RET")); } - /* ───────────── 工具函数 ───────────── */ - + /** + * 获取某个虚拟寄存器映射到的槽位索引 + * + * @param r 虚拟寄存器 + * @return 槽位编号 + */ private int slot(IRVirtualRegister r) { Integer s = slotMap.get(r); - if (s == null) throw new IllegalStateException("Register " + r + " 未映射槽位"); + if (s == null) throw new IllegalStateException("寄存器 " + r + " 未映射槽位"); return s; } + /** + * 通过反射方式获取 VMOpCode 中定义的静态常量值(字符串形式) + * + * @param name VM 指令名(如 "I_ADD") + * @return 指令码文本 + */ private String op(String name) { try { - Field f = VMOpCode.class.getField(name); + Field f = Class.forName("org.jcnc.snow.vm.engine.VMOpCode").getField(name); return f.get(null).toString(); } catch (Exception e) { - throw new RuntimeException("Unknown opcode " + name, e); + throw new RuntimeException("未知的 opcode: " + name, e); } } + /** + * 输出一条指令到代码列表中 + * + * @param opcode 指令名 + * @param args 参数(可选) + */ private void emit(String opcode, String... args) { StringBuilder sb = new StringBuilder(opcode); for (String a : args) sb.append(' ').append(a);