text: //===- ARMELFAttributeData.h ----------------------------------------------===//
  //
  //                     The MCLinker Project
  //
  // This file is distributed under the University of Illinois Open Source
  // License. See LICENSE.TXT for details.
  //
  //===----------------------------------------------------------------------===//
  #include "ARMELFAttributeData.h"
  
  #include <mcld/MC/Input.h>
  #include <mcld/Support/LEB128.h>
  #include <mcld/Support/MsgHandling.h>
  
  using namespace mcld;
  
  const ELFAttributeValue *ARMELFAttributeData::getAttributeValue(TagType pTag) const
  {
    if (pTag <= Tag_Max) {
      const ELFAttributeValue &attr_value = m_Attrs[pTag];
  
      if (attr_value.isInitialized()) {
        return &attr_value;
      } else {
        // Don't return uninitialized attribute value.
        return NULL;
      }
    } else {
      UnknownAttrsMap::const_iterator attr_it = m_UnknownAttrs.find(pTag);
  
      if (attr_it == m_UnknownAttrs.end()) {
        return NULL;
      } else {
        return &attr_it->second;
      }
    }
  }
  
  std::pair<ELFAttributeValue*, bool>
  ARMELFAttributeData::getOrCreateAttributeValue(TagType pTag)
  {
    ELFAttributeValue *attr_value = NULL;
  
    if (pTag <= Tag_Max) {
      attr_value = &m_Attrs[pTag];
    } else {
      // An unknown tag encounterred.
      attr_value = &m_UnknownAttrs[pTag];
    }
  
    assert(attr_value != NULL);
  
    // Setup the value type.
    if (!attr_value->isUninitialized()) {
      return std::make_pair(attr_value, false);
    } else {
      attr_value->setType(GetAttributeValueType(pTag));
      return std::make_pair(attr_value, true);
    }
  }
  
  unsigned int ARMELFAttributeData::GetAttributeValueType(TagType pTag)
  {
    // See ARM [ABI-addenda], 2.2.6.
    switch (pTag) {
      case Tag_compatibility: {
        return (ELFAttributeValue::Int | ELFAttributeValue::String);
      }
      case Tag_nodefaults: {
        return (ELFAttributeValue::Int | ELFAttributeValue::NoDefault);
      }
      case Tag_CPU_raw_name:
      case Tag_CPU_name: {
        return ELFAttributeValue::String;
      }
      default: {
        if (pTag < 32)
          return ELFAttributeValue::Int;
        else
          return ((pTag & 1) ? ELFAttributeValue::String :
                               ELFAttributeValue::Int);
      }
    }
    // unreachable
  }
  
  //===--------------------------------------------------------------------===//
  // Helper Functions for merge()
  //===--------------------------------------------------------------------===//
  
  namespace {
  
  /*
   * Helper function to decode value in Tag_also_compatible_with.
   *
   * @ref ARM [ABI-addenda], 2.3.7.3
   */
  static int
  decode_secondary_compatibility_attribute(const ELFAttributeValue &pValue)
  {
    // The encoding of Tag_also_compatible_with is:
    //
    // Tag_also_compatible_with (=65), NTSB: data
    //
    // The data can be either an ULEB128-encoded number followed by a NULL byte or
    // a NULL-terminated string. Currently, only the following byte sequence in
    // data are currently defined:
    //
    // Tag_CPU_arch (=6) [The arch] 0
    assert((pValue.type() == ELFAttributeValue::String) &&
           "Value of Tag_also_compatible_with must be a string!");
  
    const std::string &data = pValue.getStringValue();
  
    // Though the integer is in LEB128 format, but they occupy only 1 byte in
    // currently defined value.
    if (data.length() < 2)
      // Must have a byte for Tag_CPU_arch (=6)
      //           a byte for specifying the CPU architecture (CPU_Arch_ARM_*)
      //
      // Currently, the 2nd byte can only be v4T (=2) or v6-M (=11).
      return -1;
  
    if ((static_cast<uint8_t>(data[0]) == ARMELFAttributeData::Tag_CPU_arch) &&
        ((data[1] == ARMELFAttributeData::CPU_Arch_ARM_V4T) ||
         (data[1] == ARMELFAttributeData::CPU_Arch_ARM_V6_M)))
      return static_cast<uint32_t>(data[1]);
  
    // Tag_also_compatible_with can be safely ignored.
    return -1;
  }
  
  /*
   * This helper array keeps the ordering of the values in attributes such as
   * Tag_ABI_align_needed which are sored as 1 > 2 > 0.
   */
  static const int value_ordering_120[] = { 0, 2, 1 };
  
  } // anonymous namespace
  
  //===--------------------------------------------------------------------===//
  // End Helper Functions for merge()
  //===--------------------------------------------------------------------===//
  
  bool ARMELFAttributeData::merge(const Input &pInput, TagType pTag,
                                  const ELFAttributeValue& pInAttr)
  {
    // Pre-condition
    //  1. The out_attr must be initailized and has value of the same type as
    //     pInAttr.
    //  2. The value helf by out_attr and pInAttr must be different.
    ELFAttributeValue &out_attr = m_Attrs[pTag];
  
    // Attribute in the output must have value assigned.
    assert(out_attr.isInitialized() && "No output attribute to be merged!");
  
    switch (pTag) {
      case Tag_CPU_arch: {
        // Need value of Tag_also_compatible_with in the input for merge.
        if (pInAttr.getIntValue() <= CPU_Arch_Max) {
          m_CPUArch = pInAttr.getIntValue();
        } else {
          error(diag::error_unknown_cpu_arch) << pInput.name();
          return false;
        }
        break;
      }
      case Tag_CPU_name: {
        // need value of Tag_CPU_arch in the input for merge
        m_CPUName = pInAttr.getStringValue();
        break;
      }
      case Tag_CPU_raw_name: {
        // need value of Tag_CPU_arch in the input for merge
        m_CPURawName = pInAttr.getStringValue();
        break;
      }
      case Tag_FP_arch: {
        // need value of Tag_HardFP_use in the input for merge
        m_FPArch = pInAttr.getIntValue();
        break;
      }
      case Tag_ABI_HardFP_use: {
        // need value of Tag_FP_arch in the input for merge
        m_HardFPUse = pInAttr.getIntValue();
        break;
      }
      case Tag_also_compatible_with: {
        // need value of Tag_CPU_arch in the input for merge
        m_SecondaryCPUArch = decode_secondary_compatibility_attribute(pInAttr);
        break;
      }
      case Tag_ABI_VFP_args: {
        // need value of Tag_ABI_FP_number_model in the input for merge
        m_VFPArgs = pInAttr.getIntValue();
        break;
      }
      // The value of these tags are integers and after merge, only the greatest
      // value held by pInAttr and out_attr goes into output.
      case Tag_ARM_ISA_use:
      case Tag_THUMB_ISA_use:
      case Tag_WMMX_arch:
      case Tag_Advanced_SIMD_arch:
      case Tag_ABI_FP_rounding:
      case Tag_ABI_FP_exceptions:
      case Tag_ABI_FP_user_exceptions:
      case Tag_ABI_FP_number_model:
      case Tag_FP_HP_extension:
      case Tag_CPU_unaligned_access:
      case Tag_T2EE_use: {
        assert((out_attr.type() == ELFAttributeValue::Int) &&
               (pInAttr.type() == ELFAttributeValue::Int) &&
                "should have integer parameeter!");
        if (pInAttr.getIntValue() > out_attr.getIntValue())
          out_attr.setIntValue(pInAttr.getIntValue());
        break;
      }
      // The value of these tags are integers and after merge, only the smallest
      // value held by pInAttr and out_attr goes into output.
      case Tag_ABI_align_preserved:
      case Tag_ABI_PCS_RO_data: {
        assert((out_attr.type() == ELFAttributeValue::Int) &&
               (pInAttr.type() == ELFAttributeValue::Int) &&
                "should have integer parameeter!");
        if (pInAttr.getIntValue() < out_attr.getIntValue())
          out_attr.setIntValue(pInAttr.getIntValue());
        break;
      }
      // The values of these attributes are sorted as 1 > 2 > 0. And the greater
      // value becomes output.
      case Tag_ABI_align_needed:
      case Tag_ABI_FP_denormal:
      case Tag_ABI_PCS_GOT_use: {
        const int in_val = pInAttr.getIntValue();
        const int out_val = out_attr.getIntValue();
  
        if (in_val <= 2) {
          if (out_val <= 2) {
            // Use value_ordering_120 to determine the ordering.
            if (value_ordering_120[in_val] > value_ordering_120[out_val]) {
              out_attr.setIntValue(in_val);
            }
          }
        } else {
          // input value > 2, for future-proofing
          if (in_val > out_val) {
            out_attr.setIntValue(in_val);
          }
        }
        break;
      }
      // These tags use the first value ever seen.
      case Tag_ABI_optimization_goals:
      case Tag_ABI_FP_optimization_goals: {
        break;
      }
      // Tag_CPU_arch_profile
      case Tag_CPU_arch_profile: {
        if (pInAttr.getIntValue() == Arch_Profile_None)
          return true;
  
        switch (out_attr.getIntValue()) {
          case Arch_Profile_None: {
            out_attr.setIntValue(pInAttr.getIntValue());
            break;
          }
          case Arch_Profile_RealOrApp: {
            if (pInAttr.getIntValue() != Arch_Profile_Microcontroller)
              out_attr.setIntValue(pInAttr.getIntValue());
            else
              warning(diag::warn_mismatch_cpu_arch_profile)
                  << pInAttr.getIntValue() << pInput.name();
            break;
          }
          default: {
            // out_attr is Arch_Profile_Application or Arch_Profile_Realtime or
            // Arch_Profile_Microcontroller.
            if ((pInAttr.getIntValue() == Arch_Profile_RealOrApp) &&
                (out_attr.getIntValue() != Arch_Profile_Microcontroller)) {
              // do nothing
            } else {
              warning(diag::warn_mismatch_cpu_arch_profile)
                  << pInAttr.getIntValue() << pInput.name();
            }
            break;
          }
        }
        break;
      }
      // Tag_MPextension_use and Tag_MPextension_use_legacy
      case Tag_MPextension_use:
      case Tag_MPextension_use_legacy: {
        if (m_MPextensionUse < 0) {
          m_MPextensionUse = pInAttr.getIntValue();
        } else {
          if (static_cast<unsigned>(m_MPextensionUse) != pInAttr.getIntValue()) {
            warning(diag::error_mismatch_mpextension_use) << pInput.name();
          }
        }
        break;
      }
      // Tag_DIV_use
      case Tag_DIV_use: {
        if (pInAttr.getIntValue() == 2) {
          // 2 means the code was permitted to use SDIV/UDIV in anyway.
          out_attr.setIntValue(2);
        } else {
          // Merge until settling down Tag_CPU_arch.
          m_DIVUse = pInAttr.getIntValue();
        }
        break;
      }
      // Tag_ABI_enum_size
      case Tag_ABI_enum_size: {
        if ((out_attr.getIntValue() == Enum_Unused) ||
            (out_attr.getIntValue() == Enum_Containerized_As_Possible))
          out_attr.setIntValue(pInAttr.getIntValue());
        else if (pInAttr.getIntValue() != Enum_Containerized_As_Possible)
          warning(diag::warn_mismatch_enum_size)
              << pInput.name() << pInAttr.getIntValue()
              << out_attr.getIntValue();
        break;
      }
      // Tag_ABI_FP_16bit_format
      case Tag_ABI_FP_16bit_format: {
        // 0: doesn't use any 16-bit FP number
        // 1: use IEEE 754 format 16-bit FP number
        // 2: use VFPv3/Advanced SIMD "alternative format" 16-bit FP number
        if (pInAttr.getIntValue() != 0) {
          if (out_attr.getIntValue() == 0) {
            out_attr.setIntValue(pInAttr.getIntValue());
          } else {
            warning(diag::warn_mismatch_fp16_format) << pInput.name();
          }
        }
        break;
      }
      // Tag_nodefaults
      case Tag_nodefaults: {
        // There's nothing to do for this tag. It doesn't have an actual value.
        break;
      }
      // Tag_conformance
      case Tag_conformance: {
        // Throw away the value if the attribute value doesn't match.
        if (out_attr.getStringValue() != pInAttr.getStringValue())
          out_attr.setStringValue("");
        break;
      }
      // Tag_Virtualization_use
      case Tag_Virtualization_use: {
        // 0: No use of any virtualization extension
        // 1: TrustZone
        // 2: Virtualization extension such as HVC and ERET
        // 3: TrustZone and virtualization extension are permitted
        if (pInAttr.getIntValue() != 0) {
          if (out_attr.getIntValue() == 0) {
            out_attr.setIntValue(pInAttr.getIntValue());
          } else {
            if ((out_attr.getIntValue() <= 3) && (pInAttr.getIntValue() <= 3)) {
              // Promote to 3
              out_attr.setIntValue(3);
            } else {
              warning(diag::warn_unrecognized_virtualization_use)
                  << pInput.name() << pInAttr.getIntValue();
            }
          }
        }
        break;
      }
      // Tag_ABI_WMMX_args
      case Tag_ABI_WMMX_args: {
        // There's no way to merge this value (i.e., objects contain different
        // value in this tag are definitely incompatible.)
        warning(diag::warn_mismatch_abi_wmmx_args) << pInput.name();
        break;
      }
      // Tag_PCS_config
      case Tag_PCS_config: {
        // 0 means no standard configuration used or no information recorded.
        if (pInAttr.getIntValue() != 0) {
          if (out_attr.getIntValue() == 0)
            out_attr.setIntValue(pInAttr.getIntValue());
          else
            // Different values in these attribute are conflict
            warning(diag::warn_mismatch_pcs_config) << pInput.name();
        }
        break;
      }
      // Tag_ABI_PCS_R9_use
      case Tag_ABI_PCS_R9_use: {
        if (pInAttr.getIntValue() != R9_Unused) {
          if (out_attr.getIntValue() == R9_Unused)
            out_attr.setIntValue(pInAttr.getIntValue());
          else
            warning(diag::warn_mismatch_r9_use) << pInput.name();
        }
        break;
      }
      // Tag_ABI_PCS_RW_data
      case Tag_ABI_PCS_RW_data: {
        if (pInAttr.getIntValue() == RW_data_SB_Relative) {
          // Require using R9 as SB (global Static Base register).
          if ((out_attr.getIntValue() != R9_Unused) &&
              (out_attr.getIntValue() != R9_SB))
            warning(diag::warn_mismatch_r9_use) << pInput.name();
        }
        // Choose the smaller value
        if (pInAttr.getIntValue() < out_attr.getIntValue())
          out_attr.setIntValue(pInAttr.getIntValue());
        break;
      }
      // Tag_ABI_PCS_wchar_t
      case Tag_ABI_PCS_wchar_t: {
        // 0: no use of wchar_t
        // 2: sizeof(wchar_t) = 2
        // 4: sizeof(wchar_t) = 4
        if (pInAttr.getIntValue() != 0) {
          if (out_attr.getIntValue() == 0)
            out_attr.setIntValue(pInAttr.getIntValue());
          else
            warning(diag::warn_mismatch_wchar_size)
                << pInput.name() << pInAttr.getIntValue()
                << out_attr.getIntValue();
        }
        break;
      }
      default: {
        // Handle unknown attributes:
        //
        // Since we don't know how to merge the value of unknown attribute, we
        // have to ignore it. There're two rules related to the processing (See
        // ARM [ABI-addenda] 2.2.6, Coding extensibility and compatibility.):
        //
        // 1. For tag N where N >= 128, tag N has the same properties as
        //    tag N % 128.
        // 2. Tag 64-127 can be safely ignored.
        // 3. Tag 0-63 must be comprehended, therefore we cannot ignore.
        if ((pTag & 127) < 64) {
          warning(diag::warn_unknown_mandatory_attribute) << pTag << pInput.name();
        } else {
          warning(diag::warn_unknown_attribute) << pTag << pInput.name();
        }
        break;
      }
    }
    return true;
  }
  
  //===--------------------------------------------------------------------===//
  // Helper Functions for postMerge()
  //===--------------------------------------------------------------------===//
  
  namespace {
  
  /*
   * Helper function to encode value in Tag_also_compatible_with.
   *
   * @ref ARM [ABI-addenda], 2.3.7.3
   */
  static void
  encode_secondary_compatibility_attribute(ELFAttributeValue &pValue, int pArch)
  {
    if ((pArch < 0) || (pArch > ARMELFAttributeData::CPU_Arch_Max)) {
      pValue.setStringValue("");
    } else {
      char new_value[] = {
          ARMELFAttributeData::Tag_CPU_arch,
          static_cast<char>(pArch),
          0
      };
      pValue.setStringValue(std::string(new_value, sizeof(new_value)));
    }
    return;
  }
  
  /*
   * Combine the main and secondary CPU arch value
   */
  static int
  calculate_cpu_arch(int cpu_arch, int secondary_arch)
  {
    // short-circuit
    if ((secondary_arch < 0) ||
        ((cpu_arch + secondary_arch) != (ARMELFAttributeData::CPU_Arch_ARM_V4T +
                                         ARMELFAttributeData::CPU_Arch_ARM_V6_M)))
      return cpu_arch;
  
    if ((cpu_arch == ARMELFAttributeData::CPU_Arch_ARM_V4T) &&
        (secondary_arch == ARMELFAttributeData::CPU_Arch_ARM_V6_M))
      return ARMELFAttributeData::CPU_Arch_ARM_V4T_Plus_V6_M;
    else if ((cpu_arch == ARMELFAttributeData::CPU_Arch_ARM_V6_M) &&
             (secondary_arch == ARMELFAttributeData::CPU_Arch_ARM_V4T))
      return ARMELFAttributeData::CPU_Arch_ARM_V4T_Plus_V6_M;
    else
      return cpu_arch;
  }
  
  /*
   * Given a CPU arch X and a CPU arch Y in which Y is newer than X, the value in
   * cpu_compatibility_table[X][Y] is the CPU arch required to run ISA both from X
   * and Y. 0 in the table means unreachable and -1 means conflict architecture
   * profile.
   */
  #define CPU(C)  ARMELFAttributeData::CPU_Arch_ARM_ ## C
  static const int cpu_compatibility_table[][CPU(V4T_Plus_V6_M) + 1] =
  {
    /* old\new          ARM v6T2    ARM v6K   ARM v7   ARM v6-M   ARM v6S-M   ARM v7E-M    ARMv8, ARM v4t + v6-M     */
    /* Pre v4     */ { CPU(V6T2),  CPU(V6K), CPU(V7),        -1,         -1,         -1,      -1,       -1           },
    /* ARM v4     */ { CPU(V6T2),  CPU(V6K), CPU(V7),        -1,         -1,         -1,      -1,       -1           },
    /* ARM v4T    */ { CPU(V6T2),  CPU(V6K), CPU(V7),  CPU(V6K),   CPU(V6K), CPU(V7E_M), CPU(V8), CPU(V4T)           },
    /* ARM v5T    */ { CPU(V6T2),  CPU(V6K), CPU(V7),  CPU(V6K),   CPU(V6K), CPU(V7E_M), CPU(V8), CPU(V5T)           },
    /* ARM v5TE   */ { CPU(V6T2),  CPU(V6K), CPU(V7),  CPU(V6K),   CPU(V6K), CPU(V7E_M), CPU(V8), CPU(V5TE)          },
    /* ARM v5TEJ  */ { CPU(V6T2),  CPU(V6K), CPU(V7),  CPU(V6K),   CPU(V6K), CPU(V7E_M), CPU(V8), CPU(V5TEJ)         },
    /* ARM v6     */ { CPU(V6T2),  CPU(V6K), CPU(V7),  CPU(V6K),   CPU(V6K), CPU(V7E_M), CPU(V8), CPU(V6)            },
    /* ARM v6KZ   */ {   CPU(V7), CPU(V6KZ), CPU(V7), CPU(V6KZ),  CPU(V6KZ), CPU(V7E_M), CPU(V8), CPU(V6KZ)          },
    /* ARM v6T2   */ { CPU(V6T2),   CPU(V7), CPU(V7),   CPU(V7),    CPU(V7), CPU(V7E_M), CPU(V8), CPU(V6T2)          },
    /* ARM v6K    */ {         0,  CPU(V6K), CPU(V7),  CPU(V6K),   CPU(V6K), CPU(V7E_M), CPU(V8), CPU(V6K)           },
    /* ARM v7     */ {         0,         0, CPU(V7),   CPU(V7),    CPU(V7), CPU(V7E_M), CPU(V8), CPU(V7)            },
    /* ARM v6-M   */ {         0,         0,       0, CPU(V6_M), CPU(V6S_M), CPU(V7E_M), CPU(V8), CPU(V6_M)          },
    /* ARM v6S-M  */ {         0,         0,       0,         0, CPU(V6S_M), CPU(V7E_M), CPU(V8), CPU(V6S_M)         },
    /* ARM v7E-M  */ {         0,         0,       0,         0,          0, CPU(V7E_M), CPU(V8), CPU(V7E_M)         },
    /* ARM v8     */ {         0,         0,       0,         0,          0,          0, CPU(V8), CPU(V8)            },
    /* v4T + v6-M */ {         0,         0,       0,         0,          0,          0,       0, CPU(V4T_Plus_V6_M) }
  };
  
  /*
   * Helper function to determine the merge of two different CPU arch.
   */
  static int merge_cpu_arch(int out_cpu_arch, int in_cpu_arch)
  {
    if (out_cpu_arch > CPU(V4T_Plus_V6_M))
      return in_cpu_arch;
  
    int new_cpu_arch, old_cpu_arch;
    if (out_cpu_arch > in_cpu_arch) {
      new_cpu_arch = out_cpu_arch;
      old_cpu_arch = in_cpu_arch;
    } else {
      new_cpu_arch = in_cpu_arch;
      old_cpu_arch = out_cpu_arch;
    }
  
    // No need to check the compatibility since the CPU architectures before
    // V6KZ add features monotonically.
    if (new_cpu_arch <= CPU(V6KZ))
      return new_cpu_arch;
  
    return cpu_compatibility_table[old_cpu_arch][new_cpu_arch - CPU(V6T2)];
  }
  #undef CPU
  
  /*
   * Generic CPU name is used when Tag_CPU_name is unable to guess during the
   * merge of Tag_CPU_arch.
   */
  static const char* generic_cpu_name_table[] = {
    /* Pre v4    */"Pre v4",
    /* Pre v4    */"ARM v4",
    /* ARM v4T   */"ARM v4T",
    /* ARM v5T   */"ARM v5T",
    /* ARM v5TE  */"ARM v5TE",
    /* ARM v5TEJ */"ARM v5TEJ",
    /* ARM v6    */"ARM v6",
    /* ARM v6KZ  */"ARM v6KZ",
    /* ARM v6T2  */"ARM v6T2",
    /* ARM v6K   */"ARM v6K",
    /* ARM v7    */"ARM v7",
    /* ARM v6-M  */"ARM v6-M",
    /* ARM v6S-M */"ARM v6S-M",
    /* ARM v7E-M */"ARM v7E-M",
    /* ARM v8    */"ARM v8",
  };
  
  static const char* get_generic_cpu_name(int cpu_arch) {
    assert(cpu_arch < sizeof(generic_cpu_name_table) / sizeof(generic_cpu_name_table[0]));
    return generic_cpu_name_table[cpu_arch];
  }
  
  /*
   * Helper functions & data used in the merge of two different FP arch.
   */
  static const struct fp_config_data {
    int version;
    int regs;
  } fp_configs[] = {
    { 0, 0  },
    { 1, 16 },
    { 2, 16 },
    { 3, 32 },
    { 3, 16 },
    { 4, 32 },
    { 4, 16 },
    { 8, 32 },
    { 8, 16 },
  };
  
  static const size_t num_fp_configs =
      sizeof(fp_configs) / sizeof(fp_config_data);
  
  // Given h(x, y) = (x * (y >> 4) + (y >> 5))
  //
  // fp_config_hash_table[ h(0, 0)  =  0 ] = 0
  // fp_config_hash_table[ h(1, 16) =  1 ] = 1
  // fp_config_hash_table[ h(2, 16) =  2 ] = 2
  // fp_config_hash_table[ h(3, 32) =  7 ] = 3
  // fp_config_hash_table[ h(3, 16) =  3 ] = 4
  // fp_config_hash_table[ h(4, 32) =  9 ] = 5
  // fp_config_hash_table[ h(4, 16) =  4 ] = 6
  // fp_config_hash_table[ h(8, 32) = 17 ] = 7
  // fp_config_hash_table[ h(8, 16) =  8 ] = 8
  //
  // h(0, 0) = 0
  static const uint8_t fp_config_hash_table[] =
  {
  #define UND static_cast<uint8_t>(-1)
    /*  0 */0,
    /*  1 */1,
    /*  2 */2,
    /*  3 */4,
    /*  4 */6,
    /*  5 */UND,
    /*  6 */UND,
    /*  7 */3,
    /*  8 */8,
    /*  9 */5,
    /* 10 */UND,
    /* 11 */UND,
    /* 12 */UND,
    /* 13 */UND,
    /* 14 */UND,
    /* 15 */UND,
    /* 16 */UND,
    /* 17 */7,
  #undef UND
  };
  
  static const size_t num_hash_table_entries =
      sizeof(fp_config_hash_table) / sizeof(fp_config_hash_table[0]);
  
  static int calculate_fp_config_hash(const struct fp_config_data &pConfig)
  {
    int x = pConfig.version;
    int y = pConfig.regs;
    return (x * (y >> 4) + (y >> 5));
  }
  
  static int get_fp_arch_of_config(const struct fp_config_data &pConfig)
  {
    int hash = calculate_fp_config_hash(pConfig);
    assert(hash < num_hash_table_entries);
    return fp_config_hash_table[hash];
  }
  
  static bool is_allowed_use_of_div(int cpu_arch, int cpu_arch_profile,
                                    int div_use) {
    // 0: The code was permitted to use SDIV and UDIV in the Thumb ISA on v7-R or
    //    v7-M.
    // 1: The code was not permitted to use SDIV and UDIV.
    // 2: The code was explicitly permitted to use SDIV and UDIV.
    switch (div_use) {
      case 0: {
        if ((cpu_arch == ARMELFAttributeData::CPU_Arch_ARM_V7) &&
            ((cpu_arch_profile == 'R') || (cpu_arch_profile == 'M'))) {
          return true;
        } else {
          return (cpu_arch >= ARMELFAttributeData::CPU_Arch_ARM_V7E_M);
        }
      }
      case 1: {
        return false;
      }
      case 2:
      // For future proofing
      default: {
        return true;
      }
    }
  }
  
  } // anonymous namespace
  
  //===--------------------------------------------------------------------===//
  // End Helper Functions for postMerge()
  //===--------------------------------------------------------------------===//
  
  bool ARMELFAttributeData::postMerge(const Input &pInput)
  {
    // Process Tag_CPU_arch, Tag_CPU_name, Tag_CPU_raw_name, and
    // Tag_also_compatible_with.
    ELFAttributeValue &out_cpu_arch_attr = m_Attrs[Tag_CPU_arch];
    ELFAttributeValue &out_secondary_compatibility_attr =
        m_Attrs[Tag_also_compatible_with];
  
    if ((m_CurrentCPUArch < 0) && out_cpu_arch_attr.isInitialized()) {
      // Current input initializes the value of Tag_CPU_arch. Validate it.
      int out_cpu_arch = out_cpu_arch_attr.getIntValue();
  
      if (out_cpu_arch > CPU_Arch_Max) {
        error(diag::error_unknown_cpu_arch) << pInput.name();
        return false;
      }
  
      // Initialize m_CurrentCPUArch.
      int out_secondary_arch = -1;
      if (out_secondary_compatibility_attr.isInitialized())
        out_secondary_arch = decode_secondary_compatibility_attribute(
                                out_secondary_compatibility_attr);
  
      m_CurrentCPUArch = calculate_cpu_arch(out_cpu_arch, out_secondary_arch);
    }
  
    if (m_CPUArch >= 0) {
      assert(out_cpu_arch_attr.isInitialized() && "CPU arch has never set!");
      assert(m_CurrentCPUArch >= 0);
  
      int in_cpu_arch = calculate_cpu_arch(m_CPUArch, m_SecondaryCPUArch);
      int result_cpu_arch = merge_cpu_arch(m_CurrentCPUArch, in_cpu_arch);
  
      if (result_cpu_arch < 0) {
        warning(diag::warn_mismatch_cpu_arch_profile)
            << in_cpu_arch << pInput.name();
      } else {
        if (result_cpu_arch != m_CurrentCPUArch) {
          // Value of Tag_CPU_arch are going to changea.
          m_CurrentCPUArch = result_cpu_arch;
  
          // Write the result value to the output.
          if (result_cpu_arch == CPU_Arch_ARM_V4T_Plus_V6_M) {
            out_cpu_arch_attr.setIntValue(CPU_Arch_ARM_V4T);
            encode_secondary_compatibility_attribute(
                out_secondary_compatibility_attr, CPU_Arch_ARM_V6_M);
          } else {
            out_cpu_arch_attr.setIntValue(result_cpu_arch);
            encode_secondary_compatibility_attribute(
                out_secondary_compatibility_attr, -1);
          }
  
          ELFAttributeValue &out_cpu_name = m_Attrs[Tag_CPU_name];
          ELFAttributeValue &out_cpu_raw_name = m_Attrs[Tag_CPU_raw_name];
  
          if (m_CurrentCPUArch != in_cpu_arch) {
            // Unable to guess the Tag_CPU_name. Use the generic name.
            if (out_cpu_name.isInitialized()) {
              out_cpu_name.setStringValue(get_generic_cpu_name(m_CurrentCPUArch));
            }
  
            // Tag_CPU_raw_name becomes unknown. Set to default value to disable
            // it.
            out_cpu_raw_name.setStringValue("");
          } else {
            // Use the value of Tag_CPU_name and Tag_CPU_raw_name from the input.
            if (!m_CPUName.empty()) {
              ELFAttributeValue &out_cpu_name = m_Attrs[Tag_CPU_name];
              assert(out_cpu_name.isInitialized() && "CPU name has never set!");
              out_cpu_name.setStringValue(m_CPUName);
            }
  
            if (!m_CPURawName.empty()) {
              ELFAttributeValue &out_cpu_raw_name = m_Attrs[Tag_CPU_raw_name];
              assert(out_cpu_raw_name.isInitialized() &&
                     "CPU raw name has never set!");
              out_cpu_raw_name.setStringValue(m_CPURawName);
            }
          }
        }
      }
    } // (m_CPUArch >= 0)
  
    // Process Tag_ABI_VFP_args.
    if (m_VFPArgs >= 0) {
      ELFAttributeValue &out_attr = m_Attrs[Tag_ABI_VFP_args];
      ELFAttributeValue &out_float_number_model_attr =
          m_Attrs[Tag_ABI_FP_number_model];
  
      assert(out_attr.isInitialized() && "VFP args has never set!");
  
      // If the output is not permitted to use floating number, this attribute
      // is ignored (migrate the value from input directly.)
      if (out_float_number_model_attr.isUninitialized() ||
          (out_float_number_model_attr.getIntValue() == 0)) {
        // Inherit requirement from input.
        out_attr.setIntValue(m_VFPArgs);
      } else {
        warning(diag::warn_mismatch_vfp_args) << pInput.name();
      }
    }
  
    // Process Tag_FP_arch.
    ELFAttributeValue &out_fp_arch_attr = m_Attrs[Tag_FP_arch];
    if (m_FPArch >= 0) {
      assert(out_fp_arch_attr.isInitialized() && "FP arch has never set!");
  
      // Tag_FP_arch
      //  0: instructions requiring FP hardware are not permitted
      //  1: VFP1
      //  2: VFP2
      //  3: VFP3 D32
      //  4: VFP3 D16
      //  5: VFP4 D32
      //  6: VFP4 D16
      //  7: ARM v8-A D32
      //  8: ARM v8-A D16
      if (out_fp_arch_attr.getIntValue() == 0) {
        // Output has no constraints on FP hardware. Copy the requirement from
        // input.
        out_fp_arch_attr.setIntValue(m_FPArch);
      } else if (m_FPArch == 0) {
        // Input has no constraints on FP hardware. Do nothing.
      } else {
        // If here, both output and input contain non-zero value of Tag_FP_arch.
  
        // Version greater than num_fp_configs is not defined. Choose the greater
        // one for future-proofing.
        if (static_cast<unsigned>(m_FPArch) > num_fp_configs) {
          if (static_cast<unsigned>(m_FPArch) > out_fp_arch_attr.getIntValue()) {
            out_fp_arch_attr.setIntValue(m_FPArch);
          }
        } else {
          if (out_fp_arch_attr.getIntValue() < num_fp_configs) {
            const struct fp_config_data &input_fp_config = fp_configs[ m_FPArch ];
  
            const struct fp_config_data &output_fp_config =
                fp_configs[ out_fp_arch_attr.getIntValue() ];
  
            const struct fp_config_data result_fp_config = {
              /*version*/((output_fp_config.version > input_fp_config.version) ?
                           output_fp_config.version : input_fp_config.version),
              /* regs */((output_fp_config.regs > input_fp_config.regs) ?
                          output_fp_config.regs : input_fp_config.regs),
            };
            // Find the attribute value corresponding the result_fp_config
            out_fp_arch_attr.setIntValue(get_fp_arch_of_config(result_fp_config));
          }
        }
      }
    } // (m_FPArch >= 0)
  
    // Process Tag_ABI_HardFP_use.
    ELFAttributeValue &out_hardfp_use_attr = m_Attrs[Tag_ABI_HardFP_use];
  
    if (!m_HardFPUseInitialized && out_hardfp_use_attr.isInitialized()) {
      m_HardFPUse = out_hardfp_use_attr.getIntValue();
      m_HardFPUseInitialized = true;
    }
  
    if (m_HardFPUse >= 0) {
      // Tag_ABI_HardFP_use depends on the meaning of Tag_FP_arch when it's 0.
      assert(out_hardfp_use_attr.isInitialized() && "HardFP use has never set!");
  
      if (out_fp_arch_attr.isUninitialized() ||
          (out_fp_arch_attr.getIntValue() == 0)) {
        // Has no constraints on FP hardware.
        out_hardfp_use_attr.setIntValue(m_HardFPUse);
      } else {
        // Both output and input contain non-zero value of Tag_FP_arch and we have
        // different Tag_ABI_HaedFP_Use settings other than 0.
        if ((out_fp_arch_attr.getIntValue() > 0) && (m_HardFPUse > 0))
          // Promote to 3 (The user permitted this entity to use both SP and DP
          // VFP instruction.)
          out_hardfp_use_attr.setIntValue(3);
      }
    }
  
    // Move the value of Tag_MPextension_use_legacy to Tag_MPextension_use.
    ELFAttributeValue &out_mpextension_use_legacy =
        m_Attrs[Tag_MPextension_use_legacy];
  
    ELFAttributeValue &out_mpextension_use = m_Attrs[Tag_MPextension_use];
  
    // If Tag_MPextension_use_legacy has value, it must be introduced by current
    // input since it is reset every time after the merge completed.
    if (out_mpextension_use_legacy.isInitialized()) {
      if (out_mpextension_use.isInitialized()) {
        if (m_MPextensionUse < 0) {
          // The value of Tag_MPextension_use is introduced by the current input.
          // Check whether it is consistent with the one set in legacy.
          m_MPextensionUse = out_mpextension_use.getIntValue();
        } else {
          // Current input introduces value of Tag_MPextension_use in
          // m_MPextensionUse.
        }
  
        // Check the consistency between m_MPextensionUse and the value of
        // Tag_MPextension_use_legacy.
        if (static_cast<unsigned>(m_MPextensionUse) !=
                out_mpextension_use_legacy.getIntValue()) {
          error(diag::error_mismatch_mpextension_use) << pInput.name();
          return false;
        }
      } else {
        if (m_MPextensionUse < 0) {
          // Tag_MPextension_use is not set. Initialize it and move the value.
          out_mpextension_use.setType(ELFAttributeValue::Int);
          out_mpextension_use.setIntValue(out_mpextension_use.getIntValue());
        } else {
          // Unreachable case since the value to unitialized attribute is directly
          // assigned in ELFAttribute::Subsection::merge().
          assert(false && "Tag_MPextension_use is uninitialized but have value?");
        }
      }
  
      // Reset the attribute to uninitialized so it won't be included in the
      // output.
      out_mpextension_use_legacy.setType(ELFAttributeValue::Uninitialized);
    }
  
    // Process Tag_MPextension_use.
    if (m_MPextensionUse > 0) {
      assert(out_mpextension_use.isInitialized());
  
      if (static_cast<unsigned>(m_MPextensionUse) >
              out_mpextension_use.getIntValue()) {
        out_mpextension_use.setIntValue(m_MPextensionUse);
      }
    }
  
    // Process Tag_DIV_use.
    ELFAttributeValue &out_div_use_attr = m_Attrs[Tag_DIV_use];
  
    if (!m_DIVUseInitialized && out_div_use_attr.isInitialized()) {
      // Perform the merge by reverting value of Tag_DIV_use and setup m_DIVUse.
      m_DIVUse = out_div_use_attr.getIntValue();
      out_div_use_attr.setIntValue(0);
      m_DIVUseInitialized = true;
    }
  
    if (m_DIVUse >= 0) {
      assert(out_div_use_attr.isInitialized());
  
      const ELFAttributeValue &out_cpu_arch_profile_attr =
          m_Attrs[Tag_CPU_arch_profile];
  
      int out_cpu_arch_profile = Arch_Profile_None;
      if (out_cpu_arch_profile_attr.isInitialized()) {
        out_cpu_arch_profile = out_cpu_arch_profile_attr.getIntValue();
      }
  
      if (m_DIVUse == 1) {
        // Input (=1) was not permitted to use SDIV and UDIV. See whether current
        // output was explicitly permitted the use.
        if (!is_allowed_use_of_div(m_CurrentCPUArch, out_cpu_arch_profile,
                                   out_div_use_attr.getIntValue())) {
          out_div_use_attr.setIntValue(1);
        }
      } else {
        if (out_div_use_attr.getIntValue() != 1) {
          // Output does not explicitly forbid the use of SDIV/UDIV. See whether
          // the input attribute can allow it under current CPU architecture
          // profile.
          if (is_allowed_use_of_div(m_CurrentCPUArch, out_cpu_arch_profile,
                                    m_DIVUse)) {
            out_div_use_attr.setIntValue(m_DIVUse);
          }
        }
      }
    }
  
    return true;
  }
  
  size_t ARMELFAttributeData::sizeOutput() const {
    size_t result = 0;
  
    // Size contributed by known attributes
    for (unsigned i = 0; i <= Tag_Max; ++i) {
      TagType tag = static_cast<TagType>(i);
      const ELFAttributeValue &value = m_Attrs[tag];
  
      if (value.shouldEmit()) {
        result += leb128::size(static_cast<uint32_t>(tag));
        result += value.getSize();
      }
    }
  
    // Size contributed by unknown attributes
    for (UnknownAttrsMap::const_iterator unknown_attr_it = m_UnknownAttrs.begin(),
            unknown_attr_end = m_UnknownAttrs.end();
         unknown_attr_it != unknown_attr_end; ++unknown_attr_it) {
      TagType tag = unknown_attr_it->first;
      const ELFAttributeValue &value = unknown_attr_it->second;
  
      if (value.shouldEmit()) {
        result += leb128::size(static_cast<uint32_t>(tag));
        result += value.getSize();
      }
    }
  
    return result;
  }
  
  size_t ARMELFAttributeData::emit(char *pBuf) const {
    char *buffer = pBuf;
  
    // Tag_conformance "should be emitted first in a file-scope sub-subsection of
    // the first public subsection of the attribute section."
    //
    // See ARM [ABI-addenda], 2.3.7.4 Conformance tag
    const ELFAttributeValue &attr_conformance = m_Attrs[Tag_conformance];
  
    if (attr_conformance.shouldEmit()) {
      if (!ELFAttributeData::WriteAttribute(Tag_conformance,  attr_conformance,
                                            buffer)) {
        return 0;
      }
    }
  
    // Tag_nodefaults "should be emitted before any other tag in an attribute
    // subsection other that the conformance tag"
    //
    // See ARM [ABI-addenda], 2.3.7.5 No defaults tag
    const ELFAttributeValue &attr_nodefaults = m_Attrs[Tag_nodefaults];
  
    if (attr_nodefaults.shouldEmit()) {
      if (!ELFAttributeData::WriteAttribute(Tag_nodefaults,  attr_nodefaults,
                                            buffer)) {
        return 0;
      }
    }
  
    // Tag_conformance (=67)
    // Tag_nodefaults (=64)
    for (unsigned i = 0; i < Tag_nodefaults; ++i) {
      TagType tag = static_cast<TagType>(i);
      const ELFAttributeValue &value = m_Attrs[tag];
  
      if (value.shouldEmit() &&
          !ELFAttributeData::WriteAttribute(tag, value, buffer)) {
        return 0;
      }
    }
  
    for (unsigned i = (Tag_nodefaults + 1); i <= Tag_Max; ++i) {
      TagType tag = static_cast<TagType>(i);
      const ELFAttributeValue &value = m_Attrs[tag];
  
      if (value.shouldEmit() && (i != Tag_conformance) &&
          !ELFAttributeData::WriteAttribute(tag, value, buffer)) {
        return 0;
      }
    }
  
    for (UnknownAttrsMap::const_iterator unknown_attr_it = m_UnknownAttrs.begin(),
            unknown_attr_end = m_UnknownAttrs.end();
         unknown_attr_it != unknown_attr_end; ++unknown_attr_it) {
      TagType tag = unknown_attr_it->first;
      const ELFAttributeValue &value = unknown_attr_it->second;
  
      if (value.shouldEmit() &&
          !ELFAttributeData::WriteAttribute(tag, value, buffer)) {
        return 0;
      }
    }
  
    return (buffer - pBuf);
  }
  