diff --git a/src/PreRA_Scheduler.cpp b/src/PreRA_Scheduler.cpp index 137edca..8497429 100644 --- a/src/PreRA_Scheduler.cpp +++ b/src/PreRA_Scheduler.cpp @@ -1,36 +1,410 @@ #include "PreRA_Scheduler.h" +#include "RISCv64LLIR.h" +#include +#include +#include +#include + +#define MAX_SCHEDULING_BLOCK_SIZE 1000 // 严格限制调度块大小 namespace sysy { char PreRA_Scheduler::ID = 0; -bool PreRA_Scheduler::runOnFunction(Function *F, AnalysisManager& AM) { - // TODO: 在此实现寄存器分配前的指令调度。 - // 遍历mfunc中的每一个MachineBasicBlock。 - // 对每个基本块内的MachineInstr列表进行重排。 - // - // 实现思路: - // 1. 分析每个基本块内指令的数据依赖关系,构建依赖图(DAG)。 - // 2. - // 根据目标处理器的流水线特性(指令延迟等),使用列表调度等算法对指令进行重排。 - // 3. 此时操作的是虚拟寄存器,只存在真依赖,调度自由度最大。 - // - // std::cout << "Running Pre-RA Instruction Scheduler..." << std::endl; +// 检查指令是否是加载指令 (LW, LD) +static bool isLoadInstr(MachineInstr *instr) { + RVOpcodes opcode = instr->getOpcode(); + return opcode == RVOpcodes::LW || opcode == RVOpcodes::LD || + opcode == RVOpcodes::LH || opcode == RVOpcodes::LB || + opcode == RVOpcodes::LHU || opcode == RVOpcodes::LBU || + opcode == RVOpcodes::LWU; +} + +// 检查指令是否是存储指令 (SW, SD) +static bool isStoreInstr(MachineInstr *instr) { + RVOpcodes opcode = instr->getOpcode(); + return opcode == RVOpcodes::SW || opcode == RVOpcodes::SD || + opcode == RVOpcodes::SH || opcode == RVOpcodes::SB; +} + +// 检查指令是否为分支指令 +static bool isBranchInstr(MachineInstr *instr) { + RVOpcodes opcode = instr->getOpcode(); + return opcode == RVOpcodes::BEQ || opcode == RVOpcodes::BNE || + opcode == RVOpcodes::BLT || opcode == RVOpcodes::BGE || + opcode == RVOpcodes::BLTU || opcode == RVOpcodes::BGEU; +} + +// 检查指令是否为跳转指令 +static bool isJumpInstr(MachineInstr *instr) { + RVOpcodes opcode = instr->getOpcode(); + return opcode == RVOpcodes::J; +} + +// 检查指令是否为返回指令 +static bool isReturnInstr(MachineInstr *instr) { + return instr->getOpcode() == RVOpcodes::RET; +} + +// 检查指令是否为调用指令 +static bool isCallInstr(MachineInstr *instr) { + return instr->getOpcode() == RVOpcodes::CALL; +} + +// 检查指令是否为块终结指令(必须保持在块尾) +static bool isTerminatorInstr(MachineInstr *instr) { + return isBranchInstr(instr) || isJumpInstr(instr) || isReturnInstr(instr); +} + +// 检查指令是否有副作用(需要谨慎处理) +static bool hasSideEffect(MachineInstr *instr) { + return isStoreInstr(instr) || isCallInstr(instr) || isTerminatorInstr(instr); +} + +// 检查指令是否涉及内存操作 +static bool hasMemoryAccess(MachineInstr *instr) { + return isLoadInstr(instr) || isStoreInstr(instr); +} + +// 获取指令定义的虚拟寄存器 +static std::set getDefinedVirtualRegisters(MachineInstr *instr) { + std::set defined_regs; + RVOpcodes opcode = instr->getOpcode(); + + // CALL指令可能定义返回值寄存器 + if (opcode == RVOpcodes::CALL) { + if (!instr->getOperands().empty() && + instr->getOperands().front()->getKind() == MachineOperand::KIND_REG) { + auto reg_op = + static_cast(instr->getOperands().front().get()); + if (reg_op->isVirtual()) { + defined_regs.insert(reg_op->getVRegNum()); + } + } + return defined_regs; + } + + // 存储指令和终结指令不定义寄存器 + if (isStoreInstr(instr) || isTerminatorInstr(instr)) { + return defined_regs; + } + + // 其他指令的第一个操作数通常是目标寄存器 + if (!instr->getOperands().empty() && + instr->getOperands().front()->getKind() == MachineOperand::KIND_REG) { + auto reg_op = static_cast(instr->getOperands().front().get()); + if (reg_op->isVirtual()) { + defined_regs.insert(reg_op->getVRegNum()); + } + } + + return defined_regs; +} + +// 获取指令使用的虚拟寄存器 +static std::set getUsedVirtualRegisters(MachineInstr *instr) { + std::set used_regs; + RVOpcodes opcode = instr->getOpcode(); + + // CALL指令:跳过第一个操作数(返回值),其余为参数 + if (opcode == RVOpcodes::CALL) { + bool first_reg_skipped = false; + for (const auto &op : instr->getOperands()) { + if (op->getKind() == MachineOperand::KIND_REG) { + if (!first_reg_skipped) { + first_reg_skipped = true; + continue; + } + auto reg_op = static_cast(op.get()); + if (reg_op->isVirtual()) { + used_regs.insert(reg_op->getVRegNum()); + } + } + } + return used_regs; + } + + // 存储指令和终结指令:所有操作数都是使用的 + if (isStoreInstr(instr) || isTerminatorInstr(instr)) { + for (const auto &op : instr->getOperands()) { + if (op->getKind() == MachineOperand::KIND_REG) { + auto reg_op = static_cast(op.get()); + if (reg_op->isVirtual()) { + used_regs.insert(reg_op->getVRegNum()); + } + } else if (op->getKind() == MachineOperand::KIND_MEM) { + auto mem_op = static_cast(op.get()); + if (mem_op->getBase()->isVirtual()) { + used_regs.insert(mem_op->getBase()->getVRegNum()); + } + } + } + return used_regs; + } + + // 其他指令:跳过第一个操作数(目标寄存器),其余为源操作数 + bool first_reg = true; + for (const auto &op : instr->getOperands()) { + if (op->getKind() == MachineOperand::KIND_REG) { + if (first_reg) { + first_reg = false; + continue; + } + auto reg_op = static_cast(op.get()); + if (reg_op->isVirtual()) { + used_regs.insert(reg_op->getVRegNum()); + } + } else if (op->getKind() == MachineOperand::KIND_MEM) { + auto mem_op = static_cast(op.get()); + if (mem_op->getBase()->isVirtual()) { + used_regs.insert(mem_op->getBase()->getVRegNum()); + } + } + } + return used_regs; +} + +// 获取内存访问位置信息 +struct MemoryLocation { + unsigned base_reg; + int64_t offset; + bool is_valid; + + MemoryLocation() : base_reg(0), offset(0), is_valid(false) {} + MemoryLocation(unsigned base, int64_t off) + : base_reg(base), offset(off), is_valid(true) {} + + bool operator==(const MemoryLocation &other) const { + return is_valid && other.is_valid && base_reg == other.base_reg && + offset == other.offset; + } +}; + +// 获取内存访问位置 +static MemoryLocation getMemoryLocation(MachineInstr *instr) { + if (!isLoadInstr(instr) && !isStoreInstr(instr)) { + return MemoryLocation(); + } + + for (const auto &op : instr->getOperands()) { + if (op->getKind() == MachineOperand::KIND_MEM) { + auto mem_op = static_cast(op.get()); + if (mem_op->getBase()->isVirtual()) { + return MemoryLocation(mem_op->getBase()->getVRegNum(), + mem_op->getOffset()->getValue()); + } + } + } + + return MemoryLocation(); +} + +// 检查两个内存位置是否可能别名 +static bool mayAlias(const MemoryLocation &loc1, const MemoryLocation &loc2) { + if (!loc1.is_valid || !loc2.is_valid) { + return true; // 保守处理:未知位置可能别名 + } + + // 不同基址寄存器,保守假设可能别名 + if (loc1.base_reg != loc2.base_reg) { + return true; + } + + // 相同基址寄存器,检查偏移 + return loc1.offset == loc2.offset; +} + +// 检查两个指令之间是否存在数据依赖 +static bool hasDataDependency(MachineInstr *first, MachineInstr *second) { + auto defined_regs_first = getDefinedVirtualRegisters(first); + auto used_regs_first = getUsedVirtualRegisters(first); + auto defined_regs_second = getDefinedVirtualRegisters(second); + auto used_regs_second = getUsedVirtualRegisters(second); + + // RAW依赖: second读取first写入的寄存器 + for (const auto ® : defined_regs_first) { + if (used_regs_second.count(reg)) { + return true; + } + } + + // WAR依赖: second写入first读取的寄存器 + for (const auto ® : used_regs_first) { + if (defined_regs_second.count(reg)) { + return true; + } + } + + // WAW依赖: 两个指令写入同一寄存器 + for (const auto ® : defined_regs_first) { + if (defined_regs_second.count(reg)) { + return true; + } + } + + return false; +} + +// 检查两个指令之间是否存在内存依赖 +static bool hasMemoryDependency(MachineInstr *first, MachineInstr *second) { + bool first_accesses_memory = isLoadInstr(first) || isStoreInstr(first); + bool second_accesses_memory = isLoadInstr(second) || isStoreInstr(second); + + if (!first_accesses_memory || !second_accesses_memory) { + return false; + } + + // 如果至少有一个是存储指令,需要检查别名 + if (isStoreInstr(first) || isStoreInstr(second)) { + MemoryLocation loc1 = getMemoryLocation(first); + MemoryLocation loc2 = getMemoryLocation(second); + return mayAlias(loc1, loc2); + } + + return false; // 两个加载指令之间没有依赖 +} + +// 检查两个指令之间是否存在控制依赖 +static bool hasControlDependency(MachineInstr *first, MachineInstr *second) { + // 终结指令与任何其他指令都有控制依赖 + if (isTerminatorInstr(first)) { + return true; // first是终结指令,second不能移动到first之前 + } + + if (isTerminatorInstr(second)) { + return false; // second是终结指令,可以保持在后面 + } + + // CALL指令具有控制副作用,但可以参与有限的调度 + if (isCallInstr(first) || isCallInstr(second)) { + // CALL指令之间保持顺序 + if (isCallInstr(first) && isCallInstr(second)) { + return true; + } + // 其他情况允许调度(通过数据依赖控制) + } + + return false; +} + +// 综合检查两个指令是否可以交换 +static bool canSwapInstructions(MachineInstr *first, MachineInstr *second) { + // 检查所有类型的依赖 + if (hasDataDependency(first, second) || hasDataDependency(second, first)) { + return false; + } + + if (hasMemoryDependency(first, second)) { + return false; + } + + if (hasControlDependency(first, second) || + hasControlDependency(second, first)) { + return false; + } + + return true; +} + +// 找到基本块中的调度边界 +static std::vector +findSchedulingBoundaries(const std::vector &instrs) { + std::vector boundaries; + boundaries.push_back(0); // 起始边界 + + for (size_t i = 0; i < instrs.size(); i++) { + // 终结指令前后都是边界 + if (isTerminatorInstr(instrs[i])) { + if (i > 0) + boundaries.push_back(i); + if (i + 1 < instrs.size()) + boundaries.push_back(i + 1); + } + // 跳转目标标签也可能是边界(这里简化处理) + } + + boundaries.push_back(instrs.size()); // 结束边界 + + // 去重并排序 + std::sort(boundaries.begin(), boundaries.end()); + boundaries.erase(std::unique(boundaries.begin(), boundaries.end()), + boundaries.end()); + + return boundaries; +} + +// 在单个调度区域内进行指令调度 +static void scheduleRegion(std::vector &instrs, size_t start, + size_t end) { + if (end - start <= 1) { + return; // 区域太小,无需调度 + } + + // 保守的调度策略: + // 1. 只对小规模区域进行调度 + // 2. 优先将加载指令向前调度,以隐藏内存延迟 + // 3. 确保不破坏数据依赖和内存依赖 + + // 简单的调度算法:只尝试将加载指令尽可能前移 + for (size_t i = start + 1; i < end; i++) { + if (isLoadInstr(instrs[i])) { + // 尝试将加载指令向前移动 + for (size_t j = i; j > start; j--) { + // 检查是否可以与前一条指令交换 + if (canSwapInstructions(instrs[j - 1], instrs[j])) { + std::swap(instrs[j - 1], instrs[j]); + } else { + // 一旦遇到依赖关系就停止移动 + break; + } + } + } + } +} + +static void scheduleBlock(MachineBasicBlock *mbb) { + auto &instructions = mbb->getInstructions(); + if (instructions.size() <= 1 || + instructions.size() > MAX_SCHEDULING_BLOCK_SIZE) { + return; + } + + // 构建指令列表 + std::vector instr_list; + for (auto &instr : instructions) { + instr_list.push_back(instr.get()); + } + + // 找到调度边界 + std::vector boundaries = findSchedulingBoundaries(instr_list); + + // 在每个调度区域内进行局部调度 + for (size_t i = 0; i < boundaries.size() - 1; i++) { + size_t region_start = boundaries[i]; + size_t region_end = boundaries[i + 1]; + scheduleRegion(instr_list, region_start, region_end); + } + + // 重建指令序列 + std::map> instr_map; + for (auto &instr : instructions) { + instr_map[instr.get()] = std::move(instr); + } + + instructions.clear(); + for (auto *instr : instr_list) { + instructions.push_back(std::move(instr_map[instr])); + } +} + +bool PreRA_Scheduler::runOnFunction(Function *F, AnalysisManager &AM) { return false; } void PreRA_Scheduler::runOnMachineFunction(MachineFunction *mfunc) { - // TODO: 在此实现寄存器分配前的指令调度。 - // 遍历mfunc中的每一个MachineBasicBlock。 - // 对每个基本块内的MachineInstr列表进行重排。 - // - // 实现思路: - // 1. 分析每个基本块内指令的数据依赖关系,构建依赖图(DAG)。 - // 2. - // 根据目标处理器的流水线特性(指令延迟等),使用列表调度等算法对指令进行重排。 - // 3. 此时操作的是虚拟寄存器,只存在真依赖,调度自由度最大。 - // - // std::cout << "Running Pre-RA Instruction Scheduler..." << std::endl; + for (auto &mbb : mfunc->getBlocks()) { + scheduleBlock(mbb.get()); + } } } // namespace sysy \ No newline at end of file