合并backend、backend-IRC到midend

This commit is contained in:
Lixuanwang
2025-08-03 15:18:52 +08:00
parent 5b43f208ac
commit f8e423f579
17 changed files with 1966 additions and 1135 deletions

View File

@@ -2,8 +2,8 @@
#include <stdexcept>
#include <set>
#include <functional>
#include <cmath> // For std::fabs
#include <limits> // For std::numeric_limits
#include <cmath>
#include <limits>
#include <iostream>
namespace sysy {
@@ -402,7 +402,7 @@ void RISCv64ISel::selectNode(DAGNode* node) {
Value* base = nullptr;
Value* offset = nullptr;
// [修改] 扩展基地址的判断,使其可以识别 AllocaInst 或 GlobalValue
// 扩展基地址的判断,使其可以识别 AllocaInst 或 GlobalValue
if (dynamic_cast<AllocaInst*>(lhs) || dynamic_cast<GlobalValue*>(lhs)) {
base = lhs;
offset = rhs;
@@ -421,7 +421,7 @@ void RISCv64ISel::selectNode(DAGNode* node) {
CurMBB->addInstruction(std::move(li));
}
// 2. [修改] 根据基地址的类型,生成不同的指令来获取基地址
// 2. 根据基地址的类型,生成不同的指令来获取基地址
auto base_addr_vreg = getNewVReg(Type::getIntType()); // 创建一个新的临时vreg来存放基地址
// 情况一:基地址是局部栈变量
@@ -452,7 +452,7 @@ void RISCv64ISel::selectNode(DAGNode* node) {
}
}
// [V2优点] 在BINARY节点内部按需加载常量操作数。
// 在BINARY节点内部按需加载常量操作数。
auto load_val_if_const = [&](Value* val) {
if (auto c = dynamic_cast<ConstantValue*>(val)) {
if (DEBUG) {
@@ -483,7 +483,7 @@ void RISCv64ISel::selectNode(DAGNode* node) {
auto dest_vreg = getVReg(bin);
auto lhs_vreg = getVReg(lhs);
// [V2优点] 融合 ADDIW 优化。
// 融合 ADDIW 优化。
if (rhs_is_imm_opt) {
auto rhs_const = dynamic_cast<ConstantValue*>(rhs);
auto instr = std::make_unique<MachineInstr>(RVOpcodes::ADDIW);
@@ -952,7 +952,7 @@ void RISCv64ISel::selectNode(DAGNode* node) {
// --- 步骤 3: 生成CALL指令 ---
auto call_instr = std::make_unique<MachineInstr>(RVOpcodes::CALL);
// [协议] 如果函数有返回值,将它的目标虚拟寄存器作为第一个操作数
// 如果函数有返回值,将它的目标虚拟寄存器作为第一个操作数
if (!call->getType()->isVoid()) {
unsigned dest_vreg = getVReg(call);
call_instr->addOperand(std::make_unique<RegOperand>(dest_vreg));
@@ -1029,7 +1029,7 @@ void RISCv64ISel::selectNode(DAGNode* node) {
} else {
// --- 处理整数/指针返回值 ---
// 返回值需要被放入 a0
// [V2优点] 在RETURN节点内加载常量返回值
// 在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));
@@ -1043,7 +1043,7 @@ void RISCv64ISel::selectNode(DAGNode* node) {
}
}
}
// [V1设计保留] 函数尾声epilogue不由RETURN节点生成
// 函数尾声epilogue不由RETURN节点生成
// 而是由后续的AsmPrinter或其它Pass统一处理这是一种常见且有效的模块化设计。
auto ret_mi = std::make_unique<MachineInstr>(RVOpcodes::RET);
CurMBB->addInstruction(std::move(ret_mi));
@@ -1057,7 +1057,7 @@ void RISCv64ISel::selectNode(DAGNode* node) {
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
@@ -1072,7 +1072,7 @@ void RISCv64ISel::selectNode(DAGNode* node) {
}
// 如果条件不是常量,则执行标准流程
else {
// [修复] 为条件变量生成加载指令(如果它是常量的话,尽管上面已经处理了)
// 为条件变量生成加载指令(如果它是常量的话,尽管上面已经处理了)
// 这一步是为了逻辑完整,以防有其他类型的常量没有被捕获
if (auto const_val = dynamic_cast<ConstantValue*>(condition)) {
auto li = std::make_unique<MachineInstr>(RVOpcodes::LI);
@@ -1106,7 +1106,7 @@ void RISCv64ISel::selectNode(DAGNode* node) {
}
case DAGNode::MEMSET: {
// [V1设计保留] Memset的核心展开逻辑在虚拟寄存器层面是正确的无需修改。
// Memset的核心展开逻辑在虚拟寄存器层面是正确的无需修改。
// 之前的bug是由于其输入地址、值、大小的虚拟寄存器未被正确初始化。
// 在修复了CONSTANT/ALLOCA_ADDR的加载问题后此处的逻辑现在可以正常工作。
@@ -1454,7 +1454,7 @@ std::vector<std::unique_ptr<RISCv64ISel::DAGNode>> RISCv64ISel::build_dag(BasicB
// 依次添加所有索引作为后续的操作数
for (auto index : gep->getIndices()) {
// [修复] 从 Use 对象中获取真正的 Value*
// 从 Use 对象中获取真正的 Value*
gep_node->operands.push_back(get_operand_node(index->getValue(), value_to_node, nodes_storage));
}
} else if (auto load = dynamic_cast<LoadInst*>(inst)) {
@@ -1558,7 +1558,7 @@ unsigned RISCv64ISel::getTypeSizeInBytes(Type* type) {
}
}
// [新] 打印DAG图以供调试的辅助函数
// 打印DAG图以供调试的辅助函数
void RISCv64ISel::print_dag(const std::vector<std::unique_ptr<DAGNode>>& dag, const std::string& bb_name) {
// 检查是否有DEBUG宏或者全局变量避免在非调试模式下打印
// if (!DEBUG) return;