fix: 修复取反类型推断错误

This commit is contained in:
Luke 2025-06-13 14:46:42 +08:00
parent 616d361c9d
commit 6843bb4af2
5 changed files with 138 additions and 71 deletions

View File

@ -4,7 +4,9 @@ import org.jcnc.snow.compiler.backend.builder.VMProgramBuilder;
import org.jcnc.snow.compiler.backend.core.InstructionGenerator; import org.jcnc.snow.compiler.backend.core.InstructionGenerator;
import org.jcnc.snow.compiler.backend.util.IROpCodeMapper; import org.jcnc.snow.compiler.backend.util.IROpCodeMapper;
import org.jcnc.snow.compiler.backend.util.OpHelper; import org.jcnc.snow.compiler.backend.util.OpHelper;
import org.jcnc.snow.compiler.ir.core.IRValue;
import org.jcnc.snow.compiler.ir.instruction.BinaryOperationInstruction; import org.jcnc.snow.compiler.ir.instruction.BinaryOperationInstruction;
import org.jcnc.snow.compiler.ir.value.IRConstant;
import org.jcnc.snow.compiler.ir.value.IRVirtualRegister; import org.jcnc.snow.compiler.ir.value.IRVirtualRegister;
import java.util.Map; import java.util.Map;
@ -13,15 +15,18 @@ import java.util.concurrent.atomic.AtomicInteger;
/** /**
* 二元运算指令生成器 * 二元运算指令生成器
* <p> * <p>
* 负责将中间表示的二元运算指令算术运算及比较运算生成对应的虚拟机指令序列 * 负责将中间表示的二元运算指令算术位运算及比较运算生成对应的虚拟机指令序列
* 支持对操作数进行自动类型提升以保证运算结果的正确性 * 并自动进行类型提升
* 同时实现 "+0 → MOV" Peephole 优化避免多余的 PUSH/ADD 序列
* </p> * </p>
* <p>类型提升优先级D &gt; F &gt; L &gt; I &gt; S &gt; B</p> * <p>类型提升优先级D &gt; F &gt; L &gt; I &gt; S &gt; B</p>
*/ */
public class BinaryOpGenerator implements InstructionGenerator<BinaryOperationInstruction> { public class BinaryOpGenerator implements InstructionGenerator<BinaryOperationInstruction> {
/* -------------------- 常量与工具 -------------------- */
/** /**
* 用于生成唯一标签的计数器 * 用于生成唯一标签的计数器
*/ */
private static final AtomicInteger COUNTER = new AtomicInteger(0); private static final AtomicInteger COUNTER = new AtomicInteger(0);
@ -30,17 +35,14 @@ public class BinaryOpGenerator implements InstructionGenerator<BinaryOperationIn
* *
* @param fn 当前函数名用于标签前缀 * @param fn 当前函数名用于标签前缀
* @param tag 标签用途标识 * @param tag 标签用途标识
* @return 格式为 fn$tag$序号 的唯一标签字符串 * @return 形如 fn$tag$序号 的唯一标签
*/ */
private static String fresh(String fn, String tag) { private static String fresh(String fn, String tag) {
return fn + "$" + tag + "$" + COUNTER.getAndIncrement(); return fn + "$" + tag + "$" + COUNTER.getAndIncrement();
} }
/** /**
* 返回类型字符对应的优先级 * 类型优先级D &gt; F &gt; L &gt; I &gt; S &gt; B
*
* @param p 类型字符例如 'D','F','L','I','S','B'
* @return 对应的优先级整数数值越大优先级越高
*/ */
private static int rank(char p) { private static int rank(char p) {
return switch (p) { return switch (p) {
@ -50,38 +52,44 @@ public class BinaryOpGenerator implements InstructionGenerator<BinaryOperationIn
case 'I' -> 3; case 'I' -> 3;
case 'S' -> 2; case 'S' -> 2;
case 'B' -> 1; case 'B' -> 1;
default -> 0; default -> 0;
}; };
} }
/** /**
* 比较两个类型字符返回优先级更高的那个 * 返回优先级更高的类型字符
*
* @param a 左操作数类型
* @param b 右操作数类型
* @return 优先级更高者的类型字符
*/ */
private static char promote(char a, char b) { private static char promote(char a, char b) {
return rank(a) >= rank(b) ? a : b; return rank(a) >= rank(b) ? a : b;
} }
/** /**
* 将类型字符转换为字符串形式 * 单字符转字符串
*
* @param p 类型字符
* @return 长度为1的字符串
*/ */
private static String str(char p) { private static String str(char p) {
return String.valueOf(p); return String.valueOf(p);
} }
/**
* 判断常量值是否等于 0
* 仅支持 Java 原生数值类型
*/
private static boolean isZero(Object v) {
if (v == null) return false;
return switch (v) {
case Integer i -> i == 0;
case Long l -> l == 0L;
case Short s -> s == (short) 0;
case Byte b -> b == (byte) 0;
case Float f -> f == 0.0f;
case Double d -> d == 0.0;
default -> false;
};
}
/** /**
* 获取从类型 from 到类型 to 的转换指令名称 * 获取从类型 {@code from} {@code to} 的转换指令名
* * 相同类型或无显式转换需求返回 {@code null}
* @param from 源类型字符
* @param to 目标类型字符
* @return 对应的指令名称 "I2L"若两类型相同或不可转换则返回 null
*/ */
private static String convert(char from, char to) { private static String convert(char from, char to) {
if (from == to) return null; if (from == to) return null;
@ -100,55 +108,60 @@ public class BinaryOpGenerator implements InstructionGenerator<BinaryOperationIn
case "DF" -> "D2F"; case "DF" -> "D2F";
case "SI" -> "S2I"; case "SI" -> "S2I";
case "BI" -> "B2I"; case "BI" -> "B2I";
default -> null; default -> null;
}; };
} }
/** /* -------------------- 接口实现 -------------------- */
* 返回该生成器支持的指令类型
*
* @return BinaryOperationInstruction Class 对象
*/
@Override @Override
public Class<BinaryOperationInstruction> supportedClass() { public Class<BinaryOperationInstruction> supportedClass() {
return BinaryOperationInstruction.class; return BinaryOperationInstruction.class;
} }
/**
* 根据中间表示的二元运算指令生成对应的虚拟机指令序列
*
* <p>步骤</p>
* <ol>
* <li>获取操作数与目标操作数寄存槽位及其类型</li>
* <li>将左右操作数加载到栈并根据需要进行类型转换</li>
* <li>区分算术/位运算与比较运算分别生成不同指令序列</li>
* <ul>
* <li>算术/位运算直接调用对应的运算指令并保存结果</li>
* <li>比较运算使用条件跳转生成布尔结果</li>
* </ul>
* <li>将结果存回目标槽位并更新槽位类型</li>
* </ol>
*
* @param ins 中间表示的二元运算指令实例
* @param out 字节码生成器用于输出虚拟机指令
* @param slotMap 虚拟寄存器到槽位编号的映射
* @param currentFn 当前函数名用于生成唯一标签
*/
@Override @Override
public void generate(BinaryOperationInstruction ins, public void generate(BinaryOperationInstruction ins,
VMProgramBuilder out, VMProgramBuilder out,
Map<IRVirtualRegister, Integer> slotMap, Map<IRVirtualRegister, Integer> slotMap,
String currentFn) { String currentFn) {
/* ---------- 0. +0 → MOV Peephole 优化 ---------- */
String irName = ins.op().name();
if (irName.startsWith("ADD_")) {
IRValue lhs = ins.operands().getFirst();
IRValue rhs = ins.operands().get(1);
boolean lhsZero = lhs instanceof IRConstant && isZero(((IRConstant) lhs).value());
boolean rhsZero = rhs instanceof IRConstant && isZero(((IRConstant) rhs).value());
// 仅当一侧为常量 0 时可替换为 MOV
if (lhsZero ^ rhsZero) {
IRVirtualRegister srcVr = null;
if ((lhsZero ? rhs : lhs) instanceof IRVirtualRegister) {
srcVr = (IRVirtualRegister) (lhsZero ? rhs : lhs);
}
int srcSlot = slotMap.get(srcVr);
int destSlot = slotMap.get(ins.dest());
// 源与目标槽位不同才需要发 MOV
if (srcSlot != destSlot) {
out.emit(OpHelper.opcode("MOV") + " " + srcSlot + " " + destSlot);
}
// 复制槽位类型信息
out.setSlotType(destSlot, out.getSlotType(srcSlot));
return; // 优化路径结束
}
}
/* ---------- 1. 槽位与类型 ---------- */ /* ---------- 1. 槽位与类型 ---------- */
int lSlot = slotMap.get((IRVirtualRegister) ins.operands().get(0)); int lSlot = slotMap.get((IRVirtualRegister) ins.operands().get(0));
int rSlot = slotMap.get((IRVirtualRegister) ins.operands().get(1)); int rSlot = slotMap.get((IRVirtualRegister) ins.operands().get(1));
int dSlot = slotMap.get(ins.dest()); int dSlot = slotMap.get(ins.dest());
char lType = out.getSlotType(lSlot); // 如未登记默认 'I' char lType = out.getSlotType(lSlot); // 未登记默认 'I'
char rType = out.getSlotType(rSlot); char rType = out.getSlotType(rSlot);
char tType = promote(lType, rType); // 类型提升结果 char tType = promote(lType, rType); // 类型提升结果
String tPre = str(tType); String tPre = str(tType);
/* ---------- 2. 加载并做类型转换 ---------- */ /* ---------- 2. 加载并做类型转换 ---------- */
@ -161,13 +174,12 @@ public class BinaryOpGenerator implements InstructionGenerator<BinaryOperationIn
if (cvt != null) out.emit(OpHelper.opcode(cvt)); if (cvt != null) out.emit(OpHelper.opcode(cvt));
/* ---------- 3. 区分算术 / 比较 ---------- */ /* ---------- 3. 区分算术 / 比较 ---------- */
String irName = ins.op().name();
boolean isCmp = irName.startsWith("CMP_"); boolean isCmp = irName.startsWith("CMP_");
/* === 3-A. 普通算术 / 位运算 === */ /* === 3-A. 普通算术 / 位运算 === */
if (!isCmp) { if (!isCmp) {
String opName = irName.split("_")[0]; // ADD / SUB / MUL String opCore = irName.split("_")[0]; // ADD / SUB / MUL
out.emit(OpHelper.opcode(tPre + "_" + opName)); // I_ADD / D_MUL out.emit(OpHelper.opcode(tPre + "_" + opCore));
out.emit(OpHelper.opcode(tPre + "_STORE") + " " + dSlot); out.emit(OpHelper.opcode(tPre + "_STORE") + " " + dSlot);
out.setSlotType(dSlot, tType); out.setSlotType(dSlot, tType);
return; return;
@ -175,8 +187,8 @@ public class BinaryOpGenerator implements InstructionGenerator<BinaryOperationIn
/* === 3-B. CMP_* —— 生成布尔结果 === */ /* === 3-B. CMP_* —— 生成布尔结果 === */
String branchOp = OpHelper.opcode(IROpCodeMapper.toVMOp(ins.op())); // IC_E / IC_NE String branchOp = OpHelper.opcode(IROpCodeMapper.toVMOp(ins.op())); // IC_E / IC_NE
String lblTrue = fresh(currentFn, "true"); String lblTrue = fresh(currentFn, "true");
String lblEnd = fresh(currentFn, "end"); String lblEnd = fresh(currentFn, "end");
// 条件跳转成立 lblTrue // 条件跳转成立 lblTrue
out.emitBranch(branchOp, lblTrue); out.emitBranch(branchOp, lblTrue);
@ -194,6 +206,6 @@ public class BinaryOpGenerator implements InstructionGenerator<BinaryOperationIn
// 写入目标槽位 // 写入目标槽位
out.emit(OpHelper.opcode("I_STORE") + " " + dSlot); out.emit(OpHelper.opcode("I_STORE") + " " + dSlot);
out.setSlotType(dSlot, 'I'); // 布尔 int out.setSlotType(dSlot, 'I'); // 布尔 int
} }
} }

View File

@ -41,13 +41,29 @@ public class UnaryOpGenerator implements InstructionGenerator<UnaryOperationInst
VMProgramBuilder out, VMProgramBuilder out,
Map<IRVirtualRegister, Integer> slotMap, Map<IRVirtualRegister, Integer> slotMap,
String currentFn) { String currentFn) {
// 获取操作数所在槽号
int slotId = slotMap.get((IRVirtualRegister) ins.operands().getFirst()); /* -------- 1. 源槽位与类型 -------- */
// 加载操作数到虚拟机栈顶 int srcSlot = slotMap.get((IRVirtualRegister) ins.operands().getFirst());
out.emit(OpHelper.opcode("I_LOAD") + " " + slotId); char prefix = out.getSlotType(srcSlot); // 未登记则返回默认 'I'
// 生成对应的一元运算操作码如取负等
out.emit(OpHelper.opcode(IROpCodeMapper.toVMOp(ins.op()))); String loadOp = prefix + "_LOAD";
// 将结果存储到目标寄存器槽 String storeOp = prefix + "_STORE";
out.emit(OpHelper.opcode("I_STORE") + " " + slotMap.get(ins.dest()));
/* -------- 2. 指令序列 -------- */
// 2-A. 加载操作数
out.emit(OpHelper.opcode(loadOp) +
" " + srcSlot);
// 2-B. 执行具体一元运算NEGNOT
out.emit(OpHelper.opcode(
IROpCodeMapper.toVMOp(ins.op())));
// 2-C. 存结果到目标槽
int destSlot = slotMap.get(ins.dest());
out.emit(OpHelper.opcode(storeOp) +
" " + destSlot);
/* -------- 3. 更新目标槽类型 -------- */
out.setSlotType(destSlot, prefix);
} }
} }

View File

@ -74,15 +74,16 @@ public record ExpressionBuilder(IRContext ctx) {
}; };
} }
/** 处理一元表达式 */
private IRVirtualRegister buildUnary(UnaryExpressionNode un) { private IRVirtualRegister buildUnary(UnaryExpressionNode un) {
String op = un.operator(); String op = un.operator();
IRVirtualRegister val = build(un.operand()); IRVirtualRegister val = build(un.operand());
// -x NEG_I32 // -x NEG_*根据类型自动选择位宽
if (op.equals("-")) { if (op.equals("-")) {
IRVirtualRegister dest = ctx.newRegister(); IRVirtualRegister dest = ctx.newRegister();
ctx.addInstruction(new UnaryOperationInstruction( IROpCode code = ExpressionUtils.negOp(un.operand());
IROpCode.NEG_I32, dest, val)); ctx.addInstruction(new UnaryOperationInstruction(code, dest, val));
return dest; return dest;
} }

View File

@ -8,6 +8,8 @@ import org.jcnc.snow.compiler.parser.ast.*;
import org.jcnc.snow.compiler.parser.ast.base.ExpressionNode; import org.jcnc.snow.compiler.parser.ast.base.ExpressionNode;
import org.jcnc.snow.compiler.parser.ast.base.StatementNode; import org.jcnc.snow.compiler.parser.ast.base.StatementNode;
import java.util.Locale;
/** /**
* StatementBuilder AST 语句节点 ({@link StatementNode}) 转换为 IR 指令序列的构建器 * StatementBuilder AST 语句节点 ({@link StatementNode}) 转换为 IR 指令序列的构建器
* <p> * <p>
@ -177,4 +179,16 @@ public class StatementBuilder {
InstructionFactory.cmpJump(ctx, IROpCode.CMP_EQ, condReg, zero, falseLabel); InstructionFactory.cmpJump(ctx, IROpCode.CMP_EQ, condReg, zero, falseLabel);
} }
} }
private static char typeSuffixFromType(String type) {
if (type == null) return '\0';
return switch (type.toLowerCase(Locale.ROOT)) {
case "byte" -> 'b';
case "short" -> 's';
case "long" -> 'l';
case "float" -> 'f';
case "double" -> 'd';
default -> '\0'; // 其余默认按 32-bit 整型处理
};
}
} }

View File

@ -78,6 +78,30 @@ public class ExpressionUtils {
}; };
} }
/**
* 根据表达式节点推断一元取负-运算应使用的操作码
*
* <p>优先级与 {@link #resolveOpCode} 使用的类型提升规则保持一致</p>
* <ul>
* <li>字面量或标识符带显式后缀时直接以后缀决定位宽</li>
* <li>未显式指定时默认使用 32 位整型 {@link IROpCode#NEG_I32}</li>
* </ul>
*
* @param operand 一元取负运算的操作数
* @return 匹配的 {@link IROpCode}
*/
public static IROpCode negOp(ExpressionNode operand) {
char t = typeChar(operand);
return switch (t) {
case 'b' -> IROpCode.NEG_B8;
case 's' -> IROpCode.NEG_S16;
case 'l' -> IROpCode.NEG_L64;
case 'f' -> IROpCode.NEG_F32;
case 'd' -> IROpCode.NEG_D64;
default -> IROpCode.NEG_I32;
};
}
/* =================== 类型推断与操作符匹配 =================== */ /* =================== 类型推断与操作符匹配 =================== */
/** /**