//===- BranchIslandFactory.cpp --------------------------------------------===//
//
// The MCLinker Project
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include <mcld/LD/BranchIslandFactory.h>
#include <mcld/Fragment/Fragment.h>
using namespace mcld;
//===----------------------------------------------------------------------===//
// BranchIslandFactory
//===----------------------------------------------------------------------===//
/// ctor
/// @param pMaxBranchRange - the max branch range of the target backend
/// @param pMaxIslandSize - a predifned value (1KB here) to decide the max
/// size of the island
BranchIslandFactory::BranchIslandFactory(uint64_t pMaxBranchRange,
uint64_t pMaxIslandSize)
: GCFactory<BranchIsland, 0>(1u), // magic number
m_MaxBranchRange(pMaxBranchRange - pMaxIslandSize),
m_MaxIslandSize(pMaxIslandSize)
{
}
BranchIslandFactory::~BranchIslandFactory()
{
}
/// 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;
}
/// find - find a island for the given fragment
/// @param pFragment - the fragment needs a branch isladn
BranchIsland* BranchIslandFactory::find(const Fragment& pFragment)
{
// Currently we always find the island in a forward direction.
// TODO: If we can search backward, then we may reduce the number of islands.
for (iterator it = begin(), ie = end(); it != ie; ++it) {
if ((pFragment.getOffset() < (*it).offset()) &&
((pFragment.getOffset() + m_MaxBranchRange) >= (*it).offset()))
return &(*it);
}
return NULL;
}