1cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines//===- MipsAbiFlags.cpp ---------------------------------------------------===//
2cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines//
3cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines//                     The MCLinker Project
4cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines//
5cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines// This file is distributed under the University of Illinois Open Source
6cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines// License. See LICENSE.TXT for details.
7cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines//
8cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines//===----------------------------------------------------------------------===//
9cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines#include "MipsAbiFlags.h"
10cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines
11cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines#include "mcld/Fragment/RegionFragment.h"
12cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines#include "mcld/LD/LDSection.h"
13cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines#include "mcld/LD/SectionData.h"
14cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines#include "mcld/MC/Input.h"
15cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines#include "mcld/Support/MsgHandling.h"
16cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines
17cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines#include <llvm/Support/Casting.h>
18cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines#include <llvm/Support/MipsABIFlags.h>
19cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines
20cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hinesnamespace mcld {
21cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines
22cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines// SHT_MIPS_ABIFLAGS has the same format for both 32/64-bit targets.
23cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines// We do not support linking of big-endian code now so 32-bit LE
24cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines// combination is Okay.
25cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hinestypedef llvm::object::ELFType<llvm::support::little, false> ELF32LE;
26cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hinestypedef llvm::object::Elf_Mips_ABIFlags<ELF32LE> ElfMipsAbiFlags;
27cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines
28cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hinesuint64_t MipsAbiFlags::size() {
29cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines  return sizeof(ElfMipsAbiFlags);
30cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines}
31cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines
32cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hinesuint64_t MipsAbiFlags::emit(const MipsAbiFlags& pInfo, MemoryRegion& pRegion) {
33cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines  auto* buf = reinterpret_cast<ElfMipsAbiFlags*>(pRegion.begin());
34cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines  buf->version = 0;
35cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines  buf->isa_level = pInfo.m_IsaLevel;
36cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines  buf->isa_rev = pInfo.m_IsaRev;
37cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines  buf->gpr_size = pInfo.m_GprSize;
38cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines  buf->cpr1_size = pInfo.m_Cpr1Size;
39cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines  buf->cpr2_size = pInfo.m_Cpr2Size;
40cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines  buf->fp_abi = pInfo.m_FpAbi;
41cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines  buf->isa_ext = pInfo.m_IsaExt;
42cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines  buf->ases = pInfo.m_Ases;
43cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines  buf->flags1 = pInfo.m_Flags1;
44cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines  buf->flags2 = 0;
45cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines  return size();
46cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines}
47cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines
48cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hinesbool MipsAbiFlags::fillBySection(const Input& pInput, const LDSection& pSection,
49cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines                                 MipsAbiFlags& mipsAbi) {
50cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines  assert(pSection.type() == llvm::ELF::SHT_MIPS_ABIFLAGS &&
51cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines         "Unexpected section type");
52cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines
53cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines  if (pSection.size() != size()) {
54cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines    error(diag::error_Mips_abiflags_invalid_size) << pInput.name();
55cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines    return false;
56cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines  }
57cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines
58cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines  const SectionData* secData = pSection.getSectionData();
59cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines  if (secData->size() != 2 || !llvm::isa<RegionFragment>(secData->front())) {
60cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines    error(diag::error_Mips_abiflags_invalid_size) << pInput.name();
61cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines    return false;
62cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines  }
63cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines
64cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines  const auto& frag = llvm::cast<RegionFragment>(secData->front());
65cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines  auto* data =
66cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines      reinterpret_cast<const ElfMipsAbiFlags*>(frag.getRegion().data());
67cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines  if (data->version != 0) {
68cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines    error(diag::error_Mips_abiflags_invalid_version) << int(data->version)
69cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines                                                     << pInput.name();
70cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines    return false;
71cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines  }
72cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines
73cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines  mipsAbi.m_IsaLevel = data->isa_level;
74cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines  mipsAbi.m_IsaRev = data->isa_rev;
75cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines  mipsAbi.m_GprSize = data->gpr_size;
76cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines  mipsAbi.m_Cpr1Size = data->cpr1_size;
77cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines  mipsAbi.m_Cpr2Size = data->cpr2_size;
78cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines  mipsAbi.m_FpAbi = data->fp_abi;
79cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines  mipsAbi.m_IsaExt = data->isa_ext;
80cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines  mipsAbi.m_Ases = data->ases;
81cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines  mipsAbi.m_Flags1 = data->flags1;
82cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines  return true;
83cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines}
84cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines
85cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hinesstatic unsigned getIsaLevel(uint64_t flags) {
86cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines  switch (flags & llvm::ELF::EF_MIPS_ARCH) {
87cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines    case llvm::ELF::EF_MIPS_ARCH_1:
88cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines      return 1;
89cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines    case llvm::ELF::EF_MIPS_ARCH_2:
90cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines      return 2;
91cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines    case llvm::ELF::EF_MIPS_ARCH_3:
92cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines      return 3;
93cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines    case llvm::ELF::EF_MIPS_ARCH_4:
94cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines      return 4;
95cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines    case llvm::ELF::EF_MIPS_ARCH_5:
96cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines      return 5;
97cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines    case llvm::ELF::EF_MIPS_ARCH_32:
98cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines    case llvm::ELF::EF_MIPS_ARCH_32R2:
99cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines    case llvm::ELF::EF_MIPS_ARCH_32R6:
100cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines      return 32;
101cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines    case llvm::ELF::EF_MIPS_ARCH_64:
102cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines    case llvm::ELF::EF_MIPS_ARCH_64R2:
103cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines    case llvm::ELF::EF_MIPS_ARCH_64R6:
104cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines      return 64;
105cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines    default:
106cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines      // We check ELF flags and show error in case
107cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines      // of unknown value in other place.
108cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines      llvm_unreachable("Unknown MIPS architecture flag");
109cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines  }
110cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines}
111cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines
112cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hinesstatic unsigned getIsaRev(uint64_t flags) {
113cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines  switch (flags & llvm::ELF::EF_MIPS_ARCH) {
114cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines    case llvm::ELF::EF_MIPS_ARCH_1:
115cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines    case llvm::ELF::EF_MIPS_ARCH_2:
116cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines    case llvm::ELF::EF_MIPS_ARCH_3:
117cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines    case llvm::ELF::EF_MIPS_ARCH_4:
118cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines    case llvm::ELF::EF_MIPS_ARCH_5:
119cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines      return 0;
120cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines    case llvm::ELF::EF_MIPS_ARCH_32:
121cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines    case llvm::ELF::EF_MIPS_ARCH_64:
122cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines      return 1;
123cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines    case llvm::ELF::EF_MIPS_ARCH_32R2:
124cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines    case llvm::ELF::EF_MIPS_ARCH_64R2:
125cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines      return 2;
126cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines    case llvm::ELF::EF_MIPS_ARCH_32R6:
127cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines    case llvm::ELF::EF_MIPS_ARCH_64R6:
128cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines      return 6;
129cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines    default:
130cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines      // We check ELF flags and show error in case
131cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines      // of unknown value in other place.
132cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines      llvm_unreachable("Unknown MIPS architecture flag");
133cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines  }
134cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines}
135cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines
136cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hinesstatic unsigned getIsaExt(uint64_t flags) {
137cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines  switch (flags & llvm::ELF::EF_MIPS_MACH) {
138cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines    case 0:
139cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines      return llvm::Mips::AFL_EXT_NONE;
140cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines    case llvm::ELF::EF_MIPS_MACH_3900: return llvm::Mips::AFL_EXT_3900;
141cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines    case llvm::ELF::EF_MIPS_MACH_4010: return llvm::Mips::AFL_EXT_4010;
142cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines    case llvm::ELF::EF_MIPS_MACH_4100: return llvm::Mips::AFL_EXT_4010;
143cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines    case llvm::ELF::EF_MIPS_MACH_4111: return llvm::Mips::AFL_EXT_4111;
144cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines    case llvm::ELF::EF_MIPS_MACH_4120: return llvm::Mips::AFL_EXT_4120;
145cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines    case llvm::ELF::EF_MIPS_MACH_4650: return llvm::Mips::AFL_EXT_4650;
146cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines    case llvm::ELF::EF_MIPS_MACH_5400: return llvm::Mips::AFL_EXT_5400;
147cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines    case llvm::ELF::EF_MIPS_MACH_5500: return llvm::Mips::AFL_EXT_5500;
148cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines    case llvm::ELF::EF_MIPS_MACH_5900: return llvm::Mips::AFL_EXT_5900;
149cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines    case llvm::ELF::EF_MIPS_MACH_SB1: return llvm::Mips::AFL_EXT_SB1;
150cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines    case llvm::ELF::EF_MIPS_MACH_LS2E: return llvm::Mips::AFL_EXT_LOONGSON_2E;
151cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines    case llvm::ELF::EF_MIPS_MACH_LS2F: return llvm::Mips::AFL_EXT_LOONGSON_2F;
152cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines    case llvm::ELF::EF_MIPS_MACH_LS3A: return llvm::Mips::AFL_EXT_LOONGSON_3A;
153cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines    case llvm::ELF::EF_MIPS_MACH_OCTEON3: return llvm::Mips::AFL_EXT_OCTEON3;
154cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines    case llvm::ELF::EF_MIPS_MACH_OCTEON2: return llvm::Mips::AFL_EXT_OCTEON2;
155cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines    case llvm::ELF::EF_MIPS_MACH_OCTEON: return llvm::Mips::AFL_EXT_OCTEON;
156cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines    case llvm::ELF::EF_MIPS_MACH_XLR: return llvm::Mips::AFL_EXT_XLR;
157cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines    default:
158cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines      // We check ELF flags and show error in case
159cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines      // of unknown value in other place.
160cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines      llvm_unreachable("Unknown MIPS extension flag");
161cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines  }
162cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines}
163cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines
164cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hinesstatic bool is32BitElfFlags(uint64_t flags) {
165cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines  if (flags & llvm::ELF::EF_MIPS_32BITMODE)
166cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines    return true;
167cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines
168cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines  uint64_t arch = flags & llvm::ELF::EF_MIPS_ARCH;
169cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines  if (arch == llvm::ELF::EF_MIPS_ARCH_1 ||
170cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines      arch == llvm::ELF::EF_MIPS_ARCH_2 ||
171cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines      arch == llvm::ELF::EF_MIPS_ARCH_32 ||
172cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines      arch == llvm::ELF::EF_MIPS_ARCH_32R2 ||
173cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines      arch == llvm::ELF::EF_MIPS_ARCH_32R6)
174cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines    return true;
175cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines
176cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines  uint64_t abi = flags & llvm::ELF::EF_MIPS_ABI;
177cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines  if (abi == llvm::ELF::EF_MIPS_ABI_O32 || abi == llvm::ELF::EF_MIPS_ABI_EABI32)
178cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines    return true;
179cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines
180cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines  return false;
181cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines}
182cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines
183cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hinesbool MipsAbiFlags::fillByElfFlags(const Input& pInput, uint64_t elfFlags,
184cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines                                  MipsAbiFlags& mipsAbi) {
185cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines  mipsAbi.m_IsaLevel = getIsaLevel(elfFlags);
186cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines  mipsAbi.m_IsaRev = getIsaRev(elfFlags);
187cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines  mipsAbi.m_IsaExt = getIsaExt(elfFlags);
188cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines
189cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines  mipsAbi.m_GprSize = is32BitElfFlags(elfFlags) ?
190cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines                      llvm::Mips::AFL_REG_32 : llvm::Mips::AFL_REG_64;
191cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines
192cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines  mipsAbi.m_Cpr1Size = llvm::Mips::AFL_REG_NONE;
193cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines  mipsAbi.m_Cpr2Size = llvm::Mips::AFL_REG_NONE;
194cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines  mipsAbi.m_FpAbi = llvm::Mips::Val_GNU_MIPS_ABI_FP_ANY;
195cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines
196cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines  mipsAbi.m_Ases = 0;
197cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines  if (elfFlags & llvm::ELF::EF_MIPS_MICROMIPS)
198cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines    mipsAbi.m_Ases |= llvm::Mips::AFL_ASE_MICROMIPS;
199cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines  if (elfFlags & llvm::ELF::EF_MIPS_ARCH_ASE_M16)
200cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines    mipsAbi.m_Ases |= llvm::Mips::AFL_ASE_MIPS16;
201cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines  if (elfFlags & llvm::ELF::EF_MIPS_ARCH_ASE_MDMX)
202cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines    mipsAbi.m_Ases |= llvm::Mips::AFL_ASE_MDMX;
203cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines
204cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines  mipsAbi.m_Flags1 = 0;
205cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines  return true;
206cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines}
207cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines
208cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hinesbool MipsAbiFlags::isCompatible(const Input& pInput, const MipsAbiFlags& elf,
209cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines                                const MipsAbiFlags& abi) {
210cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines  unsigned isaRev = abi.m_IsaRev;
211cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines  if (isaRev == 3 || isaRev == 5)
212cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines    isaRev = 2;
213cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines  if (abi.m_IsaLevel != elf.m_IsaLevel || isaRev != elf.m_IsaRev) {
214cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines    warning(diag::warn_Mips_isa_incompatible) << pInput.name();
215cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines    return false;
216cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines  }
217cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines  if (abi.m_IsaExt != elf.m_IsaExt) {
218cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines    warning(diag::warn_Mips_isa_ext_incompatible) << pInput.name();
219cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines    return false;
220cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines  }
221cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines  if ((abi.m_Ases & elf.m_Ases) != elf.m_Ases) {
222cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines    warning(diag::warn_Mips_ases_incompatible) << pInput.name();
223cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines    return false;
224cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines  }
225cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines  return true;
226cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines}
227cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines
228cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hinesstatic bool isFpGreater(uint64_t fpA, uint64_t fpB) {
229cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines  if (fpB == llvm::Mips::Val_GNU_MIPS_ABI_FP_ANY)
230cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines    return true;
231cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines  if (fpB == llvm::Mips::Val_GNU_MIPS_ABI_FP_64A &&
232cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines      fpA == llvm::Mips::Val_GNU_MIPS_ABI_FP_64)
233cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines    return true;
234cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines  if (fpB != llvm::Mips::Val_GNU_MIPS_ABI_FP_XX)
235cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines    return false;
236cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines  return fpA == llvm::Mips::Val_GNU_MIPS_ABI_FP_DOUBLE ||
237cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines         fpA == llvm::Mips::Val_GNU_MIPS_ABI_FP_64 ||
238cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines         fpA == llvm::Mips::Val_GNU_MIPS_ABI_FP_64A;
239cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines}
240cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines
241cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hinesstatic llvm::StringRef getFpAbiName(uint64_t abi) {
242cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines  switch (abi) {
243cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines    case llvm::Mips::Val_GNU_MIPS_ABI_FP_ANY:
244cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines      return "<any>";
245cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines    case llvm::Mips::Val_GNU_MIPS_ABI_FP_DOUBLE:
246cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines      return "-mdouble-float";
247cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines    case llvm::Mips::Val_GNU_MIPS_ABI_FP_SINGLE:
248cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines      return "-msingle-float";
249cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines    case llvm::Mips::Val_GNU_MIPS_ABI_FP_SOFT:
250cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines      return "-msoft-float";
251cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines    case llvm::Mips::Val_GNU_MIPS_ABI_FP_OLD_64:
252cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines      return "-mips32r2 -mfp64 (old)";
253cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines    case llvm::Mips::Val_GNU_MIPS_ABI_FP_XX:
254cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines      return "-mfpxx";
255cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines    case llvm::Mips::Val_GNU_MIPS_ABI_FP_64:
256cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines      return "-mgp32 -mfp64";
257cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines    case llvm::Mips::Val_GNU_MIPS_ABI_FP_64A:
258cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines      return "-mgp32 -mfp64 -mno-odd-spreg";
259cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines    default:
260cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines      return "<unknown>";
261cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines  }
262cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines}
263cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines
264cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hinesbool MipsAbiFlags::merge(const Input& pInput, MipsAbiFlags& oldFlags,
265cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines                         const MipsAbiFlags& newFlags) {
266cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines  if (oldFlags.m_IsaLevel == 0) {
267cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines    oldFlags = newFlags;
268cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines    return true;
269cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines  }
270cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines
271cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines  if (newFlags.m_IsaLevel > oldFlags.m_IsaLevel)
272cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines    oldFlags.m_IsaLevel = newFlags.m_IsaLevel;
273cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines
274cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines  oldFlags.m_IsaRev = std::max(oldFlags.m_IsaRev, newFlags.m_IsaRev);
275cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines  oldFlags.m_GprSize = std::max(oldFlags.m_GprSize, newFlags.m_GprSize);
276cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines  oldFlags.m_Cpr1Size = std::max(oldFlags.m_Cpr1Size, newFlags.m_Cpr1Size);
277cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines  oldFlags.m_Cpr2Size = std::max(oldFlags.m_Cpr2Size, newFlags.m_Cpr2Size);
278cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines  oldFlags.m_Ases |= newFlags.m_Ases;
279cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines  oldFlags.m_Flags1 |= newFlags.m_Flags1;
280cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines
281cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines  if (oldFlags.m_FpAbi == newFlags.m_FpAbi)
282cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines    return true;
283cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines
284cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines  if (isFpGreater(newFlags.m_FpAbi, oldFlags.m_FpAbi)) {
285cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines    oldFlags.m_FpAbi = newFlags.m_FpAbi;
286cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines    return true;
287cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines  }
288cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines
289cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines  if (isFpGreater(oldFlags.m_FpAbi, newFlags.m_FpAbi))
290cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines    return true;
291cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines
292cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines  llvm::StringRef oldAbiName = getFpAbiName(oldFlags.m_FpAbi);
293cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines  llvm::StringRef newAbiName = getFpAbiName(newFlags.m_FpAbi);
294cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines  warning(diag::warn_Mips_fp_abi_incompatible) << oldAbiName << newAbiName
295cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines                                               << pInput.name();
296cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines  return false;
297cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines}
298cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines}  // namespace mcld
299