[peephole]添加7项窥孔优化规则初步测试生效成功,有待进一步检查,TODO: 指令调度优化
This commit is contained in:
@ -1,43 +1,667 @@
|
||||
#include "RISCv64Passes.h"
|
||||
#include <iostream>
|
||||
// #include <iostream>
|
||||
#include <functional>
|
||||
|
||||
namespace sysy {
|
||||
|
||||
// --- 寄存器分配前优化 ---
|
||||
|
||||
void PreRA_Scheduler::runOnMachineFunction(MachineFunction* mfunc) {
|
||||
void PreRA_Scheduler::runOnMachineFunction(MachineFunction *mfunc) {
|
||||
// TODO: 在此实现寄存器分配前的指令调度。
|
||||
// 遍历mfunc中的每一个MachineBasicBlock。
|
||||
// 对每个基本块内的MachineInstr列表进行重排。
|
||||
//
|
||||
// 实现思路:
|
||||
// 1. 分析每个基本块内指令的数据依赖关系,构建依赖图(DAG)。
|
||||
// 2. 根据目标处理器的流水线特性(指令延迟等),使用列表调度等算法对指令进行重排。
|
||||
// 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<std::unique_ptr<MachineInstr>> &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<RegOperand *>(instr->getOperands()[k].get());
|
||||
if (areRegsEqual(reg, use_reg))
|
||||
return true;
|
||||
}
|
||||
// 检查内存操作数中的基址寄存器
|
||||
if (instr->getOperands()[k]->getKind() == MachineOperand::KIND_MEM) {
|
||||
auto *mem =
|
||||
static_cast<MemOperand *>(instr->getOperands()[k].get());
|
||||
if (areRegsEqual(reg, mem->getBase()))
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
// 检查寄存器是否在指令中被重新定义(用于更精确的分析)
|
||||
auto isRegRedefinedAt =
|
||||
[](MachineInstr *instr, RegOperand *reg,
|
||||
const std::function<bool(RegOperand *, RegOperand *)> &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<RegOperand *>(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<std::unique_ptr<MachineInstr>> &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<MemOperand *>(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<RegOperand *>(mi1->getOperands()[0].get());
|
||||
auto *src1 = static_cast<RegOperand *>(mi1->getOperands()[1].get());
|
||||
auto *dst2 = static_cast<RegOperand *>(mi2->getOperands()[0].get());
|
||||
auto *src2 = static_cast<RegOperand *>(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<RegOperand *>(mi1->getOperands()[0].get());
|
||||
auto *store_mem =
|
||||
static_cast<MemOperand *>(mi1->getOperands()[1].get());
|
||||
auto *load_val =
|
||||
static_cast<RegOperand *>(mi2->getOperands()[0].get());
|
||||
auto *load_mem =
|
||||
static_cast<MemOperand *>(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<MachineInstr>(RVOpcodes::MV);
|
||||
newInstr->addOperand(std::make_unique<RegOperand>(*load_val));
|
||||
newInstr->addOperand(
|
||||
std::make_unique<RegOperand>(*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<RegOperand *>(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<ImmOperand *>(src2_op)->getValue());
|
||||
if (shift >= 0)
|
||||
src_reg = static_cast<RegOperand *>(src1_op);
|
||||
} else if (src1_op->getKind() == MachineOperand::KIND_IMM &&
|
||||
src2_op->getKind() == MachineOperand::KIND_REG) {
|
||||
shift =
|
||||
isPowerOfTwo(static_cast<ImmOperand *>(src1_op)->getValue());
|
||||
if (shift >= 0)
|
||||
src_reg = static_cast<RegOperand *>(src2_op);
|
||||
}
|
||||
|
||||
if (src_reg && shift >= 0 &&
|
||||
shift <= 31) { // RISC-V 移位量限制 (0-31)
|
||||
auto newInstr = std::make_unique<MachineInstr>(RVOpcodes::SLLI);
|
||||
newInstr->addOperand(std::make_unique<RegOperand>(*dst_reg));
|
||||
newInstr->addOperand(std::make_unique<RegOperand>(*src_reg));
|
||||
newInstr->addOperand(std::make_unique<ImmOperand>(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<RegOperand *>(mi1->getOperands()[0].get());
|
||||
auto *addi_base =
|
||||
static_cast<RegOperand *>(mi1->getOperands()[1].get());
|
||||
auto *addi_imm =
|
||||
static_cast<ImmOperand *>(mi1->getOperands()[2].get());
|
||||
|
||||
auto *mem_op =
|
||||
static_cast<MemOperand *>(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<MemOperand>(
|
||||
std::make_unique<RegOperand>(*addi_base),
|
||||
std::make_unique<ImmOperand>(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<RegOperand *>(mi1->getOperands()[0].get());
|
||||
auto *mv_src = static_cast<RegOperand *>(mi1->getOperands()[1].get());
|
||||
|
||||
// 检查第二条指令是否使用了 mv 的目标寄存器
|
||||
std::vector<size_t> 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<RegOperand *>(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<MemOperand *>(mi2->getOperands()[k].get());
|
||||
if (areRegsEqual(mv_dst, mem->getBase())) {
|
||||
// 对于内存操作数,我们需要创建新的MemOperand
|
||||
auto new_mem = std::make_unique<MemOperand>(
|
||||
std::make_unique<RegOperand>(*mv_src),
|
||||
std::make_unique<ImmOperand>(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<RegOperand>(*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<RegOperand *>(mi1->getOperands()[0].get());
|
||||
auto *addi1_src =
|
||||
static_cast<RegOperand *>(mi1->getOperands()[1].get());
|
||||
auto *addi1_imm =
|
||||
static_cast<ImmOperand *>(mi1->getOperands()[2].get());
|
||||
|
||||
auto *addi2_dst =
|
||||
static_cast<RegOperand *>(mi2->getOperands()[0].get());
|
||||
auto *addi2_src =
|
||||
static_cast<RegOperand *>(mi2->getOperands()[1].get());
|
||||
auto *addi2_imm =
|
||||
static_cast<ImmOperand *>(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<MachineInstr>(RVOpcodes::ADDI);
|
||||
newInstr->addOperand(
|
||||
std::make_unique<RegOperand>(*addi2_dst));
|
||||
newInstr->addOperand(
|
||||
std::make_unique<RegOperand>(*addi1_src));
|
||||
newInstr->addOperand(std::make_unique<ImmOperand>(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<RegOperand *>(mi1->getOperands()[0].get());
|
||||
auto *add_src1 =
|
||||
static_cast<RegOperand *>(mi1->getOperands()[1].get());
|
||||
auto *add_src2 =
|
||||
static_cast<RegOperand *>(mi1->getOperands()[2].get());
|
||||
|
||||
// 检查第二个源操作数是否为ZERO寄存器
|
||||
if (!add_src2->isVirtual() &&
|
||||
add_src2->getPReg() == PhysicalReg::ZERO) {
|
||||
// 创建新的 MV 指令
|
||||
auto newInstr = std::make_unique<MachineInstr>(RVOpcodes::MV);
|
||||
newInstr->addOperand(std::make_unique<RegOperand>(*add_dst));
|
||||
newInstr->addOperand(std::make_unique<RegOperand>(*add_src1));
|
||||
instrs[i] = std::move(newInstr);
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 根据是否发生变化调整遍历索引
|
||||
if (!changed) {
|
||||
++i; // 没有优化,继续检查下一对指令
|
||||
} else {
|
||||
// 发生变化,适当回退以捕获新的优化机会。
|
||||
// 这是一种安全的回退策略,可以触发连锁优化,且不会导致无限循环。
|
||||
if (i > 0) {
|
||||
--i;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PostRA_Scheduler::runOnMachineFunction(MachineFunction* mfunc) {
|
||||
void PostRA_Scheduler::runOnMachineFunction(MachineFunction *mfunc) {
|
||||
// TODO: 在此实现寄存器分配后的局部指令调度。
|
||||
// 遍历mfunc中的每一个MachineBasicBlock。
|
||||
// 重点关注由寄存器分配器插入的spill/fill代码。
|
||||
|
||||
Reference in New Issue
Block a user