#include "DeadCodeElimination.h" namespace sysy { void DeadCodeElimination::runDCEPipeline() { const auto& functions = pModule->getFunctions(); for (const auto& function : functions) { const auto& func = function.second; bool changed = true; while (changed) { changed = false; eliminateDeadStores(func.get(), changed); eliminateDeadLoads(func.get(), changed); eliminateDeadAllocas(func.get(), changed); eliminateDeadRedundantLoadStore(func.get(), changed); eliminateDeadGlobals(changed); } } } // 消除无用存储 消除条件: // 存储的目标指针(pointer)不是全局变量(!isGlobal(pointer))。 // 存储的目标指针不是数组参数(!isArr(pointer) 或不在函数参数列表里)。 // 该指针的所有使用者(uses)仅限 alloca 或 store(即没有 load 或其他指令使用它)。 void DeadCodeElimination::eliminateDeadStores(Function* func, bool& changed) { for (const auto& block : func->getBasicBlocks()) { auto& instrs = block->getInstructions(); for (auto iter = instrs.begin(); iter != instrs.end();) { auto inst = iter->get(); if (!inst->isStore()) { ++iter; continue; } auto storeInst = dynamic_cast(inst); auto pointer = storeInst->getPointer(); // 如果是全局变量或者是函数的数组参数 if (isGlobal(pointer) || (isArr(pointer) && std::find(func->getEntryBlock()->getArguments().begin(), func->getEntryBlock()->getArguments().end(), pointer) != func->getEntryBlock()->getArguments().end())) { ++iter; continue; } bool changetag = true; for (auto& use : pointer->getUses()) { // 依次判断store的指针是否被其他指令使用 auto user = use->getUser(); auto userInst = dynamic_cast(user); // 如果使用store的指针的指令不是Alloca或Store,则不删除 if (userInst != nullptr && !userInst->isAlloca() && !userInst->isStore()) { changetag = false; break; } } if (changetag) { changed = true; usedelete(storeInst); iter = instrs.erase(iter); } else { ++iter; } } } } // 消除无用加载 消除条件: // 该指令的结果未被使用(inst->getUses().empty())。 void DeadCodeElimination::eliminateDeadLoads(Function* func, bool& changed) { for (const auto& block : func->getBasicBlocks()) { auto& instrs = block->getInstructions(); for (auto iter = instrs.begin(); iter != instrs.end();) { auto inst = iter->get(); if (inst->isBinary() || inst->isUnary() || inst->isLoad()) { if (inst->getUses().empty()) { changed = true; usedelete(inst); iter = instrs.erase(iter); continue; } } ++iter; } } } // 消除无用加载 消除条件: // 该 alloca 未被任何指令使用(allocaInst->getUses().empty())。 // 该 alloca 不是函数的参数(不在 entry 块的参数列表里)。 void DeadCodeElimination::eliminateDeadAllocas(Function* func, bool& changed) { for (const auto& block : func->getBasicBlocks()) { auto& instrs = block->getInstructions(); for (auto iter = instrs.begin(); iter != instrs.end();) { auto inst = iter->get(); if (inst->isAlloca()) { auto allocaInst = dynamic_cast(inst); if (allocaInst->getUses().empty() && std::find(func->getEntryBlock()->getArguments().begin(), func->getEntryBlock()->getArguments().end(), allocaInst) == func->getEntryBlock()->getArguments().end()) { changed = true; usedelete(inst); iter = instrs.erase(iter); continue; } } ++iter; } } } void DeadCodeElimination::eliminateDeadIndirectiveAllocas(Function* func, bool& changed) { // 删除mem2reg时引入的且现在已经没有value使用了的隐式alloca FunctionAnalysisInfo* funcInfo = pCFA->getFunctionAnalysisInfo(func); for (auto it = funcInfo->getIndirectAllocas().begin(); it != funcInfo->getIndirectAllocas().end();) { auto &allocaInst = *it; if (allocaInst->getUses().empty()) { changed = true; it = funcInfo->getIndirectAllocas().erase(it); } else { ++it; } } } // 该全局变量未被任何指令使用(global->getUses().empty())。 void DeadCodeElimination::eliminateDeadGlobals(bool& changed) { auto& globals = pModule->getGlobals(); for (auto it = globals.begin(); it != globals.end();) { auto& global = *it; if (global->getUses().empty()) { changed = true; it = globals.erase(it); } else { ++it; } } } // 消除冗余加载和存储 消除条件: // phi 指令的目标指针仅被该 phi 使用(无其他 store/load 使用)。 // memset 指令的目标指针未被使用(pointer->getUses().empty()) // store -> load -> store 模式 void DeadCodeElimination::eliminateDeadRedundantLoadStore(Function* func, bool& changed) { for (const auto& block : func->getBasicBlocks()) { auto& instrs = block->getInstructions(); for (auto iter = instrs.begin(); iter != instrs.end();) { auto inst = iter->get(); if (inst->isPhi()) { auto phiInst = dynamic_cast(inst); auto pointer = phiInst->getPointer(); bool tag = true; for (const auto& use : pointer->getUses()) { auto user = use->getUser(); if (user != inst) { tag = false; break; } } /// 如果 pointer 仅被该 phi 使用,可以删除 ph if (tag) { changed = true; usedelete(inst); iter = instrs.erase(iter); continue; } // 数组指令还不完善,不保证memset优化效果 } else if (inst->isMemset()) { auto memsetInst = dynamic_cast(inst); auto pointer = memsetInst->getPointer(); if (pointer->getUses().empty()) { changed = true; usedelete(inst); iter = instrs.erase(iter); continue; } }else if(inst->isLoad()) { if (iter != instrs.begin()) { auto loadInst = dynamic_cast(inst); auto loadPointer = loadInst->getPointer(); // TODO:store -> load -> store 模式 auto prevIter = std::prev(iter); auto prevInst = prevIter->get(); if (prevInst->isStore()) { auto prevStore = dynamic_cast(prevInst); auto prevStorePointer = prevStore->getPointer(); auto prevStoreValue = prevStore->getOperand(0); // 确保前一个 store 不是数组操作 if (prevStore->getIndices().empty()) { // 检查后一条指令是否是 store 同一个值 auto nextIter = std::next(iter); if (nextIter != instrs.end()) { auto nextInst = nextIter->get(); if (nextInst->isStore()) { auto nextStore = dynamic_cast(nextInst); auto nextStorePointer = nextStore->getPointer(); auto nextStoreValue = nextStore->getOperand(0); // 确保后一个 store 不是数组操作 if (nextStore->getIndices().empty()) { // 判断优化条件: // 1. prevStore 的指针操作数 == load 的指针操作数 // 2. nextStore 的值操作数 == load 指令本身 if (prevStorePointer == loadPointer && nextStoreValue == loadInst) { // 可以优化直接把prevStorePointer的值存到nextStorePointer changed = true; nextStore->setOperand(0, prevStoreValue); usedelete(loadInst); iter = instrs.erase(iter); // 删除 prevStore 这里是不是可以留给删除无用store处理? // if (prevStore->getUses().empty()) { // usedelete(prevStore); // instrs.erase(prevIter); // 删除 prevStore // } continue; // 跳过 ++iter,因为已经移动迭代器 } } } } } } } } ++iter; } } } bool DeadCodeElimination::isGlobal(Value *val){ auto gval = dynamic_cast(val); return gval != nullptr; } bool DeadCodeElimination::isArr(Value *val){ auto aval = dynamic_cast(val); return aval != nullptr && aval->getNumDims() != 0; } void DeadCodeElimination::usedelete(Instruction *instr){ for (auto &use1 : instr->getOperands()) { auto val1 = use1->getValue(); val1->removeUse(use1); } } } // namespace sysy