From 78dee0d72a62b3854a4a47cb00b0625e11b61205 Mon Sep 17 00:00:00 2001 From: CGH0S7 <776459475@qq.com> Date: Sat, 26 Jul 2025 21:44:14 +0800 Subject: [PATCH] =?UTF-8?q?[peephole]=E6=B7=BB=E5=8A=A07=E9=A1=B9=E7=AA=A5?= =?UTF-8?q?=E5=AD=94=E4=BC=98=E5=8C=96=E8=A7=84=E5=88=99=E5=88=9D=E6=AD=A5?= =?UTF-8?q?=E6=B5=8B=E8=AF=95=E7=94=9F=E6=95=88=E6=88=90=E5=8A=9F=EF=BC=8C?= =?UTF-8?q?=E6=9C=89=E5=BE=85=E8=BF=9B=E4=B8=80=E6=AD=A5=E6=A3=80=E6=9F=A5?= =?UTF-8?q?=EF=BC=8CTODO:=20=E6=8C=87=E4=BB=A4=E8=B0=83=E5=BA=A6=E4=BC=98?= =?UTF-8?q?=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/RISCv64Passes.cpp | 702 +++++++++++++++++++++++++++++++++++++++--- 1 file changed, 663 insertions(+), 39 deletions(-) diff --git a/src/RISCv64Passes.cpp b/src/RISCv64Passes.cpp index efa333f..15d397c 100644 --- a/src/RISCv64Passes.cpp +++ b/src/RISCv64Passes.cpp @@ -1,54 +1,678 @@ #include "RISCv64Passes.h" -#include +// #include +#include namespace sysy { // --- 寄存器分配前优化 --- -void PreRA_Scheduler::runOnMachineFunction(MachineFunction* mfunc) { - // TODO: 在此实现寄存器分配前的指令调度。 - // 遍历mfunc中的每一个MachineBasicBlock。 - // 对每个基本块内的MachineInstr列表进行重排。 - // - // 实现思路: - // 1. 分析每个基本块内指令的数据依赖关系,构建依赖图(DAG)。 - // 2. 根据目标处理器的流水线特性(指令延迟等),使用列表调度等算法对指令进行重排。 - // 3. 此时操作的是虚拟寄存器,只存在真依赖,调度自由度最大。 - // - // std::cout << "Running Pre-RA Instruction Scheduler..." << std::endl; +void PreRA_Scheduler::runOnMachineFunction(MachineFunction *mfunc) { + // TODO: 在此实现寄存器分配前的指令调度。 + // 遍历mfunc中的每一个MachineBasicBlock。 + // 对每个基本块内的MachineInstr列表进行重排。 + // + // 实现思路: + // 1. 分析每个基本块内指令的数据依赖关系,构建依赖图(DAG)。 + // 2. + // 根据目标处理器的流水线特性(指令延迟等),使用列表调度等算法对指令进行重排。 + // 3. 此时操作的是虚拟寄存器,只存在真依赖,调度自由度最大。 + // + // std::cout << "Running Pre-RA Instruction Scheduler..." << std::endl; } - // --- 寄存器分配后优化 --- -void PeepholeOptimizer::runOnMachineFunction(MachineFunction* mfunc) { - // TODO: 在此实现窥孔优化。 - // 遍历mfunc中的每一个MachineBasicBlock。 - // 对每个基本块内的MachineInstr列表进行扫描和替换。 - // - // 实现思路: - // 1. 维护一个大小固定(例如3-5条指令)的滑动窗口。 - // 2. 识别特定的冗余模式,例如: - // - `mv a0, a1` 后紧跟 `mv a1, a0` (可消除的交换) - // - `sw t0, 12(s0)` 后紧跟 `lw t1, 12(s0)` (冗余加载) - // - 强度削减: `mul x, x, 2` -> `slli x, x, 1` - // 3. 识别后,直接修改MachineInstr列表(删除、替换或插入指令)。 - // - // std::cout << "Running Post-RA Peephole Optimizer..." << std::endl; +void PeepholeOptimizer::runOnMachineFunction(MachineFunction *mfunc) { + if (!mfunc) + return; + using namespace sysy; + + // areRegsEqual: 检查两个寄存器操作数是否相等(考虑虚拟和物理寄存器)。 + auto areRegsEqual = [](RegOperand *r1, RegOperand *r2) { + if (!r1 || !r2 || r1->isVirtual() != r2->isVirtual()) { + return false; + } + if (r1->isVirtual()) { + return r1->getVRegNum() == r2->getVRegNum(); + } else { + return r1->getPReg() == r2->getPReg(); + } + }; + + // 改进的 isRegUsedLater 函数 - 更完整和准确的实现 + auto isRegUsedLater = + [&](const std::vector> &instrs, + RegOperand *reg, size_t start_idx) -> bool { + for (size_t j = start_idx; j < instrs.size(); ++j) { + auto *instr = instrs[j].get(); + auto opcode = instr->getOpcode(); + + // 检查所有操作数 + for (size_t k = 0; k < instr->getOperands().size(); ++k) { + bool isDefOperand = false; + + // 更完整的定义操作数判断逻辑 + if (k == 0) { // 第一个操作数通常是目标寄存器 + switch (opcode) { + // 算术和逻辑指令 - 第一个操作数是定义 + case RVOpcodes::MV: + case RVOpcodes::ADDI: + case RVOpcodes::SLLI: + case RVOpcodes::SRLI: + case RVOpcodes::SRAI: + case RVOpcodes::SLTI: + case RVOpcodes::SLTIU: + case RVOpcodes::XORI: + case RVOpcodes::ORI: + case RVOpcodes::ANDI: + case RVOpcodes::ADD: + case RVOpcodes::SUB: + case RVOpcodes::SLL: + case RVOpcodes::SLT: + case RVOpcodes::SLTU: + case RVOpcodes::XOR: + case RVOpcodes::SRL: + case RVOpcodes::SRA: + case RVOpcodes::OR: + case RVOpcodes::AND: + case RVOpcodes::MUL: + case RVOpcodes::DIV: + case RVOpcodes::REM: + case RVOpcodes::LW: + case RVOpcodes::LH: + case RVOpcodes::LB: + case RVOpcodes::LHU: + case RVOpcodes::LBU: + + // 存储指令 - 第一个操作数是使用(要存储的值) + case RVOpcodes::SW: + case RVOpcodes::SH: + case RVOpcodes::SB: + // 分支指令 - 第一个操作数是使用 + case RVOpcodes::BEQ: + case RVOpcodes::BNE: + case RVOpcodes::BLT: + case RVOpcodes::BGE: + case RVOpcodes::BLTU: + case RVOpcodes::BGEU: + // 跳转指令 - 可能使用寄存器 + case RVOpcodes::JALR: + isDefOperand = false; + break; + + default: + // 对于未知指令,保守地假设第一个操作数可能是使用 + isDefOperand = false; + break; + } + } + + // 如果不是定义操作数,检查是否使用了目标寄存器 + if (!isDefOperand) { + if (instr->getOperands()[k]->getKind() == MachineOperand::KIND_REG) { + auto *use_reg = + static_cast(instr->getOperands()[k].get()); + if (areRegsEqual(reg, use_reg)) + return true; + } + // 检查内存操作数中的基址寄存器 + if (instr->getOperands()[k]->getKind() == MachineOperand::KIND_MEM) { + auto *mem = + static_cast(instr->getOperands()[k].get()); + if (areRegsEqual(reg, mem->getBase())) + return true; + } + } + } + } + return false; + }; + + // 检查寄存器是否在指令中被重新定义(用于更精确的分析) + auto isRegRedefinedAt = + [](MachineInstr *instr, RegOperand *reg, + const std::function &areRegsEqual) + -> bool { + if (instr->getOperands().empty()) + return false; + + auto opcode = instr->getOpcode(); + // 只有当第一个操作数是定义操作数时才检查 + switch (opcode) { + case RVOpcodes::MV: + case RVOpcodes::ADDI: + case RVOpcodes::ADD: + case RVOpcodes::SUB: + case RVOpcodes::MUL: + case RVOpcodes::LW: + // ... 其他定义指令 + if (instr->getOperands()[0]->getKind() == MachineOperand::KIND_REG) { + auto *def_reg = + static_cast(instr->getOperands()[0].get()); + return areRegsEqual(reg, def_reg); + } + break; + default: + break; + } + return false; + }; + + // 检查是否为存储-加载模式,支持不同大小的访问 + auto isStoreLoadPattern = [](MachineInstr *store_instr, + MachineInstr *load_instr) -> bool { + auto store_op = store_instr->getOpcode(); + auto load_op = load_instr->getOpcode(); + + // 检查存储-加载对应关系 + return (store_op == RVOpcodes::SW && load_op == RVOpcodes::LW) || // 32位 + (store_op == RVOpcodes::SH && + load_op == RVOpcodes::LH) || // 16位有符号 + (store_op == RVOpcodes::SH && + load_op == RVOpcodes::LHU) || // 16位无符号 + (store_op == RVOpcodes::SB && + load_op == RVOpcodes::LB) || // 8位有符号 + (store_op == RVOpcodes::SB && + load_op == RVOpcodes::LBU) || // 8位无符号 + (store_op == RVOpcodes::SD && load_op == RVOpcodes::LD); // 64位 + }; + + // 检查两个内存访问是否访问相同的内存位置 + auto areMemoryAccessesEqual = + [&areRegsEqual](MachineInstr *store_instr, MemOperand *store_mem, + MachineInstr *load_instr, MemOperand *load_mem) -> bool { + // 基址寄存器必须相同 + if (!areRegsEqual(store_mem->getBase(), load_mem->getBase())) { + return false; + } + + // 偏移量必须相同 + if (store_mem->getOffset()->getValue() != + load_mem->getOffset()->getValue()) { + return false; + } + + // 检查访问大小是否兼容 + auto store_op = store_instr->getOpcode(); + auto load_op = load_instr->getOpcode(); + + // 获取访问大小(字节数) + auto getAccessSize = [](RVOpcodes opcode) -> int { + switch (opcode) { + case RVOpcodes::LB: + case RVOpcodes::LBU: + case RVOpcodes::SB: + return 1; // 8位 + case RVOpcodes::LH: + case RVOpcodes::LHU: + case RVOpcodes::SH: + return 2; // 16位 + case RVOpcodes::LW: + case RVOpcodes::SW: + return 4; // 32位 + case RVOpcodes::LD: + case RVOpcodes::SD: + return 8; // 64位 + default: + return -1; // 未知 + } + }; + + int store_size = getAccessSize(store_op); + int load_size = getAccessSize(load_op); + + // 只有访问大小完全匹配时才能进行优化 + // 这避免了部分重叠访问的复杂情况 + return store_size > 0 && store_size == load_size; + }; + + // 简单的内存别名分析:检查两个内存访问之间是否可能有冲突的内存操作 + auto isMemoryAccessSafe = + [&](const std::vector> &instrs, + size_t store_idx, size_t load_idx, MemOperand *mem) -> bool { + // 检查存储和加载之间是否有可能影响内存的指令 + for (size_t j = store_idx + 1; j < load_idx; ++j) { + auto *between_instr = instrs[j].get(); + auto between_op = between_instr->getOpcode(); + + // 检查是否有其他内存写入操作 + switch (between_op) { + case RVOpcodes::SW: + case RVOpcodes::SH: + case RVOpcodes::SB: + case RVOpcodes::SD: { + // 如果有其他存储操作,需要检查是否可能访问相同的内存 + if (between_instr->getOperands().size() >= 2 && + between_instr->getOperands()[1]->getKind() == + MachineOperand::KIND_MEM) { + + auto *other_mem = + static_cast(between_instr->getOperands()[1].get()); + + // 保守的别名分析:如果使用不同的基址寄存器,假设可能别名 + if (!areRegsEqual(mem->getBase(), other_mem->getBase())) { + return false; // 可能的别名,不安全 + } + + // 如果基址相同但偏移量不同,检查是否重叠 + int64_t offset1 = mem->getOffset()->getValue(); + int64_t offset2 = other_mem->getOffset()->getValue(); + + // 获取访问大小来检查重叠 + auto getAccessSize = [](RVOpcodes opcode) -> int { + switch (opcode) { + case RVOpcodes::SB: + return 1; + case RVOpcodes::SH: + return 2; + case RVOpcodes::SW: + return 4; + case RVOpcodes::SD: + return 8; + default: + return 4; // 默认假设4字节 + } + }; + + int size1 = getAccessSize(RVOpcodes::SW); // 从原存储指令推断 + int size2 = getAccessSize(between_op); + + // 检查内存区域是否重叠 + bool overlaps = + !(offset1 + size1 <= offset2 || offset2 + size2 <= offset1); + if (overlaps) { + return false; // 内存重叠,不安全 + } + } + break; + } + + // 函数调用可能有副作用 + case RVOpcodes::JAL: + case RVOpcodes::JALR: + return false; // 函数调用可能修改内存,不安全 + + // 原子操作或其他可能修改内存的指令 + // 根据具体的RISC-V扩展添加更多指令 + default: + // 对于未知指令,采用保守策略 + // 可以根据具体需求调整 + break; + } + } + + return true; // 没有发现潜在的内存冲突 + }; + + // isPowerOfTwo: 检查数值是否为2的幂次,并返回其指数。 + auto isPowerOfTwo = [](int64_t n) -> int { + if (n <= 0 || (n & (n - 1)) != 0) + return -1; + int shift = 0; + while (n > 1) { + n >>= 1; + shift++; + } + return shift; + }; + + for (auto &mbb_uptr : mfunc->getBlocks()) { + auto &mbb = *mbb_uptr; + auto &instrs = mbb.getInstructions(); + if (instrs.size() < 2) + continue; // 基本块至少需要两条指令进行窥孔 + + // 遍历指令序列进行窥孔优化 + for (size_t i = 0; i + 1 < instrs.size();) { + auto *mi1 = instrs[i].get(); + auto *mi2 = instrs[i + 1].get(); + bool changed = false; + + // 1. 消除冗余交换移动: mv a, b; mv b, a -> mv a, b + if (mi1->getOpcode() == RVOpcodes::MV && + mi2->getOpcode() == RVOpcodes::MV) { + if (mi1->getOperands().size() == 2 && mi2->getOperands().size() == 2) { + if (mi1->getOperands()[0]->getKind() == MachineOperand::KIND_REG && + mi1->getOperands()[1]->getKind() == MachineOperand::KIND_REG && + mi2->getOperands()[0]->getKind() == MachineOperand::KIND_REG && + mi2->getOperands()[1]->getKind() == MachineOperand::KIND_REG) { + auto *dst1 = static_cast(mi1->getOperands()[0].get()); + auto *src1 = static_cast(mi1->getOperands()[1].get()); + auto *dst2 = static_cast(mi2->getOperands()[0].get()); + auto *src2 = static_cast(mi2->getOperands()[1].get()); + if (areRegsEqual(dst1, src2) && areRegsEqual(src1, dst2)) { + instrs.erase(instrs.begin() + i + 1); // 移除第二条指令 + changed = true; + } + } + } + } + // 2. 冗余加载消除: sw t0, offset(base); lw t1, offset(base) -> 替换或消除 + // lw 添加ld sd支持 + else if (isStoreLoadPattern(mi1, mi2)) { + if (mi1->getOperands().size() == 2 && mi2->getOperands().size() == 2) { + if (mi1->getOperands()[0]->getKind() == MachineOperand::KIND_REG && + mi1->getOperands()[1]->getKind() == MachineOperand::KIND_MEM && + mi2->getOperands()[0]->getKind() == MachineOperand::KIND_REG && + mi2->getOperands()[1]->getKind() == MachineOperand::KIND_MEM) { + + auto *store_val = + static_cast(mi1->getOperands()[0].get()); + auto *store_mem = + static_cast(mi1->getOperands()[1].get()); + auto *load_val = + static_cast(mi2->getOperands()[0].get()); + auto *load_mem = + static_cast(mi2->getOperands()[1].get()); + + // 检查内存访问是否匹配(基址、偏移量和访问大小) + if (areMemoryAccessesEqual(mi1, store_mem, mi2, load_mem)) { + // 进行简单的内存别名分析 + if (isMemoryAccessSafe(instrs, i, i + 1, store_mem)) { + if (areRegsEqual(store_val, load_val)) { + // sw r1, mem; lw r1, mem -> 消除冗余的lw + instrs.erase(instrs.begin() + i + 1); + changed = true; + } else { + // sw r1, mem; lw r2, mem -> 替换lw为mv r2, r1 + auto newInstr = std::make_unique(RVOpcodes::MV); + newInstr->addOperand(std::make_unique(*load_val)); + newInstr->addOperand( + std::make_unique(*store_val)); + instrs[i + 1] = std::move(newInstr); + changed = true; + } + } + } + } + } + } + // 3. 强度削减: mul y, x, 2^n -> slli y, x, n + else if (mi1->getOpcode() == RVOpcodes::MUL && + mi1->getOperands().size() == 3) { + auto *dst_op = mi1->getOperands()[0].get(); + auto *src1_op = mi1->getOperands()[1].get(); + auto *src2_op = mi1->getOperands()[2].get(); + + if (dst_op->getKind() == MachineOperand::KIND_REG) { + auto *dst_reg = static_cast(dst_op); + RegOperand *src_reg = nullptr; + int shift = -1; + + if (src1_op->getKind() == MachineOperand::KIND_REG && + src2_op->getKind() == MachineOperand::KIND_IMM) { + shift = + isPowerOfTwo(static_cast(src2_op)->getValue()); + if (shift >= 0) + src_reg = static_cast(src1_op); + } else if (src1_op->getKind() == MachineOperand::KIND_IMM && + src2_op->getKind() == MachineOperand::KIND_REG) { + shift = + isPowerOfTwo(static_cast(src1_op)->getValue()); + if (shift >= 0) + src_reg = static_cast(src2_op); + } + + if (src_reg && shift >= 0 && + shift <= 31) { // RISC-V 移位量限制 (0-31) + auto newInstr = std::make_unique(RVOpcodes::SLLI); + newInstr->addOperand(std::make_unique(*dst_reg)); + newInstr->addOperand(std::make_unique(*src_reg)); + newInstr->addOperand(std::make_unique(shift)); + instrs[i] = std::move(newInstr); + changed = true; + } + } + } + // 4. 地址计算优化: addi dst, base, imm1; lw/sw val, imm2(dst) -> lw/sw + // val, (imm1+imm2)(base) + else if (mi1->getOpcode() == RVOpcodes::ADDI && + mi1->getOperands().size() == 3) { + auto opcode2 = mi2->getOpcode(); + if (opcode2 == RVOpcodes::LW || opcode2 == RVOpcodes::SW) { + if (mi2->getOperands().size() == 2 && + mi2->getOperands()[1]->getKind() == MachineOperand::KIND_MEM && + mi1->getOperands()[0]->getKind() == MachineOperand::KIND_REG && + mi1->getOperands()[1]->getKind() == MachineOperand::KIND_REG && + mi1->getOperands()[2]->getKind() == MachineOperand::KIND_IMM) { + + auto *addi_dst = + static_cast(mi1->getOperands()[0].get()); + auto *addi_base = + static_cast(mi1->getOperands()[1].get()); + auto *addi_imm = + static_cast(mi1->getOperands()[2].get()); + + auto *mem_op = + static_cast(mi2->getOperands()[1].get()); + auto *mem_base = mem_op->getBase(); + auto *mem_imm = mem_op->getOffset(); + + // 检查 ADDI 的目标寄存器是否是内存操作的基址 + if (areRegsEqual(addi_dst, mem_base)) { + // 改进的使用检查:考虑寄存器可能在后续被重新定义的情况 + bool canOptimize = true; + + // 检查从 i+2 开始的指令 + for (size_t j = i + 2; j < instrs.size(); ++j) { + auto *later_instr = instrs[j].get(); + + // 如果寄存器被重新定义,那么它后面的使用就不相关了 + if (isRegRedefinedAt(later_instr, addi_dst, areRegsEqual)) { + break; // 寄存器被重新定义,可以安全优化 + } + + // 如果寄存器被使用,则不能优化 + if (isRegUsedLater(instrs, addi_dst, j)) { + canOptimize = false; + break; + } + } + + if (canOptimize) { + int64_t new_offset = addi_imm->getValue() + mem_imm->getValue(); + // 检查新偏移量是否符合 RISC-V 12位有符号立即数范围 + if (new_offset >= -2048 && new_offset <= 2047) { + auto new_mem_op = std::make_unique( + std::make_unique(*addi_base), + std::make_unique(new_offset)); + mi2->getOperands()[1] = std::move(new_mem_op); + instrs.erase(instrs.begin() + i); + changed = true; + } + } + } + } + } + } + // 5. 冗余移动指令消除: mv x, y; op z, x, ... -> op z, y, ... (如果 x + // 之后不再使用) + else if (mi1->getOpcode() == RVOpcodes::MV && + mi1->getOperands().size() == 2) { + if (mi1->getOperands()[0]->getKind() == MachineOperand::KIND_REG && + mi1->getOperands()[1]->getKind() == MachineOperand::KIND_REG) { + + auto *mv_dst = static_cast(mi1->getOperands()[0].get()); + auto *mv_src = static_cast(mi1->getOperands()[1].get()); + + // 检查第二条指令是否使用了 mv 的目标寄存器 + std::vector use_positions; + for (size_t k = 1; k < mi2->getOperands().size(); ++k) { + if (mi2->getOperands()[k]->getKind() == MachineOperand::KIND_REG) { + auto *use_reg = + static_cast(mi2->getOperands()[k].get()); + if (areRegsEqual(mv_dst, use_reg)) { + use_positions.push_back(k); + } + } + // 也检查内存操作数中的基址寄存器 + else if (mi2->getOperands()[k]->getKind() == + MachineOperand::KIND_MEM) { + auto *mem = + static_cast(mi2->getOperands()[k].get()); + if (areRegsEqual(mv_dst, mem->getBase())) { + // 对于内存操作数,我们需要创建新的MemOperand + auto new_mem = std::make_unique( + std::make_unique(*mv_src), + std::make_unique(mem->getOffset()->getValue())); + mi2->getOperands()[k] = std::move(new_mem); + use_positions.push_back(k); // 标记已处理 + } + } + } + + if (!use_positions.empty()) { + // 改进的后续使用检查 + bool canOptimize = true; + for (size_t j = i + 2; j < instrs.size(); ++j) { + auto *later_instr = instrs[j].get(); + + // 如果寄存器被重新定义,后续使用就不相关了 + if (isRegRedefinedAt(later_instr, mv_dst, areRegsEqual)) { + break; + } + + // 检查是否还有其他使用 + if (isRegUsedLater(instrs, mv_dst, j)) { + canOptimize = false; + break; + } + } + + if (canOptimize) { + // 替换所有寄存器使用(内存操作数已在上面处理) + for (size_t pos : use_positions) { + if (mi2->getOperands()[pos]->getKind() == + MachineOperand::KIND_REG) { + mi2->getOperands()[pos] = + std::make_unique(*mv_src); + } + } + instrs.erase(instrs.begin() + i); + changed = true; + } + } + } + } + // 6. 连续加法指令合并: addi t1, t0, imm1; addi t2, t1, imm2 -> addi t2, + // t0, (imm1+imm2) + else if (mi1->getOpcode() == RVOpcodes::ADDI && + mi2->getOpcode() == RVOpcodes::ADDI) { + if (mi1->getOperands().size() == 3 && mi2->getOperands().size() == 3) { + if (mi1->getOperands()[0]->getKind() == MachineOperand::KIND_REG && + mi1->getOperands()[1]->getKind() == MachineOperand::KIND_REG && + mi1->getOperands()[2]->getKind() == MachineOperand::KIND_IMM && + mi2->getOperands()[0]->getKind() == MachineOperand::KIND_REG && + mi2->getOperands()[1]->getKind() == MachineOperand::KIND_REG && + mi2->getOperands()[2]->getKind() == MachineOperand::KIND_IMM) { + + auto *addi1_dst = + static_cast(mi1->getOperands()[0].get()); + auto *addi1_src = + static_cast(mi1->getOperands()[1].get()); + auto *addi1_imm = + static_cast(mi1->getOperands()[2].get()); + + auto *addi2_dst = + static_cast(mi2->getOperands()[0].get()); + auto *addi2_src = + static_cast(mi2->getOperands()[1].get()); + auto *addi2_imm = + static_cast(mi2->getOperands()[2].get()); + + // 检查第一个ADDI的目标是否是第二个ADDI的源 + if (areRegsEqual(addi1_dst, addi2_src)) { + // 改进的中间寄存器使用检查 + bool canOptimize = true; + for (size_t j = i + 2; j < instrs.size(); ++j) { + auto *later_instr = instrs[j].get(); + + // 如果中间寄存器被重新定义,后续使用不相关 + if (isRegRedefinedAt(later_instr, addi1_dst, areRegsEqual)) { + break; + } + + // 检查是否有其他使用 + if (isRegUsedLater(instrs, addi1_dst, j)) { + canOptimize = false; + break; + } + } + + if (canOptimize) { + int64_t new_imm = addi1_imm->getValue() + addi2_imm->getValue(); + // 检查新立即数范围 + if (new_imm >= -2048 && new_imm <= 2047) { + auto newInstr = + std::make_unique(RVOpcodes::ADDI); + newInstr->addOperand( + std::make_unique(*addi2_dst)); + newInstr->addOperand( + std::make_unique(*addi1_src)); + newInstr->addOperand(std::make_unique(new_imm)); + instrs[i + 1] = std::move(newInstr); + instrs.erase(instrs.begin() + i); + changed = true; + } + } + } + } + } + } + + // 7. ADD with zero optimization: add r1, r2, zero -> mv r1, r2 + else if (mi1->getOpcode() == RVOpcodes::ADD && + mi1->getOperands().size() == 3) { + if (mi1->getOperands()[0]->getKind() == MachineOperand::KIND_REG && + mi1->getOperands()[1]->getKind() == MachineOperand::KIND_REG && + mi1->getOperands()[2]->getKind() == MachineOperand::KIND_REG) { + + auto *add_dst = + static_cast(mi1->getOperands()[0].get()); + auto *add_src1 = + static_cast(mi1->getOperands()[1].get()); + auto *add_src2 = + static_cast(mi1->getOperands()[2].get()); + + // 检查第二个源操作数是否为ZERO寄存器 + if (!add_src2->isVirtual() && + add_src2->getPReg() == PhysicalReg::ZERO) { + // 创建新的 MV 指令 + auto newInstr = std::make_unique(RVOpcodes::MV); + newInstr->addOperand(std::make_unique(*add_dst)); + newInstr->addOperand(std::make_unique(*add_src1)); + instrs[i] = std::move(newInstr); + changed = true; + } + } + } + + // 根据是否发生变化调整遍历索引 + if (!changed) { + ++i; // 没有优化,继续检查下一对指令 + } else { + // 发生变化,适当回退以捕获新的优化机会。 + // 这是一种安全的回退策略,可以触发连锁优化,且不会导致无限循环。 + if (i > 0) { + --i; + } + } + } + } } -void PostRA_Scheduler::runOnMachineFunction(MachineFunction* mfunc) { - // TODO: 在此实现寄存器分配后的局部指令调度。 - // 遍历mfunc中的每一个MachineBasicBlock。 - // 重点关注由寄存器分配器插入的spill/fill代码。 - // - // 实现思路: - // 1. 识别出用于spill/fill的lw/sw指令。 - // 2. 在不违反数据依赖(包括物理寄存器引入的伪依赖)的前提下, - // 尝试将lw指令向上移动,使其与使用它的指令之间有足够的距离,以隐藏访存延迟。 - // 3. 同样,可以尝试将sw指令向下移动。 - // - // std::cout << "Running Post-RA Local Scheduler..." << std::endl; +void PostRA_Scheduler::runOnMachineFunction(MachineFunction *mfunc) { + // TODO: 在此实现寄存器分配后的局部指令调度。 + // 遍历mfunc中的每一个MachineBasicBlock。 + // 重点关注由寄存器分配器插入的spill/fill代码。 + // + // 实现思路: + // 1. 识别出用于spill/fill的lw/sw指令。 + // 2. 在不违反数据依赖(包括物理寄存器引入的伪依赖)的前提下, + // 尝试将lw指令向上移动,使其与使用它的指令之间有足够的距离,以隐藏访存延迟。 + // 3. 同样,可以尝试将sw指令向下移动。 + // + // std::cout << "Running Post-RA Local Scheduler..." << std::endl; } void CalleeSavedHandler::runOnMachineFunction(MachineFunction* mfunc) {