private Set<SSA> directBlockLive(Set<SSA> liveJoin, BasicBlock joinBlock, BasicBlock headBlock) {

    Set<SSA> liveDirectLast = new HashSet<SSA>();
    liveDirectLast.addAll(liveJoin);
    liveDirectLast.addAll(joinBlock.getPhiManager().getPhiDirects());
    return buildIGRecursive(headBlock.getDirectSuccessor(), liveDirectLast);
  }
  public Set<SSA> buildIGRecursive(BasicBlock curBB, Set<SSA> liveLast) {
    if (curBB.getJoinSuccessor() != null && curBB.getDirectSuccessor() != null) {

      // liveness before the join block
      BasicBlock joinBlock = curBB.getJoinSuccessor();
      Set<SSA> liveJoin = buildIGRecursive(curBB.getJoinSuccessor(), liveLast);

      this.connectPhiFuncs(liveJoin, joinBlock);

      // liveness before the else block
      Set<SSA> liveElseInitial = this.elseBlockLive(liveJoin, joinBlock, curBB);

      // liveness before the if block
      Set<SSA> liveDirectInitial = this.directBlockLive(liveJoin, joinBlock, curBB);

      // merge liveDirect and liveELse
      liveDirectInitial.addAll(liveElseInitial);
      // build IG from initial block
      Set<SSA> liveInitial = buildIGFromBlock(curBB, liveDirectInitial);

      return liveInitial;

    } else if (curBB.getDirectSuccessor() != null && curBB.getDirectSuccessor().isLoop()) {

      BasicBlock loopHead = curBB.getDirectSuccessor();
      // liveness before the follow block
      BasicBlock followBlock = loopHead.getElseSuccessor();
      Set<SSA> liveFollow = buildIGRecursive(followBlock, liveLast);

      // liveness before the loop head
      Set<SSA> liveLoopHead = buildIGFromBlock(loopHead, new HashSet<SSA>(liveFollow));

      this.connectPhiFuncs(liveLoopHead, loopHead);

      // liveness at the end of loop body
      Set<SSA> liveLoopBodyInitial = this.loopBodyLive(liveLoopHead, loopHead);

      // merge liveDirect and liveELse
      liveLoopBodyInitial.addAll(liveFollow);
      // liveness before the loop head again
      Set<SSA> liveLoopHeadNew = buildIGFromBlock(loopHead, liveLoopBodyInitial);

      this.connectPhiFuncs(liveLoopHeadNew, loopHead);

      // the block before the loop head
      Set<SSA> liveBeforeLoop = liveLoopHeadNew;
      liveBeforeLoop.addAll(loopHead.getPhiManager().getPhiElses());
      Set<SSA> liveInitial = buildIGFromBlock(curBB, liveBeforeLoop);

      return liveInitial;

    } else {
      // if recursion reaches a normal block
      Set<SSA> liveInitial = buildIGFromBlock(curBB, liveLast);
      return liveInitial;
    }
  }
  private Set<SSA> elseBlockLive(Set<SSA> liveJoin, BasicBlock joinBlock, BasicBlock headBlock) {

    if (headBlock.getElseSuccessor() != headBlock.getJoinSuccessor()) {
      Set<SSA> liveElseLast = new HashSet<SSA>();
      liveElseLast.addAll(liveJoin);
      liveElseLast.addAll(joinBlock.getPhiManager().getPhiElses());
      return buildIGRecursive(headBlock.getElseSuccessor(), liveElseLast);
    }
    return new HashSet<SSA>();
  }
 private void connectPhiFuncs(Set<SSA> liveJoin, BasicBlock joinBlock) {
   for (SSA result : joinBlock.getPhiManager().getPhiResults()) {
     liveJoin.remove(result);
     Cluster resultCluster = this.getCluster(result);
     for (SSA x : liveJoin) {
       Cluster xCluster = this.getCluster(x);
       // add edge i <-> x
       xCluster.connectWith(resultCluster);
     }
   }
 }
  private Set<SSA> buildIGFromBlock(BasicBlock curBB, Set<SSA> live) {
    List<Instruction> instList = curBB.getInstructions();
    for (int i = instList.size() - 1; i >= 0; i--) {
      Instruction inst = instList.get(i);
      // ignore phi function
      if (inst.getOperator() == Instruction.phi) {
        return live;
      }
      if (inst.getOperator() == Instruction.subroutine) {
        live = this.buildIGRecursive(inst.getOperand2().block, live);
        continue;
      }
      List<SSA> results = VariableManager.getSSAsByVersion(inst.getId());
      // live = live - {i}
      live.removeAll(results);
      live.remove(null);
      // for all x belong to live do

      for (SSA result : results) {
        Cluster resultCluster = this.getCluster(result);
        for (SSA x : live) {
          Cluster xCluster = this.getCluster(x);
          // add edge i <-> x
          xCluster.connectWith(resultCluster);
        }
      }

      // live = live + {j, k}
      if (inst.getOperand1() != null) {
        SSA j = inst.getOperand1().ssa;
        if (j != null) {
          live.add(j);
        }
      }

      if (inst.getOperand2() != null) {
        SSA k = inst.getOperand2().ssa;
        if (k != null) {
          live.add(k);
        }
      }
    }
    return live;
  }
  private void insertSpillCode(Cluster x) {
    for (int i = 0; i < x.getSSAList().size(); i++) {
      Instruction assignInst = ControlFlowGraph.getInstruction(x.getSSAList().get(i).getVersion());
      BasicBlock blockOfAssign = ControlFlowGraph.findBlockOf(assignInst);

      Operand storeAddr = Operand.makeConst(spillMemory);
      if (assignInst.getOperand1().kind == Operand.constant) {
        Operand temp = Operand.makeReg(25);
        Instruction store = Instruction.noUseInstruction(Instruction.store, temp, storeAddr);
        store.setId(assignInst.getId());
        blockOfAssign.replaceInst(assignInst, store);
        Instruction move =
            Instruction.noUseInstruction(Instruction.move, assignInst.getOperand1(), temp);
        move.setId(store.getId() - 1);
        blockOfAssign.insertBefore(store, move);
      } else {
        Instruction store =
            Instruction.noUseInstruction(Instruction.store, assignInst.getOperand1(), storeAddr);
        store.setId(assignInst.getId());
        blockOfAssign.replaceInst(assignInst, store);
      }

      for (Operand use : x.getSSAList().get(i).getUseChain()) {
        Instruction useInst = ControlFlowGraph.getInstruction(use.inst);
        if (useInst != null && use.inst != x.getSSAList().get(i).getVersion()) {
          BasicBlock blockOfUse = ControlFlowGraph.findBlockOf(useInst);

          Operand loadAddr = Operand.makeConst(spillMemory);
          Operand loadTemp = Operand.makeReg(26);

          Instruction load = Instruction.noUseInstruction(Instruction.load, loadAddr, loadTemp);
          blockOfUse.insertBefore(useInst, load);

          if (useInst.getOperand1() != null && useInst.getOperand1().ssa == x.getSSAList().get(i)) {
            useInst.setOperand1(loadTemp);
          }
          if (useInst.getOperand2() != null && useInst.getOperand2().ssa == x.getSSAList().get(i)) {
            useInst.setOperand2(loadTemp);
          }
        }
      }
    }
  }
 private Set<SSA> loopBodyLive(Set<SSA> liveLoopBodyLast, BasicBlock loopHead) {
   liveLoopBodyLast.addAll(loopHead.getPhiManager().getPhiDirects());
   return buildIGRecursive(loopHead.getDirectSuccessor(), liveLoopBodyLast);
 }