#include "llvm/CodeGen/BasicBlockSectionsProfileReader.h"
#include "llvm/ADT/SmallSet.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringMap.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/Support/Error.h"
#include "llvm/Support/LineIterator.h"
#include "llvm/Support/MemoryBuffer.h"
using namespace llvm;
char BasicBlockSectionsProfileReader::ID = 0;
INITIALIZE_PASS(BasicBlockSectionsProfileReader, "bbsections-profile-reader",
                "Reads and parses a basic block sections profile.", false,
                false)
bool BasicBlockSectionsProfileReader::isFunctionHot(StringRef FuncName) const {
  return getBBClusterInfoForFunction(FuncName).first;
}
std::pair<bool, SmallVector<BBClusterInfo>>
BasicBlockSectionsProfileReader::getBBClusterInfoForFunction(
    StringRef FuncName) const {
  std::pair<bool, SmallVector<BBClusterInfo>> cluster_info(false, {});
  auto R = ProgramBBClusterInfo.find(getAliasName(FuncName));
  if (R != ProgramBBClusterInfo.end()) {
    cluster_info.second = R->second;
    cluster_info.first = true;
  }
  return cluster_info;
}
static Error getBBClusterInfo(const MemoryBuffer *MBuf,
                              ProgramBBClusterInfoMapTy &ProgramBBClusterInfo,
                              StringMap<StringRef> &FuncAliasMap) {
  assert(MBuf);
  line_iterator LineIt(*MBuf, true, '#');
  auto invalidProfileError = [&](auto Message) {
    return make_error<StringError>(
        Twine("Invalid profile " + MBuf->getBufferIdentifier() + " at line " +
              Twine(LineIt.line_number()) + ": " + Message),
        inconvertibleErrorCode());
  };
  auto FI = ProgramBBClusterInfo.end();
    unsigned CurrentCluster = 0;
    unsigned CurrentPosition = 0;
      SmallSet<unsigned, 4> FuncBBIDs;
  for (; !LineIt.is_at_eof(); ++LineIt) {
    StringRef S(*LineIt);
    if (S[0] == '@')
      continue;
        if (!S.consume_front("!") || S.empty())
      break;
        if (S.consume_front("!")) {
      if (FI == ProgramBBClusterInfo.end())
        return invalidProfileError(
            "Cluster list does not follow a function name specifier.");
      SmallVector<StringRef, 4> BBIndexes;
      S.split(BBIndexes, ' ');
            CurrentPosition = 0;
      for (auto BBIndexStr : BBIndexes) {
        unsigned long long BBIndex;
        if (getAsUnsignedInteger(BBIndexStr, 10, BBIndex))
          return invalidProfileError(Twine("Unsigned integer expected: '") +
                                     BBIndexStr + "'.");
        if (!FuncBBIDs.insert(BBIndex).second)
          return invalidProfileError(Twine("Duplicate basic block id found '") +
                                     BBIndexStr + "'.");
        if (!BBIndex && CurrentPosition)
          return invalidProfileError("Entry BB (0) does not begin a cluster.");
        FI->second.emplace_back(BBClusterInfo{
            ((unsigned)BBIndex), CurrentCluster, CurrentPosition++});
      }
      CurrentCluster++;
    } else {                         SmallVector<StringRef, 4> Aliases;
      S.split(Aliases, '/');
      for (size_t i = 1; i < Aliases.size(); ++i)
        FuncAliasMap.try_emplace(Aliases[i], Aliases.front());
                  FI = ProgramBBClusterInfo.try_emplace(Aliases.front()).first;
      CurrentCluster = 0;
      FuncBBIDs.clear();
    }
  }
  return Error::success();
}
void BasicBlockSectionsProfileReader::initializePass() {
  if (!MBuf)
    return;
  if (auto Err = getBBClusterInfo(MBuf, ProgramBBClusterInfo, FuncAliasMap))
    report_fatal_error(std::move(Err));
}
ImmutablePass *
llvm::createBasicBlockSectionsProfileReaderPass(const MemoryBuffer *Buf) {
  return new BasicBlockSectionsProfileReader(Buf);
}