mem2reg流程基本跑通,修复phi函数打印,需要删除调试print

This commit is contained in:
rain2133
2025-06-25 12:23:59 +08:00
parent bd0b624e87
commit 4fabcc9952
4 changed files with 214 additions and 41 deletions

View File

@ -46,42 +46,116 @@ std::unordered_set<BasicBlock *> Mem2Reg::computeIterDf(const std::unordered_set
* 这里的value2AllocBlocks、value2DefBlocks和value2UseBlocks改变了函数级别的分析信息
*/
auto Mem2Reg::computeValue2Blocks() -> void {
SysYPrinter printer(pModule); // 初始化打印机
std::cout << "===== Start computeValue2Blocks =====" << std::endl;
auto &functions = pModule->getFunctions();
for (const auto &function : functions) {
auto func = function.second.get();
auto basicBlocks = func->getBasicBlocks();
std::cout << "\nProcessing function: " << func->getName() << std::endl;
FunctionAnalysisInfo* funcInfo = controlFlowAnalysis->getFunctionAnalysisInfo(func);
if (!funcInfo) {
std::cerr << "ERROR: No analysis info for function " << func->getName() << std::endl;
continue;
}
auto basicBlocks = func->getBasicBlocks();
std::cout << "BasicBlocks count: " << basicBlocks.size() << std::endl;
for (auto &it : basicBlocks) {
auto basicBlock = it.get();
std::cout << "\nProcessing BB: " << basicBlock->getName() << std::endl;
// printer.printBlock(basicBlock); // 打印基本块内容
auto &instrs = basicBlock->getInstructions();
for (auto &instr : instrs) {
// 如果指令本身就是alloca指令则加到allocblocks中
std::cout << " Analyzing instruction: ";
printer.printInst(instr.get());
std::cout << std::endl;
if (instr->isAlloca()) {
if (!(isArr(instr.get()) || isGlobal(instr.get()))) {
std::cout << " Found alloca: ";
printer.printInst(instr.get());
std::cout << " -> Adding to allocBlocks" << std::endl;
funcInfo->addValue2AllocBlocks(instr.get(), basicBlock);
// func->addValue2AllocBlocks(instr.get(), basicBlock);
} else {
std::cout << " Skip array/global alloca: ";
printer.printInst(instr.get());
std::cout << std::endl;
}
} else if (instr->isStore()) {
// 否则就看Store指令找到operands里的alloc指令
}
else if (instr->isStore()) {
auto val = instr->getOperand(1);
std::cout << " Store target: ";
printer.printInst(dynamic_cast<Instruction *>(val));
if (!(isArr(val) || isGlobal(val))) {
funcInfo->addValue2DefBlocks(instr.get(), basicBlock);
// func->addValue2DefBlocks(val, basicBlock);
std::cout << " Adding store to defBlocks for value: ";
printer.printInst(dynamic_cast<Instruction *>(instr.get()));
std::cout << std::endl;
// 将store的目标值添加到defBlocks中
funcInfo->addValue2DefBlocks(val, basicBlock);
} else {
std::cout << " Skip array/global store" << std::endl;
}
} else if (instr->isLoad()) {
// 如果是load指令那么就是use看operand(因为IR是reg-reg型所以use只看load就行)
}
else if (instr->isLoad()) {
auto val = instr->getOperand(0);
std::cout << " Load source: ";
printer.printInst(dynamic_cast<Instruction *>(val));
std::cout << std::endl;
if (!(isArr(val) || isGlobal(val))) {
funcInfo->addValue2UseBlocks(instr.get(), basicBlock);
// func->addValue2UseBlocks(val, basicBlock);
std::cout << " Adding load to useBlocks for value: ";
printer.printInst(dynamic_cast<Instruction *>(val));
std::cout << std::endl;
funcInfo->addValue2UseBlocks(val, basicBlock);
} else {
std::cout << " Skip array/global load" << std::endl;
}
}
}
}
// 打印分析结果
std::cout << "\nAnalysis results for function " << func->getName() << ":" << std::endl;
auto &allocMap = funcInfo->getValue2AllocBlocks();
std::cout << "AllocBlocks (" << allocMap.size() << "):" << std::endl;
for (auto &[val, bb] : allocMap) {
std::cout << " ";
printer.printInst(dynamic_cast<Instruction *>(val));
std::cout << " in BB: " << bb->getName() << std::endl;
}
auto &defMap = funcInfo->getValue2DefBlocks();
std::cout << "DefBlocks (" << defMap.size() << "):" << std::endl;
for (auto &[val, bbs] : defMap) {
std::cout << " ";
printer.printInst(dynamic_cast<Instruction *>(val));
for (const auto &[bb, count] : bbs) {
std::cout << " in BB: " << bb->getName() << " (count: " << count << ")";
}
}
auto &useMap = funcInfo->getValue2UseBlocks();
std::cout << "UseBlocks (" << useMap.size() << "):" << std::endl;
for (auto &[val, bbs] : useMap) {
std::cout << " ";
printer.printInst(dynamic_cast<Instruction *>(val));
for (const auto &[bb, count] : bbs) {
std::cout << " in BB: " << bb->getName() << " (count: " << count << ")";
}
}
}
std::cout << "===== End computeValue2Blocks =====" << std::endl;
}
/**
* @brief 级联关系的顺带消除用于llvm mem2reg类预优化1
*
@ -148,22 +222,80 @@ auto Mem2Reg::cascade(Instruction *instr, bool &changed, Function *func, BasicBl
* @return 无返回值,但满足条件的情况下会对指令进行删除
*/
auto Mem2Reg::preOptimize1() -> void {
SysYPrinter printer(pModule); // 初始化打印机
auto &functions = pModule->getFunctions();
std::cout << "===== Start preOptimize1 =====" << std::endl;
for (const auto &function : functions) {
auto func = function.second.get();
std::cout << "\nProcessing function: " << func->getName() << std::endl;
FunctionAnalysisInfo* funcInfo = controlFlowAnalysis->getFunctionAnalysisInfo(func);
if (!funcInfo) {
std::cerr << "ERROR: No analysis info for function " << func->getName() << std::endl;
continue;
}
auto &vToDefB = funcInfo->getValue2DefBlocks();
auto &vToUseB = funcInfo->getValue2UseBlocks();
// 先删除孤零零的alloca即没有store的alloca
auto &vToAllocB = funcInfo->getValue2AllocBlocks();
// 打印初始状态
std::cout << "Initial allocas: " << vToAllocB.size() << std::endl;
for (auto &[val, bb] : vToAllocB) {
std::cout << " Alloca: ";
printer.printInst(dynamic_cast<Instruction *>(val));
std::cout << " in BB: " << bb->getName() << std::endl;
}
// 阶段1删除无store的alloca
std::cout << "\nPhase 1: Remove unused allocas" << std::endl;
for (auto iter = vToAllocB.begin(); iter != vToAllocB.end();) {
auto val = iter->first;
auto bb = iter->second;
std::cout << "Checking alloca: ";
printer.printInst(dynamic_cast<Instruction *>(val));
std::cout << " in BB: " << bb->getName() << std::endl;
// 如果该alloca没有对应的store指令且不在函数参数中
// 这里的vToDefB是value2DefBlocksvToUseB是value2UseBlocks
// 打印vToDefB
std::cout << "DefBlocks (" << vToDefB.size() << "):" << std::endl;
for (auto &[val, bbs] : vToDefB) {
std::cout << " ";
printer.printInst(dynamic_cast<Instruction *>(val));
for (const auto &[bb, count] : bbs) {
std::cout << " in BB: " << bb->getName() << " (count: " << count << ")" << std::endl;
}
}
std::cout << vToDefB.count(val) << std::endl;
bool hasStore = false;
if (vToDefB.count(val) == 0U &&
std::find(func->getEntryBlock()->getArguments().begin(), func->getEntryBlock()->getArguments().end(), val) ==
func->getEntryBlock()->getArguments().end()) {
auto bb = iter->second;
auto tofind = std::find_if(bb->getInstructions().begin(), bb->getInstructions().end(),
[val](const auto &instr) { return instr.get() == val; });
std::find(func->getEntryBlock()->getArguments().begin(),
func->getEntryBlock()->getArguments().end(),
val) == func->getEntryBlock()->getArguments().end()) {
std::cout << " Removing unused alloca: ";
printer.printInst(dynamic_cast<Instruction *>(val));
std::cout << std::endl;
auto tofind = std::find_if(bb->getInstructions().begin(),
bb->getInstructions().end(),
[val](const auto &instr) {
return instr.get() == val;
});
if (tofind == bb->getInstructions().end()) {
std::cerr << "ERROR: Alloca not found in BB!" << std::endl;
++iter;
continue;
}
usedelete(tofind->get());
bb->getInstructions().erase(tofind);
iter = vToAllocB.erase(iter);
@ -171,45 +303,83 @@ auto Mem2Reg::preOptimize1() -> void {
++iter;
}
}
// 阶段2删除无load的store
std::cout << "\nPhase 2: Remove dead stores" << std::endl;
bool changed = true;
// 不动点法
int iteration = 0;
while (changed) {
changed = false;
iteration++;
std::cout << "\nIteration " << iteration << std::endl;
for (auto iter = vToDefB.begin(); iter != vToDefB.end();) {
auto val = iter->first;
// 找到没有load的变量删除关于该变量的store
std::cout << "Checking value: ";
printer.printInst(dynamic_cast<Instruction *>(val));
std::cout << std::endl;
if (vToUseB.count(val) == 0U) {
std::cout << " Found dead store for value: ";
printer.printInst(dynamic_cast<Instruction *>(val));
std::cout << std::endl;
auto blocks = funcInfo->getDefBlocksByValue(val);
for (auto block : blocks) {
std::cout << " Processing BB: " << block->getName() << std::endl;
// printer.printBlock(block); // 打印基本块内容
auto &instrs = block->getInstructions();
for (auto it = instrs.begin(); it != instrs.end();) {
if (((*it)->isStore() && (*it)->getOperand(1) == val)) {
// 关于该变量的store指令删除了那对于之前的用于作store指令第0个操作数的那些指令就冗余了也要删除
// 只考虑为指令,不考虑字面量和常数,因为它们与之前的指令无关了
// 同时考虑指令的话,该指令可能又与前面的指令可能有较强的级联关系,级联之间又有级联,因此又要考虑前面指令的删除
if ((*it)->isStore() && (*it)->getOperand(1) == val) {
std::cout << " Removing store: ";
printer.printInst(it->get());
std::cout << std::endl;
auto valUsedByStore = dynamic_cast<Instruction *>((*it)->getOperand(0));
usedelete(it->get());
// if it is constantvalue which it not instruction
if (valUsedByStore != nullptr && valUsedByStore->getUses().size() == 1 &&
if (valUsedByStore != nullptr &&
valUsedByStore->getUses().size() == 1 &&
valUsedByStore->getUses().front()->getUser() == (*it).get()) {
std::cout << " Cascade deleting: ";
printer.printInst(valUsedByStore);
std::cout << std::endl;
cascade(valUsedByStore, changed, func, block, instrs);
}
it = instrs.erase(it);
changed = true;
} else {
++it;
}
}
}
// 再删除关于该变量的alloc如果是函数参数的就不删除函数参数的alloca在entry块的arguments内
if (std::find(func->getEntryBlock()->getArguments().begin(), func->getEntryBlock()->getArguments().end(),
// 删除对应的alloca
if (std::find(func->getEntryBlock()->getArguments().begin(),
func->getEntryBlock()->getArguments().end(),
val) == func->getEntryBlock()->getArguments().end()) {
auto bb = funcInfo->getAllocBlockByValue(val);
if (bb != nullptr) {
std::cout << " Removing alloca: ";
printer.printInst(dynamic_cast<Instruction *>(val));
std::cout << " in BB: " << bb->getName() << std::endl;
funcInfo->removeValue2AllocBlock(val);
auto tofind = std::find_if(bb->getInstructions().begin(), bb->getInstructions().end(),
[val](const auto &instr) { return instr.get() == val; });
usedelete(tofind->get());
bb->getInstructions().erase(tofind);
auto tofind = std::find_if(bb->getInstructions().begin(),
bb->getInstructions().end(),
[val](const auto &instr) {
return instr.get() == val;
});
if (tofind != bb->getInstructions().end()) {
usedelete(tofind->get());
bb->getInstructions().erase(tofind);
} else {
std::cerr << "ERROR: Alloca not found in BB!" << std::endl;
}
}
}
iter = vToDefB.erase(iter);
@ -219,6 +389,7 @@ auto Mem2Reg::preOptimize1() -> void {
}
}
}
std::cout << "===== End preOptimize1 =====" << std::endl;
}
/**
@ -584,18 +755,18 @@ auto Mem2Reg::mem2regPipeline() -> void {
// 计算所有valueToBlocks的定义映射
computeValue2Blocks();
SysYPrinter printer(pModule);
// SysYPrinter printer(pModule);
// 参考llvm的mem2reg遍在插入phi结点之前先做些优化
preOptimize1();
printer.printIR();
// printer.printIR();
preOptimize2();
printer.printIR();
// printer.printIR();
// 优化三 可能会针对局部变量优化而删除整个块的alloca/store
preOptimize3();
//再进行活跃变量分析
// 报错?
printer.printIR();
// printer.printIR();
dataFlowAnalysisUtils.backwardAnalyze(pModule);
// 为所有变量插入phi结点
insertPhi();

View File

@ -264,7 +264,7 @@ std::any SysYIRGenerator::visitAssignStmt(SysYParser::AssignStmtContext *ctx) {
dims.push_back(std::any_cast<Value *>(visitExp(exp)));
}
User* variable = module->getVariable(name);
auto variable = module->getVariable(name);
Value* value = std::any_cast<Value *>(visitExp(ctx->exp()));
Type* variableType = dynamic_cast<PointerType *>(variable->getType())->getBaseType();

View File

@ -438,14 +438,16 @@ void SysYPrinter::printInst(Instruction *pInst) {
case Kind::kPhi: {
auto phiInst = dynamic_cast<PhiInst *>(pInst);
std::cout << "%" << phiInst->getName() << " = phi ";
std::cout << "%";
printValue(phiInst->getOperand(0));
std::cout << " = phi ";
printType(phiInst->getType());
for (unsigned i = 0; i < phiInst->getNumOperands(); i += 2) {
for (unsigned i = 1; i < phiInst->getNumOperands(); i++) {
if (i > 0) std::cout << ", ";
std::cout << "[ ";
printValue(phiInst->getOperand(i));
std::cout << ", %" << dynamic_cast<BasicBlock*>(phiInst->getOperand(i+1))->getName() << " ]";
std::cout << " ]";
}
std::cout << std::endl;
} break;

View File

@ -94,7 +94,7 @@ public:
std::set<Function*> callees; ///< 函数调用集合
Loop_list loops; ///< 所有循环
Loop_list topLoops; ///< 顶层循环
block_loop_map basicblock2Loop; ///< 基本块到循环映射
// block_loop_map basicblock2Loop; ///< 基本块到循环映射
std::list<std::unique_ptr<AllocaInst>> indirectAllocas; ///< 间接分配内存
// 值定义/使用信息
@ -198,7 +198,7 @@ public:
callees.clear();
loops.clear();
topLoops.clear();
basicblock2Loop.clear();
// basicblock2Loop.clear();
indirectAllocas.clear();
value2AllocBlocks.clear();
value2DefBlocks.clear();