/*
  in addition to the original condition of the loop, insert one cond
  on the virtual iterator, given the linf and lsup bounds for the chunk
  this cond exits and returns to the decision block to start a new chunk
*/
BasicBlock *insertChunkCond(Loop *&L, LoopInfo *LI, Value *vi, Value *lsup,
                            BasicBlock *dcb, Value *vi_dcb_val,
                            PHINode *&phi_vi) {

  BasicBlock *H = L->getHeader();

  BasicBlock *newCond = BasicBlock::Create(
      H->getContext(), Twine("__kernel__" + H->getName().str() + "_viCond"),
      H->getParent(), H);

  std::vector<BasicBlock *> Lblocks = L->getBlocks();

  BasicBlock *exitBlock = BasicBlock::Create(
      H->getContext(), Twine(H->getName().str() + "_exitChunk"), H->getParent(),
      H);
  BranchInst::Create(dcb, exitBlock);

  phi_vi = PHINode::Create(Type::getInt64Ty(H->getContext()), 2, "vi_value",
                           newCond);
  phi_vi->addIncoming(vi_dcb_val, dcb);

  LoadInst *load_lsup = new LoadInst(lsup, "lsup_value", newCond);

  ICmpInst *cmp = new ICmpInst(*newCond, ICmpInst::ICMP_SLT, phi_vi, load_lsup,
                               vi->getName() + "_cmp");

  // Make sure all predecessors now go to our new condition
  std::vector<TerminatorInst *> termInstrs;
  BasicBlock *lp = L->getLoopPredecessor();

  for (auto it = pred_begin(H), end = pred_end(H); it != end; ++it) {
    if ((*it) == lp) {
      // Original entry should be redirected to dcb
      TerminatorInst *tinstr = (*it)->getTerminator();
      for (auto it = tinstr->op_begin(), end = tinstr->op_end(); it != end;
           ++it) {
        Use *use = &*it;
        if (use->get() == H) {
          use->set(dcb);
        }
      }
    } else {
      termInstrs.push_back((*it)->getTerminator());
    }
  }

  for (auto &tinstr : termInstrs) {
    for (auto it = tinstr->op_begin(), end = tinstr->op_end(); it != end;
         ++it) {
      Use *use = &*it;
      if (use->get() == H) {
        use->set(newCond);
      }
    }
  }

  BranchInst::Create(H, exitBlock, cmp, newCond);

  // update loop info
  if (L != LI->getLoopFor(newCond)) {
    L->addBasicBlockToLoop(newCond, *LI);
  }

  L->moveToHeader(newCond);

  Loop *Lp = L->getParentLoop();
  if (Lp)
    Lp->addBasicBlockToLoop(exitBlock, *LI);
  return newCond;
}