fix:更正 int 与 long 操作数的比较跳转前缀

This commit is contained in:
Luke 2025-06-25 10:45:03 +08:00
parent c7a953995a
commit db80395159

View File

@ -10,18 +10,26 @@ import org.jcnc.snow.compiler.ir.value.IRVirtualRegister;
import java.util.Map;
/**
* 条件比较跳转指令生成器
* <b>条件比较跳转指令生成器</b>
* <p>
* 该类实现了 {@link InstructionGenerator} 接口用于将 IR 中的条件比较跳转指令
* 转换为虚拟机可执行的指令序列主要流程是先将比较操作数加载到虚拟机栈中生成比较操作码
* 并发出跳转到目标标签的指令
* 该类实现了 {@link InstructionGenerator} 接口
* 负责将 IR 中的 {@link IRCompareJumpInstruction}条件比较并跳转指令
* 转换为目标虚拟机VM可执行的指令序列
* </p>
*
* <b>主要功能</b>
* <ul>
* <li>根据 IR 比较指令左右操作数的类型自动进行类型提升与转换</li>
* <li>生成相应的 VM 加载类型转换比较与跳转指令</li>
* <li>保证指令的类型前缀与操作数类型一致提升兼容性与正确性</li>
* </ul>
*/
public class CmpJumpGenerator implements InstructionGenerator<IRCompareJumpInstruction> {
/**
* 返回该生成器所支持的指令类型
* 返回本生成器支持的 IR 指令类型
*
* @return {@link IRCompareJumpInstruction} 的类对象
* @return IRCompareJumpInstruction 的类对象
*/
@Override
public Class<IRCompareJumpInstruction> supportedClass() {
@ -29,7 +37,19 @@ public class CmpJumpGenerator implements InstructionGenerator<IRCompareJumpInstr
}
/**
* 类型优先级D &gt; F &gt; L &gt; I &gt; S &gt; B
* <b>类型宽度优先级</b>D > F > L > I > S > B
* <ul>
* <li>Ddouble6</li>
* <li>Ffloat5</li>
* <li>Llong4</li>
* <li>Iint3</li>
* <li>Sshort2</li>
* <li>Bbyte1</li>
* <li>未识别类型0</li>
* </ul>
*
* @param p 类型标记字符
* @return 优先级数值越大类型越宽
*/
private static int rank(char p) {
return switch (p) {
@ -39,27 +59,40 @@ public class CmpJumpGenerator implements InstructionGenerator<IRCompareJumpInstr
case 'I' -> 3;
case 'S' -> 2;
case 'B' -> 1;
default -> 0;
default -> 0;
};
}
/**
* 返回优先级更高的类型字符
* 返回更的公共类型即优先级高的类型
*
* @param a 类型标记字符 1
* @param b 类型标记字符 2
* @return 宽度更高的类型标记字符
*/
private static char promote(char a, char b) {
return rank(a) >= rank(b) ? a : b;
}
/**
* 单字符转字符串
* 单字符类型标记转字符串
*
* @param p 类型标记字符
* @return 类型字符串
*/
private static String str(char p) {
return String.valueOf(p);
}
/**
* 获取从类型 {@code from} {@code to} 的转换指令名
* 相同类型或无显式转换需求返回 {@code null}
* 获取 {@code from to} 的类型转换指令名如不需转换则返回 {@code null}
* <p>
* 仅覆盖目前常见的整数与浮点类型提升与转换后续有新类型可补充
* </p>
*
* @param from 源类型标记字符
* @param to 目标类型标记字符
* @return 转换指令名L2I无转换返回 {@code null}
*/
private static String convert(char from, char to) {
if (from == to) return null;
@ -78,46 +111,64 @@ public class CmpJumpGenerator implements InstructionGenerator<IRCompareJumpInstr
case "DF" -> "D2F";
case "SI" -> "S2I";
case "BI" -> "B2I";
default -> null;
default -> null;
};
}
/**
* 生成条件比较跳转相关的虚拟机指令
* 生成 IR 条件比较跳转指令的 VM 指令序列
* <ol>
* <li>确定左右操作数的槽位及静态类型</li>
* <li>加载并按需类型提升转换</li>
* <li>根据公共类型调整比较指令前缀</li>
* <li>发出最终比较和跳转指令</li>
* </ol>
*
* @param ins 需要生成的条件比较跳转中间指令IR
* @param out 虚拟机程序构建器用于输出生成的指令
* @param slotMap 虚拟寄存器到实际槽slot编号的映射表
* @param currentFn 当前处理的函数名可用于调试或作用域标识
* @param ins IR 条件比较跳转指令
* @param out VMProgramBuilder用于发出 VM 指令
* @param slotMap 虚拟寄存器到 VM 槽位的映射表
* @param currentFn 当前处理的函数名调试用当前未使用
*/
@Override
public void generate(IRCompareJumpInstruction ins,
VMProgramBuilder out,
Map<IRVirtualRegister, Integer> slotMap,
String currentFn) {
// 获取左操作数所在的寄存器槽编号
int leftSlot = slotMap.get(ins.left());
// 获取右操作数所在的寄存器槽编号
int rightSlot = slotMap.get(ins.right());
public void generate(IRCompareJumpInstruction ins,
VMProgramBuilder out,
Map<IRVirtualRegister,Integer> slotMap,
String currentFn) {
char lType = out.getSlotType(leftSlot); // 未登记默认 'I'
char rType = out.getSlotType(rightSlot);
// 1. 获取左右操作数的槽位与静态类型
int leftSlot = slotMap.get(ins.left());
int rightSlot = slotMap.get(ins.right());
char lType = out.getSlotType(leftSlot); // 若未登记则默认 'I'
char rType = out.getSlotType(rightSlot);
char tType = promote(lType, rType); // 公共类型提升
char tType = promote(lType, rType); // 类型提升结果
// 加载左操作数到虚拟机栈
// 2. 加载左右操作数并按需类型转换
// 左操作数
out.emit(OpHelper.opcode(str(lType) + "_LOAD") + " " + leftSlot);
String cvt = convert(lType, tType);
if (cvt != null) out.emit(OpHelper.opcode(cvt));
if (cvt != null) {
out.emit(OpHelper.opcode(cvt));
}
// 加载右操作数到虚拟机栈
// 右操作数
out.emit(OpHelper.opcode(str(rType) + "_LOAD") + " " + rightSlot);
cvt = convert(rType, tType);
if (cvt != null) out.emit(OpHelper.opcode(cvt));
if (cvt != null) {
out.emit(OpHelper.opcode(cvt));
}
// 获取与当前比较操作对应的虚拟机操作码
// 3. 选择正确的比较指令前缀
String cmpOp = IROpCodeMapper.toVMOp(ins.op());
// 生成分支跳转指令如果比较成立则跳转到目标标签
/*
* 修正指令前缀 int 类型要用 IC_*, long 类型要用 LC_*
*/
if (tType == 'I' && cmpOp.startsWith("LC_")) {
cmpOp = "IC_" + cmpOp.substring(3);
} else if (tType == 'L' && cmpOp.startsWith("IC_")) {
cmpOp = "LC_" + cmpOp.substring(3);
}
// 4. 发出比较与跳转指令
out.emitBranch(OpHelper.opcode(cmpOp), ins.label());
}
}