Merge branch 'backend' into midend

This commit is contained in:
Lixuanwang
2025-07-23 19:30:19 +08:00
14 changed files with 1096 additions and 202 deletions

View File

@@ -57,11 +57,22 @@ bool AddressCalculationExpansion::run() {
}
}
} else if (GlobalValue* globalValue = dynamic_cast<GlobalValue*>(basePointer)) {
std::cerr << "Warning: GlobalValue dimension handling needs explicit implementation for GEP expansion. Skipping GEP for: ";
SysYPrinter::printValue(globalValue);
std::cerr << "\n";
++it;
continue;
// 遍历 GlobalValue 的所有维度操作数
for (const auto& use_ptr : globalValue->getDims()) {
Value* dimValue = use_ptr->getValue();
// 将维度值转换为常量整数
if (ConstantInteger* constVal = dynamic_cast<ConstantInteger*>(dimValue)) {
dims.push_back(constVal->getInt());
} else {
// 如果维度不是常量整数,则无法处理。
// 根据 IR.h 中 GlobalValue 的构造函数,这种情况不应发生,但作为安全检查是好的。
std::cerr << "Warning: GlobalValue dimension is not a constant integer. Skipping GEP expansion for: ";
SysYPrinter::printValue(globalValue);
std::cerr << "\n";
dims.clear(); // 清空已收集的部分维度信息
break;
}
}
} else {
std::cerr << "Warning: Base pointer is not AllocaInst/GlobalValue or its array dimensions cannot be determined for GEP expansion. Skipping GEP for: ";
SysYPrinter::printValue(basePointer);

View File

@@ -18,7 +18,7 @@ bool isMemoryOp(RVOpcodes opcode) {
RISCv64AsmPrinter::RISCv64AsmPrinter(MachineFunction* mfunc) : MFunc(mfunc) {}
void RISCv64AsmPrinter::run(std::ostream& os) {
void RISCv64AsmPrinter::run(std::ostream& os, bool debug) {
OS = &os;
*OS << ".globl " << MFunc->getName() << "\n";
@@ -27,7 +27,7 @@ void RISCv64AsmPrinter::run(std::ostream& os) {
printPrologue();
for (auto& mbb : MFunc->getBlocks()) {
printBasicBlock(mbb.get());
printBasicBlock(mbb.get(), debug);
}
}
@@ -42,7 +42,7 @@ void RISCv64AsmPrinter::printPrologue() {
*OS << " addi sp, sp, -" << aligned_stack_size << "\n";
*OS << " sd ra, " << (aligned_stack_size - 8) << "(sp)\n";
*OS << " sd s0, " << (aligned_stack_size - 16) << "(sp)\n";
*OS << " mv s0, sp\n";
*OS << " addi s0, sp, " << aligned_stack_size << "\n";
}
// 忠实还原保存函数入口参数的逻辑
@@ -73,24 +73,31 @@ void RISCv64AsmPrinter::printEpilogue() {
}
}
void RISCv64AsmPrinter::printBasicBlock(MachineBasicBlock* mbb) {
void RISCv64AsmPrinter::printBasicBlock(MachineBasicBlock* mbb, bool debug) {
if (!mbb->getName().empty()) {
*OS << mbb->getName() << ":\n";
}
for (auto& instr : mbb->getInstructions()) {
printInstruction(instr.get());
printInstruction(instr.get(), debug);
}
}
void RISCv64AsmPrinter::printInstruction(MachineInstr* instr) {
void RISCv64AsmPrinter::printInstruction(MachineInstr* instr, bool debug) {
auto opcode = instr->getOpcode();
if (opcode == RVOpcodes::RET) {
printEpilogue();
}
if (opcode != RVOpcodes::LABEL) {
*OS << " ";
if (opcode == RVOpcodes::LABEL) {
// 标签直接打印,不加缩进
printOperand(instr->getOperands()[0].get());
*OS << ":\n";
return; // 处理完毕,直接返回
}
// 对于所有非标签指令,先打印缩进
*OS << " ";
switch (opcode) {
case RVOpcodes::ADD: *OS << "add "; break; case RVOpcodes::ADDI: *OS << "addi "; break;
case RVOpcodes::ADDW: *OS << "addw "; break; case RVOpcodes::ADDIW: *OS << "addiw "; break;
@@ -126,13 +133,21 @@ void RISCv64AsmPrinter::printInstruction(MachineInstr* instr) {
case RVOpcodes::SNEZ: *OS << "snez "; break;
case RVOpcodes::CALL: *OS << "call "; break;
case RVOpcodes::LABEL:
printOperand(instr->getOperands()[0].get());
*OS << ":";
// printOperand(instr->getOperands()[0].get());
// *OS << ":";
break;
case RVOpcodes::FRAME_LOAD:
// It should have been eliminated by RegAlloc
if (!debug) throw std::runtime_error("FRAME pseudo-instruction not eliminated before AsmPrinter");
*OS << "frame_load "; break;
case RVOpcodes::FRAME_STORE:
// These should have been eliminated by RegAlloc
throw std::runtime_error("FRAME pseudo-instruction not eliminated before AsmPrinter");
// It should have been eliminated by RegAlloc
if (!debug) throw std::runtime_error("FRAME pseudo-instruction not eliminated before AsmPrinter");
*OS << "frame_store "; break;
case RVOpcodes::FRAME_ADDR:
// It should have been eliminated by RegAlloc
if (!debug) throw std::runtime_error("FRAME pseudo-instruction not eliminated before AsmPrinter");
*OS << "frame_addr "; break;
default:
throw std::runtime_error("Unknown opcode in AsmPrinter");
}

View File

@@ -61,6 +61,10 @@ std::string RISCv64CodeGen::function_gen(Function* func) {
RISCv64ISel isel;
std::unique_ptr<MachineFunction> mfunc = isel.runOnFunction(func);
std::stringstream ss1;
RISCv64AsmPrinter printer1(mfunc.get());
printer1.run(ss1, true);
// 阶段 2: 指令调度 (Instruction Scheduling)
PreRA_Scheduler scheduler;
scheduler.runOnMachineFunction(mfunc.get());
@@ -81,7 +85,7 @@ std::string RISCv64CodeGen::function_gen(Function* func) {
std::stringstream ss;
RISCv64AsmPrinter printer(mfunc.get());
printer.run(ss);
if (DEBUG) ss << ss1.str(); // 将指令选择阶段的结果也包含在最终输出中
return ss.str();
}

View File

@@ -4,6 +4,7 @@
#include <functional>
#include <cmath> // For std::fabs
#include <limits> // For std::numeric_limits
#include <iostream>
namespace sysy {
@@ -82,6 +83,10 @@ void RISCv64ISel::selectBasicBlock(BasicBlock* bb) {
CurMBB = bb_map.at(bb);
auto dag = build_dag(bb);
if (DEBUG) { // 使用 DEBUG 宏或变量来控制是否打印
print_dag(dag, bb->getName());
}
std::map<Value*, DAGNode*> value_to_node;
for(const auto& node : dag) {
if (node->value) {
@@ -92,6 +97,10 @@ void RISCv64ISel::selectBasicBlock(BasicBlock* bb) {
std::set<DAGNode*> selected_nodes;
std::function<void(DAGNode*)> select_recursive =
[&](DAGNode* node) {
if (DEEPDEBUG) {
std::cout << "[DEEPDEBUG] select_recursive: Visiting node with kind: " << node->kind
<< " (Value: " << (node->value ? node->value->getName() : "null") << ")" << std::endl;
}
if (!node || selected_nodes.count(node)) return;
for (auto operand : node->operands) {
select_recursive(operand);
@@ -118,24 +127,37 @@ void RISCv64ISel::selectBasicBlock(BasicBlock* bb) {
}
}
// 核心函数为DAG节点选择并生成MachineInstr (忠实移植版)
// 核心函数为DAG节点选择并生成MachineInstr (已修复和增强的完整版本)
void RISCv64ISel::selectNode(DAGNode* node) {
// 调用者select_recursive已经保证了操作数节点会先于当前节点被选择。
// 因此,这里我们只处理当前节点。
switch (node->kind) {
// [V2优点] 采纳“延迟物化”Late Materialization思想。
// 这两个节点仅作为标记不直接生成指令。它们的目的是在DAG中保留类型信息。
// 加载其值的责任被转移给了使用它们的父节点如STORE, BINARY等
// 这修复了之前版本中“使用未初始化虚拟寄存器”的根本性bug。
case DAGNode::CONSTANT:
case DAGNode::ALLOCA_ADDR:
if (node->value) getVReg(node->value);
if (node->value) {
// 确保它有一个关联的虚拟寄存器即可,不生成代码。
getVReg(node->value);
}
break;
case DAGNode::LOAD: {
auto dest_vreg = getVReg(node->value);
Value* ptr_val = node->operands[0]->value;
// [V1设计保留] 对于从栈变量加载,继续使用伪指令 FRAME_LOAD。
// 这种设计将栈帧布局的具体计算推迟到后续的 `eliminateFrameIndices` 阶段,保持了模块化。
if (auto alloca = dynamic_cast<AllocaInst*>(ptr_val)) {
auto instr = std::make_unique<MachineInstr>(RVOpcodes::FRAME_LOAD);
instr->addOperand(std::make_unique<RegOperand>(dest_vreg));
instr->addOperand(std::make_unique<RegOperand>(getVReg(alloca)));
CurMBB->addInstruction(std::move(instr));
} else if (auto global = dynamic_cast<GlobalValue*>(ptr_val)) {
// 对于全局变量,先用 la 加载其地址,再用 lw 加载其值。
auto addr_vreg = getNewVReg();
auto la = std::make_unique<MachineInstr>(RVOpcodes::LA);
la->addOperand(std::make_unique<RegOperand>(addr_vreg));
@@ -150,6 +172,7 @@ void RISCv64ISel::selectNode(DAGNode* node) {
));
CurMBB->addInstruction(std::move(lw));
} else {
// 对于已经在虚拟寄存器中的指针地址,直接通过该地址加载。
auto ptr_vreg = getVReg(ptr_val);
auto lw = std::make_unique<MachineInstr>(RVOpcodes::LW);
lw->addOperand(std::make_unique<RegOperand>(dest_vreg));
@@ -166,7 +189,13 @@ void RISCv64ISel::selectNode(DAGNode* node) {
Value* val_to_store = node->operands[0]->value;
Value* ptr_val = node->operands[1]->value;
// [V2优点] 在STORE节点内部负责加载作为源的常量。
// 如果要存储的值是一个常量,就在这里生成 `li` 指令加载它。
if (auto val_const = dynamic_cast<ConstantValue*>(val_to_store)) {
if (DEBUG) {
std::cout << "[DEBUG] selectNode-BINARY: Found constant operand with value " << val_const->getInt()
<< ". Generating LI instruction." << std::endl;
}
auto li = std::make_unique<MachineInstr>(RVOpcodes::LI);
li->addOperand(std::make_unique<RegOperand>(getVReg(val_const)));
li->addOperand(std::make_unique<ImmOperand>(val_const->getInt()));
@@ -174,13 +203,15 @@ void RISCv64ISel::selectNode(DAGNode* node) {
}
auto val_vreg = getVReg(val_to_store);
// [V1设计保留] 同样,对于向栈变量的存储,使用 FRAME_STORE 伪指令。
if (auto alloca = dynamic_cast<AllocaInst*>(ptr_val)) {
auto instr = std::make_unique<MachineInstr>(RVOpcodes::FRAME_STORE);
instr->addOperand(std::make_unique<RegOperand>(val_vreg));
instr->addOperand(std::make_unique<RegOperand>(getVReg(alloca)));
CurMBB->addInstruction(std::move(instr));
} else if (auto global = dynamic_cast<GlobalValue*>(ptr_val)) {
auto addr_vreg = getNewVReg();
// 向全局变量存储。
auto addr_vreg = getNewVReg();
auto la = std::make_unique<MachineInstr>(RVOpcodes::LA);
la->addOperand(std::make_unique<RegOperand>(addr_vreg));
la->addOperand(std::make_unique<LabelOperand>(global->getName()));
@@ -194,6 +225,7 @@ void RISCv64ISel::selectNode(DAGNode* node) {
));
CurMBB->addInstruction(std::move(sw));
} else {
// 向一个指针(存储在虚拟寄存器中)指向的地址存储。
auto ptr_vreg = getVReg(ptr_val);
auto sw = std::make_unique<MachineInstr>(RVOpcodes::SW);
sw->addOperand(std::make_unique<RegOperand>(val_vreg));
@@ -210,37 +242,108 @@ void RISCv64ISel::selectNode(DAGNode* node) {
auto bin = dynamic_cast<BinaryInst*>(node->value);
Value* lhs = bin->getLhs();
Value* rhs = bin->getRhs();
if (bin->getKind() == BinaryInst::kAdd) {
Value* base = nullptr;
Value* offset = nullptr;
// [修改] 扩展基地址的判断,使其可以识别 AllocaInst 或 GlobalValue
if (dynamic_cast<AllocaInst*>(lhs) || dynamic_cast<GlobalValue*>(lhs)) {
base = lhs;
offset = rhs;
} else if (dynamic_cast<AllocaInst*>(rhs) || dynamic_cast<GlobalValue*>(rhs)) {
base = rhs;
offset = lhs;
}
// 如果成功匹配到地址计算模式
if (base) {
// 1. 先为偏移量加载常量(如果它是常量的话)
if (auto const_offset = dynamic_cast<ConstantValue*>(offset)) {
auto li = std::make_unique<MachineInstr>(RVOpcodes::LI);
li->addOperand(std::make_unique<RegOperand>(getVReg(const_offset)));
li->addOperand(std::make_unique<ImmOperand>(const_offset->getInt()));
CurMBB->addInstruction(std::move(li));
}
// 2. [修改] 根据基地址的类型,生成不同的指令来获取基地址
auto base_addr_vreg = getNewVReg(); // 创建一个新的临时vreg来存放基地址
// 情况一:基地址是局部栈变量
if (auto alloca_base = dynamic_cast<AllocaInst*>(base)) {
auto frame_addr_instr = std::make_unique<MachineInstr>(RVOpcodes::FRAME_ADDR);
frame_addr_instr->addOperand(std::make_unique<RegOperand>(base_addr_vreg));
frame_addr_instr->addOperand(std::make_unique<RegOperand>(getVReg(alloca_base)));
CurMBB->addInstruction(std::move(frame_addr_instr));
}
// 情况二:基地址是全局变量
else if (auto global_base = dynamic_cast<GlobalValue*>(base)) {
auto la_instr = std::make_unique<MachineInstr>(RVOpcodes::LA);
la_instr->addOperand(std::make_unique<RegOperand>(base_addr_vreg));
la_instr->addOperand(std::make_unique<LabelOperand>(global_base->getName()));
CurMBB->addInstruction(std::move(la_instr));
}
// 3. 生成真正的add指令计算最终地址这部分逻辑保持不变
auto final_addr_vreg = getVReg(bin); // 这是整个二元运算的结果vreg
auto offset_vreg = getVReg(offset);
auto add_instr = std::make_unique<MachineInstr>(RVOpcodes::ADD); // 指针运算是64位
add_instr->addOperand(std::make_unique<RegOperand>(final_addr_vreg));
add_instr->addOperand(std::make_unique<RegOperand>(base_addr_vreg));
add_instr->addOperand(std::make_unique<RegOperand>(offset_vreg));
CurMBB->addInstruction(std::move(add_instr));
return; // 地址计算处理完毕,直接返回
}
}
// [V2优点] 在BINARY节点内部按需加载常量操作数。
auto load_val_if_const = [&](Value* val) {
if (auto c = dynamic_cast<ConstantValue*>(val)) {
if (DEBUG) {
std::cout << "[DEBUG] selectNode-BINARY: Found constant operand with value " << c->getInt()
<< ". Generating LI instruction." << std::endl;
}
auto li = std::make_unique<MachineInstr>(RVOpcodes::LI);
li->addOperand(std::make_unique<RegOperand>(getVReg(c)));
li->addOperand(std::make_unique<ImmOperand>(c->getInt()));
CurMBB->addInstruction(std::move(li));
}
};
load_val_if_const(lhs);
load_val_if_const(rhs);
auto dest_vreg = getVReg(bin);
auto lhs_vreg = getVReg(lhs);
auto rhs_vreg = getVReg(rhs);
if (bin->getKind() == BinaryInst::kAdd) {
if (auto rhs_const = dynamic_cast<ConstantValue*>(rhs)) {
if (rhs_const->getInt() >= -2048 && rhs_const->getInt() < 2048) {
auto instr = std::make_unique<MachineInstr>(RVOpcodes::ADDIW);
instr->addOperand(std::make_unique<RegOperand>(dest_vreg));
instr->addOperand(std::make_unique<RegOperand>(lhs_vreg));
instr->addOperand(std::make_unique<ImmOperand>(rhs_const->getInt()));
CurMBB->addInstruction(std::move(instr));
return;
}
// 检查是否能应用立即数优化。
bool rhs_is_imm_opt = false;
if (auto rhs_const = dynamic_cast<ConstantValue*>(rhs)) {
if (bin->getKind() == BinaryInst::kAdd && rhs_const->getInt() >= -2048 && rhs_const->getInt() < 2048) {
rhs_is_imm_opt = true;
}
}
// 仅在不能作为立即数操作数时才需要提前加载。
load_val_if_const(lhs);
if (!rhs_is_imm_opt) {
load_val_if_const(rhs);
}
auto dest_vreg = getVReg(bin);
auto lhs_vreg = getVReg(lhs);
// [V2优点] 融合 ADDIW 优化。
if (rhs_is_imm_opt) {
auto rhs_const = dynamic_cast<ConstantValue*>(rhs);
auto instr = std::make_unique<MachineInstr>(RVOpcodes::ADDIW);
instr->addOperand(std::make_unique<RegOperand>(dest_vreg));
instr->addOperand(std::make_unique<RegOperand>(lhs_vreg));
instr->addOperand(std::make_unique<ImmOperand>(rhs_const->getInt()));
CurMBB->addInstruction(std::move(instr));
return; // 指令已生成,直接返回。
}
auto rhs_vreg = getVReg(rhs);
switch (bin->getKind()) {
case BinaryInst::kAdd: {
// 区分指针运算64位和整数运算32位
RVOpcodes opcode = (lhs->getType()->isPointer() || rhs->getType()->isPointer()) ? RVOpcodes::ADD : RVOpcodes::ADDW;
auto instr = std::make_unique<MachineInstr>(opcode);
instr->addOperand(std::make_unique<RegOperand>(dest_vreg));
@@ -281,7 +384,7 @@ void RISCv64ISel::selectNode(DAGNode* node) {
CurMBB->addInstruction(std::move(instr));
break;
}
case BinaryInst::kICmpEQ: {
case BinaryInst::kICmpEQ: { // 等于 (a == b) -> (subw; seqz)
auto sub = std::make_unique<MachineInstr>(RVOpcodes::SUBW);
sub->addOperand(std::make_unique<RegOperand>(dest_vreg));
sub->addOperand(std::make_unique<RegOperand>(lhs_vreg));
@@ -294,7 +397,7 @@ void RISCv64ISel::selectNode(DAGNode* node) {
CurMBB->addInstruction(std::move(seqz));
break;
}
case BinaryInst::kICmpNE: {
case BinaryInst::kICmpNE: { // 不等于 (a != b) -> (subw; snez)
auto sub = std::make_unique<MachineInstr>(RVOpcodes::SUBW);
sub->addOperand(std::make_unique<RegOperand>(dest_vreg));
sub->addOperand(std::make_unique<RegOperand>(lhs_vreg));
@@ -307,7 +410,7 @@ void RISCv64ISel::selectNode(DAGNode* node) {
CurMBB->addInstruction(std::move(snez));
break;
}
case BinaryInst::kICmpLT: {
case BinaryInst::kICmpLT: { // 小于 (a < b) -> slt
auto instr = std::make_unique<MachineInstr>(RVOpcodes::SLT);
instr->addOperand(std::make_unique<RegOperand>(dest_vreg));
instr->addOperand(std::make_unique<RegOperand>(lhs_vreg));
@@ -315,7 +418,7 @@ void RISCv64ISel::selectNode(DAGNode* node) {
CurMBB->addInstruction(std::move(instr));
break;
}
case BinaryInst::kICmpGT: {
case BinaryInst::kICmpGT: { // 大于 (a > b) -> (b < a) -> slt
auto instr = std::make_unique<MachineInstr>(RVOpcodes::SLT);
instr->addOperand(std::make_unique<RegOperand>(dest_vreg));
instr->addOperand(std::make_unique<RegOperand>(rhs_vreg));
@@ -323,7 +426,7 @@ void RISCv64ISel::selectNode(DAGNode* node) {
CurMBB->addInstruction(std::move(instr));
break;
}
case BinaryInst::kICmpLE: {
case BinaryInst::kICmpLE: { // 小于等于 (a <= b) -> !(b < a) -> (slt; xori)
auto slt = std::make_unique<MachineInstr>(RVOpcodes::SLT);
slt->addOperand(std::make_unique<RegOperand>(dest_vreg));
slt->addOperand(std::make_unique<RegOperand>(rhs_vreg));
@@ -337,7 +440,7 @@ void RISCv64ISel::selectNode(DAGNode* node) {
CurMBB->addInstruction(std::move(xori));
break;
}
case BinaryInst::kICmpGE: {
case BinaryInst::kICmpGE: { // 大于等于 (a >= b) -> !(a < b) -> (slt; xori)
auto slt = std::make_unique<MachineInstr>(RVOpcodes::SLT);
slt->addOperand(std::make_unique<RegOperand>(dest_vreg));
slt->addOperand(std::make_unique<RegOperand>(lhs_vreg));
@@ -363,7 +466,7 @@ void RISCv64ISel::selectNode(DAGNode* node) {
auto src_vreg = getVReg(unary->getOperand());
switch (unary->getKind()) {
case UnaryInst::kNeg: {
case UnaryInst::kNeg: { // 取负: 0 - src
auto instr = std::make_unique<MachineInstr>(RVOpcodes::SUBW);
instr->addOperand(std::make_unique<RegOperand>(dest_vreg));
instr->addOperand(std::make_unique<RegOperand>(PhysicalReg::ZERO));
@@ -371,7 +474,7 @@ void RISCv64ISel::selectNode(DAGNode* node) {
CurMBB->addInstruction(std::move(instr));
break;
}
case UnaryInst::kNot: {
case UnaryInst::kNot: { // 逻辑非: src == 0 ? 1 : 0
auto instr = std::make_unique<MachineInstr>(RVOpcodes::SEQZ);
instr->addOperand(std::make_unique<RegOperand>(dest_vreg));
instr->addOperand(std::make_unique<RegOperand>(src_vreg));
@@ -386,7 +489,10 @@ void RISCv64ISel::selectNode(DAGNode* node) {
case DAGNode::CALL: {
auto call = dynamic_cast<CallInst*>(node->value);
for (size_t i = 0; i < node->operands.size() && i < 8; ++i) {
// 处理函数参数放入a0-a7物理寄存器
size_t num_operands = node->operands.size();
size_t reg_arg_count = std::min(num_operands, (size_t)8);
for (size_t i = 0; i < reg_arg_count; ++i) {
DAGNode* arg_node = node->operands[i];
auto arg_preg = static_cast<PhysicalReg>(static_cast<int>(PhysicalReg::A0) + i);
@@ -405,11 +511,64 @@ void RISCv64ISel::selectNode(DAGNode* node) {
CurMBB->addInstruction(std::move(mv));
}
}
if (num_operands > 8) {
size_t stack_arg_count = num_operands - 8;
int stack_space = stack_arg_count * 8; // RV64中每个参数槽位8字节
// 2a. 在栈上分配空间
auto alloc_instr = std::make_unique<MachineInstr>(RVOpcodes::ADDI);
alloc_instr->addOperand(std::make_unique<RegOperand>(PhysicalReg::SP));
alloc_instr->addOperand(std::make_unique<RegOperand>(PhysicalReg::SP));
alloc_instr->addOperand(std::make_unique<ImmOperand>(-stack_space));
CurMBB->addInstruction(std::move(alloc_instr));
// 2b. 存储每个栈参数
for (size_t i = 8; i < num_operands; ++i) {
DAGNode* arg_node = node->operands[i];
unsigned src_vreg;
// 准备源寄存器
if (arg_node->kind == DAGNode::CONSTANT) {
// 如果是常量,先加载到临时寄存器
src_vreg = getNewVReg();
auto const_val = dynamic_cast<ConstantValue*>(arg_node->value);
auto li = std::make_unique<MachineInstr>(RVOpcodes::LI);
li->addOperand(std::make_unique<RegOperand>(src_vreg));
li->addOperand(std::make_unique<ImmOperand>(const_val->getInt()));
CurMBB->addInstruction(std::move(li));
} else {
src_vreg = getVReg(arg_node->value);
}
// 计算在栈上的偏移量
int offset = (i - 8) * 8;
// 生成 sd 指令
auto sd_instr = std::make_unique<MachineInstr>(RVOpcodes::SD);
sd_instr->addOperand(std::make_unique<RegOperand>(src_vreg));
sd_instr->addOperand(std::make_unique<MemOperand>(
std::make_unique<RegOperand>(PhysicalReg::SP),
std::make_unique<ImmOperand>(offset)
));
CurMBB->addInstruction(std::move(sd_instr));
}
}
auto call_instr = std::make_unique<MachineInstr>(RVOpcodes::CALL);
call_instr->addOperand(std::make_unique<LabelOperand>(call->getCallee()->getName()));
CurMBB->addInstruction(std::move(call_instr));
if (num_operands > 8) {
size_t stack_arg_count = num_operands - 8;
int stack_space = stack_arg_count * 8;
auto dealloc_instr = std::make_unique<MachineInstr>(RVOpcodes::ADDI);
dealloc_instr->addOperand(std::make_unique<RegOperand>(PhysicalReg::SP));
dealloc_instr->addOperand(std::make_unique<RegOperand>(PhysicalReg::SP));
dealloc_instr->addOperand(std::make_unique<ImmOperand>(stack_space));
CurMBB->addInstruction(std::move(dealloc_instr));
}
// 处理返回值从a0移动到目标虚拟寄存器
if (!call->getType()->isVoid()) {
auto mv_instr = std::make_unique<MachineInstr>(RVOpcodes::MV);
mv_instr->addOperand(std::make_unique<RegOperand>(getVReg(call)));
@@ -423,6 +582,7 @@ void RISCv64ISel::selectNode(DAGNode* node) {
auto ret_inst_ir = dynamic_cast<ReturnInst*>(node->value);
if (ret_inst_ir && ret_inst_ir->hasReturnValue()) {
Value* ret_val = ret_inst_ir->getReturnValue();
// [V2优点] 在RETURN节点内加载常量返回值
if (auto const_val = dynamic_cast<ConstantValue*>(ret_val)) {
auto li_instr = std::make_unique<MachineInstr>(RVOpcodes::LI);
li_instr->addOperand(std::make_unique<RegOperand>(PhysicalReg::A0));
@@ -435,36 +595,121 @@ void RISCv64ISel::selectNode(DAGNode* node) {
CurMBB->addInstruction(std::move(mv_instr));
}
}
// [V1设计保留] 函数尾声epilogue不由RETURN节点生成
// 而是由后续的AsmPrinter或其它Pass统一处理这是一种常见且有效的模块化设计。
auto ret_mi = std::make_unique<MachineInstr>(RVOpcodes::RET);
CurMBB->addInstruction(std::move(ret_mi));
break;
}
case DAGNode::BRANCH: {
if (auto cond_br = dynamic_cast<CondBrInst*>(node->value)) {
// 处理条件分支
if (auto cond_br = dynamic_cast<CondBrInst*>(node->value)) {
Value* condition = cond_br->getCondition();
auto then_bb_name = cond_br->getThenBlock()->getName();
auto else_bb_name = cond_br->getElseBlock()->getName();
// [优化] 检查分支条件是否为编译期常量
if (auto const_cond = dynamic_cast<ConstantValue*>(condition)) {
// 如果条件是常量直接生成一个无条件跳转J而不是BNE
if (const_cond->getInt() != 0) { // 条件为 true
auto j_instr = std::make_unique<MachineInstr>(RVOpcodes::J);
j_instr->addOperand(std::make_unique<LabelOperand>(then_bb_name));
CurMBB->addInstruction(std::move(j_instr));
} else { // 条件为 false
auto j_instr = std::make_unique<MachineInstr>(RVOpcodes::J);
j_instr->addOperand(std::make_unique<LabelOperand>(else_bb_name));
CurMBB->addInstruction(std::move(j_instr));
}
}
// 如果条件不是常量,则执行标准流程
else {
// [修复] 为条件变量生成加载指令(如果它是常量的话,尽管上面已经处理了)
// 这一步是为了逻辑完整,以防有其他类型的常量没有被捕获
if (auto const_val = dynamic_cast<ConstantValue*>(condition)) {
auto li = std::make_unique<MachineInstr>(RVOpcodes::LI);
li->addOperand(std::make_unique<RegOperand>(getVReg(const_val)));
li->addOperand(std::make_unique<ImmOperand>(const_val->getInt()));
CurMBB->addInstruction(std::move(li));
}
auto cond_vreg = getVReg(condition);
// 生成 bne cond, zero, then_label (如果cond不为0则跳转到then)
auto br_instr = std::make_unique<MachineInstr>(RVOpcodes::BNE);
br_instr->addOperand(std::make_unique<RegOperand>(getVReg(cond_br->getCondition())));
br_instr->addOperand(std::make_unique<RegOperand>(cond_vreg));
br_instr->addOperand(std::make_unique<RegOperand>(PhysicalReg::ZERO));
br_instr->addOperand(std::make_unique<LabelOperand>(cond_br->getThenBlock()->getName()));
br_instr->addOperand(std::make_unique<LabelOperand>(then_bb_name));
CurMBB->addInstruction(std::move(br_instr));
} else if (auto uncond_br = dynamic_cast<UncondBrInst*>(node->value)) {
// 为else分支生成无条件跳转 (后续Pass可以优化掉不必要的跳转)
auto j_instr = std::make_unique<MachineInstr>(RVOpcodes::J);
j_instr->addOperand(std::make_unique<LabelOperand>(uncond_br->getBlock()->getName()));
j_instr->addOperand(std::make_unique<LabelOperand>(else_bb_name));
CurMBB->addInstruction(std::move(j_instr));
}
break;
}
// 处理无条件分支
else if (auto uncond_br = dynamic_cast<UncondBrInst*>(node->value)) {
auto j_instr = std::make_unique<MachineInstr>(RVOpcodes::J);
j_instr->addOperand(std::make_unique<LabelOperand>(uncond_br->getBlock()->getName()));
CurMBB->addInstruction(std::move(j_instr));
}
break;
}
case DAGNode::MEMSET: {
// [V1设计保留] Memset的核心展开逻辑在虚拟寄存器层面是正确的无需修改。
// 之前的bug是由于其输入地址、值、大小的虚拟寄存器未被正确初始化。
// 在修复了CONSTANT/ALLOCA_ADDR的加载问题后此处的逻辑现在可以正常工作。
if (DEBUG) {
std::cout << "[DEBUG] selectNode-MEMSET: Processing MEMSET node." << std::endl;
}
auto memset = dynamic_cast<MemsetInst*>(node->value);
Value* val_to_set = memset->getValue();
Value* size_to_set = memset->getSize();
Value* ptr_val = memset->getPointer();
auto dest_addr_vreg = getVReg(ptr_val);
if (auto const_val = dynamic_cast<ConstantValue*>(val_to_set)) {
if (DEBUG) {
std::cout << "[DEBUG] selectNode-MEMSET: Found constant 'value' operand (" << const_val->getInt() << "). Generating LI." << std::endl;
}
auto li = std::make_unique<MachineInstr>(RVOpcodes::LI);
li->addOperand(std::make_unique<RegOperand>(getVReg(const_val)));
li->addOperand(std::make_unique<ImmOperand>(const_val->getInt()));
CurMBB->addInstruction(std::move(li));
}
if (auto const_size = dynamic_cast<ConstantValue*>(size_to_set)) {
if (DEBUG) {
std::cout << "[DEBUG] selectNode-MEMSET: Found constant 'size' operand (" << const_size->getInt() << "). Generating LI." << std::endl;
}
auto li = std::make_unique<MachineInstr>(RVOpcodes::LI);
li->addOperand(std::make_unique<RegOperand>(getVReg(const_size)));
li->addOperand(std::make_unique<ImmOperand>(const_size->getInt()));
CurMBB->addInstruction(std::move(li));
}
if (auto alloca = dynamic_cast<AllocaInst*>(ptr_val)) {
if (DEBUG) {
std::cout << "[DEBUG] selectNode-MEMSET: Found 'pointer' operand is an AllocaInst. Generating FRAME_ADDR." << std::endl;
}
// 生成新的伪指令来获取栈地址
auto instr = std::make_unique<MachineInstr>(RVOpcodes::FRAME_ADDR);
instr->addOperand(std::make_unique<RegOperand>(dest_addr_vreg)); // 目标虚拟寄存器
instr->addOperand(std::make_unique<RegOperand>(getVReg(alloca))); // 源AllocaInst
CurMBB->addInstruction(std::move(instr));
}
auto r_dest_addr = getVReg(memset->getPointer());
auto r_num_bytes = getVReg(memset->getSize());
auto r_value_byte = getVReg(memset->getValue());
// 为memset内部逻辑创建新的临时虚拟寄存器
auto r_counter = getNewVReg();
auto r_end_addr = getNewVReg();
auto r_current_addr = getNewVReg();
auto r_temp_val = getNewVReg();
// 定义一系列lambda表达式来简化指令创建
auto add_instr = [&](RVOpcodes op, unsigned rd, unsigned rs1, unsigned rs2) {
auto i = std::make_unique<MachineInstr>(op);
i->addOperand(std::make_unique<RegOperand>(rd));
@@ -503,12 +748,14 @@ void RISCv64ISel::selectNode(DAGNode* node) {
CurMBB->addInstruction(std::move(i));
};
// 生成唯一的循环标签
int unique_id = this->local_label_counter++;
std::string loop_start_label = MFunc->getName() + "_memset_loop_start_" + std::to_string(unique_id);
std::string loop_end_label = MFunc->getName() + "_memset_loop_end_" + std::to_string(unique_id);
std::string remainder_label = MFunc->getName() + "_memset_remainder_" + std::to_string(unique_id);
std::string done_label = MFunc->getName() + "_memset_done_" + std::to_string(unique_id);
// 构造64位的填充值
addi_instr(RVOpcodes::ANDI, r_temp_val, r_value_byte, 255);
addi_instr(RVOpcodes::SLLI, r_value_byte, r_temp_val, 8);
add_instr(RVOpcodes::OR, r_temp_val, r_temp_val, r_value_byte);
@@ -516,6 +763,8 @@ void RISCv64ISel::selectNode(DAGNode* node) {
add_instr(RVOpcodes::OR, r_temp_val, r_temp_val, r_value_byte);
addi_instr(RVOpcodes::SLLI, r_value_byte, r_temp_val, 32);
add_instr(RVOpcodes::OR, r_temp_val, r_temp_val, r_value_byte);
// 计算循环边界
add_instr(RVOpcodes::ADD, r_end_addr, r_dest_addr, r_num_bytes);
auto mv = std::make_unique<MachineInstr>(RVOpcodes::MV);
mv->addOperand(std::make_unique<RegOperand>(r_current_addr));
@@ -523,17 +772,22 @@ void RISCv64ISel::selectNode(DAGNode* node) {
CurMBB->addInstruction(std::move(mv));
addi_instr(RVOpcodes::ANDI, r_counter, r_num_bytes, -8);
add_instr(RVOpcodes::ADD, r_counter, r_dest_addr, r_counter);
// 8字节主循环
label_instr(loop_start_label);
branch_instr(RVOpcodes::BGEU, r_current_addr, r_counter, loop_end_label);
store_instr(RVOpcodes::SD, r_temp_val, r_current_addr, 0);
addi_instr(RVOpcodes::ADDI, r_current_addr, r_current_addr, 8);
jump_instr(loop_start_label);
// 1字节收尾循环
label_instr(loop_end_label);
label_instr(remainder_label);
branch_instr(RVOpcodes::BGEU, r_current_addr, r_end_addr, done_label);
store_instr(RVOpcodes::SB, r_temp_val, r_current_addr, 0);
addi_instr(RVOpcodes::ADDI, r_current_addr, r_current_addr, 1);
jump_instr(remainder_label);
label_instr(done_label);
break;
}
@@ -590,6 +844,12 @@ std::vector<std::unique_ptr<RISCv64ISel::DAGNode>> RISCv64ISel::build_dag(BasicB
memset_node->operands.push_back(get_operand_node(memset->getBegin(), value_to_node, nodes_storage));
memset_node->operands.push_back(get_operand_node(memset->getSize(), value_to_node, nodes_storage));
memset_node->operands.push_back(get_operand_node(memset->getValue(), value_to_node, nodes_storage));
if (DEBUG) {
std::cout << "[DEBUG] build_dag: Created MEMSET node for: " << memset->getName() << std::endl;
for (size_t i = 0; i < memset_node->operands.size(); ++i) {
std::cout << " -> Operand " << i << " has kind: " << memset_node->operands[i]->kind << std::endl;
}
}
} else if (auto load = dynamic_cast<LoadInst*>(inst)) {
auto load_node = create_node(DAGNode::LOAD, load, value_to_node, nodes_storage);
load_node->operands.push_back(get_operand_node(load->getPointer(), value_to_node, nodes_storage));
@@ -632,4 +892,98 @@ std::vector<std::unique_ptr<RISCv64ISel::DAGNode>> RISCv64ISel::build_dag(BasicB
return nodes_storage;
}
// [新] 打印DAG图以供调试的辅助函数
void RISCv64ISel::print_dag(const std::vector<std::unique_ptr<DAGNode>>& dag, const std::string& bb_name) {
// 检查是否有DEBUG宏或者全局变量避免在非调试模式下打印
// if (!DEBUG) return;
std::cerr << "=== DAG for Basic Block: " << bb_name << " ===\n";
std::set<DAGNode*> visited;
// 为节点分配临时ID方便阅读
std::map<DAGNode*, int> node_to_id;
int current_id = 0;
for (const auto& node_ptr : dag) {
node_to_id[node_ptr.get()] = current_id++;
}
// 将NodeKind枚举转换为字符串的辅助函数
auto get_kind_string = [](DAGNode::NodeKind kind) {
switch (kind) {
case DAGNode::CONSTANT: return "CONSTANT";
case DAGNode::LOAD: return "LOAD";
case DAGNode::STORE: return "STORE";
case DAGNode::BINARY: return "BINARY";
case DAGNode::CALL: return "CALL";
case DAGNode::RETURN: return "RETURN";
case DAGNode::BRANCH: return "BRANCH";
case DAGNode::ALLOCA_ADDR: return "ALLOCA_ADDR";
case DAGNode::UNARY: return "UNARY";
case DAGNode::MEMSET: return "MEMSET";
default: return "UNKNOWN";
}
};
// 递归打印节点的lambda表达式
std::function<void(DAGNode*, int)> print_node =
[&](DAGNode* node, int indent) {
if (!node) return;
std::string current_indent(indent, ' ');
int node_id = node_to_id.count(node) ? node_to_id[node] : -1;
std::cerr << current_indent << "Node#" << node_id << ": " << get_kind_string(node->kind);
// 尝试打印关联的虚拟寄存器
if (node->value && vreg_map.count(node->value)) {
std::cerr << " (vreg: %vreg" << vreg_map.at(node->value) << ")";
}
// 打印关联的IR Value信息
if (node->value) {
std::cerr << " [";
if (auto inst = dynamic_cast<Instruction*>(node->value)) {
std::cerr << inst->getKindString();
if (!inst->getName().empty()) {
std::cerr << "(" << inst->getName() << ")";
}
} else if (auto constant = dynamic_cast<ConstantValue*>(node->value)) {
std::cerr << "Const(" << constant->getInt() << ")";
} else if (auto global = dynamic_cast<GlobalValue*>(node->value)) {
std::cerr << "Global(" << global->getName() << ")";
} else if (auto alloca = dynamic_cast<AllocaInst*>(node->value)) {
std::cerr << "Alloca(" << alloca->getName() << ")";
}
std::cerr << "]";
}
std::cerr << "\n";
if (visited.count(node)) {
std::cerr << current_indent << " (已打印过子节点)\n";
return;
}
visited.insert(node);
if (!node->operands.empty()) {
std::cerr << current_indent << " Operands:\n";
for (auto operand : node->operands) {
print_node(operand, indent + 4);
}
}
};
// 从根节点(没有用户的节点,或有副作用的节点)开始打印
for (const auto& node_ptr : dag) {
if (node_ptr->users.empty() ||
node_ptr->kind == DAGNode::STORE ||
node_ptr->kind == DAGNode::RETURN ||
node_ptr->kind == DAGNode::BRANCH ||
node_ptr->kind == DAGNode::MEMSET)
{
print_node(node_ptr.get(), 0);
}
}
std::cerr << "======================================\n\n";
}
} // namespace sysy

View File

@@ -27,7 +27,8 @@ void RISCv64RegAlloc::run() {
void RISCv64RegAlloc::eliminateFrameIndices() {
StackFrameInfo& frame_info = MFunc->getFrameInfo();
int current_offset = 0;
int current_offset = 20; // 这里写20是为了在$s0和第一个变量之间留出20字节的安全区
// 以防止一些函数调用方面的恶性bug。
Function* F = MFunc->getFunc();
RISCv64ISel* isel = MFunc->getISel();
@@ -94,6 +95,18 @@ void RISCv64RegAlloc::eliminateFrameIndices() {
std::make_unique<RegOperand>(addr_vreg),
std::make_unique<ImmOperand>(0)));
new_instructions.push_back(std::move(sw));
} else if (instr_ptr->getOpcode() == RVOpcodes::FRAME_ADDR) { // [新] 处理FRAME_ADDR
auto& operands = instr_ptr->getOperands();
unsigned dest_vreg = static_cast<RegOperand*>(operands[0].get())->getVRegNum();
unsigned alloca_vreg = static_cast<RegOperand*>(operands[1].get())->getVRegNum();
int offset = frame_info.alloca_offsets.at(alloca_vreg);
// 将 `frame_addr rd, rs` 展开为 `addi rd, s0, offset`
auto addi = std::make_unique<MachineInstr>(RVOpcodes::ADDI);
addi->addOperand(std::make_unique<RegOperand>(dest_vreg));
addi->addOperand(std::make_unique<RegOperand>(PhysicalReg::S0)); // 基地址是帧指针 s0
addi->addOperand(std::make_unique<ImmOperand>(offset));
new_instructions.push_back(std::move(addi));
} else {
new_instructions.push_back(std::move(instr_ptr));
}

View File

@@ -4,20 +4,23 @@
#include "RISCv64LLIR.h"
#include <iostream>
extern int DEBUG;
extern int DEEPDEBUG;
namespace sysy {
class RISCv64AsmPrinter {
public:
RISCv64AsmPrinter(MachineFunction* mfunc);
// 主入口
void run(std::ostream& os);
void run(std::ostream& os, bool debug = false);
private:
// 打印各个部分
void printPrologue();
void printEpilogue();
void printBasicBlock(MachineBasicBlock* mbb);
void printInstruction(MachineInstr* instr);
void printBasicBlock(MachineBasicBlock* mbb, bool debug = false);
void printInstruction(MachineInstr* instr, bool debug = false);
// 辅助函数
std::string regToString(PhysicalReg reg);

View File

@@ -4,6 +4,9 @@
#include "IR.h"
#include <string>
extern int DEBUG;
extern int DEEPDEBUG;
namespace sysy {
// RISCv64CodeGen 现在是一个高层驱动器

View File

@@ -3,6 +3,9 @@
#include "RISCv64LLIR.h"
extern int DEBUG;
extern int DEEPDEBUG;
namespace sysy {
class RISCv64ISel {
@@ -31,6 +34,8 @@ private:
DAGNode* get_operand_node(Value* val_ir, std::map<Value*, DAGNode*>&, std::vector<std::unique_ptr<DAGNode>>&);
DAGNode* create_node(int kind, Value* val, std::map<Value*, DAGNode*>&, std::vector<std::unique_ptr<DAGNode>>&);
void print_dag(const std::vector<std::unique_ptr<DAGNode>>& dag, const std::string& bb_name);
// 状态
Function* F; // 当前处理的高层IR函数
std::unique_ptr<MachineFunction> MFunc; // 正在构建的底层LLIR函数

View File

@@ -46,6 +46,7 @@ enum class RVOpcodes {
// 新增伪指令,用于解耦栈帧处理
FRAME_LOAD, // 从栈帧加载 (AllocaInst)
FRAME_STORE, // 保存到栈帧 (AllocaInst)
FRAME_ADDR, // [新] 获取栈帧变量的地址
};
class MachineOperand;

View File

@@ -216,7 +216,7 @@ int main(int argc, char **argv) {
// 设置 DEBUG 模式(如果指定了 'asmd'
if (argStopAfter == "asmd") {
DEBUG = 1;
// DEEPDEBUG = 1;
DEEPDEBUG = 1;
}
sysy::RISCv64CodeGen codegen(moduleIR); // 传入优化后的 moduleIR
string asmCode = codegen.code_gen();