#include "Reg2Mem.h"
#include <cstddef>
#include <iostream>
#include <list>
#include <memory>

namespace sysy {

/**
 * 删除phi节点
 * 删除phi节点后可能会生成冗余存储代码
 */
void Reg2Mem::DeletePhiInst(){
  auto &functions = pModule->getFunctions();
  for (auto &function : functions) {
    auto basicBlocks = function.second->getBasicBlocks();
    for (auto &basicBlock : basicBlocks) {

      for (auto iter = basicBlock->begin(); iter != basicBlock->end();) {
        auto &instruction = *iter;
        if (instruction->isPhi()) {
          auto predBlocks = basicBlock->getPredecessors();
          // 寻找源和目的
          // 目的就是phi指令的第一个操作数
          // 源就是phi指令的后续操作数
          auto destination = instruction->getOperand(0);
          int predBlockindex = 0;
          for (auto &predBlock : predBlocks) {
            ++predBlockindex;
            // 判断前驱块儿只有一个后继还是多个后继
            // 如果有多个
            auto source = instruction->getOperand(predBlockindex);
            if (source == destination) {
              continue;
            }
            // std::cout << predBlock->getNumSuccessors() << std::endl;
            if (predBlock->getNumSuccessors() > 1) {
              // 创建一个basicblock
              auto newbasicBlock = function.second->addBasicBlock();
              std::stringstream ss;
              ss << " phidel.L" << pBuilder->getLabelIndex();
              newbasicBlock->setName(ss.str());
              ss.str("");
              // // 修改前驱后继关系
              basicBlock->replacePredecessor(predBlock, newbasicBlock);
              // predBlock = newbasicBlock;
              newbasicBlock->addPredecessor(predBlock);
              newbasicBlock->addSuccessor(basicBlock.get());
              predBlock->removeSuccessor(basicBlock.get());
              predBlock->addSuccessor(newbasicBlock);
              // std::cout << "the block name is " << basicBlock->getName() << std::endl;
              // for (auto pb : basicBlock->getPredecessors()) {
              //   // newbasicBlock->addPredecessor(pb);
              //   std::cout << pb->getName() << std::endl;
              // }
              // sysy::BasicBlock::conectBlocks(newbasicBlock, static_cast<BasicBlock *>(basicBlock.get()));
              // 若后为跳转指令，应该修改跳转指令所到达的位置
              auto thelastinst = predBlock->end();
              (--thelastinst);

              if (thelastinst->get()->isConditional() || thelastinst->get()->isUnconditional()) {  // 如果是跳转指令
                auto opnum = thelastinst->get()->getNumOperands();
                for (size_t i = 0; i < opnum; i++) {
                  if (thelastinst->get()->getOperand(i) == basicBlock.get()) {
                    thelastinst->get()->replaceOperand(i, newbasicBlock);
                  }
                }
              }
              // 在新块中插入store指令
              pBuilder->setPosition(newbasicBlock, newbasicBlock->end());
              // pBuilder->createStoreInst(source, destination);
              if (source->isInt() || source->isFloat()) {
                pBuilder->createStoreInst(source, destination);
              } else {
                auto loadInst = pBuilder->createLoadInst(source);
                pBuilder->createStoreInst(loadInst, destination);
              }
              // pBuilder->createMoveInst(Instruction::kMove, destination->getType(), destination, source,
              // newbasicBlock);
              pBuilder->setPosition(newbasicBlock, newbasicBlock->end());
              pBuilder->createUncondBrInst(basicBlock.get(), {});
            } else {
              // 如果前驱块只有一个后继
              auto thelastinst = predBlock->end();
              (--thelastinst);
              // std::cout << predBlock->getName() << std::endl;
              // std::cout << thelastinst->get() << std::endl;
              // std::cout << "First point  11 " << std::endl;
              if (thelastinst->get()->isConditional() || thelastinst->get()->isUnconditional()) {
                // 在跳转语句前insert st指令
                pBuilder->setPosition(predBlock, thelastinst);
              } else {
                pBuilder->setPosition(predBlock, predBlock->end());
              }

              if (source->isInt() || source->isFloat()) {
                pBuilder->createStoreInst(source, destination);
              } else {
                auto loadInst = pBuilder->createLoadInst(source);
                pBuilder->createStoreInst(loadInst, destination);
              }
            }
          }
          // 删除phi指令
          auto &instructions = basicBlock->getInstructions();
          usedelete(iter->get());
          iter = instructions.erase(iter);
          if (basicBlock->getNumInstructions() == 0) {
            if (basicBlock->getNumSuccessors() == 1) {
              pBuilder->setPosition(basicBlock.get(), basicBlock->end());
              pBuilder->createUncondBrInst(basicBlock->getSuccessors()[0], {});
            }
          }
        } else {
          break;
        }
      }
    }
  }
}

void Reg2Mem::usedelete(Instruction *instr) {
  for (auto &use : instr->getOperands()) {
    auto val = use->getValue();
    val->removeUse(use);
  }
}

}  // namespace sysy
