276 lines
9.9 KiB
C++
276 lines
9.9 KiB
C++
#include "DeadCodeElimination.h"
|
||
#include <iostream>
|
||
|
||
extern int DEBUG;
|
||
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<StoreInst*>(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<Instruction*>(user);
|
||
// 如果使用store的指针的指令不是Alloca或Store,则不删除
|
||
if (userInst != nullptr && !userInst->isAlloca() && !userInst->isStore()) {
|
||
changetag = false;
|
||
break;
|
||
}
|
||
}
|
||
|
||
if (changetag) {
|
||
changed = true;
|
||
if(DEBUG){
|
||
std::cout << "=== Dead Store Found ===\n";
|
||
SysYPrinter::printInst(storeInst);
|
||
}
|
||
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;
|
||
if(DEBUG){
|
||
std::cout << "=== Dead Load Binary Unary Found ===\n";
|
||
SysYPrinter::printInst(inst);
|
||
}
|
||
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<AllocaInst*>(inst);
|
||
if (allocaInst->getUses().empty() &&
|
||
std::find(func->getEntryBlock()->getArguments().begin(),
|
||
func->getEntryBlock()->getArguments().end(),
|
||
allocaInst) == func->getEntryBlock()->getArguments().end()) {
|
||
changed = true;
|
||
if(DEBUG){
|
||
std::cout << "=== Dead Alloca Found ===\n";
|
||
SysYPrinter::printInst(inst);
|
||
}
|
||
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;
|
||
if(DEBUG){
|
||
std::cout << "=== Dead Indirect Alloca Found ===\n";
|
||
SysYPrinter::printInst(allocaInst.get());
|
||
}
|
||
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;
|
||
if(DEBUG){
|
||
std::cout << "=== Dead Global Found ===\n";
|
||
SysYPrinter::printValue(global.get());
|
||
}
|
||
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<PhiInst*>(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<MemsetInst*>(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<LoadInst*>(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<StoreInst*>(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<StoreInst*>(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);
|
||
if(DEBUG){
|
||
std::cout << "=== Dead Store Load Store Found(now only del Load) ===\n";
|
||
SysYPrinter::printInst(prevStore);
|
||
SysYPrinter::printInst(loadInst);
|
||
SysYPrinter::printInst(nextStore);
|
||
}
|
||
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<GlobalValue *>(val);
|
||
return gval != nullptr;
|
||
}
|
||
|
||
bool DeadCodeElimination::isArr(Value *val){
|
||
auto aval = dynamic_cast<AllocaInst *>(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
|