989 lines
50 KiB
C++
989 lines
50 KiB
C++
#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
|