//===----------------------------------------------------------------------===//
// Helper Functions
//===----------------------------------------------------------------------===//
/// compunteFragmentSize - compute the specific Fragment size
uint64_t mcld::computeFragmentSize(const Layout& pLayout,
                                   const Fragment& pFrag)
{
  switch (pFrag.getKind()) {
    case Fragment::Fillment:
      return static_cast<const FillFragment&>(pFrag).getSize();

    case Fragment::Alignment: {
      uint64_t offset = pLayout.getOutputOffset(pFrag);
      const AlignFragment& align_frag = llvm::cast<AlignFragment>(pFrag);
      uint64_t size = llvm::OffsetToAlignment(offset, align_frag.getAlignment());
      if (size > align_frag.getMaxBytesToEmit())
        return 0;
      return size;
    }

    case Fragment::Region:
      return llvm::cast<RegionFragment>(pFrag).getRegion().size();

    case Fragment::Target:
      return llvm::cast<TargetFragment>(pFrag).getSize();

    case Fragment::Relocation:
      assert(0 && "the size of FT_Reloc fragment is handled by backend");
      return 0;

    default:
      assert(0 && "invalid fragment kind");
      return 0;
  }
}
/// group - group fragments and create islands when needed
/// @param pSectionData - the SectionData holds fragments need to be grouped
void BranchIslandFactory::group(Module& pModule) {
  /* FIXME: Currently only support relaxing .text section! */
  LDSection* text = pModule.getSection(".text");
  if (text != NULL && text->hasSectionData()) {
    SectionData& sd = *text->getSectionData();
    uint64_t group_end = m_MaxFwdBranchRange;
    for (SectionData::iterator it = sd.begin(), ie = sd.end(); it != ie; ++it) {
      if ((*it).getOffset() + (*it).size() > group_end) {
        Fragment* frag = (*it).getPrevNode();
        while (frag != NULL && frag->getKind() == Fragment::Alignment) {
          frag = frag->getPrevNode();
        }
        if (frag != NULL) {
          produce(*frag);
          group_end = (*it).getOffset() + m_MaxFwdBranchRange;
        }
      }
    }
    if (getIslands(sd.back()).first == NULL)
      produce(sd.back());
  }
}
/// produce - produce a island for the given fragment
/// @param pFragment - the fragment needs a branch island
BranchIsland* BranchIslandFactory::produce(Fragment& pFragment)
{
  assert(NULL == find(pFragment));
  uint64_t island_offset = pFragment.getOffset() + m_MaxBranchRange -
                           (pFragment.getOffset() % m_MaxBranchRange);

  // find out the last fragment whose offset is smaller than the calculated
  // offset of the island
  Fragment* frag = &pFragment;
  while (NULL != frag->getNextNode()) {
    if (frag->getNextNode()->getOffset() > island_offset)
      break;
    frag = frag->getNextNode();
  }

  // fall back one step if needed
  if (NULL != frag &&
      (frag->getOffset() + frag->size()) > island_offset)
    frag = frag->getPrevNode();

  // check not to break the alignment constraint in the target section
  // (i.e., do not insert the island after a Alignment fragment)
  while (NULL != frag &&
         Fragment::Alignment == frag->getKind()) {
    frag = frag->getPrevNode();
  }

  // can not find an entry fragment to bridge the island
  if (NULL == frag)
    return NULL;

  BranchIsland *island = allocate();
  new (island) BranchIsland(*frag,           // entry fragment to the island
                            m_MaxIslandSize, // the max size of the island
                            size() - 1u);     // index in the island factory
  return island;
}