#include "RISCv64ISel.h" #include "IR.h" // For GlobalValue #include #include #include #include #include #include namespace sysy { // DAG节点定义 (内部实现) struct RISCv64ISel::DAGNode { enum NodeKind { ARGUMENT, CONSTANT, // 整数或地址常量 LOAD, STORE, BINARY, // 整数二元运算 CALL, RETURN, BRANCH, ALLOCA_ADDR, UNARY, // 整数一元运算 MEMSET, GET_ELEMENT_PTR, FP_CONSTANT, // 浮点常量 FBINARY, // 浮点二元运算 (如 FADD, FSUB, FCMP) FUNARY, // 浮点一元运算 (如 FCVT, FNEG) }; NodeKind kind; Value* value = nullptr; std::vector operands; std::vector 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 保留 } unsigned new_vreg = vreg_counter++; vreg_map[val] = new_vreg; vreg_to_value_map[new_vreg] = val; vreg_type_map[new_vreg] = val->getType(); } return vreg_map.at(val); } unsigned RISCv64ISel::getNewVReg(Type* type) { unsigned new_vreg = vreg_counter++; vreg_type_map[new_vreg] = type; // 记录这个新vreg的类型 return new_vreg; } // 主入口函数 std::unique_ptr RISCv64ISel::runOnFunction(Function* func) { F = func; if (!F) return nullptr; MFunc = std::make_unique(F, this); vreg_map.clear(); bb_map.clear(); vreg_counter = 0; local_label_counter = 0; select(); return std::move(MFunc); } // 指令选择主流程 void RISCv64ISel::select() { // 遍历基本块,为它们创建对应的MachineBasicBlock bool is_first_block = true; for (const auto& bb_ptr : F->getBasicBlocks()) { std::string mbb_name; if (is_first_block) { // 对于函数的第一个基本块,其标签必须与函数名完全相同 mbb_name = F->getName(); is_first_block = false; } else { // 对于后续的基本块,继续使用它们在IR中的原始名称 mbb_name = bb_ptr->getName(); } auto mbb = std::make_unique(mbb_name, MFunc.get()); bb_map[bb_ptr.get()] = mbb.get(); MFunc->addBlock(std::move(mbb)); } // 遍历Argument对象,为它们分配虚拟寄存器。 if (F) { for (Argument* arg : F->getArguments()) { // getVReg会为每个代表参数的Argument对象在vreg_map中创建一个条目。 // 这样,当后续的store指令使用这个参数时,就能找到对应的vreg。 getVReg(arg); } } // 遍历基本块,进行指令选择 for (const auto& bb_ptr : F->getBasicBlocks()) { selectBasicBlock(bb_ptr.get()); } // 链接MachineBasicBlock的前驱和后继 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_to_node; for(const auto& node : dag) { if (node->value) { value_to_node[node->value] = node.get(); } } std::set selected_nodes; std::function 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; auto it = value_to_node.find(inst_ptr.get()); if (it != value_to_node.end()) { node_to_select = it->second; } 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) { // “延迟物化”(Late Materialization)思想。 // 这三种节点仅作为标记,不直接生成指令。它们的目的是在DAG中保留类型信息。 // 加载其值的责任,被转移给了使用它们的父节点(如STORE, BINARY等)。 case DAGNode::ARGUMENT: case DAGNode::CONSTANT: case DAGNode::ALLOCA_ADDR: { if (node->value) { // GlobalValue objects (global variables) should not get virtual registers // since they represent memory addresses, not register-allocated values if (dynamic_cast(node->value) == nullptr) { // 确保它有一个关联的虚拟寄存器即可,不生成代码。 getVReg(node->value); } } if (auto const_val1 = dynamic_cast(node->value)) { if (const_val1->getInt() == 128875) { foo3 = 1; std::cerr << "Found constant 128875 in selectNode!" << std::endl; } } break; } case DAGNode::FP_CONSTANT: { // RISC-V没有直接加载浮点立即数的指令 // 标准做法是:1. 将浮点数的32位二进制表示加载到一个整数寄存器 // 2. 使用 fmv.w.x 指令将位模式从整数寄存器移动到浮点寄存器 auto const_val = dynamic_cast(node->value); auto float_vreg = getVReg(const_val); auto temp_int_vreg = getNewVReg(Type::getIntType()); // 临时整数虚拟寄存器 float f_val = const_val->getFloat(); // 使用 reinterpret_cast 获取浮点数的32位二进制表示 uint32_t float_bits = *reinterpret_cast(&f_val); // 1. li temp_int_vreg, float_bits auto li = std::make_unique(RVOpcodes::LI); li->addOperand(std::make_unique(temp_int_vreg)); li->addOperand(std::make_unique(float_bits)); CurMBB->addInstruction(std::move(li)); // 2. fmv.w.x float_vreg, temp_int_vreg auto fmv = std::make_unique(RVOpcodes::FMV_W_X); fmv->addOperand(std::make_unique(float_vreg)); fmv->addOperand(std::make_unique(temp_int_vreg)); CurMBB->addInstruction(std::move(fmv)); break; } case DAGNode::LOAD: { auto dest_vreg = getVReg(node->value); Value* ptr_val = node->operands[0]->value; // 1. 获取加载结果的类型 (即这个LOAD指令自身的类型) Type* loaded_type = node->value->getType(); // 2. 根据类型选择正确的伪指令或真实指令操作码 RVOpcodes frame_opcode; RVOpcodes real_opcode; if (loaded_type->isPointer()) { frame_opcode = RVOpcodes::FRAME_LOAD_D; real_opcode = RVOpcodes::LD; } else if (loaded_type->isFloat()) { frame_opcode = RVOpcodes::FRAME_LOAD_F; real_opcode = RVOpcodes::FLW; } else { // 默认为整数 frame_opcode = RVOpcodes::FRAME_LOAD_W; real_opcode = RVOpcodes::LW; } if (auto alloca = dynamic_cast(ptr_val)) { // 3. 创建使用新的、区分宽度的伪指令 auto instr = std::make_unique(frame_opcode); instr->addOperand(std::make_unique(dest_vreg)); instr->addOperand(std::make_unique(getVReg(alloca))); CurMBB->addInstruction(std::move(instr)); } else if (auto global = dynamic_cast(ptr_val)) { // 对于全局变量,先用 la 加载其地址 auto addr_vreg = getNewVReg(Type::getPointerType(global->getType())); auto la = std::make_unique(RVOpcodes::LA); la->addOperand(std::make_unique(addr_vreg)); la->addOperand(std::make_unique(global->getName())); CurMBB->addInstruction(std::move(la)); // 然后根据类型使用 ld 或 lw 加载其值 auto load_instr = std::make_unique(real_opcode); load_instr->addOperand(std::make_unique(dest_vreg)); load_instr->addOperand(std::make_unique( std::make_unique(addr_vreg), std::make_unique(0) )); CurMBB->addInstruction(std::move(load_instr)); } else { // 对于已经在虚拟寄存器中的指针地址,直接通过该地址加载 auto ptr_vreg = getVReg(ptr_val); // 根据类型使用 ld 或 lw auto load_instr = std::make_unique(real_opcode); load_instr->addOperand(std::make_unique(dest_vreg)); load_instr->addOperand(std::make_unique( std::make_unique(ptr_vreg), std::make_unique(0) )); CurMBB->addInstruction(std::move(load_instr)); } break; } case DAGNode::STORE: { Value* val_to_store = node->operands[0]->value; Value* ptr_val = node->operands[1]->value; // 如果要存储的值是一个常量,就在这里生成 `li` 指令加载它 if (auto val_const = dynamic_cast(val_to_store)) { // 区分整数常量和浮点常量 if (val_const->isInt()) { auto li = std::make_unique(RVOpcodes::LI); li->addOperand(std::make_unique(getVReg(val_const))); li->addOperand(std::make_unique(val_const->getInt())); CurMBB->addInstruction(std::move(li)); } else if (val_const->isFloat()) { // 先将浮点数的位模式加载到整数vreg,再用fmv.w.x移到浮点vreg auto temp_int_vreg = getNewVReg(Type::getIntType()); auto float_vreg = getVReg(val_const); float f_val = val_const->getFloat(); uint32_t float_bits = *reinterpret_cast(&f_val); // 1. li temp_int_vreg, float_bits auto li = std::make_unique(RVOpcodes::LI); li->addOperand(std::make_unique(temp_int_vreg)); li->addOperand(std::make_unique(float_bits)); CurMBB->addInstruction(std::move(li)); // 2. fmv.w.x float_vreg, temp_int_vreg auto fmv = std::make_unique(RVOpcodes::FMV_W_X); fmv->addOperand(std::make_unique(float_vreg)); fmv->addOperand(std::make_unique(temp_int_vreg)); CurMBB->addInstruction(std::move(fmv)); } } auto val_vreg = getVReg(val_to_store); // 1. 获取被存储的值的类型 Type* stored_type = val_to_store->getType(); // 2. 根据类型选择正确的伪指令或真实指令操作码 RVOpcodes frame_opcode; RVOpcodes real_opcode; if (stored_type->isPointer()) { frame_opcode = RVOpcodes::FRAME_STORE_D; real_opcode = RVOpcodes::SD; } else if (stored_type->isFloat()) { frame_opcode = RVOpcodes::FRAME_STORE_F; real_opcode = RVOpcodes::FSW; } else { // 默认为整数 frame_opcode = RVOpcodes::FRAME_STORE_W; real_opcode = RVOpcodes::SW; } if (auto alloca = dynamic_cast(ptr_val)) { // 3. 创建使用新的、区分宽度的伪指令 auto instr = std::make_unique(frame_opcode); instr->addOperand(std::make_unique(val_vreg)); instr->addOperand(std::make_unique(getVReg(alloca))); CurMBB->addInstruction(std::move(instr)); } else if (auto global = dynamic_cast(ptr_val)) { // 向全局变量存储 auto addr_vreg = getNewVReg(Type::getIntType()); auto la = std::make_unique(RVOpcodes::LA); la->addOperand(std::make_unique(addr_vreg)); la->addOperand(std::make_unique(global->getName())); CurMBB->addInstruction(std::move(la)); // 根据类型使用 sd 或 sw auto store_instr = std::make_unique(real_opcode); store_instr->addOperand(std::make_unique(val_vreg)); store_instr->addOperand(std::make_unique( std::make_unique(addr_vreg), std::make_unique(0) )); CurMBB->addInstruction(std::move(store_instr)); } else { // 向一个指针(存储在虚拟寄存器中)指向的地址存储 auto ptr_vreg = getVReg(ptr_val); // 根据类型使用 sd 或 sw auto store_instr = std::make_unique(real_opcode); store_instr->addOperand(std::make_unique(val_vreg)); store_instr->addOperand(std::make_unique( std::make_unique(ptr_vreg), std::make_unique(0) )); CurMBB->addInstruction(std::move(store_instr)); } break; } case DAGNode::BINARY: { auto bin = dynamic_cast(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(lhs) || dynamic_cast(lhs)) { base = lhs; offset = rhs; } else if (dynamic_cast(rhs) || dynamic_cast(rhs)) { base = rhs; offset = lhs; } // 如果成功匹配到地址计算模式 if (base) { // 1. 先为偏移量加载常量(如果它是常量的话) if (auto const_offset = dynamic_cast(offset)) { auto li = std::make_unique(RVOpcodes::LI); li->addOperand(std::make_unique(getVReg(const_offset))); li->addOperand(std::make_unique(const_offset->getInt())); CurMBB->addInstruction(std::move(li)); } // 2. 根据基地址的类型,生成不同的指令来获取基地址 auto base_addr_vreg = getNewVReg(Type::getIntType()); // 创建一个新的临时vreg来存放基地址 // 情况一:基地址是局部栈变量 if (auto alloca_base = dynamic_cast(base)) { auto frame_addr_instr = std::make_unique(RVOpcodes::FRAME_ADDR); frame_addr_instr->addOperand(std::make_unique(base_addr_vreg)); frame_addr_instr->addOperand(std::make_unique(getVReg(alloca_base))); CurMBB->addInstruction(std::move(frame_addr_instr)); } // 情况二:基地址是全局变量 else if (auto global_base = dynamic_cast(base)) { auto la_instr = std::make_unique(RVOpcodes::LA); la_instr->addOperand(std::make_unique(base_addr_vreg)); la_instr->addOperand(std::make_unique(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(RVOpcodes::ADD); // 指针运算是64位 add_instr->addOperand(std::make_unique(final_addr_vreg)); add_instr->addOperand(std::make_unique(base_addr_vreg)); add_instr->addOperand(std::make_unique(offset_vreg)); CurMBB->addInstruction(std::move(add_instr)); return; // 地址计算处理完毕,直接返回 } } // 在BINARY节点内部按需加载常量操作数。 auto load_val_if_const = [&](Value* val) { if (auto c = dynamic_cast(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(RVOpcodes::LI); li->addOperand(std::make_unique(getVReg(c))); li->addOperand(std::make_unique(c->getInt())); CurMBB->addInstruction(std::move(li)); } }; // 检查是否能应用立即数优化。 bool rhs_is_imm_opt = false; if (auto rhs_const = dynamic_cast(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); // 融合 ADDIW 优化。 if (rhs_is_imm_opt) { auto rhs_const = dynamic_cast(rhs); auto instr = std::make_unique(RVOpcodes::ADDIW); instr->addOperand(std::make_unique(dest_vreg)); instr->addOperand(std::make_unique(lhs_vreg)); instr->addOperand(std::make_unique(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(opcode); instr->addOperand(std::make_unique(dest_vreg)); instr->addOperand(std::make_unique(lhs_vreg)); instr->addOperand(std::make_unique(rhs_vreg)); CurMBB->addInstruction(std::move(instr)); break; } case BinaryInst::kSub: { auto instr = std::make_unique(RVOpcodes::SUBW); instr->addOperand(std::make_unique(dest_vreg)); instr->addOperand(std::make_unique(lhs_vreg)); instr->addOperand(std::make_unique(rhs_vreg)); CurMBB->addInstruction(std::move(instr)); break; } case BinaryInst::kMul: { auto instr = std::make_unique(RVOpcodes::MULW); instr->addOperand(std::make_unique(dest_vreg)); instr->addOperand(std::make_unique(lhs_vreg)); instr->addOperand(std::make_unique(rhs_vreg)); CurMBB->addInstruction(std::move(instr)); break; } case Instruction::kDiv: { auto instr = std::make_unique(RVOpcodes::DIVW); instr->addOperand(std::make_unique(dest_vreg)); instr->addOperand(std::make_unique(lhs_vreg)); instr->addOperand(std::make_unique(rhs_vreg)); CurMBB->addInstruction(std::move(instr)); break; } case Instruction::kRem: { auto instr = std::make_unique(RVOpcodes::REMW); instr->addOperand(std::make_unique(dest_vreg)); instr->addOperand(std::make_unique(lhs_vreg)); instr->addOperand(std::make_unique(rhs_vreg)); CurMBB->addInstruction(std::move(instr)); break; } case Instruction::kSRA: { auto rhs_const = dynamic_cast(rhs); auto instr = std::make_unique(RVOpcodes::SRAIW); instr->addOperand(std::make_unique(dest_vreg)); instr->addOperand(std::make_unique(lhs_vreg)); instr->addOperand(std::make_unique(rhs_const->getInt())); CurMBB->addInstruction(std::move(instr)); break; } case BinaryInst::kICmpEQ: { // 等于 (a == b) -> (subw; seqz) auto sub = std::make_unique(RVOpcodes::SUBW); sub->addOperand(std::make_unique(dest_vreg)); sub->addOperand(std::make_unique(lhs_vreg)); sub->addOperand(std::make_unique(rhs_vreg)); CurMBB->addInstruction(std::move(sub)); auto seqz = std::make_unique(RVOpcodes::SEQZ); seqz->addOperand(std::make_unique(dest_vreg)); seqz->addOperand(std::make_unique(dest_vreg)); CurMBB->addInstruction(std::move(seqz)); break; } case BinaryInst::kICmpNE: { // 不等于 (a != b) -> (subw; snez) auto sub = std::make_unique(RVOpcodes::SUBW); sub->addOperand(std::make_unique(dest_vreg)); sub->addOperand(std::make_unique(lhs_vreg)); sub->addOperand(std::make_unique(rhs_vreg)); CurMBB->addInstruction(std::move(sub)); auto snez = std::make_unique(RVOpcodes::SNEZ); snez->addOperand(std::make_unique(dest_vreg)); snez->addOperand(std::make_unique(dest_vreg)); CurMBB->addInstruction(std::move(snez)); break; } case BinaryInst::kICmpLT: { // 小于 (a < b) -> slt auto instr = std::make_unique(RVOpcodes::SLT); instr->addOperand(std::make_unique(dest_vreg)); instr->addOperand(std::make_unique(lhs_vreg)); instr->addOperand(std::make_unique(rhs_vreg)); CurMBB->addInstruction(std::move(instr)); break; } case BinaryInst::kICmpGT: { // 大于 (a > b) -> (b < a) -> slt auto instr = std::make_unique(RVOpcodes::SLT); instr->addOperand(std::make_unique(dest_vreg)); instr->addOperand(std::make_unique(rhs_vreg)); instr->addOperand(std::make_unique(lhs_vreg)); CurMBB->addInstruction(std::move(instr)); break; } case BinaryInst::kICmpLE: { // 小于等于 (a <= b) -> !(b < a) -> (slt; xori) auto slt = std::make_unique(RVOpcodes::SLT); slt->addOperand(std::make_unique(dest_vreg)); slt->addOperand(std::make_unique(rhs_vreg)); slt->addOperand(std::make_unique(lhs_vreg)); CurMBB->addInstruction(std::move(slt)); auto xori = std::make_unique(RVOpcodes::XORI); xori->addOperand(std::make_unique(dest_vreg)); xori->addOperand(std::make_unique(dest_vreg)); xori->addOperand(std::make_unique(1)); CurMBB->addInstruction(std::move(xori)); break; } case BinaryInst::kICmpGE: { // 大于等于 (a >= b) -> !(a < b) -> (slt; xori) auto slt = std::make_unique(RVOpcodes::SLT); slt->addOperand(std::make_unique(dest_vreg)); slt->addOperand(std::make_unique(lhs_vreg)); slt->addOperand(std::make_unique(rhs_vreg)); CurMBB->addInstruction(std::move(slt)); auto xori = std::make_unique(RVOpcodes::XORI); xori->addOperand(std::make_unique(dest_vreg)); xori->addOperand(std::make_unique(dest_vreg)); xori->addOperand(std::make_unique(1)); CurMBB->addInstruction(std::move(xori)); break; } default: throw std::runtime_error("Unsupported binary instruction in ISel"); } break; } case DAGNode::FBINARY: { auto bin = dynamic_cast(node->value); auto dest_vreg = getVReg(bin); auto lhs_vreg = getVReg(bin->getLhs()); auto rhs_vreg = getVReg(bin->getRhs()); switch (bin->getKind()) { case Instruction::kFAdd: { auto instr = std::make_unique(RVOpcodes::FADD_S); instr->addOperand(std::make_unique(dest_vreg)); instr->addOperand(std::make_unique(lhs_vreg)); instr->addOperand(std::make_unique(rhs_vreg)); CurMBB->addInstruction(std::move(instr)); break; } case Instruction::kFSub: { auto instr = std::make_unique(RVOpcodes::FSUB_S); instr->addOperand(std::make_unique(dest_vreg)); instr->addOperand(std::make_unique(lhs_vreg)); instr->addOperand(std::make_unique(rhs_vreg)); CurMBB->addInstruction(std::move(instr)); break; } case Instruction::kFMul: { auto instr = std::make_unique(RVOpcodes::FMUL_S); instr->addOperand(std::make_unique(dest_vreg)); instr->addOperand(std::make_unique(lhs_vreg)); instr->addOperand(std::make_unique(rhs_vreg)); CurMBB->addInstruction(std::move(instr)); break; } case Instruction::kFDiv: { auto instr = std::make_unique(RVOpcodes::FDIV_S); instr->addOperand(std::make_unique(dest_vreg)); instr->addOperand(std::make_unique(lhs_vreg)); instr->addOperand(std::make_unique(rhs_vreg)); CurMBB->addInstruction(std::move(instr)); break; } // --- 浮点比较指令 --- // 注意:比较结果(0或1)写入的是一个通用整数寄存器(dest_vreg) case Instruction::kFCmpEQ: { auto instr = std::make_unique(RVOpcodes::FEQ_S); instr->addOperand(std::make_unique(dest_vreg)); instr->addOperand(std::make_unique(lhs_vreg)); instr->addOperand(std::make_unique(rhs_vreg)); CurMBB->addInstruction(std::move(instr)); break; } case Instruction::kFCmpLT: { auto instr = std::make_unique(RVOpcodes::FLT_S); instr->addOperand(std::make_unique(dest_vreg)); instr->addOperand(std::make_unique(lhs_vreg)); instr->addOperand(std::make_unique(rhs_vreg)); CurMBB->addInstruction(std::move(instr)); break; } case Instruction::kFCmpLE: { auto instr = std::make_unique(RVOpcodes::FLE_S); instr->addOperand(std::make_unique(dest_vreg)); instr->addOperand(std::make_unique(lhs_vreg)); instr->addOperand(std::make_unique(rhs_vreg)); CurMBB->addInstruction(std::move(instr)); break; } // --- 通过交换操作数或组合指令实现其余比较 --- case Instruction::kFCmpGT: { // a > b 等价于 b < a auto instr = std::make_unique(RVOpcodes::FLT_S); instr->addOperand(std::make_unique(dest_vreg)); instr->addOperand(std::make_unique(rhs_vreg)); // 操作数交换 instr->addOperand(std::make_unique(lhs_vreg)); CurMBB->addInstruction(std::move(instr)); break; } case Instruction::kFCmpGE: { // a >= b 等价于 b <= a auto instr = std::make_unique(RVOpcodes::FLE_S); instr->addOperand(std::make_unique(dest_vreg)); instr->addOperand(std::make_unique(rhs_vreg)); // 操作数交换 instr->addOperand(std::make_unique(lhs_vreg)); CurMBB->addInstruction(std::move(instr)); break; } case Instruction::kFCmpNE: { // a != b 等价于 !(a == b) // 1. 先用 feq.s 比较,结果存入 dest_vreg auto feq = std::make_unique(RVOpcodes::FEQ_S); feq->addOperand(std::make_unique(dest_vreg)); feq->addOperand(std::make_unique(lhs_vreg)); feq->addOperand(std::make_unique(rhs_vreg)); CurMBB->addInstruction(std::move(feq)); // 2. 再用 seqz 对结果取反 (如果相等(1),则变0;如果不等(0),则变1) auto seqz = std::make_unique(RVOpcodes::SEQZ); seqz->addOperand(std::make_unique(dest_vreg)); seqz->addOperand(std::make_unique(dest_vreg)); CurMBB->addInstruction(std::move(seqz)); break; } default: throw std::runtime_error("Unsupported float binary instruction in ISel"); } break; } case DAGNode::UNARY: { auto unary = dynamic_cast(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(RVOpcodes::SUBW); instr->addOperand(std::make_unique(dest_vreg)); instr->addOperand(std::make_unique(PhysicalReg::ZERO)); instr->addOperand(std::make_unique(src_vreg)); CurMBB->addInstruction(std::move(instr)); break; } case UnaryInst::kNot: { // 逻辑非: src == 0 ? 1 : 0 auto instr = std::make_unique(RVOpcodes::SEQZ); instr->addOperand(std::make_unique(dest_vreg)); instr->addOperand(std::make_unique(src_vreg)); CurMBB->addInstruction(std::move(instr)); break; } default: throw std::runtime_error("Unsupported unary instruction in ISel"); } break; } case DAGNode::FUNARY: { auto unary = dynamic_cast(node->value); auto dest_vreg = getVReg(unary); auto src_vreg = getVReg(unary->getOperand()); switch (unary->getKind()) { case Instruction::kItoF: { // 整数 to 浮点 auto instr = std::make_unique(RVOpcodes::FCVT_S_W); instr->addOperand(std::make_unique(dest_vreg)); // 目标是浮点vreg instr->addOperand(std::make_unique(src_vreg)); // 源是整数vreg CurMBB->addInstruction(std::move(instr)); break; } case Instruction::kFtoI: { // 浮点 to 整数 (C/C++: 截断) // C/C++ 标准要求向零截断 (truncate), 对应的RISC-V舍入模式是 RTZ (Round Towards Zero). // fcvt.w.s 指令使用 fcsr 中的 frm 字段来决定舍入模式。 // 我们需要手动设置 frm=1 (RTZ), 执行转换, 然后恢复 frm=0 (RNE, 默认). // 1. fsrmi x0, 1 (set rounding mode to RTZ) auto fsrmi1 = std::make_unique(RVOpcodes::FSRMI); fsrmi1->addOperand(std::make_unique(PhysicalReg::ZERO)); fsrmi1->addOperand(std::make_unique(1)); CurMBB->addInstruction(std::move(fsrmi1)); // 2. fcvt.w.s dest_vreg, src_vreg auto fcvt = std::make_unique(RVOpcodes::FCVT_W_S); fcvt->addOperand(std::make_unique(dest_vreg)); fcvt->addOperand(std::make_unique(src_vreg)); CurMBB->addInstruction(std::move(fcvt)); // 3. fsrmi x0, 0 (restore rounding mode to RNE) auto fsrmi0 = std::make_unique(RVOpcodes::FSRMI); fsrmi0->addOperand(std::make_unique(PhysicalReg::ZERO)); fsrmi0->addOperand(std::make_unique(0)); CurMBB->addInstruction(std::move(fsrmi0)); break; } case Instruction::kFNeg: { // 浮点取负 auto instr = std::make_unique(RVOpcodes::FNEG_S); instr->addOperand(std::make_unique(dest_vreg)); instr->addOperand(std::make_unique(src_vreg)); CurMBB->addInstruction(std::move(instr)); break; } // --- 处理位传送指令 --- case Instruction::kBitItoF: { // 整数位模式 -> 浮点寄存器 auto instr = std::make_unique(RVOpcodes::FMV_W_X); instr->addOperand(std::make_unique(dest_vreg)); // 目标是浮点vreg instr->addOperand(std::make_unique(src_vreg)); // 源是整数vreg CurMBB->addInstruction(std::move(instr)); break; } case Instruction::kBitFtoI: { // 浮点位模式 -> 整数寄存器 auto instr = std::make_unique(RVOpcodes::FMV_X_W); instr->addOperand(std::make_unique(dest_vreg)); // 目标是整数vreg instr->addOperand(std::make_unique(src_vreg)); // 源是浮点vreg CurMBB->addInstruction(std::move(instr)); break; } default: throw std::runtime_error("Unsupported float unary instruction in ISel"); } break; } case DAGNode::CALL: { auto call = dynamic_cast(node->value); size_t num_operands = node->operands.size(); // --- 步骤 1: 分配寄存器参数和栈参数 --- // 根据RISC-V调用约定,前8个整数/指针参数通过a0-a7传递, // 前8个浮点参数通过fa0-fa7传递 (物理寄存器 f10-f17)。其余参数通过栈传递。 int int_reg_idx = 0; // a0-a7 的索引 int fp_reg_idx = 0; // fa0-fa7 的索引 // 用于存储需要通过栈传递的参数 std::vector stack_args; for (size_t i = 0; i < num_operands; ++i) { DAGNode* arg_node = node->operands[i]; Value* arg_val = arg_node->value; Type* arg_type = arg_val->getType(); // 判断参数是浮点类型还是整型/指针类型 if (arg_type->isFloat()) { if (fp_reg_idx < 8) { // --- 处理浮点寄存器参数 (fa0-fa7, 对应物理寄存器 F10-F17) --- auto arg_preg = static_cast(static_cast(PhysicalReg::F10) + fp_reg_idx); fp_reg_idx++; if (auto const_val = dynamic_cast(arg_val)) { // 如果是浮点常量,需要先物化 // 1. 获取其32位二进制表示 float f_val = const_val->getFloat(); uint32_t float_bits = *reinterpret_cast(&f_val); // 2. 将位模式加载到一个临时整数寄存器 (使用t0) auto li = std::make_unique(RVOpcodes::LI); li->addOperand(std::make_unique(PhysicalReg::T0)); li->addOperand(std::make_unique(float_bits)); CurMBB->addInstruction(std::move(li)); // 3. 使用fmv.w.x将位模式从整数寄存器移动到目标浮点参数寄存器 auto fmv_wx = std::make_unique(RVOpcodes::FMV_W_X); fmv_wx->addOperand(std::make_unique(arg_preg)); fmv_wx->addOperand(std::make_unique(PhysicalReg::T0)); CurMBB->addInstruction(std::move(fmv_wx)); } else { // 如果已经是虚拟寄存器,直接用 fmv.s 移动 auto src_vreg = getVReg(arg_val); auto fmv_s = std::make_unique(RVOpcodes::FMV_S); fmv_s->addOperand(std::make_unique(arg_preg)); fmv_s->addOperand(std::make_unique(src_vreg)); CurMBB->addInstruction(std::move(fmv_s)); } } else { // 浮点寄存器已用完,放到栈上传递 stack_args.push_back(arg_node); } } else { // 整数或指针参数 if (int_reg_idx < 8) { // --- 处理整数/指针寄存器参数 (a0-a7) --- auto arg_preg = static_cast(static_cast(PhysicalReg::A0) + int_reg_idx); int_reg_idx++; if (arg_node->kind == DAGNode::CONSTANT) { if (auto const_val = dynamic_cast(arg_val)) { auto li = std::make_unique(RVOpcodes::LI); li->addOperand(std::make_unique(arg_preg)); li->addOperand(std::make_unique(const_val->getInt())); CurMBB->addInstruction(std::move(li)); } } else { auto src_vreg = getVReg(arg_val); auto mv = std::make_unique(RVOpcodes::MV); mv->addOperand(std::make_unique(arg_preg)); mv->addOperand(std::make_unique(src_vreg)); CurMBB->addInstruction(std::move(mv)); } } else { // 整数寄存器已用完,放到栈上传递 stack_args.push_back(arg_node); } } } // --- 步骤 2: 处理所有栈参数 --- int stack_space = 0; if (!stack_args.empty()) { // 计算栈参数所需的总空间,RV64中每个槽位为8字节 stack_space = stack_args.size() * 8; // 根据ABI,为call分配的栈空间需要16字节对齐 if (stack_space % 16 != 0) { stack_space += 16 - (stack_space % 16); } // 在栈上分配空间 if (stack_space > 0) { auto alloc_instr = std::make_unique(RVOpcodes::ADDI); alloc_instr->addOperand(std::make_unique(PhysicalReg::SP)); alloc_instr->addOperand(std::make_unique(PhysicalReg::SP)); alloc_instr->addOperand(std::make_unique(-stack_space)); CurMBB->addInstruction(std::move(alloc_instr)); } // 将每个参数存储到栈上对应的位置 for (size_t i = 0; i < stack_args.size(); ++i) { DAGNode* arg_node = stack_args[i]; Value* arg_val = arg_node->value; Type* arg_type = arg_val->getType(); int offset = i * 8; unsigned src_vreg; // 如果是常量,先加载到临时vreg if (auto const_val = dynamic_cast(arg_val)) { src_vreg = getNewVReg(arg_type); if(arg_type->isFloat()) { auto temp_int_vreg = getNewVReg(Type::getIntType()); float f_val = const_val->getFloat(); uint32_t float_bits = *reinterpret_cast(&f_val); auto li = std::make_unique(RVOpcodes::LI); li->addOperand(std::make_unique(temp_int_vreg)); li->addOperand(std::make_unique(float_bits)); CurMBB->addInstruction(std::move(li)); auto fmv_wx = std::make_unique(RVOpcodes::FMV_W_X); fmv_wx->addOperand(std::make_unique(src_vreg)); fmv_wx->addOperand(std::make_unique(temp_int_vreg)); CurMBB->addInstruction(std::move(fmv_wx)); } else { auto li = std::make_unique(RVOpcodes::LI); li->addOperand(std::make_unique(src_vreg)); li->addOperand(std::make_unique(const_val->getInt())); CurMBB->addInstruction(std::move(li)); } } else { src_vreg = getVReg(arg_val); } // 根据类型选择 fsw (浮点) 或 sd (整型/指针) 存储指令 std::unique_ptr store_instr; if (arg_type->isFloat()) { store_instr = std::make_unique(RVOpcodes::FSW); } else { store_instr = std::make_unique(RVOpcodes::SD); } store_instr->addOperand(std::make_unique(src_vreg)); store_instr->addOperand(std::make_unique( std::make_unique(PhysicalReg::SP), std::make_unique(offset) )); CurMBB->addInstruction(std::move(store_instr)); } } // --- 步骤 3: 生成CALL指令 --- auto call_instr = std::make_unique(RVOpcodes::CALL); // 如果函数有返回值,将它的目标虚拟寄存器作为第一个操作数 if (!call->getType()->isVoid()) { unsigned dest_vreg = getVReg(call); call_instr->addOperand(std::make_unique(dest_vreg)); } // 将函数名标签作为后续操作数 call_instr->addOperand(std::make_unique(call->getCallee()->getName())); // 将所有参数的虚拟寄存器也作为后续操作数,供getInstrUseDef分析 for (size_t i = 0; i < num_operands; ++i) { if (node->operands[i]->kind != DAGNode::CONSTANT && node->operands[i]->kind != DAGNode::FP_CONSTANT) { call_instr->addOperand(std::make_unique(getVReg(node->operands[i]->value))); } } CurMBB->addInstruction(std::move(call_instr)); // --- 步骤 4: 处理返回值 --- if (!call->getType()->isVoid()) { unsigned dest_vreg = getVReg(call); if (call->getType()->isFloat()) { // 浮点返回值在 fa0 (物理寄存器 F10) auto fmv_s = std::make_unique(RVOpcodes::FMV_S); fmv_s->addOperand(std::make_unique(dest_vreg)); fmv_s->addOperand(std::make_unique(PhysicalReg::F10)); // fa0 CurMBB->addInstruction(std::move(fmv_s)); } else { // 整数/指针返回值在 a0 auto mv = std::make_unique(RVOpcodes::MV); mv->addOperand(std::make_unique(dest_vreg)); mv->addOperand(std::make_unique(PhysicalReg::A0)); CurMBB->addInstruction(std::move(mv)); } } // --- 步骤 5: 回收为栈参数分配的空间 --- if (stack_space > 0) { auto dealloc_instr = std::make_unique(RVOpcodes::ADDI); dealloc_instr->addOperand(std::make_unique(PhysicalReg::SP)); dealloc_instr->addOperand(std::make_unique(PhysicalReg::SP)); dealloc_instr->addOperand(std::make_unique(stack_space)); CurMBB->addInstruction(std::move(dealloc_instr)); } break; } case DAGNode::RETURN: { auto ret_inst_ir = dynamic_cast(node->value); if (ret_inst_ir && ret_inst_ir->hasReturnValue()) { Value* ret_val = ret_inst_ir->getReturnValue(); Type* ret_type = ret_val->getType(); if (ret_type->isFloat()) { // --- 处理浮点返回值 --- // 返回值需要被放入 fa0 (物理寄存器 F10) if (auto const_val = dynamic_cast(ret_val)) { // 如果是浮点常量,需要先物化到fa0 float f_val = const_val->getFloat(); uint32_t float_bits = *reinterpret_cast(&f_val); // 1. 加载位模式到临时整数寄存器 (t0) auto li = std::make_unique(RVOpcodes::LI); li->addOperand(std::make_unique(PhysicalReg::T0)); li->addOperand(std::make_unique(float_bits)); CurMBB->addInstruction(std::move(li)); // 2. 将位模式从 t0 移动到 fa0 auto fmv_wx = std::make_unique(RVOpcodes::FMV_W_X); fmv_wx->addOperand(std::make_unique(PhysicalReg::F10)); // fa0 fmv_wx->addOperand(std::make_unique(PhysicalReg::T0)); CurMBB->addInstruction(std::move(fmv_wx)); } else { // 如果是vreg,直接用 fmv.s 移动到 fa0 auto fmv_s = std::make_unique(RVOpcodes::FMV_S); fmv_s->addOperand(std::make_unique(PhysicalReg::F10)); // fa0 fmv_s->addOperand(std::make_unique(getVReg(ret_val))); CurMBB->addInstruction(std::move(fmv_s)); } } else { // --- 处理整数/指针返回值 --- // 返回值需要被放入 a0 // 在RETURN节点内加载常量返回值 if (auto const_val = dynamic_cast(ret_val)) { auto li_instr = std::make_unique(RVOpcodes::LI); li_instr->addOperand(std::make_unique(PhysicalReg::A0)); li_instr->addOperand(std::make_unique(const_val->getInt())); CurMBB->addInstruction(std::move(li_instr)); } else { auto mv_instr = std::make_unique(RVOpcodes::MV); mv_instr->addOperand(std::make_unique(PhysicalReg::A0)); mv_instr->addOperand(std::make_unique(getVReg(ret_val))); CurMBB->addInstruction(std::move(mv_instr)); } } } // 函数尾声(epilogue)不由RETURN节点生成, // 而是由后续的AsmPrinter或其它Pass统一处理,这是一种常见且有效的模块化设计。 auto ret_mi = std::make_unique(RVOpcodes::RET); CurMBB->addInstruction(std::move(ret_mi)); break; } case DAGNode::BRANCH: { // 处理条件分支 if (auto cond_br = dynamic_cast(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(condition)) { // 如果条件是常量,直接生成一个无条件跳转J,而不是BNE if (const_cond->getInt() != 0) { // 条件为 true auto j_instr = std::make_unique(RVOpcodes::J); j_instr->addOperand(std::make_unique(then_bb_name)); CurMBB->addInstruction(std::move(j_instr)); } else { // 条件为 false auto j_instr = std::make_unique(RVOpcodes::J); j_instr->addOperand(std::make_unique(else_bb_name)); CurMBB->addInstruction(std::move(j_instr)); } } // 如果条件不是常量,则执行标准流程 else { // 为条件变量生成加载指令(如果它是常量的话,尽管上面已经处理了) // 这一步是为了逻辑完整,以防有其他类型的常量没有被捕获 if (auto const_val = dynamic_cast(condition)) { auto li = std::make_unique(RVOpcodes::LI); li->addOperand(std::make_unique(getVReg(const_val))); li->addOperand(std::make_unique(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(RVOpcodes::BNE); br_instr->addOperand(std::make_unique(cond_vreg)); br_instr->addOperand(std::make_unique(PhysicalReg::ZERO)); br_instr->addOperand(std::make_unique(then_bb_name)); CurMBB->addInstruction(std::move(br_instr)); // 为else分支生成无条件跳转 (后续Pass可以优化掉不必要的跳转) auto j_instr = std::make_unique(RVOpcodes::J); j_instr->addOperand(std::make_unique(else_bb_name)); CurMBB->addInstruction(std::move(j_instr)); } } // 处理无条件分支 else if (auto uncond_br = dynamic_cast(node->value)) { auto j_instr = std::make_unique(RVOpcodes::J); j_instr->addOperand(std::make_unique(uncond_br->getBlock()->getName())); CurMBB->addInstruction(std::move(j_instr)); } break; } case DAGNode::MEMSET: { // Memset的核心展开逻辑在虚拟寄存器层面是正确的,无需修改。 // 之前的bug是由于其输入(地址、值、大小)的虚拟寄存器未被正确初始化。 // 在修复了CONSTANT/ALLOCA_ADDR的加载问题后,此处的逻辑现在可以正常工作。 if (DEBUG) { std::cout << "[DEBUG] selectNode-MEMSET: Processing MEMSET node." << std::endl; } auto memset = dynamic_cast(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(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(RVOpcodes::LI); li->addOperand(std::make_unique(getVReg(const_val))); li->addOperand(std::make_unique(const_val->getInt())); CurMBB->addInstruction(std::move(li)); } if (auto const_size = dynamic_cast(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(RVOpcodes::LI); li->addOperand(std::make_unique(getVReg(const_size))); li->addOperand(std::make_unique(const_size->getInt())); CurMBB->addInstruction(std::move(li)); } if (auto alloca = dynamic_cast(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(RVOpcodes::FRAME_ADDR); instr->addOperand(std::make_unique(dest_addr_vreg)); // 目标虚拟寄存器 instr->addOperand(std::make_unique(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内部逻辑创建新的临时虚拟寄存器 Type* ptr_type = Type::getPointerType(Type::getIntType()); auto r_counter = getNewVReg(ptr_type); auto r_end_addr = getNewVReg(ptr_type); auto r_current_addr = getNewVReg(ptr_type); auto r_temp_val = getNewVReg(Type::getIntType()); // 定义一系列lambda表达式来简化指令创建 auto add_instr = [&](RVOpcodes op, unsigned rd, unsigned rs1, unsigned rs2) { auto i = std::make_unique(op); i->addOperand(std::make_unique(rd)); i->addOperand(std::make_unique(rs1)); i->addOperand(std::make_unique(rs2)); CurMBB->addInstruction(std::move(i)); }; auto addi_instr = [&](RVOpcodes op, unsigned rd, unsigned rs1, int64_t imm) { auto i = std::make_unique(op); i->addOperand(std::make_unique(rd)); i->addOperand(std::make_unique(rs1)); i->addOperand(std::make_unique(imm)); CurMBB->addInstruction(std::move(i)); }; auto store_instr = [&](RVOpcodes op, unsigned src, unsigned base, int64_t off) { auto i = std::make_unique(op); i->addOperand(std::make_unique(src)); i->addOperand(std::make_unique(std::make_unique(base), std::make_unique(off))); CurMBB->addInstruction(std::move(i)); }; auto branch_instr = [&](RVOpcodes op, unsigned rs1, unsigned rs2, const std::string& label) { auto i = std::make_unique(op); i->addOperand(std::make_unique(rs1)); i->addOperand(std::make_unique(rs2)); i->addOperand(std::make_unique(label)); CurMBB->addInstruction(std::move(i)); }; auto jump_instr = [&](const std::string& label) { auto i = std::make_unique(RVOpcodes::J); i->addOperand(std::make_unique(label)); CurMBB->addInstruction(std::move(i)); }; auto label_instr = [&](const std::string& name) { auto i = std::make_unique(RVOpcodes::LABEL); i->addOperand(std::make_unique(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(RVOpcodes::MV); mv->addOperand(std::make_unique(r_current_addr)); mv->addOperand(std::make_unique(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; } case DAGNode::GET_ELEMENT_PTR: { auto gep = dynamic_cast(node->value); auto result_vreg = getVReg(gep); // --- Step 1: 获取基地址 (此部分逻辑正确,保持不变) --- auto base_ptr_node = node->operands[0]; auto current_addr_vreg = getNewVReg(gep->getType()); if (auto alloca_base = dynamic_cast(base_ptr_node->value)) { auto frame_addr_instr = std::make_unique(RVOpcodes::FRAME_ADDR); frame_addr_instr->addOperand(std::make_unique(current_addr_vreg)); frame_addr_instr->addOperand(std::make_unique(getVReg(alloca_base))); CurMBB->addInstruction(std::move(frame_addr_instr)); } else if (auto global_base = dynamic_cast(base_ptr_node->value)) { auto la_instr = std::make_unique(RVOpcodes::LA); la_instr->addOperand(std::make_unique(current_addr_vreg)); la_instr->addOperand(std::make_unique(global_base->getName())); CurMBB->addInstruction(std::move(la_instr)); } else if (auto const_global_base = dynamic_cast(base_ptr_node->value)) { auto la_instr = std::make_unique(RVOpcodes::LA); la_instr->addOperand(std::make_unique(current_addr_vreg)); la_instr->addOperand(std::make_unique(const_global_base->getName())); CurMBB->addInstruction(std::move(la_instr)); } else { auto base_vreg = getVReg(base_ptr_node->value); auto mv = std::make_unique(RVOpcodes::MV); mv->addOperand(std::make_unique(current_addr_vreg)); mv->addOperand(std::make_unique(base_vreg)); CurMBB->addInstruction(std::move(mv)); } // --- Step 2: 遵循LLVM GEP语义迭代计算地址 --- // 初始被索引的类型,是基指针指向的那个类型 (例如, [2 x i32]) Type* current_type = gep->getBasePointer()->getType()->as()->getBaseType(); // 迭代处理 GEP 的每一个索引 for (size_t i = 0; i < gep->getNumIndices(); ++i) { Value* indexValue = gep->getIndex(i); // GEP的第一个索引以整个 `current_type` 的大小为步长。 // 后续的索引则以 `current_type` 的元素大小为步长。 // 这一步是计算地址偏移的关键。 unsigned stride = getTypeSizeInBytes(current_type); // 如果步长为0(例如对一个void类型或空结构体索引),则不产生任何偏移 if (stride != 0) { // --- 为当前索引和步长生成偏移计算指令 --- auto offset_vreg = getNewVReg(Type::getIntType()); // 处理索引 - 区分常量与动态值 unsigned index_vreg; if (auto const_index = dynamic_cast(indexValue)) { // 对于常量索引,直接创建新的虚拟寄存器 index_vreg = getNewVReg(Type::getIntType()); auto li = std::make_unique(RVOpcodes::LI); li->addOperand(std::make_unique(index_vreg)); li->addOperand(std::make_unique(const_index->getInt())); CurMBB->addInstruction(std::move(li)); } else { // 对于动态索引,使用已存在的虚拟寄存器 index_vreg = getVReg(indexValue); } // 优化:如果步长是1,可以直接移动(MV)作为偏移量,无需乘法 if (stride == 1) { auto mv = std::make_unique(RVOpcodes::MV); mv->addOperand(std::make_unique(offset_vreg)); mv->addOperand(std::make_unique(index_vreg)); CurMBB->addInstruction(std::move(mv)); } else { // 步长不为1,需要生成乘法指令 auto size_vreg = getNewVReg(Type::getIntType()); auto li_size = std::make_unique(RVOpcodes::LI); li_size->addOperand(std::make_unique(size_vreg)); li_size->addOperand(std::make_unique(stride)); CurMBB->addInstruction(std::move(li_size)); auto mul = std::make_unique(RVOpcodes::MULW); mul->addOperand(std::make_unique(offset_vreg)); mul->addOperand(std::make_unique(index_vreg)); mul->addOperand(std::make_unique(size_vreg)); CurMBB->addInstruction(std::move(mul)); } // 将计算出的偏移量累加到当前地址上 auto add = std::make_unique(RVOpcodes::ADD); add->addOperand(std::make_unique(current_addr_vreg)); add->addOperand(std::make_unique(current_addr_vreg)); add->addOperand(std::make_unique(offset_vreg)); CurMBB->addInstruction(std::move(add)); } // --- 为下一次迭代更新类型:深入一层 --- if (auto array_type = current_type->as()) { current_type = array_type->getElementType(); } else if (auto ptr_type = current_type->as()) { // 这种情况不应该在第二次迭代后发生,但为了逻辑健壮性保留 current_type = ptr_type->getBaseType(); } // 如果`current_type`已经是i32等基本类型,它会保持不变, // 但下一次循环如果还有索引,`getTypeSizeInBytes(i32)`仍然能正确计算步长。 } // --- Step 3: 将最终计算出的地址存入GEP的目标虚拟寄存器 (保持不变) --- auto final_mv = std::make_unique(RVOpcodes::MV); final_mv->addOperand(std::make_unique(result_vreg)); final_mv->addOperand(std::make_unique(current_addr_vreg)); CurMBB->addInstruction(std::move(final_mv)); 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_to_node, std::vector>& nodes_storage) { auto kind = static_cast(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(kind); node->value = val; DAGNode* raw_node_ptr = node.get(); nodes_storage.push_back(std::move(node)); if (val && !val->getType()->isVoid() && (dynamic_cast(val) || dynamic_cast(val))) { value_to_node[val] = raw_node_ptr; } return raw_node_ptr; } RISCv64ISel::DAGNode* RISCv64ISel::get_operand_node( Value* val_ir, std::map& value_to_node, std::vector>& nodes_storage ) { // 空指针错误处理 if (val_ir == nullptr) { throw std::runtime_error("get_operand_node received a null Value."); } // 规则1:如果这个Value已经有对应的节点,直接返回 if (value_to_node.count(val_ir)) { return value_to_node[val_ir]; } if (auto const_val = dynamic_cast(val_ir)) { if (const_val->isInt()) { return create_node(DAGNode::CONSTANT, val_ir, value_to_node, nodes_storage); } else { // 为浮点常量创建新的FP_CONSTANT节点 return create_node(DAGNode::FP_CONSTANT, val_ir, value_to_node, nodes_storage); } } if (dynamic_cast(val_ir)) { return create_node(DAGNode::CONSTANT, val_ir, value_to_node, nodes_storage); } if (dynamic_cast(val_ir)) { return create_node(DAGNode::ALLOCA_ADDR, val_ir, value_to_node, nodes_storage); } if (dynamic_cast(val_ir)) { return create_node(DAGNode::ARGUMENT, val_ir, value_to_node, nodes_storage); } if (dynamic_cast(val_ir)) { // 全局常量数组和全局变量类似,在指令选择层面都表现为一个常量地址 // 因此也为它创建一个 CONSTANT 类型的节点 return create_node(DAGNode::CONSTANT, val_ir, value_to_node, nodes_storage); } // 如果代码执行到这里,意味着val_ir不是上述任何一种叶子节点, // 且它也不是在当前基本块中定义的(否则它会在value_to_node中被找到)。 // 这说明它是一个来自前驱块的Live-In值。 // 我们将其视为一个与函数参数(Argument)类似的“块输入值”,并为它创建一个ARGUMENT节点。 // 这样,后续的指令选择逻辑就知道这个值是直接可用的,无需在当前块内计算。 if (dynamic_cast(val_ir)) { return create_node(DAGNode::ARGUMENT, val_ir, value_to_node, nodes_storage); } // 如果一个Value不是任何已知类型,也不是指令,那说明出现了未处理的情况,抛出异常。 throw std::runtime_error("Unhandled Value type in get_operand_node for value named: " + val_ir->getName()); } std::vector> RISCv64ISel::build_dag(BasicBlock* bb) { std::vector> nodes_storage; std::map value_to_node; for (const auto& inst_ptr : bb->getInstructions()) { Instruction* inst = inst_ptr.get(); if (auto alloca = dynamic_cast(inst)) { create_node(DAGNode::ALLOCA_ADDR, alloca, value_to_node, nodes_storage); } else if (auto store = dynamic_cast(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(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 gep = dynamic_cast(inst)) { // 如果这个GEP指令已经创建过节点,则跳过 if(value_to_node.count(gep)) continue; // 创建一个新的 GET_ELEMENT_PTR 类型的节点 auto gep_node = create_node(DAGNode::GET_ELEMENT_PTR, gep, value_to_node, nodes_storage); // 第一个操作数是基指针(即数组本身) gep_node->operands.push_back(get_operand_node(gep->getBasePointer(), value_to_node, nodes_storage)); // 依次添加所有索引作为后续的操作数 for (auto index : gep->getIndices()) { // 从 Use 对象中获取真正的 Value* gep_node->operands.push_back(get_operand_node(index->getValue(), value_to_node, nodes_storage)); } } else if (auto load = dynamic_cast(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(inst)) { if(value_to_node.count(bin)) continue; if (bin->getKind() == Instruction::kFSub) { if (auto const_lhs = dynamic_cast(bin->getLhs())) { // 使用isZero()来判断浮点数0.0,比直接比较更健壮 if (const_lhs->isZero()) { // 这是一个浮点取负操作,创建 FUNARY 节点 auto funary_node = create_node(DAGNode::FUNARY, bin, value_to_node, nodes_storage); funary_node->operands.push_back(get_operand_node(bin->getRhs(), value_to_node, nodes_storage)); continue; // 处理完毕,跳到下一条指令 } } } if (bin->getKind() == BinaryInst::kSub) { if (auto const_lhs = dynamic_cast(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; } } } if (bin->isFPBinary()) { // 假设浮点指令枚举值更大 auto fbin_node = create_node(DAGNode::FBINARY, bin, value_to_node, nodes_storage); fbin_node->operands.push_back(get_operand_node(bin->getLhs(), value_to_node, nodes_storage)); fbin_node->operands.push_back(get_operand_node(bin->getRhs(), value_to_node, nodes_storage)); } else { 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(inst)) { if(value_to_node.count(un)) continue; if (un->getKind() >= Instruction::kFNeg) { auto funary_node = create_node(DAGNode::FUNARY, un, value_to_node, nodes_storage); funary_node->operands.push_back(get_operand_node(un->getOperand(), value_to_node, nodes_storage)); } else { 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(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(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(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(inst)) { create_node(DAGNode::BRANCH, uncond_br, value_to_node, nodes_storage); } } return nodes_storage; } /** * @brief 计算一个类型在内存中占用的字节数。 * @param type 需要计算大小的IR类型。 * @return 该类型占用的字节数。 */ unsigned RISCv64ISel::getTypeSizeInBytes(Type* type) { if (!type) { assert(false && "Cannot get size of a null type."); return 0; } switch (type->getKind()) { // 对于SysY语言,基本类型int和float都占用4字节 case Type::kInt: case Type::kFloat: return 4; // 指针类型在RISC-V 64位架构下占用8字节 // 虽然SysY没有'int*'语法,但数组变量在IR层面本身就是指针类型 case Type::kPointer: return 8; // 数组类型的总大小 = 元素数量 * 单个元素的大小 case Type::kArray: { auto arrayType = type->as(); // 递归调用以计算元素大小 return arrayType->getNumElements() * getTypeSizeInBytes(arrayType->getElementType()); } // 其他类型,如Void, Label等不占用栈空间,或者不应该出现在这里 default: // 如果遇到未处理的类型,触发断言,方便调试 assert(false && "Unsupported type for size calculation."); return 0; } } // 打印DAG图以供调试的辅助函数 void RISCv64ISel::print_dag(const std::vector>& dag, const std::string& bb_name) { // 检查是否有DEBUG宏或者全局变量,避免在非调试模式下打印 // if (!DEBUG) return; std::cerr << "=== DAG for Basic Block: " << bb_name << " ===\n"; std::set visited; // 为节点分配临时ID,方便阅读 std::map 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::ARGUMENT: return "ARGUMENT"; 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"; case DAGNode::GET_ELEMENT_PTR: return "GET_ELEMENT_PTR"; default: return "UNKNOWN"; } }; // 递归打印节点的lambda表达式 std::function 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(node->value)) { std::cerr << inst->getKindString(); if (!inst->getName().empty()) { std::cerr << "(" << inst->getName() << ")"; } } else if (auto constant = dynamic_cast(node->value)) { std::cerr << "Const(" << constant->getInt() << ")"; } else if (auto global = dynamic_cast(node->value)) { std::cerr << "Global(" << global->getName() << ")"; } else if (auto alloca = dynamic_cast(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"; } unsigned int RISCv64ISel::getVRegCounter() const { return vreg_counter; } } // namespace sysy