Files
mysysy/src/RISCv64ISel.cpp

989 lines
50 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#include "RISCv64ISel.h"
#include <stdexcept>
#include <set>
#include <functional>
#include <cmath> // For std::fabs
#include <limits> // For std::numeric_limits
#include <iostream>
namespace sysy {
// DAG节点定义 (内部实现)
struct RISCv64ISel::DAGNode {
enum NodeKind { CONSTANT, LOAD, STORE, BINARY, CALL, RETURN, BRANCH, ALLOCA_ADDR, UNARY, MEMSET };
NodeKind kind;
Value* value = nullptr;
std::vector<DAGNode*> operands;
std::vector<DAGNode*> users;
DAGNode(NodeKind k) : kind(k) {}
};
RISCv64ISel::RISCv64ISel() : vreg_counter(0), local_label_counter(0) {}
// 为一个IR Value获取或分配一个新的虚拟寄存器
unsigned RISCv64ISel::getVReg(Value* val) {
if (!val) {
throw std::runtime_error("Cannot get vreg for a null Value.");
}
if (vreg_map.find(val) == vreg_map.end()) {
if (vreg_counter == 0) {
vreg_counter = 1; // vreg 0 保留
}
vreg_map[val] = vreg_counter++;
}
return vreg_map.at(val);
}
// 主入口函数
std::unique_ptr<MachineFunction> RISCv64ISel::runOnFunction(Function* func) {
F = func;
if (!F) return nullptr;
MFunc = std::make_unique<MachineFunction>(F, this);
vreg_map.clear();
bb_map.clear();
vreg_counter = 0;
local_label_counter = 0;
select();
return std::move(MFunc);
}
// 指令选择主流程
void RISCv64ISel::select() {
for (const auto& bb_ptr : F->getBasicBlocks()) {
auto mbb = std::make_unique<MachineBasicBlock>(bb_ptr->getName(), MFunc.get());
bb_map[bb_ptr.get()] = mbb.get();
MFunc->addBlock(std::move(mbb));
}
if (F->getEntryBlock()) {
for (auto* arg_alloca : F->getEntryBlock()->getArguments()) {
getVReg(arg_alloca);
}
}
for (const auto& bb_ptr : F->getBasicBlocks()) {
selectBasicBlock(bb_ptr.get());
}
for (const auto& bb_ptr : F->getBasicBlocks()) {
CurMBB = bb_map.at(bb_ptr.get());
for (auto succ : bb_ptr->getSuccessors()) {
CurMBB->successors.push_back(bb_map.at(succ));
}
for (auto pred : bb_ptr->getPredecessors()) {
CurMBB->predecessors.push_back(bb_map.at(pred));
}
}
}
// 处理单个基本块
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) {
value_to_node[node->value] = node.get();
}
}
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);
}
selectNode(node);
selected_nodes.insert(node);
};
for (const auto& inst_ptr : bb->getInstructions()) {
DAGNode* node_to_select = nullptr;
if (value_to_node.count(inst_ptr.get())) {
node_to_select = value_to_node.at(inst_ptr.get());
} else {
for(const auto& node : dag) {
if(node->value == inst_ptr.get()) {
node_to_select = node.get();
break;
}
}
}
if(node_to_select) {
select_recursive(node_to_select);
}
}
}
// 核心函数为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);
}
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));
la->addOperand(std::make_unique<LabelOperand>(global->getName()));
CurMBB->addInstruction(std::move(la));
auto lw = std::make_unique<MachineInstr>(RVOpcodes::LW);
lw->addOperand(std::make_unique<RegOperand>(dest_vreg));
lw->addOperand(std::make_unique<MemOperand>(
std::make_unique<RegOperand>(addr_vreg),
std::make_unique<ImmOperand>(0)
));
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));
lw->addOperand(std::make_unique<MemOperand>(
std::make_unique<RegOperand>(ptr_vreg),
std::make_unique<ImmOperand>(0)
));
CurMBB->addInstruction(std::move(lw));
}
break;
}
case DAGNode::STORE: {
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()));
CurMBB->addInstruction(std::move(li));
}
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 la = std::make_unique<MachineInstr>(RVOpcodes::LA);
la->addOperand(std::make_unique<RegOperand>(addr_vreg));
la->addOperand(std::make_unique<LabelOperand>(global->getName()));
CurMBB->addInstruction(std::move(la));
auto sw = std::make_unique<MachineInstr>(RVOpcodes::SW);
sw->addOperand(std::make_unique<RegOperand>(val_vreg));
sw->addOperand(std::make_unique<MemOperand>(
std::make_unique<RegOperand>(addr_vreg),
std::make_unique<ImmOperand>(0)
));
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));
sw->addOperand(std::make_unique<MemOperand>(
std::make_unique<RegOperand>(ptr_vreg),
std::make_unique<ImmOperand>(0)
));
CurMBB->addInstruction(std::move(sw));
}
break;
}
case DAGNode::BINARY: {
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));
}
};
// 检查是否能应用立即数优化。
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));
instr->addOperand(std::make_unique<RegOperand>(lhs_vreg));
instr->addOperand(std::make_unique<RegOperand>(rhs_vreg));
CurMBB->addInstruction(std::move(instr));
break;
}
case BinaryInst::kSub: {
auto instr = std::make_unique<MachineInstr>(RVOpcodes::SUBW);
instr->addOperand(std::make_unique<RegOperand>(dest_vreg));
instr->addOperand(std::make_unique<RegOperand>(lhs_vreg));
instr->addOperand(std::make_unique<RegOperand>(rhs_vreg));
CurMBB->addInstruction(std::move(instr));
break;
}
case BinaryInst::kMul: {
auto instr = std::make_unique<MachineInstr>(RVOpcodes::MULW);
instr->addOperand(std::make_unique<RegOperand>(dest_vreg));
instr->addOperand(std::make_unique<RegOperand>(lhs_vreg));
instr->addOperand(std::make_unique<RegOperand>(rhs_vreg));
CurMBB->addInstruction(std::move(instr));
break;
}
case Instruction::kDiv: {
auto instr = std::make_unique<MachineInstr>(RVOpcodes::DIVW);
instr->addOperand(std::make_unique<RegOperand>(dest_vreg));
instr->addOperand(std::make_unique<RegOperand>(lhs_vreg));
instr->addOperand(std::make_unique<RegOperand>(rhs_vreg));
CurMBB->addInstruction(std::move(instr));
break;
}
case Instruction::kRem: {
auto instr = std::make_unique<MachineInstr>(RVOpcodes::REMW);
instr->addOperand(std::make_unique<RegOperand>(dest_vreg));
instr->addOperand(std::make_unique<RegOperand>(lhs_vreg));
instr->addOperand(std::make_unique<RegOperand>(rhs_vreg));
CurMBB->addInstruction(std::move(instr));
break;
}
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));
sub->addOperand(std::make_unique<RegOperand>(rhs_vreg));
CurMBB->addInstruction(std::move(sub));
auto seqz = std::make_unique<MachineInstr>(RVOpcodes::SEQZ);
seqz->addOperand(std::make_unique<RegOperand>(dest_vreg));
seqz->addOperand(std::make_unique<RegOperand>(dest_vreg));
CurMBB->addInstruction(std::move(seqz));
break;
}
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));
sub->addOperand(std::make_unique<RegOperand>(rhs_vreg));
CurMBB->addInstruction(std::move(sub));
auto snez = std::make_unique<MachineInstr>(RVOpcodes::SNEZ);
snez->addOperand(std::make_unique<RegOperand>(dest_vreg));
snez->addOperand(std::make_unique<RegOperand>(dest_vreg));
CurMBB->addInstruction(std::move(snez));
break;
}
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));
instr->addOperand(std::make_unique<RegOperand>(rhs_vreg));
CurMBB->addInstruction(std::move(instr));
break;
}
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));
instr->addOperand(std::make_unique<RegOperand>(lhs_vreg));
CurMBB->addInstruction(std::move(instr));
break;
}
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));
slt->addOperand(std::make_unique<RegOperand>(lhs_vreg));
CurMBB->addInstruction(std::move(slt));
auto xori = std::make_unique<MachineInstr>(RVOpcodes::XORI);
xori->addOperand(std::make_unique<RegOperand>(dest_vreg));
xori->addOperand(std::make_unique<RegOperand>(dest_vreg));
xori->addOperand(std::make_unique<ImmOperand>(1));
CurMBB->addInstruction(std::move(xori));
break;
}
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));
slt->addOperand(std::make_unique<RegOperand>(rhs_vreg));
CurMBB->addInstruction(std::move(slt));
auto xori = std::make_unique<MachineInstr>(RVOpcodes::XORI);
xori->addOperand(std::make_unique<RegOperand>(dest_vreg));
xori->addOperand(std::make_unique<RegOperand>(dest_vreg));
xori->addOperand(std::make_unique<ImmOperand>(1));
CurMBB->addInstruction(std::move(xori));
break;
}
default:
throw std::runtime_error("Unsupported binary instruction in ISel");
}
break;
}
case DAGNode::UNARY: {
auto unary = dynamic_cast<UnaryInst*>(node->value);
auto dest_vreg = getVReg(unary);
auto src_vreg = getVReg(unary->getOperand());
switch (unary->getKind()) {
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));
instr->addOperand(std::make_unique<RegOperand>(src_vreg));
CurMBB->addInstruction(std::move(instr));
break;
}
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));
CurMBB->addInstruction(std::move(instr));
break;
}
default:
throw std::runtime_error("Unsupported unary instruction in ISel");
}
break;
}
case DAGNode::CALL: {
auto call = dynamic_cast<CallInst*>(node->value);
// 处理函数参数放入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);
if (arg_node->kind == DAGNode::CONSTANT) {
if (auto const_val = dynamic_cast<ConstantValue*>(arg_node->value)) {
auto li = std::make_unique<MachineInstr>(RVOpcodes::LI);
li->addOperand(std::make_unique<RegOperand>(arg_preg));
li->addOperand(std::make_unique<ImmOperand>(const_val->getInt()));
CurMBB->addInstruction(std::move(li));
}
} else {
auto src_vreg = getVReg(arg_node->value);
auto mv = std::make_unique<MachineInstr>(RVOpcodes::MV);
mv->addOperand(std::make_unique<RegOperand>(arg_preg));
mv->addOperand(std::make_unique<RegOperand>(src_vreg));
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)));
mv_instr->addOperand(std::make_unique<RegOperand>(PhysicalReg::A0));
CurMBB->addInstruction(std::move(mv_instr));
}
break;
}
case DAGNode::RETURN: {
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));
li_instr->addOperand(std::make_unique<ImmOperand>(const_val->getInt()));
CurMBB->addInstruction(std::move(li_instr));
} else {
auto mv_instr = std::make_unique<MachineInstr>(RVOpcodes::MV);
mv_instr->addOperand(std::make_unique<RegOperand>(PhysicalReg::A0));
mv_instr->addOperand(std::make_unique<RegOperand>(getVReg(ret_val)));
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)) {
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>(cond_vreg));
br_instr->addOperand(std::make_unique<RegOperand>(PhysicalReg::ZERO));
br_instr->addOperand(std::make_unique<LabelOperand>(then_bb_name));
CurMBB->addInstruction(std::move(br_instr));
// 为else分支生成无条件跳转 (后续Pass可以优化掉不必要的跳转)
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 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));
i->addOperand(std::make_unique<RegOperand>(rs1));
i->addOperand(std::make_unique<RegOperand>(rs2));
CurMBB->addInstruction(std::move(i));
};
auto addi_instr = [&](RVOpcodes op, unsigned rd, unsigned rs1, int64_t imm) {
auto i = std::make_unique<MachineInstr>(op);
i->addOperand(std::make_unique<RegOperand>(rd));
i->addOperand(std::make_unique<RegOperand>(rs1));
i->addOperand(std::make_unique<ImmOperand>(imm));
CurMBB->addInstruction(std::move(i));
};
auto store_instr = [&](RVOpcodes op, unsigned src, unsigned base, int64_t off) {
auto i = std::make_unique<MachineInstr>(op);
i->addOperand(std::make_unique<RegOperand>(src));
i->addOperand(std::make_unique<MemOperand>(std::make_unique<RegOperand>(base), std::make_unique<ImmOperand>(off)));
CurMBB->addInstruction(std::move(i));
};
auto branch_instr = [&](RVOpcodes op, unsigned rs1, unsigned rs2, const std::string& label) {
auto i = std::make_unique<MachineInstr>(op);
i->addOperand(std::make_unique<RegOperand>(rs1));
i->addOperand(std::make_unique<RegOperand>(rs2));
i->addOperand(std::make_unique<LabelOperand>(label));
CurMBB->addInstruction(std::move(i));
};
auto jump_instr = [&](const std::string& label) {
auto i = std::make_unique<MachineInstr>(RVOpcodes::J);
i->addOperand(std::make_unique<LabelOperand>(label));
CurMBB->addInstruction(std::move(i));
};
auto label_instr = [&](const std::string& name) {
auto i = std::make_unique<MachineInstr>(RVOpcodes::LABEL);
i->addOperand(std::make_unique<LabelOperand>(name));
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);
addi_instr(RVOpcodes::SLLI, r_value_byte, r_temp_val, 16);
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));
mv->addOperand(std::make_unique<RegOperand>(r_dest_addr));
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;
}
default:
throw std::runtime_error("Unsupported DAGNode kind in ISel");
}
}
// 以下是忠实移植的DAG构建函数
RISCv64ISel::DAGNode* RISCv64ISel::create_node(int kind_int, Value* val, std::map<Value*, DAGNode*>& value_to_node, std::vector<std::unique_ptr<DAGNode>>& nodes_storage) {
auto kind = static_cast<DAGNode::NodeKind>(kind_int);
if (val && value_to_node.count(val) && kind != DAGNode::STORE && kind != DAGNode::RETURN && kind != DAGNode::BRANCH && kind != DAGNode::MEMSET) {
return value_to_node[val];
}
auto node = std::make_unique<DAGNode>(kind);
node->value = val;
DAGNode* raw_node_ptr = node.get();
nodes_storage.push_back(std::move(node));
if (val && !val->getType()->isVoid() && (dynamic_cast<Instruction*>(val) || dynamic_cast<GlobalValue*>(val))) {
value_to_node[val] = raw_node_ptr;
}
return raw_node_ptr;
}
RISCv64ISel::DAGNode* RISCv64ISel::get_operand_node(Value* val_ir, std::map<Value*, DAGNode*>& value_to_node, std::vector<std::unique_ptr<DAGNode>>& nodes_storage) {
if (value_to_node.count(val_ir)) {
return value_to_node[val_ir];
} else if (dynamic_cast<ConstantValue*>(val_ir)) {
return create_node(DAGNode::CONSTANT, val_ir, value_to_node, nodes_storage);
} else if (dynamic_cast<GlobalValue*>(val_ir)) {
return create_node(DAGNode::CONSTANT, val_ir, value_to_node, nodes_storage);
} else if (dynamic_cast<AllocaInst*>(val_ir)) {
return create_node(DAGNode::ALLOCA_ADDR, val_ir, value_to_node, nodes_storage);
}
return create_node(DAGNode::LOAD, val_ir, value_to_node, nodes_storage);
}
std::vector<std::unique_ptr<RISCv64ISel::DAGNode>> RISCv64ISel::build_dag(BasicBlock* bb) {
std::vector<std::unique_ptr<DAGNode>> nodes_storage;
std::map<Value*, DAGNode*> value_to_node;
for (const auto& inst_ptr : bb->getInstructions()) {
Instruction* inst = inst_ptr.get();
if (auto alloca = dynamic_cast<AllocaInst*>(inst)) {
create_node(DAGNode::ALLOCA_ADDR, alloca, value_to_node, nodes_storage);
} else if (auto store = dynamic_cast<StoreInst*>(inst)) {
auto store_node = create_node(DAGNode::STORE, store, value_to_node, nodes_storage);
store_node->operands.push_back(get_operand_node(store->getValue(), value_to_node, nodes_storage));
store_node->operands.push_back(get_operand_node(store->getPointer(), value_to_node, nodes_storage));
} else if (auto memset = dynamic_cast<MemsetInst*>(inst)) {
auto memset_node = create_node(DAGNode::MEMSET, memset, value_to_node, nodes_storage);
memset_node->operands.push_back(get_operand_node(memset->getPointer(), value_to_node, nodes_storage));
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));
} else if (auto bin = dynamic_cast<BinaryInst*>(inst)) {
if(value_to_node.count(bin)) continue;
if (bin->getKind() == BinaryInst::kSub) {
if (auto const_lhs = dynamic_cast<ConstantValue*>(bin->getLhs())) {
if (const_lhs->getInt() == 0) {
auto unary_node = create_node(DAGNode::UNARY, bin, value_to_node, nodes_storage);
unary_node->operands.push_back(get_operand_node(bin->getRhs(), value_to_node, nodes_storage));
continue;
}
}
}
auto bin_node = create_node(DAGNode::BINARY, bin, value_to_node, nodes_storage);
bin_node->operands.push_back(get_operand_node(bin->getLhs(), value_to_node, nodes_storage));
bin_node->operands.push_back(get_operand_node(bin->getRhs(), value_to_node, nodes_storage));
} else if (auto un = dynamic_cast<UnaryInst*>(inst)) {
if(value_to_node.count(un)) continue;
auto unary_node = create_node(DAGNode::UNARY, un, value_to_node, nodes_storage);
unary_node->operands.push_back(get_operand_node(un->getOperand(), value_to_node, nodes_storage));
} else if (auto call = dynamic_cast<CallInst*>(inst)) {
if(value_to_node.count(call)) continue;
auto call_node = create_node(DAGNode::CALL, call, value_to_node, nodes_storage);
for (auto arg : call->getArguments()) {
call_node->operands.push_back(get_operand_node(arg->getValue(), value_to_node, nodes_storage));
}
} else if (auto ret = dynamic_cast<ReturnInst*>(inst)) {
auto ret_node = create_node(DAGNode::RETURN, ret, value_to_node, nodes_storage);
if (ret->hasReturnValue()) {
ret_node->operands.push_back(get_operand_node(ret->getReturnValue(), value_to_node, nodes_storage));
}
} else if (auto cond_br = dynamic_cast<CondBrInst*>(inst)) {
auto br_node = create_node(DAGNode::BRANCH, cond_br, value_to_node, nodes_storage);
br_node->operands.push_back(get_operand_node(cond_br->getCondition(), value_to_node, nodes_storage));
} else if (auto uncond_br = dynamic_cast<UncondBrInst*>(inst)) {
create_node(DAGNode::BRANCH, uncond_br, value_to_node, nodes_storage);
}
}
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