#include "Peephole.h" #include namespace sysy { char PeepholeOptimizer::ID = 0; bool PeepholeOptimizer::runOnFunction(Function *F, AnalysisManager& AM) { // This pass works on MachineFunction level, not IR level return false; } 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; } } } } } } // namespace sysy