Compiler projects using llvm
//===-- llvm/BinaryFormat/XCOFF.cpp - The XCOFF file format -----*- C++/-*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

#include "llvm/BinaryFormat/XCOFF.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/Support/Errc.h"
#include "llvm/Support/Error.h"

using namespace llvm;

#define SMC_CASE(A)                                                            \
  case XCOFF::XMC_##A:                                                         \
    return #A;
StringRef XCOFF::getMappingClassString(XCOFF::StorageMappingClass SMC) {
  switch (SMC) {
    SMC_CASE(PR)
    SMC_CASE(RO)
    SMC_CASE(DB)
    SMC_CASE(GL)
    SMC_CASE(XO)
    SMC_CASE(SV)
    SMC_CASE(SV64)
    SMC_CASE(SV3264)
    SMC_CASE(TI)
    SMC_CASE(TB)
    SMC_CASE(RW)
    SMC_CASE(TC0)
    SMC_CASE(TC)
    SMC_CASE(TD)
    SMC_CASE(DS)
    SMC_CASE(UA)
    SMC_CASE(BS)
    SMC_CASE(UC)
    SMC_CASE(TL)
    SMC_CASE(UL)
    SMC_CASE(TE)
#undef SMC_CASE
  }

  // TODO: need to add a test case for "Unknown" and other SMC.
  return "Unknown";
}

#define RELOC_CASE(A)                                                          \
  case XCOFF::A:                                                               \
    return #A;
StringRef XCOFF::getRelocationTypeString(XCOFF::RelocationType Type) {
  switch (Type) {
    RELOC_CASE(R_POS)
    RELOC_CASE(R_RL)
    RELOC_CASE(R_RLA)
    RELOC_CASE(R_NEG)
    RELOC_CASE(R_REL)
    RELOC_CASE(R_TOC)
    RELOC_CASE(R_TRL)
    RELOC_CASE(R_TRLA)
    RELOC_CASE(R_GL)
    RELOC_CASE(R_TCL)
    RELOC_CASE(R_REF)
    RELOC_CASE(R_BA)
    RELOC_CASE(R_BR)
    RELOC_CASE(R_RBA)
    RELOC_CASE(R_RBR)
    RELOC_CASE(R_TLS)
    RELOC_CASE(R_TLS_IE)
    RELOC_CASE(R_TLS_LD)
    RELOC_CASE(R_TLS_LE)
    RELOC_CASE(R_TLSM)
    RELOC_CASE(R_TLSML)
    RELOC_CASE(R_TOCU)
    RELOC_CASE(R_TOCL)
  }
  return "Unknown";
}
#undef RELOC_CASE

#define LANG_CASE(A)                                                           \
  case XCOFF::TracebackTable::A:                                               \
    return #A;

StringRef XCOFF::getNameForTracebackTableLanguageId(
    XCOFF::TracebackTable::LanguageID LangId) {
  switch (LangId) {
    LANG_CASE(C)
    LANG_CASE(Fortran)
    LANG_CASE(Pascal)
    LANG_CASE(Ada)
    LANG_CASE(PL1)
    LANG_CASE(Basic)
    LANG_CASE(Lisp)
    LANG_CASE(Cobol)
    LANG_CASE(Modula2)
    LANG_CASE(Rpg)
    LANG_CASE(PL8)
    LANG_CASE(Assembly)
    LANG_CASE(Java)
    LANG_CASE(ObjectiveC)
    LANG_CASE(CPlusPlus)
  }
  return "Unknown";
}
#undef LANG_CASE

Expected<SmallString<32>> XCOFF::parseParmsType(uint32_t Value,
                                                unsigned FixedParmsNum,
                                                unsigned FloatingParmsNum) {
  SmallString<32> ParmsType;
  int Bits = 0;
  unsigned ParsedFixedNum = 0;
  unsigned ParsedFloatingNum = 0;
  unsigned ParsedNum = 0;
  unsigned ParmsNum = FixedParmsNum + FloatingParmsNum;

  // In the function PPCFunctionInfo::getParmsType(), when there are no vector
  // parameters, the 31st bit of ParmsType is always zero even if it indicates a
  // floating point parameter. The parameter type information is lost. There
  // are only 8 GPRs used for parameters passing, the floating parameters
  // also occupy GPRs if there are available, so the 31st bit can never be a
  // fixed parameter. At the same time, we also do not know whether the zero of
  // the 31st bit indicates a float or double parameter type here. Therefore, we
  // ignore the 31st bit.
  while (Bits < 31 && ParsedNum < ParmsNum) {
    if (++ParsedNum > 1)
      ParmsType += ", ";
    if ((Value & TracebackTable::ParmTypeIsFloatingBit) == 0) {
      // Fixed parameter type.
      ParmsType += "i";
      ++ParsedFixedNum;
      Value <<= 1;
      ++Bits;
    } else {
      if ((Value & TracebackTable::ParmTypeFloatingIsDoubleBit) == 0)
        // Float parameter type.
        ParmsType += "f";
      else
        // Double parameter type.
        ParmsType += "d";
      ++ParsedFloatingNum;
      Value <<= 2;
      Bits += 2;
    }
  }

  // We have more parameters than the 32 Bits could encode.
  if (ParsedNum < ParmsNum)
    ParmsType += ", ...";

  if (Value != 0u || ParsedFixedNum > FixedParmsNum ||
      ParsedFloatingNum > FloatingParmsNum)
    return createStringError(errc::invalid_argument,
                             "ParmsType encodes can not map to ParmsNum "
                             "parameters in parseParmsType.");
  return ParmsType;
}

SmallString<32> XCOFF::getExtendedTBTableFlagString(uint8_t Flag) {
  SmallString<32> Res;

  if (Flag & ExtendedTBTableFlag::TB_OS1)
    Res += "TB_OS1 ";
  if (Flag & ExtendedTBTableFlag::TB_RESERVED)
    Res += "TB_RESERVED ";
  if (Flag & ExtendedTBTableFlag::TB_SSP_CANARY)
    Res += "TB_SSP_CANARY ";
  if (Flag & ExtendedTBTableFlag::TB_OS2)
    Res += "TB_OS2 ";
  if (Flag & ExtendedTBTableFlag::TB_EH_INFO)
    Res += "TB_EH_INFO ";
  if (Flag & ExtendedTBTableFlag::TB_LONGTBTABLE2)
    Res += "TB_LONGTBTABLE2 ";

  // Two of the bits that haven't got used in the mask.
  if (Flag & 0x06)
    Res += "Unknown ";

  // Pop the last space.
  Res.pop_back();
  return Res;
}

Expected<SmallString<32>>
XCOFF::parseParmsTypeWithVecInfo(uint32_t Value, unsigned FixedParmsNum,
                                 unsigned FloatingParmsNum,
                                 unsigned VectorParmsNum) {
  SmallString<32> ParmsType;

  unsigned ParsedFixedNum = 0;
  unsigned ParsedFloatingNum = 0;
  unsigned ParsedVectorNum = 0;
  unsigned ParsedNum = 0;
  unsigned ParmsNum = FixedParmsNum + FloatingParmsNum + VectorParmsNum;

  for (int Bits = 0; Bits < 32 && ParsedNum < ParmsNum; Bits += 2) {
    if (++ParsedNum > 1)
      ParmsType += ", ";

    switch (Value & TracebackTable::ParmTypeMask) {
    case TracebackTable::ParmTypeIsFixedBits:
      ParmsType += "i";
      ++ParsedFixedNum;
      break;
    case TracebackTable::ParmTypeIsVectorBits:
      ParmsType += "v";
      ++ParsedVectorNum;
      break;
    case TracebackTable::ParmTypeIsFloatingBits:
      ParmsType += "f";
      ++ParsedFloatingNum;
      break;
    case TracebackTable::ParmTypeIsDoubleBits:
      ParmsType += "d";
      ++ParsedFloatingNum;
      break;
    default:
      assert(false && "Unrecognized bits in ParmsType.");
    }
    Value <<= 2;
  }

  // We have more parameters than the 32 Bits could encode.
  if (ParsedNum < ParmsNum)
    ParmsType += ", ...";

  if (Value != 0u || ParsedFixedNum > FixedParmsNum ||
      ParsedFloatingNum > FloatingParmsNum || ParsedVectorNum > VectorParmsNum)
    return createStringError(
        errc::invalid_argument,
        "ParmsType encodes can not map to ParmsNum parameters "
        "in parseParmsTypeWithVecInfo.");

  return ParmsType;
}

Expected<SmallString<32>> XCOFF::parseVectorParmsType(uint32_t Value,
                                                      unsigned ParmsNum) {
  SmallString<32> ParmsType;
  unsigned ParsedNum = 0;
  for (int Bits = 0; ParsedNum < ParmsNum && Bits < 32; Bits += 2) {
    if (++ParsedNum > 1)
      ParmsType += ", ";
    switch (Value & TracebackTable::ParmTypeMask) {
    case TracebackTable::ParmTypeIsVectorCharBit:
      ParmsType += "vc";
      break;

    case TracebackTable::ParmTypeIsVectorShortBit:
      ParmsType += "vs";
      break;

    case TracebackTable::ParmTypeIsVectorIntBit:
      ParmsType += "vi";
      break;

    case TracebackTable::ParmTypeIsVectorFloatBit:
      ParmsType += "vf";
      break;
    }

    Value <<= 2;
  }

  // We have more parameters than the 32 Bits could encode.
  if (ParsedNum < ParmsNum)
    ParmsType += ", ...";

  if (Value != 0u)
    return createStringError(errc::invalid_argument,
                             "ParmsType encodes more than ParmsNum parameters "
                             "in parseVectorParmsType.");
  return ParmsType;
}