[backend]修复了多参数传递的错误
This commit is contained in:
@ -23,7 +23,7 @@ EXECUTE_MODE=false
|
||||
CLEAN_MODE=false
|
||||
SYSYC_TIMEOUT=10 # sysyc 编译超时 (秒)
|
||||
GCC_TIMEOUT=10 # gcc 编译超时 (秒)
|
||||
EXEC_TIMEOUT=5 # qemu 自动化执行超时 (秒)
|
||||
EXEC_TIMEOUT=600 # qemu 自动化执行超时 (秒)
|
||||
MAX_OUTPUT_LINES=50 # 对比失败时显示的最大行数
|
||||
SY_FILES=() # 存储用户提供的 .sy 文件列表
|
||||
PASSED_CASES=0
|
||||
|
||||
@ -1,12 +1,27 @@
|
||||
#include "PrologueEpilogueInsertion.h"
|
||||
#include "RISCv64ISel.h"
|
||||
#include "RISCv64RegAlloc.h" // 需要访问RegAlloc的结果
|
||||
#include <algorithm>
|
||||
|
||||
namespace sysy {
|
||||
|
||||
char PrologueEpilogueInsertionPass::ID = 0;
|
||||
|
||||
void PrologueEpilogueInsertionPass::runOnMachineFunction(MachineFunction* mfunc) {
|
||||
for (auto& mbb : mfunc->getBlocks()) {
|
||||
auto& instrs = mbb->getInstructions();
|
||||
|
||||
// 使用标准的 Erase-Remove Idiom 来删除满足条件的元素
|
||||
instrs.erase(
|
||||
std::remove_if(instrs.begin(), instrs.end(),
|
||||
[](const std::unique_ptr<MachineInstr>& instr) {
|
||||
return instr->getOpcode() == RVOpcodes::PSEUDO_KEEPALIVE;
|
||||
}
|
||||
),
|
||||
instrs.end()
|
||||
);
|
||||
}
|
||||
|
||||
StackFrameInfo& frame_info = mfunc->getFrameInfo();
|
||||
Function* F = mfunc->getFunc();
|
||||
RISCv64ISel* isel = mfunc->getISel();
|
||||
@ -64,54 +79,35 @@ void PrologueEpilogueInsertionPass::runOnMachineFunction(MachineFunction* mfunc)
|
||||
set_fp->addOperand(std::make_unique<ImmOperand>(aligned_stack_size));
|
||||
prologue_instrs.push_back(std::move(set_fp));
|
||||
|
||||
// --- [正确逻辑] 在s0设置完毕后,使用物理寄存器加载栈参数 ---
|
||||
// --- 在s0设置完毕后,使用物理寄存器加载栈参数 ---
|
||||
if (F && isel) {
|
||||
// 定义暂存寄存器
|
||||
const PhysicalReg INT_SCRATCH_REG = PhysicalReg::T5;
|
||||
const PhysicalReg FP_SCRATCH_REG = PhysicalReg::F7;
|
||||
|
||||
int arg_idx = 0;
|
||||
for (Argument* arg : F->getArguments()) {
|
||||
if (arg_idx >= 8) {
|
||||
unsigned vreg = isel->getVReg(arg);
|
||||
|
||||
// 确认RegAlloc已经为这个vreg计算了偏移量,并且分配了物理寄存器
|
||||
if (frame_info.alloca_offsets.count(vreg) && vreg_to_preg_map.count(vreg)) {
|
||||
int offset = frame_info.alloca_offsets.at(vreg);
|
||||
PhysicalReg dest_preg = vreg_to_preg_map.at(vreg);
|
||||
Type* arg_type = arg->getType();
|
||||
|
||||
// 根据类型执行不同的加载序列
|
||||
if (arg_type->isFloat()) {
|
||||
// 1. flw ft7, offset(s0)
|
||||
auto load_arg = std::make_unique<MachineInstr>(RVOpcodes::FLW);
|
||||
load_arg->addOperand(std::make_unique<RegOperand>(FP_SCRATCH_REG));
|
||||
load_arg->addOperand(std::make_unique<RegOperand>(dest_preg));
|
||||
load_arg->addOperand(std::make_unique<MemOperand>(
|
||||
std::make_unique<RegOperand>(PhysicalReg::S0),
|
||||
std::make_unique<ImmOperand>(offset)
|
||||
));
|
||||
prologue_instrs.push_back(std::move(load_arg));
|
||||
// 2. fmv.s dest_preg, ft7
|
||||
auto move_arg = std::make_unique<MachineInstr>(RVOpcodes::FMV_S);
|
||||
move_arg->addOperand(std::make_unique<RegOperand>(dest_preg));
|
||||
move_arg->addOperand(std::make_unique<RegOperand>(FP_SCRATCH_REG));
|
||||
prologue_instrs.push_back(std::move(move_arg));
|
||||
} else {
|
||||
// 确定是加载32位(lw)还是64位(ld)
|
||||
RVOpcodes load_op = arg_type->isPointer() ? RVOpcodes::LD : RVOpcodes::LW;
|
||||
// 1. lw/ld t5, offset(s0)
|
||||
auto load_arg = std::make_unique<MachineInstr>(load_op);
|
||||
load_arg->addOperand(std::make_unique<RegOperand>(INT_SCRATCH_REG));
|
||||
load_arg->addOperand(std::make_unique<RegOperand>(dest_preg));
|
||||
load_arg->addOperand(std::make_unique<MemOperand>(
|
||||
std::make_unique<RegOperand>(PhysicalReg::S0),
|
||||
std::make_unique<ImmOperand>(offset)
|
||||
));
|
||||
prologue_instrs.push_back(std::move(load_arg));
|
||||
// 2. mv dest_preg, t5
|
||||
auto move_arg = std::make_unique<MachineInstr>(RVOpcodes::MV);
|
||||
move_arg->addOperand(std::make_unique<RegOperand>(dest_preg));
|
||||
move_arg->addOperand(std::make_unique<RegOperand>(INT_SCRATCH_REG));
|
||||
prologue_instrs.push_back(std::move(move_arg));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -144,6 +144,9 @@ void RISCv64AsmPrinter::printInstruction(MachineInstr* instr, bool debug) {
|
||||
case RVOpcodes::FRAME_STORE_F:
|
||||
if (!debug) throw std::runtime_error("FRAME_STORE_F not eliminated before AsmPrinter");
|
||||
*OS << "frame_store_f "; break;
|
||||
case RVOpcodes::PSEUDO_KEEPALIVE:
|
||||
if (!debug) throw std::runtime_error("PSEUDO_KEEPALIVE not eliminated before AsmPrinter");
|
||||
*OS << "keepalive "; break;
|
||||
default:
|
||||
throw std::runtime_error("Unknown opcode in AsmPrinter");
|
||||
}
|
||||
|
||||
@ -166,6 +166,33 @@ void RISCv64ISel::selectBasicBlock(BasicBlock* bb) {
|
||||
select_recursive(node_to_select);
|
||||
}
|
||||
}
|
||||
|
||||
if (CurMBB == MFunc->getBlocks().front().get()) { // 只对入口块操作
|
||||
auto keepalive = std::make_unique<MachineInstr>(RVOpcodes::PSEUDO_KEEPALIVE);
|
||||
for (Argument* arg : F->getArguments()) {
|
||||
keepalive->addOperand(std::make_unique<RegOperand>(getVReg(arg)));
|
||||
}
|
||||
|
||||
auto& instrs = CurMBB->getInstructions();
|
||||
auto insert_pos = instrs.end();
|
||||
|
||||
// 关键:检查基本块是否以一个“终止指令”结尾
|
||||
if (!instrs.empty()) {
|
||||
RVOpcodes last_op = instrs.back()->getOpcode();
|
||||
// 扩充了判断条件,涵盖所有可能的终止指令
|
||||
if (last_op == RVOpcodes::J || last_op == RVOpcodes::RET ||
|
||||
last_op == RVOpcodes::BEQ || last_op == RVOpcodes::BNE ||
|
||||
last_op == RVOpcodes::BLT || last_op == RVOpcodes::BGE ||
|
||||
last_op == RVOpcodes::BLTU || last_op == RVOpcodes::BGEU)
|
||||
{
|
||||
// 如果是,插入点就在这个终止指令之前
|
||||
insert_pos = std::prev(instrs.end());
|
||||
}
|
||||
}
|
||||
|
||||
// 在计算出的正确位置插入伪指令
|
||||
instrs.insert(insert_pos, std::move(keepalive));
|
||||
}
|
||||
}
|
||||
|
||||
// 核心函数:为DAG节点选择并生成MachineInstr (已修复和增强的完整版本)
|
||||
|
||||
@ -351,6 +351,18 @@ void RISCv64RegAlloc::getInstrUseDef(MachineInstr* instr, LiveSet& use, LiveSet&
|
||||
bool first_reg_is_def = true; // 默认情况下,指令的第一个寄存器操作数是定义 (def)
|
||||
auto opcode = instr->getOpcode();
|
||||
|
||||
if (opcode == RVOpcodes::PSEUDO_KEEPALIVE) {
|
||||
for (auto& op : instr->getOperands()) {
|
||||
if (op->getKind() == MachineOperand::KIND_REG) {
|
||||
auto reg_op = static_cast<RegOperand*>(op.get());
|
||||
if (reg_op->isVirtual()) {
|
||||
use.insert(reg_op->getVRegNum()); // 它的所有操作数都是 "use"
|
||||
}
|
||||
}
|
||||
}
|
||||
return; // 处理完毕
|
||||
}
|
||||
|
||||
// 1. 特殊指令的 `is_def` 标志调整
|
||||
// 这些指令的第一个寄存器操作数是源操作数 (use),而不是目标操作数 (def)。
|
||||
if (opcode == RVOpcodes::SW || opcode == RVOpcodes::SD || opcode == RVOpcodes::FSW ||
|
||||
@ -673,6 +685,22 @@ void RISCv64RegAlloc::buildInterferenceGraph() {
|
||||
}
|
||||
}
|
||||
|
||||
// 所有在某一点上同时活跃的寄存器(即live_out集合中的所有成员),
|
||||
// 它们之间必须两两互相干扰。
|
||||
// 这会根据我们修正后的 liveness 信息,在所有参数vreg之间构建一个完全图(clique)。
|
||||
std::vector<unsigned> live_out_vec(live_out.begin(), live_out.end());
|
||||
for (size_t i = 0; i < live_out_vec.size(); ++i) {
|
||||
for (size_t j = i + 1; j < live_out_vec.size(); ++j) {
|
||||
unsigned u = live_out_vec[i];
|
||||
unsigned v = live_out_vec[j];
|
||||
if (DEEPDEBUG && interference_graph[u].find(v) == interference_graph[u].end()) {
|
||||
std::cerr << " Edge (Live-Live): %vreg" << u << " <-> %vreg" << v << "\n";
|
||||
}
|
||||
interference_graph[u].insert(v);
|
||||
interference_graph[v].insert(u);
|
||||
}
|
||||
}
|
||||
|
||||
// 在非move指令中,def 与 use 互相干扰
|
||||
if (instr->getOpcode() != RVOpcodes::MV) {
|
||||
for (unsigned d : def) {
|
||||
|
||||
@ -92,7 +92,7 @@ enum class RVOpcodes {
|
||||
FMV_X_W, // fmv.x.w rd, rs1 (浮点寄存器位模式 -> 整数寄存器)
|
||||
FNEG_S, // fneg.s rd, rs (浮点取负)
|
||||
|
||||
// 新增伪指令,用于解耦栈帧处理
|
||||
// 伪指令
|
||||
FRAME_LOAD_W, // 从栈帧加载 32位 Word (对应 lw)
|
||||
FRAME_LOAD_D, // 从栈帧加载 64位 Doubleword (对应 ld)
|
||||
FRAME_STORE_W, // 保存 32位 Word 到栈帧 (对应 sw)
|
||||
@ -100,6 +100,7 @@ enum class RVOpcodes {
|
||||
FRAME_LOAD_F, // 从栈帧加载单精度浮点数
|
||||
FRAME_STORE_F, // 将单精度浮点数存入栈帧
|
||||
FRAME_ADDR, // 获取栈帧变量的地址
|
||||
PSEUDO_KEEPALIVE, // 保持寄存器活跃,防止优化器删除
|
||||
};
|
||||
|
||||
inline bool isGPR(PhysicalReg reg) {
|
||||
|
||||
Reference in New Issue
Block a user