#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