diff --git a/src/AddressCalculationExpansion.cpp b/src/AddressCalculationExpansion.cpp new file mode 100644 index 0000000..0f03003 --- /dev/null +++ b/src/AddressCalculationExpansion.cpp @@ -0,0 +1,221 @@ +#include "AddressCalculationExpansion.h" +#include +#include +#include // for std::reverse (if needed, although not used in final version) +#include "IR.h" // 确保IR.h包含所有类型和指令的定义,特别是ConstantValue, AllocaInst, GlobalValue +#include "IRBuilder.h" // 确保这里也包含 IRBuilder.h + +extern int DEBUG; // 假设有一个全局的DEBUG宏 + +namespace sysy { + +bool AddressCalculationExpansion::run() { + bool changed = false; + + // 遍历所有函数 + for (auto& funcPair : pModule->getFunctions()) { + Function* func = funcPair.second.get(); + + // 遍历函数中的所有基本块 + for (auto& bb_ptr : func->getBasicBlocks()) { + BasicBlock* bb = bb_ptr.get(); + // 使用list迭代器,因为可能会删除元素 + for (auto it = bb->getInstructions().begin(); it != bb->getInstructions().end(); ) { + Instruction* inst = it->get(); + + Value* basePointer = nullptr; + Value* valueToStore = nullptr; // 仅用于 StoreInst + size_t firstIndexOperandIdx = 0; // 第一个索引操作数在指令操作数列表中的位置 + size_t numBaseOperands = 0; // Load/Store指令的基础操作数数量 + + if (inst->isLoad()) { + // LoadInst: %result = load Type, Type* %ptr, Index1, Index2, ... + // 操作数: pointer(0), index1(1), index2(2), ... + numBaseOperands = 1; // 只有指针操作数 + basePointer = inst->getOperand(0); + firstIndexOperandIdx = 1; + } else if (inst->isStore()) { + // StoreInst: store Type %val, Type* %ptr, Index1, Index2, ... + // 操作数: value(0), pointer(1), index1(2), index2(3), ... + numBaseOperands = 2; // value 和 pointer 操作数 + valueToStore = inst->getOperand(0); + basePointer = inst->getOperand(1); + firstIndexOperandIdx = 2; + } else { + ++it; + continue; + } + + // 如果操作数数量 <= 基础操作数数量,说明没有索引,跳过 + if (inst->getNumOperands() <= numBaseOperands) { + ++it; + continue; + } + + // 获取数组的维度信息 + std::vector dims; // 存储数组的维度大小(整数) + + // 统一获取维度的方式,不再使用 ArrayType + if (AllocaInst* allocaInst = dynamic_cast(basePointer)) { + // MODIFICATION: 将 getValue() 替换为 getValue() + for (const auto& use_ptr : allocaInst->getDims()) { + Value* dimValue = use_ptr->getValue(); + if (ConstantValue* constVal = dynamic_cast(dimValue)) { + dims.push_back(constVal->getValue()); // MODIFICATION: 明确指定模板参数为 int + } else { + // 如果维度不是 ConstantValue,或者不是整数,这里需要根据你的IR定义进行处理 + std::cerr << "Warning: AllocaInst dimension is not a constant integer. Skipping GEP expansion for: "; + SysYPrinter::printValue(allocaInst); + std::cerr << "\n"; + dims.clear(); // 清空,表示无法获取有效维度 + break; + } + } + } else if (GlobalValue* globalValue = dynamic_cast(basePointer)) { + // 处理 GlobalValue 的维度 + // 假设 GlobalValue 也有类似 AllocaInst 的 getNumDims() 和 getDim() 方法 + // 这需要根据你的 GlobalValue 实际定义来验证和实现 + // 如果 GlobalValue::getType() 是 PointerType,其 baseType 可能是另一个 PointerType + // 或者 GlobalValue 自身就存储了维度 + + // 暂时跳过 GlobalValue 的 GEP 展开,如果无法确定其维度 + std::cerr << "Warning: GlobalValue dimension handling needs explicit implementation for GEP expansion. Skipping GEP for: "; + SysYPrinter::printValue(globalValue); + std::cerr << "\n"; + ++it; + continue; + + } else { + // 基指针不是 AllocaInst 也不是 GlobalValue,或者无法处理其维度 + // 这可能是函数参数(指针到数组),或者其他复杂指针 + std::cerr << "Warning: Base pointer is not AllocaInst/GlobalValue or its array dimensions cannot be determined for GEP expansion. Skipping GEP for: "; + SysYPrinter::printValue(basePointer); + std::cerr << " in instruction "; + SysYPrinter::printInst(inst); + std::cerr << "\n"; + ++it; + continue; + } + + // 如果没有获取到有效的维度信息(例如,AllocaInst 没有维度但我们预期有,或者解析失败) + // 且不是一个标量 Load/Store(即有索引) + if (dims.empty() && (inst->getNumOperands() > numBaseOperands)) { + if (DEBUG) { + std::cerr << "ACE Warning: Could not get valid array dimensions for "; + SysYPrinter::printValue(basePointer); + std::cerr << " in instruction "; + SysYPrinter::printInst(inst); + std::cerr << " (expected dimensions for indices, but got none).\n"; + } + ++it; + continue; + } + + // 收集所有索引操作数 + std::vector indexOperands; + for (size_t i = firstIndexOperandIdx; i < inst->getNumOperands(); ++i) { + indexOperands.push_back(inst->getOperand(i)); + } + + // 检查索引数量是否与维度匹配 (一个简单的健全性检查) + // 只有当 basePointer 是 AllocaInst 或 GlobalValue 且有明确维度时才进行此检查 + if (AllocaInst* allocaInst = dynamic_cast(basePointer)) { + if (allocaInst->getNumDims() != indexOperands.size()) { + if (DEBUG) { + std::cerr << "ACE Warning: Index count (" << indexOperands.size() << ") does not match AllocaInst dimensions (" << allocaInst->getNumDims() << ") for instruction "; + SysYPrinter::printInst(inst); + std::cerr << "\n"; + } + ++it; + continue; + } + } + // TODO: 对 GlobalValue 也做类似检查 + + + // 最终线性偏移量 (字节数) + // 初始化为0,因为所有偏移都是相对于基地址 + Value* totalOffset = ConstantValue::get(0); + + // 在当前Load/Store指令之前设置插入点 + pBuilder->setPosition(bb, it); + + // 遍历所有索引来计算地址 + // 累加每个维度贡献的偏移量 + for (size_t i = 0; i < indexOperands.size(); ++i) { + Value* index = indexOperands[i]; + + // 计算当前维度索引的步长(字节数) + int stride = calculateStride(dims, i); + Value* strideConst = ConstantValue::get(stride); + + // 1. 计算当前索引的偏移量: %current_dim_offset = index * stride + Type* intType = Type::getIntType(); // 假设索引和偏移量都是int类型 + BinaryInst* currentDimOffsetInst = pBuilder->createBinaryInst(Instruction::kMul, intType, index, strideConst); + // UD 链管理由 IRBuilder 负责,不需要手动 addUse + + // 2. 将当前维度偏移量加到累计总偏移量上: %new_total_offset = total_offset + current_dim_offset + BinaryInst* newTotalOffsetInst = pBuilder->createBinaryInst(Instruction::kAdd, intType, totalOffset, currentDimOffsetInst); + // UD 链管理由 IRBuilder 负责,不需要手动 addUse + + totalOffset = newTotalOffsetInst; // 更新累计总偏移量 + } + + // 创建新的LoadInst或StoreInst,将计算出的总偏移量作为唯一的偏移量参数 + Instruction* newInst = nullptr; + // 新 Load/Store 指令的索引列表,只包含计算出的总偏移量 + std::vector newIndices = {totalOffset}; // 将 totalOffset 作为索引 + + if (inst->isLoad()) { + newInst = pBuilder->createLoadInst(basePointer, newIndices); + // 替换所有使用旧LoadInst结果的地方 + inst->replaceAllUsesWith(newInst); + } else { // StoreInst + newInst = pBuilder->createStoreInst(valueToStore, basePointer, newIndices); + } + + // 删除原始的LoadInst或StoreInst + // 注意:这里需要先让迭代器指向下一个指令,再删除当前指令 + Instruction* oldInst = it->get(); + ++it; // 提前移动迭代器 + + // 清理旧指令的UD链,修正 getOperandAsUse 的使用 + // Instruction 没有 getOperandAsUse()。我们通过 getOperand(i) 获取 Value*, + // 然后从该 Value* 的 uses 列表中找到并移除对应 oldInst 的 Use。 + for(size_t i = 0; i < oldInst->getNumOperands(); ++i) { + Value* operandValue = oldInst->getOperand(i); + if (operandValue) { + for (auto use_it = operandValue->getUses().begin(); use_it != operandValue->getUses().end(); ++use_it) { + if ((*use_it)->getUser() == oldInst && (*use_it)->getIndex() == i) { + operandValue->removeUse(*use_it); + break; // 找到并移除了,可以跳出内层循环 + } + } + } + } + + // 从基本块中删除旧指令 + // 使用 BasicBlock 的 list 的 erase 方法 + bb->getInstructions().erase(std::prev(it)); // it 已经向前移动,所以需要 prev(it) 指向旧指令的位置 + + changed = true; + if (DEBUG) { + std::cerr << "ACE: Expanded array access. New insts leading to final offset:\n"; + // 检查 totalOffset 是否是 Instruction 类型才能打印 + if (Instruction* offsetInst = dynamic_cast(totalOffset)) { + SysYPrinter::printInst(offsetInst); + } else { + SysYPrinter::printValue(totalOffset); // 如果是常量,打印Value + } + std::cerr << "ACE: New Load/Store instruction:\n"; + SysYPrinter::printInst(newInst); + std::cerr << "--------------------------------\n"; + } + // 迭代器it已经提前移动,无需再次++it + } + } + } + return changed; +} + +} // namespace sysy \ No newline at end of file diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index c89b3b0..050b63c 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -24,6 +24,7 @@ add_executable(sysyc SysYIROptPre.cpp SysYIRAnalyser.cpp DeadCodeElimination.cpp + AddressCalculationExpansion.cpp Mem2Reg.cpp Reg2Mem.cpp RISCv64Backend.cpp diff --git a/src/include/AddressCalculationExpansion.h b/src/include/AddressCalculationExpansion.h new file mode 100644 index 0000000..ba6ee6d --- /dev/null +++ b/src/include/AddressCalculationExpansion.h @@ -0,0 +1,59 @@ +#pragma once + +#include "IR.h" // 假设IR.h包含了Module, Function, BasicBlock, Instruction, Value, IRBuilder, Type等定义 +#include "IRBuilder.h" // 需要IRBuilder来创建新指令 +#include "SysYIRPrinter.h" // 新增: 用于调试输出 +#include +#include +#include +#include +#include // 用于迭代和修改指令列表 +#include // for std::reverse (if needed, although not used in final version) +#include // MODIFICATION: 用于警告输出 + +namespace sysy { + +/** + * @brief AddressCalculationExpansion Pass + * + * 这是一个IR优化Pass,用于将LoadInst和StoreInst中包含的多维数组索引 + * 显式地转换为IR中的BinaryInst(乘法和加法)序列,并生成带有线性偏移量的 + * LoadInst/StoreInst。 + * + * 目的:确保在寄存器分配之前,所有中间地址计算的结果都有明确的IR指令和对应的虚拟寄存器, + * 从而避免在后端DAG构建时临时创建值而导致寄存器分配缺失的问题。 + * + * SysY语言特性: + * - 无指针类型(所有数组访问的基地址是alloca或global的AllocaType/ArrayType) + * - 数据类型只有int和float,且都占用4字节。 + * - LoadInst和StoreInst直接接受多个索引作为额外操作数。 + */ +class AddressCalculationExpansion { +private: + Module* pModule; + IRBuilder* pBuilder; // 用于在IR中插入新指令 + + // 数组元素的固定大小,根据SysY特性,int和float都是4字节 + static const int ELEMENT_SIZE = 4; + + // 辅助函数:根据数组的维度信息和当前索引的维度,计算该索引的步长(字节数) + // dims: 包含所有维度大小的vector,例如 {2, 3, 4} + // currentDimIndex: 当前正在处理的索引在 dims 中的位置 (0, 1, 2...) + int calculateStride(const std::vector& dims, size_t currentDimIndex) { + int stride = ELEMENT_SIZE; // 最内层元素大小 (4字节) + // 乘以当前维度之后的所有维度的大小 + for (size_t i = currentDimIndex + 1; i < dims.size(); ++i) { + stride *= dims[i]; + } + return stride; + } + +public: + AddressCalculationExpansion(Module* module, IRBuilder* builder) + : pModule(module), pBuilder(builder) {} + + // 运行此Pass + bool run(); +}; + +} // namespace sysy \ No newline at end of file diff --git a/src/sysyc.cpp b/src/sysyc.cpp index 674a510..bb9b783 100644 --- a/src/sysyc.cpp +++ b/src/sysyc.cpp @@ -17,6 +17,7 @@ using namespace antlr4; #include "RISCv64Backend.h" #include "SysYIRAnalyser.h" #include "DeadCodeElimination.h" +#include "AddressCalculationExpansion.h" #include "Mem2Reg.h" #include "Reg2Mem.h" @@ -143,20 +144,19 @@ int main(int argc, char **argv) { cout << "=== After CFA & AVA (Default) ===\n"; SysYPrinter(moduleIR).printIR(); // 临时打印器用于调试 } - - DeadCodeElimination dce(moduleIR, &cfa, &ava); - dce.runDCEPipeline(); - if (DEBUG) { - cout << "=== After 1st DCE (Default) ===\n"; - SysYPrinter(moduleIR).printIR(); + AddressCalculationExpansion ace(moduleIR, builder); + if (ace.run()) { + cout << "AddressCalculationExpansion made changes.\n"; + // 如果 ACE 改变了IR,并且 DEBUG 模式开启,可以考虑打印IR + if (DEBUG) { + cout << "=== After AddressCalculationExpansion ===\n"; + SysYPrinter(moduleIR).printIR(); + } + } else { + cout << "AddressCalculationExpansion made no changes.\n"; } - - - - - // 根据优化级别,执行额外的优化 pass if (optLevel >= 1) { cout << "Applying additional -O" << optLevel << " optimizations...\n"; @@ -174,7 +174,13 @@ int main(int argc, char **argv) { // MyCustomOpt2 opt2_pass(moduleIR, builder, &cfa); // 假设需要CFA // opt2_pass.run(); // ... 更多 -O1 特有的优化 - + DeadCodeElimination dce(moduleIR, &cfa, &ava); + dce.runDCEPipeline(); + if (DEBUG) { + cout << "=== After 1st DCE (Default) ===\n"; + SysYPrinter(moduleIR).printIR(); + } + Mem2Reg mem2reg(moduleIR, builder, &cfa, &ava); mem2reg.mem2regPipeline(); if (DEBUG) { @@ -212,7 +218,7 @@ int main(int argc, char **argv) { // 设置 DEBUG 模式(如果指定了 'asmd') if (argStopAfter == "asmd") { DEBUG = 1; - DEEPDEBUG = 1; + // DEEPDEBUG = 1; } sysy::RISCv64CodeGen codegen(moduleIR); // 传入优化后的 moduleIR string asmCode = codegen.code_gen();