//===- lib/MC/MCAtom.cpp - MCAtom implementation --------------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

#include "llvm/MC/MCAnalysis/MCAtom.h"
#include "llvm/MC/MCAnalysis/MCModule.h"
#include "llvm/Support/ErrorHandling.h"
#include <iterator>

using namespace llvm;

// Pin the vtable to this file.
void MCAtom::anchor() {}

void MCAtom::remap(uint64_t NewBegin, uint64_t NewEnd) {
  Parent->remap(this, NewBegin, NewEnd);
}

void MCAtom::remapForTruncate(uint64_t TruncPt) {
  assert((TruncPt >= Begin && TruncPt < End) &&
         "Truncation point not contained in atom!");
  remap(Begin, TruncPt);
}

void MCAtom::remapForSplit(uint64_t SplitPt,
                           uint64_t &LBegin, uint64_t &LEnd,
                           uint64_t &RBegin, uint64_t &REnd) {
  assert((SplitPt > Begin && SplitPt <= End) &&
         "Splitting at point not contained in atom!");

  // Compute the new begin/end points.
  LBegin = Begin;
  LEnd = SplitPt - 1;
  RBegin = SplitPt;
  REnd = End;

  // Remap this atom to become the lower of the two new ones.
  remap(LBegin, LEnd);
}

// MCDataAtom

void MCDataAtom::addData(const MCData &D) {
  Data.push_back(D);
  if (Data.size() > End + 1 - Begin)
    remap(Begin, End + 1);
}

void MCDataAtom::truncate(uint64_t TruncPt) {
  remapForTruncate(TruncPt);

  Data.resize(TruncPt - Begin + 1);
}

MCDataAtom *MCDataAtom::split(uint64_t SplitPt) {
  uint64_t LBegin, LEnd, RBegin, REnd;
  remapForSplit(SplitPt, LBegin, LEnd, RBegin, REnd);

  MCDataAtom *RightAtom = Parent->createDataAtom(RBegin, REnd);
  RightAtom->setName(getName());

  std::vector<MCData>::iterator I = Data.begin() + (RBegin - LBegin);
  assert(I != Data.end() && "Split point not found in range!");

  std::copy(I, Data.end(), std::back_inserter(RightAtom->Data));
  Data.erase(I, Data.end());
  return RightAtom;
}

// MCTextAtom

void MCTextAtom::addInst(const MCInst &I, uint64_t Size) {
  if (NextInstAddress + Size - 1 > End)
    remap(Begin, NextInstAddress + Size - 1);
  Insts.push_back(MCDecodedInst(I, NextInstAddress, Size));
  NextInstAddress += Size;
}

void MCTextAtom::truncate(uint64_t TruncPt) {
  remapForTruncate(TruncPt);

  InstListTy::iterator I = Insts.begin();
  while (I != Insts.end() && I->Address <= TruncPt) ++I;

  assert(I != Insts.end() && "Truncation point not found in disassembly!");
  assert(I->Address == TruncPt + 1 &&
         "Truncation point does not fall on instruction boundary");

  Insts.erase(I, Insts.end());
}

MCTextAtom *MCTextAtom::split(uint64_t SplitPt) {
  uint64_t LBegin, LEnd, RBegin, REnd;
  remapForSplit(SplitPt, LBegin, LEnd, RBegin, REnd);

  MCTextAtom *RightAtom = Parent->createTextAtom(RBegin, REnd);
  RightAtom->setName(getName());

  InstListTy::iterator I = Insts.begin();
  while (I != Insts.end() && I->Address < SplitPt) ++I;
  assert(I != Insts.end() && "Split point not found in disassembly!");
  assert(I->Address == SplitPt &&
         "Split point does not fall on instruction boundary!");

  std::copy(I, Insts.end(), std::back_inserter(RightAtom->Insts));
  Insts.erase(I, Insts.end());
  Parent->splitBasicBlocksForAtom(this, RightAtom);
  return RightAtom;
}
