diff --git a/src/main/java/org/jcnc/snow/compiler/backend/generator/BinaryOpGenerator.java b/src/main/java/org/jcnc/snow/compiler/backend/generator/BinaryOpGenerator.java
index 4e5bd83..91a4d91 100644
--- a/src/main/java/org/jcnc/snow/compiler/backend/generator/BinaryOpGenerator.java
+++ b/src/main/java/org/jcnc/snow/compiler/backend/generator/BinaryOpGenerator.java
@@ -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.util.IROpCodeMapper;
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.value.IRConstant;
import org.jcnc.snow.compiler.ir.value.IRVirtualRegister;
import java.util.Map;
@@ -13,15 +15,18 @@ import java.util.concurrent.atomic.AtomicInteger;
/**
* 二元运算指令生成器。
*
- * 负责将中间表示的二元运算指令(算术运算及比较运算)生成对应的虚拟机指令序列。
- * 支持对操作数进行自动类型提升,以保证运算结果的正确性。
+ * 负责将中间表示的二元运算指令(算术、位运算及比较运算)生成对应的虚拟机指令序列,
+ * 并自动进行类型提升。
+ * 同时实现 "+0 → MOV" 的 Peephole 优化,避免多余的 PUSH/ADD 序列。
*
* 类型提升优先级:D > F > L > I > S > B
*/
public class BinaryOpGenerator implements InstructionGenerator {
+ /* -------------------- 常量与工具 -------------------- */
+
/**
- * 用于生成唯一标签的计数器。
+ * 用于生成唯一标签的计数器
*/
private static final AtomicInteger COUNTER = new AtomicInteger(0);
@@ -30,17 +35,14 @@ public class BinaryOpGenerator implements InstructionGenerator 3;
case 'S' -> 2;
case 'B' -> 1;
- default -> 0;
+ default -> 0;
};
}
/**
- * 比较两个类型字符,返回优先级更高的那个。
- *
- * @param a 左操作数类型
- * @param b 右操作数类型
- * @return 优先级更高者的类型字符
+ * 返回优先级更高的类型字符
*/
private static char promote(char a, char b) {
return rank(a) >= rank(b) ? a : b;
}
/**
- * 将类型字符转换为字符串形式。
- *
- * @param p 类型字符
- * @return 长度为1的字符串
+ * 单字符转字符串
*/
private static String str(char 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 的转换指令名称。
- *
- * @param from 源类型字符
- * @param to 目标类型字符
- * @return 对应的指令名称,如 "I2L";若两类型相同或不可转换则返回 null
+ * 获取从类型 {@code from} 到 {@code to} 的转换指令名。
+ * 相同类型或无显式转换需求返回 {@code null}。
*/
private static String convert(char from, char to) {
if (from == to) return null;
@@ -100,55 +108,60 @@ public class BinaryOpGenerator implements InstructionGenerator "D2F";
case "SI" -> "S2I";
case "BI" -> "B2I";
- default -> null;
+ default -> null;
};
}
- /**
- * 返回该生成器支持的指令类型。
- *
- * @return BinaryOperationInstruction 的 Class 对象
- */
+ /* -------------------- 接口实现 -------------------- */
+
@Override
public Class supportedClass() {
return BinaryOperationInstruction.class;
}
- /**
- * 根据中间表示的二元运算指令生成对应的虚拟机指令序列。
- *
- * 步骤:
- *
- * - 获取操作数与目标操作数寄存槽位及其类型。
- * - 将左右操作数加载到栈并根据需要进行类型转换。
- * - 区分算术/位运算与比较运算,分别生成不同指令序列:
- *
- * - 算术/位运算:直接调用对应的运算指令并保存结果。
- * - 比较运算:使用条件跳转生成布尔结果。
- *
- * - 将结果存回目标槽位,并更新槽位类型。
- *
- *
- * @param ins 中间表示的二元运算指令实例
- * @param out 字节码生成器,用于输出虚拟机指令
- * @param slotMap 虚拟寄存器到槽位编号的映射
- * @param currentFn 当前函数名,用于生成唯一标签
- */
@Override
public void generate(BinaryOperationInstruction ins,
VMProgramBuilder out,
Map slotMap,
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. 槽位与类型 ---------- */
int lSlot = slotMap.get((IRVirtualRegister) ins.operands().get(0));
int rSlot = slotMap.get((IRVirtualRegister) ins.operands().get(1));
int dSlot = slotMap.get(ins.dest());
- char lType = out.getSlotType(lSlot); // 如未登记默认 'I'
+ char lType = out.getSlotType(lSlot); // 未登记默认 'I'
char rType = out.getSlotType(rSlot);
- char tType = promote(lType, rType); // 类型提升结果
+ char tType = promote(lType, rType); // 类型提升结果
String tPre = str(tType);
/* ---------- 2. 加载并做类型转换 ---------- */
@@ -161,13 +174,12 @@ public class BinaryOpGenerator implements InstructionGenerator slotMap,
String currentFn) {
- // 获取操作数所在槽号
- int slotId = slotMap.get((IRVirtualRegister) ins.operands().getFirst());
- // 加载操作数到虚拟机栈顶
- out.emit(OpHelper.opcode("I_LOAD") + " " + slotId);
- // 生成对应的一元运算操作码(如取负等)
- out.emit(OpHelper.opcode(IROpCodeMapper.toVMOp(ins.op())));
- // 将结果存储到目标寄存器槽
- out.emit(OpHelper.opcode("I_STORE") + " " + slotMap.get(ins.dest()));
+
+ /* -------- 1. 源槽位与类型 -------- */
+ int srcSlot = slotMap.get((IRVirtualRegister) ins.operands().getFirst());
+ char prefix = out.getSlotType(srcSlot); // 未登记则返回默认 'I'
+
+ String loadOp = prefix + "_LOAD";
+ String storeOp = prefix + "_STORE";
+
+ /* -------- 2. 指令序列 -------- */
+ // 2-A. 加载操作数
+ out.emit(OpHelper.opcode(loadOp) +
+ " " + srcSlot);
+
+ // 2-B. 执行具体一元运算(NEG、NOT…)
+ 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);
}
}
diff --git a/src/main/java/org/jcnc/snow/compiler/ir/builder/ExpressionBuilder.java b/src/main/java/org/jcnc/snow/compiler/ir/builder/ExpressionBuilder.java
index 2d2e75e..11288ba 100644
--- a/src/main/java/org/jcnc/snow/compiler/ir/builder/ExpressionBuilder.java
+++ b/src/main/java/org/jcnc/snow/compiler/ir/builder/ExpressionBuilder.java
@@ -74,15 +74,16 @@ public record ExpressionBuilder(IRContext ctx) {
};
}
+ /** 处理一元表达式 */
private IRVirtualRegister buildUnary(UnaryExpressionNode un) {
- String op = un.operator();
- IRVirtualRegister val = build(un.operand());
+ String op = un.operator();
+ IRVirtualRegister val = build(un.operand());
- // -x → NEG_I32
+ // -x → NEG_*(根据类型自动选择位宽)
if (op.equals("-")) {
IRVirtualRegister dest = ctx.newRegister();
- ctx.addInstruction(new UnaryOperationInstruction(
- IROpCode.NEG_I32, dest, val));
+ IROpCode code = ExpressionUtils.negOp(un.operand());
+ ctx.addInstruction(new UnaryOperationInstruction(code, dest, val));
return dest;
}
diff --git a/src/main/java/org/jcnc/snow/compiler/ir/builder/StatementBuilder.java b/src/main/java/org/jcnc/snow/compiler/ir/builder/StatementBuilder.java
index 18f750b..8a95ca5 100644
--- a/src/main/java/org/jcnc/snow/compiler/ir/builder/StatementBuilder.java
+++ b/src/main/java/org/jcnc/snow/compiler/ir/builder/StatementBuilder.java
@@ -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.StatementNode;
+import java.util.Locale;
+
/**
* StatementBuilder —— 将 AST 语句节点 ({@link StatementNode}) 转换为 IR 指令序列的构建器。
*
@@ -177,4 +179,16 @@ public class StatementBuilder {
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 整型处理
+ };
+ }
}
diff --git a/src/main/java/org/jcnc/snow/compiler/ir/utils/ExpressionUtils.java b/src/main/java/org/jcnc/snow/compiler/ir/utils/ExpressionUtils.java
index cc1e426..91155df 100644
--- a/src/main/java/org/jcnc/snow/compiler/ir/utils/ExpressionUtils.java
+++ b/src/main/java/org/jcnc/snow/compiler/ir/utils/ExpressionUtils.java
@@ -78,6 +78,30 @@ public class ExpressionUtils {
};
}
+ /**
+ * 根据表达式节点推断一元取负(-)运算应使用的操作码。
+ *
+ *
优先级与 {@link #resolveOpCode} 使用的类型提升规则保持一致:
+ *
+ * - 字面量或标识符带显式后缀时,直接以后缀决定位宽;
+ * - 未显式指定时,默认使用 32 位整型 {@link IROpCode#NEG_I32}。
+ *
+ *
+ * @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;
+ };
+ }
+
/* =================== 类型推断与操作符匹配 =================== */
/**