xref: /freebsd-src/contrib/llvm-project/lld/ELF/Arch/MipsArchTree.cpp (revision bdd1243df58e60e85101c09001d9812a789b6bc4)
10b57cec5SDimitry Andric //===- MipsArchTree.cpp --------------------------------------------------===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===---------------------------------------------------------------------===//
80b57cec5SDimitry Andric //
90b57cec5SDimitry Andric // This file contains a helper function for the Writer.
100b57cec5SDimitry Andric //
110b57cec5SDimitry Andric //===---------------------------------------------------------------------===//
120b57cec5SDimitry Andric 
130b57cec5SDimitry Andric #include "InputFiles.h"
140b57cec5SDimitry Andric #include "SymbolTable.h"
150b57cec5SDimitry Andric #include "Writer.h"
160b57cec5SDimitry Andric 
170b57cec5SDimitry Andric #include "lld/Common/ErrorHandler.h"
180b57cec5SDimitry Andric #include "llvm/BinaryFormat/ELF.h"
190b57cec5SDimitry Andric #include "llvm/Support/MipsABIFlags.h"
200b57cec5SDimitry Andric 
210b57cec5SDimitry Andric using namespace llvm;
220b57cec5SDimitry Andric using namespace llvm::object;
230b57cec5SDimitry Andric using namespace llvm::ELF;
240b57cec5SDimitry Andric 
255ffd83dbSDimitry Andric using namespace lld;
265ffd83dbSDimitry Andric using namespace lld::elf;
270b57cec5SDimitry Andric 
280b57cec5SDimitry Andric namespace {
290b57cec5SDimitry Andric struct ArchTreeEdge {
300b57cec5SDimitry Andric   uint32_t child;
310b57cec5SDimitry Andric   uint32_t parent;
320b57cec5SDimitry Andric };
330b57cec5SDimitry Andric 
340b57cec5SDimitry Andric struct FileFlags {
350b57cec5SDimitry Andric   InputFile *file;
360b57cec5SDimitry Andric   uint32_t flags;
370b57cec5SDimitry Andric };
380b57cec5SDimitry Andric } // namespace
390b57cec5SDimitry Andric 
getAbiName(uint32_t flags)400b57cec5SDimitry Andric static StringRef getAbiName(uint32_t flags) {
410b57cec5SDimitry Andric   switch (flags) {
420b57cec5SDimitry Andric   case 0:
430b57cec5SDimitry Andric     return "n64";
440b57cec5SDimitry Andric   case EF_MIPS_ABI2:
450b57cec5SDimitry Andric     return "n32";
460b57cec5SDimitry Andric   case EF_MIPS_ABI_O32:
470b57cec5SDimitry Andric     return "o32";
480b57cec5SDimitry Andric   case EF_MIPS_ABI_O64:
490b57cec5SDimitry Andric     return "o64";
500b57cec5SDimitry Andric   case EF_MIPS_ABI_EABI32:
510b57cec5SDimitry Andric     return "eabi32";
520b57cec5SDimitry Andric   case EF_MIPS_ABI_EABI64:
530b57cec5SDimitry Andric     return "eabi64";
540b57cec5SDimitry Andric   default:
550b57cec5SDimitry Andric     return "unknown";
560b57cec5SDimitry Andric   }
570b57cec5SDimitry Andric }
580b57cec5SDimitry Andric 
getNanName(bool isNan2008)590b57cec5SDimitry Andric static StringRef getNanName(bool isNan2008) {
600b57cec5SDimitry Andric   return isNan2008 ? "2008" : "legacy";
610b57cec5SDimitry Andric }
620b57cec5SDimitry Andric 
getFpName(bool isFp64)630b57cec5SDimitry Andric static StringRef getFpName(bool isFp64) { return isFp64 ? "64" : "32"; }
640b57cec5SDimitry Andric 
checkFlags(ArrayRef<FileFlags> files)650b57cec5SDimitry Andric static void checkFlags(ArrayRef<FileFlags> files) {
660b57cec5SDimitry Andric   assert(!files.empty() && "expected non-empty file list");
670b57cec5SDimitry Andric 
680b57cec5SDimitry Andric   uint32_t abi = files[0].flags & (EF_MIPS_ABI | EF_MIPS_ABI2);
690b57cec5SDimitry Andric   bool nan = files[0].flags & EF_MIPS_NAN2008;
700b57cec5SDimitry Andric   bool fp = files[0].flags & EF_MIPS_FP64;
710b57cec5SDimitry Andric 
720b57cec5SDimitry Andric   for (const FileFlags &f : files) {
730b57cec5SDimitry Andric     if (config->is64 && f.flags & EF_MIPS_MICROMIPS)
740b57cec5SDimitry Andric       error(toString(f.file) + ": microMIPS 64-bit is not supported");
750b57cec5SDimitry Andric 
760b57cec5SDimitry Andric     uint32_t abi2 = f.flags & (EF_MIPS_ABI | EF_MIPS_ABI2);
770b57cec5SDimitry Andric     if (abi != abi2)
780b57cec5SDimitry Andric       error(toString(f.file) + ": ABI '" + getAbiName(abi2) +
790b57cec5SDimitry Andric             "' is incompatible with target ABI '" + getAbiName(abi) + "'");
800b57cec5SDimitry Andric 
810b57cec5SDimitry Andric     bool nan2 = f.flags & EF_MIPS_NAN2008;
820b57cec5SDimitry Andric     if (nan != nan2)
830b57cec5SDimitry Andric       error(toString(f.file) + ": -mnan=" + getNanName(nan2) +
840b57cec5SDimitry Andric             " is incompatible with target -mnan=" + getNanName(nan));
850b57cec5SDimitry Andric 
860b57cec5SDimitry Andric     bool fp2 = f.flags & EF_MIPS_FP64;
870b57cec5SDimitry Andric     if (fp != fp2)
880b57cec5SDimitry Andric       error(toString(f.file) + ": -mfp" + getFpName(fp2) +
890b57cec5SDimitry Andric             " is incompatible with target -mfp" + getFpName(fp));
900b57cec5SDimitry Andric   }
910b57cec5SDimitry Andric }
920b57cec5SDimitry Andric 
getMiscFlags(ArrayRef<FileFlags> files)930b57cec5SDimitry Andric static uint32_t getMiscFlags(ArrayRef<FileFlags> files) {
940b57cec5SDimitry Andric   uint32_t ret = 0;
950b57cec5SDimitry Andric   for (const FileFlags &f : files)
960b57cec5SDimitry Andric     ret |= f.flags &
970b57cec5SDimitry Andric            (EF_MIPS_ABI | EF_MIPS_ABI2 | EF_MIPS_ARCH_ASE | EF_MIPS_NOREORDER |
980b57cec5SDimitry Andric             EF_MIPS_MICROMIPS | EF_MIPS_NAN2008 | EF_MIPS_32BITMODE);
990b57cec5SDimitry Andric   return ret;
1000b57cec5SDimitry Andric }
1010b57cec5SDimitry Andric 
getPicFlags(ArrayRef<FileFlags> files)1020b57cec5SDimitry Andric static uint32_t getPicFlags(ArrayRef<FileFlags> files) {
1030b57cec5SDimitry Andric   // Check PIC/non-PIC compatibility.
1040b57cec5SDimitry Andric   bool isPic = files[0].flags & (EF_MIPS_PIC | EF_MIPS_CPIC);
1050b57cec5SDimitry Andric   for (const FileFlags &f : files.slice(1)) {
1060b57cec5SDimitry Andric     bool isPic2 = f.flags & (EF_MIPS_PIC | EF_MIPS_CPIC);
1070b57cec5SDimitry Andric     if (isPic && !isPic2)
1080b57cec5SDimitry Andric       warn(toString(f.file) +
1090b57cec5SDimitry Andric            ": linking non-abicalls code with abicalls code " +
1100b57cec5SDimitry Andric            toString(files[0].file));
1110b57cec5SDimitry Andric     if (!isPic && isPic2)
1120b57cec5SDimitry Andric       warn(toString(f.file) +
1130b57cec5SDimitry Andric            ": linking abicalls code with non-abicalls code " +
1140b57cec5SDimitry Andric            toString(files[0].file));
1150b57cec5SDimitry Andric   }
1160b57cec5SDimitry Andric 
1170b57cec5SDimitry Andric   // Compute the result PIC/non-PIC flag.
1180b57cec5SDimitry Andric   uint32_t ret = files[0].flags & (EF_MIPS_PIC | EF_MIPS_CPIC);
1190b57cec5SDimitry Andric   for (const FileFlags &f : files.slice(1))
1200b57cec5SDimitry Andric     ret &= f.flags & (EF_MIPS_PIC | EF_MIPS_CPIC);
1210b57cec5SDimitry Andric 
1220b57cec5SDimitry Andric   // PIC code is inherently CPIC and may not set CPIC flag explicitly.
1230b57cec5SDimitry Andric   if (ret & EF_MIPS_PIC)
1240b57cec5SDimitry Andric     ret |= EF_MIPS_CPIC;
1250b57cec5SDimitry Andric   return ret;
1260b57cec5SDimitry Andric }
1270b57cec5SDimitry Andric 
1280b57cec5SDimitry Andric static ArchTreeEdge archTree[] = {
1290b57cec5SDimitry Andric     // MIPS32R6 and MIPS64R6 are not compatible with other extensions
1300b57cec5SDimitry Andric     // MIPS64R2 extensions.
1310b57cec5SDimitry Andric     {EF_MIPS_ARCH_64R2 | EF_MIPS_MACH_OCTEON3, EF_MIPS_ARCH_64R2},
1320b57cec5SDimitry Andric     {EF_MIPS_ARCH_64R2 | EF_MIPS_MACH_OCTEON2, EF_MIPS_ARCH_64R2},
1330b57cec5SDimitry Andric     {EF_MIPS_ARCH_64R2 | EF_MIPS_MACH_OCTEON, EF_MIPS_ARCH_64R2},
1340b57cec5SDimitry Andric     {EF_MIPS_ARCH_64R2 | EF_MIPS_MACH_LS3A, EF_MIPS_ARCH_64R2},
1350b57cec5SDimitry Andric     // MIPS64 extensions.
1360b57cec5SDimitry Andric     {EF_MIPS_ARCH_64 | EF_MIPS_MACH_SB1, EF_MIPS_ARCH_64},
1370b57cec5SDimitry Andric     {EF_MIPS_ARCH_64 | EF_MIPS_MACH_XLR, EF_MIPS_ARCH_64},
1380b57cec5SDimitry Andric     {EF_MIPS_ARCH_64R2, EF_MIPS_ARCH_64},
1390b57cec5SDimitry Andric     // MIPS V extensions.
1400b57cec5SDimitry Andric     {EF_MIPS_ARCH_64, EF_MIPS_ARCH_5},
1410b57cec5SDimitry Andric     // R5000 extensions.
1420b57cec5SDimitry Andric     {EF_MIPS_ARCH_4 | EF_MIPS_MACH_5500, EF_MIPS_ARCH_4 | EF_MIPS_MACH_5400},
1430b57cec5SDimitry Andric     // MIPS IV extensions.
1440b57cec5SDimitry Andric     {EF_MIPS_ARCH_4 | EF_MIPS_MACH_5400, EF_MIPS_ARCH_4},
1450b57cec5SDimitry Andric     {EF_MIPS_ARCH_4 | EF_MIPS_MACH_9000, EF_MIPS_ARCH_4},
1460b57cec5SDimitry Andric     {EF_MIPS_ARCH_5, EF_MIPS_ARCH_4},
1470b57cec5SDimitry Andric     // VR4100 extensions.
1480b57cec5SDimitry Andric     {EF_MIPS_ARCH_3 | EF_MIPS_MACH_4111, EF_MIPS_ARCH_3 | EF_MIPS_MACH_4100},
1490b57cec5SDimitry Andric     {EF_MIPS_ARCH_3 | EF_MIPS_MACH_4120, EF_MIPS_ARCH_3 | EF_MIPS_MACH_4100},
1500b57cec5SDimitry Andric     // MIPS III extensions.
1510b57cec5SDimitry Andric     {EF_MIPS_ARCH_3 | EF_MIPS_MACH_4010, EF_MIPS_ARCH_3},
1520b57cec5SDimitry Andric     {EF_MIPS_ARCH_3 | EF_MIPS_MACH_4100, EF_MIPS_ARCH_3},
1530b57cec5SDimitry Andric     {EF_MIPS_ARCH_3 | EF_MIPS_MACH_4650, EF_MIPS_ARCH_3},
1540b57cec5SDimitry Andric     {EF_MIPS_ARCH_3 | EF_MIPS_MACH_5900, EF_MIPS_ARCH_3},
1550b57cec5SDimitry Andric     {EF_MIPS_ARCH_3 | EF_MIPS_MACH_LS2E, EF_MIPS_ARCH_3},
1560b57cec5SDimitry Andric     {EF_MIPS_ARCH_3 | EF_MIPS_MACH_LS2F, EF_MIPS_ARCH_3},
1570b57cec5SDimitry Andric     {EF_MIPS_ARCH_4, EF_MIPS_ARCH_3},
1580b57cec5SDimitry Andric     // MIPS32 extensions.
1590b57cec5SDimitry Andric     {EF_MIPS_ARCH_32R2, EF_MIPS_ARCH_32},
1600b57cec5SDimitry Andric     // MIPS II extensions.
1610b57cec5SDimitry Andric     {EF_MIPS_ARCH_3, EF_MIPS_ARCH_2},
1620b57cec5SDimitry Andric     {EF_MIPS_ARCH_32, EF_MIPS_ARCH_2},
1630b57cec5SDimitry Andric     // MIPS I extensions.
1640b57cec5SDimitry Andric     {EF_MIPS_ARCH_1 | EF_MIPS_MACH_3900, EF_MIPS_ARCH_1},
1650b57cec5SDimitry Andric     {EF_MIPS_ARCH_2, EF_MIPS_ARCH_1},
1660b57cec5SDimitry Andric };
1670b57cec5SDimitry Andric 
isArchMatched(uint32_t newFlags,uint32_t res)16885868e8aSDimitry Andric static bool isArchMatched(uint32_t newFlags, uint32_t res) {
16985868e8aSDimitry Andric   if (newFlags == res)
1700b57cec5SDimitry Andric     return true;
17185868e8aSDimitry Andric   if (newFlags == EF_MIPS_ARCH_32 && isArchMatched(EF_MIPS_ARCH_64, res))
1720b57cec5SDimitry Andric     return true;
17385868e8aSDimitry Andric   if (newFlags == EF_MIPS_ARCH_32R2 && isArchMatched(EF_MIPS_ARCH_64R2, res))
1740b57cec5SDimitry Andric     return true;
1750b57cec5SDimitry Andric   for (const auto &edge : archTree) {
1760b57cec5SDimitry Andric     if (res == edge.child) {
1770b57cec5SDimitry Andric       res = edge.parent;
17885868e8aSDimitry Andric       if (res == newFlags)
1790b57cec5SDimitry Andric         return true;
1800b57cec5SDimitry Andric     }
1810b57cec5SDimitry Andric   }
1820b57cec5SDimitry Andric   return false;
1830b57cec5SDimitry Andric }
1840b57cec5SDimitry Andric 
getMachName(uint32_t flags)1850b57cec5SDimitry Andric static StringRef getMachName(uint32_t flags) {
1860b57cec5SDimitry Andric   switch (flags & EF_MIPS_MACH) {
1870b57cec5SDimitry Andric   case EF_MIPS_MACH_NONE:
1880b57cec5SDimitry Andric     return "";
1890b57cec5SDimitry Andric   case EF_MIPS_MACH_3900:
1900b57cec5SDimitry Andric     return "r3900";
1910b57cec5SDimitry Andric   case EF_MIPS_MACH_4010:
1920b57cec5SDimitry Andric     return "r4010";
1930b57cec5SDimitry Andric   case EF_MIPS_MACH_4100:
1940b57cec5SDimitry Andric     return "r4100";
1950b57cec5SDimitry Andric   case EF_MIPS_MACH_4650:
1960b57cec5SDimitry Andric     return "r4650";
1970b57cec5SDimitry Andric   case EF_MIPS_MACH_4120:
1980b57cec5SDimitry Andric     return "r4120";
1990b57cec5SDimitry Andric   case EF_MIPS_MACH_4111:
2000b57cec5SDimitry Andric     return "r4111";
2010b57cec5SDimitry Andric   case EF_MIPS_MACH_5400:
2020b57cec5SDimitry Andric     return "vr5400";
2030b57cec5SDimitry Andric   case EF_MIPS_MACH_5900:
2040b57cec5SDimitry Andric     return "vr5900";
2050b57cec5SDimitry Andric   case EF_MIPS_MACH_5500:
2060b57cec5SDimitry Andric     return "vr5500";
2070b57cec5SDimitry Andric   case EF_MIPS_MACH_9000:
2080b57cec5SDimitry Andric     return "rm9000";
2090b57cec5SDimitry Andric   case EF_MIPS_MACH_LS2E:
2100b57cec5SDimitry Andric     return "loongson2e";
2110b57cec5SDimitry Andric   case EF_MIPS_MACH_LS2F:
2120b57cec5SDimitry Andric     return "loongson2f";
2130b57cec5SDimitry Andric   case EF_MIPS_MACH_LS3A:
2140b57cec5SDimitry Andric     return "loongson3a";
2150b57cec5SDimitry Andric   case EF_MIPS_MACH_OCTEON:
2160b57cec5SDimitry Andric     return "octeon";
2170b57cec5SDimitry Andric   case EF_MIPS_MACH_OCTEON2:
2180b57cec5SDimitry Andric     return "octeon2";
2190b57cec5SDimitry Andric   case EF_MIPS_MACH_OCTEON3:
2200b57cec5SDimitry Andric     return "octeon3";
2210b57cec5SDimitry Andric   case EF_MIPS_MACH_SB1:
2220b57cec5SDimitry Andric     return "sb1";
2230b57cec5SDimitry Andric   case EF_MIPS_MACH_XLR:
2240b57cec5SDimitry Andric     return "xlr";
2250b57cec5SDimitry Andric   default:
2260b57cec5SDimitry Andric     return "unknown machine";
2270b57cec5SDimitry Andric   }
2280b57cec5SDimitry Andric }
2290b57cec5SDimitry Andric 
getArchName(uint32_t flags)2300b57cec5SDimitry Andric static StringRef getArchName(uint32_t flags) {
2310b57cec5SDimitry Andric   switch (flags & EF_MIPS_ARCH) {
2320b57cec5SDimitry Andric   case EF_MIPS_ARCH_1:
2330b57cec5SDimitry Andric     return "mips1";
2340b57cec5SDimitry Andric   case EF_MIPS_ARCH_2:
2350b57cec5SDimitry Andric     return "mips2";
2360b57cec5SDimitry Andric   case EF_MIPS_ARCH_3:
2370b57cec5SDimitry Andric     return "mips3";
2380b57cec5SDimitry Andric   case EF_MIPS_ARCH_4:
2390b57cec5SDimitry Andric     return "mips4";
2400b57cec5SDimitry Andric   case EF_MIPS_ARCH_5:
2410b57cec5SDimitry Andric     return "mips5";
2420b57cec5SDimitry Andric   case EF_MIPS_ARCH_32:
2430b57cec5SDimitry Andric     return "mips32";
2440b57cec5SDimitry Andric   case EF_MIPS_ARCH_64:
2450b57cec5SDimitry Andric     return "mips64";
2460b57cec5SDimitry Andric   case EF_MIPS_ARCH_32R2:
2470b57cec5SDimitry Andric     return "mips32r2";
2480b57cec5SDimitry Andric   case EF_MIPS_ARCH_64R2:
2490b57cec5SDimitry Andric     return "mips64r2";
2500b57cec5SDimitry Andric   case EF_MIPS_ARCH_32R6:
2510b57cec5SDimitry Andric     return "mips32r6";
2520b57cec5SDimitry Andric   case EF_MIPS_ARCH_64R6:
2530b57cec5SDimitry Andric     return "mips64r6";
2540b57cec5SDimitry Andric   default:
2550b57cec5SDimitry Andric     return "unknown arch";
2560b57cec5SDimitry Andric   }
2570b57cec5SDimitry Andric }
2580b57cec5SDimitry Andric 
getFullArchName(uint32_t flags)2590b57cec5SDimitry Andric static std::string getFullArchName(uint32_t flags) {
2600b57cec5SDimitry Andric   StringRef arch = getArchName(flags);
2610b57cec5SDimitry Andric   StringRef mach = getMachName(flags);
2620b57cec5SDimitry Andric   if (mach.empty())
2630b57cec5SDimitry Andric     return arch.str();
2640b57cec5SDimitry Andric   return (arch + " (" + mach + ")").str();
2650b57cec5SDimitry Andric }
2660b57cec5SDimitry Andric 
2670b57cec5SDimitry Andric // There are (arguably too) many MIPS ISAs out there. Their relationships
2680b57cec5SDimitry Andric // can be represented as a forest. If all input files have ISAs which
2690b57cec5SDimitry Andric // reachable by repeated proceeding from the single child to the parent,
2700b57cec5SDimitry Andric // these input files are compatible. In that case we need to return "highest"
2710b57cec5SDimitry Andric // ISA. If there are incompatible input files, we show an error.
2720b57cec5SDimitry Andric // For example, mips1 is a "parent" of mips2 and such files are compatible.
2730b57cec5SDimitry Andric // Output file gets EF_MIPS_ARCH_2 flag. From the other side mips3 and mips32
2740b57cec5SDimitry Andric // are incompatible because nor mips3 is a parent for misp32, nor mips32
2750b57cec5SDimitry Andric // is a parent for mips3.
getArchFlags(ArrayRef<FileFlags> files)2760b57cec5SDimitry Andric static uint32_t getArchFlags(ArrayRef<FileFlags> files) {
2770b57cec5SDimitry Andric   uint32_t ret = files[0].flags & (EF_MIPS_ARCH | EF_MIPS_MACH);
2780b57cec5SDimitry Andric 
2790b57cec5SDimitry Andric   for (const FileFlags &f : files.slice(1)) {
28085868e8aSDimitry Andric     uint32_t newFlags = f.flags & (EF_MIPS_ARCH | EF_MIPS_MACH);
2810b57cec5SDimitry Andric 
2820b57cec5SDimitry Andric     // Check ISA compatibility.
28385868e8aSDimitry Andric     if (isArchMatched(newFlags, ret))
2840b57cec5SDimitry Andric       continue;
28585868e8aSDimitry Andric     if (!isArchMatched(ret, newFlags)) {
2860b57cec5SDimitry Andric       error("incompatible target ISA:\n>>> " + toString(files[0].file) + ": " +
2870b57cec5SDimitry Andric             getFullArchName(ret) + "\n>>> " + toString(f.file) + ": " +
28885868e8aSDimitry Andric             getFullArchName(newFlags));
2890b57cec5SDimitry Andric       return 0;
2900b57cec5SDimitry Andric     }
29185868e8aSDimitry Andric     ret = newFlags;
2920b57cec5SDimitry Andric   }
2930b57cec5SDimitry Andric   return ret;
2940b57cec5SDimitry Andric }
2950b57cec5SDimitry Andric 
calcMipsEFlags()2965ffd83dbSDimitry Andric template <class ELFT> uint32_t elf::calcMipsEFlags() {
2970b57cec5SDimitry Andric   std::vector<FileFlags> v;
298*bdd1243dSDimitry Andric   for (InputFile *f : ctx.objectFiles)
299e8d8bef9SDimitry Andric     v.push_back({f, cast<ObjFile<ELFT>>(f)->getObj().getHeader().e_flags});
30085868e8aSDimitry Andric   if (v.empty()) {
30185868e8aSDimitry Andric     // If we don't have any input files, we'll have to rely on the information
30285868e8aSDimitry Andric     // we can derive from emulation information, since this at least gets us
30385868e8aSDimitry Andric     // ABI.
30485868e8aSDimitry Andric     if (config->emulation.empty() || config->is64)
30585868e8aSDimitry Andric       return 0;
30685868e8aSDimitry Andric     return config->mipsN32Abi ? EF_MIPS_ABI2 : EF_MIPS_ABI_O32;
30785868e8aSDimitry Andric   }
3080b57cec5SDimitry Andric   checkFlags(v);
3090b57cec5SDimitry Andric   return getMiscFlags(v) | getPicFlags(v) | getArchFlags(v);
3100b57cec5SDimitry Andric }
3110b57cec5SDimitry Andric 
compareMipsFpAbi(uint8_t fpA,uint8_t fpB)3120b57cec5SDimitry Andric static int compareMipsFpAbi(uint8_t fpA, uint8_t fpB) {
3130b57cec5SDimitry Andric   if (fpA == fpB)
3140b57cec5SDimitry Andric     return 0;
3150b57cec5SDimitry Andric   if (fpB == Mips::Val_GNU_MIPS_ABI_FP_ANY)
3160b57cec5SDimitry Andric     return 1;
3170b57cec5SDimitry Andric   if (fpB == Mips::Val_GNU_MIPS_ABI_FP_64A &&
3180b57cec5SDimitry Andric       fpA == Mips::Val_GNU_MIPS_ABI_FP_64)
3190b57cec5SDimitry Andric     return 1;
3200b57cec5SDimitry Andric   if (fpB != Mips::Val_GNU_MIPS_ABI_FP_XX)
3210b57cec5SDimitry Andric     return -1;
3220b57cec5SDimitry Andric   if (fpA == Mips::Val_GNU_MIPS_ABI_FP_DOUBLE ||
3230b57cec5SDimitry Andric       fpA == Mips::Val_GNU_MIPS_ABI_FP_64 ||
3240b57cec5SDimitry Andric       fpA == Mips::Val_GNU_MIPS_ABI_FP_64A)
3250b57cec5SDimitry Andric     return 1;
3260b57cec5SDimitry Andric   return -1;
3270b57cec5SDimitry Andric }
3280b57cec5SDimitry Andric 
getMipsFpAbiName(uint8_t fpAbi)3290b57cec5SDimitry Andric static StringRef getMipsFpAbiName(uint8_t fpAbi) {
3300b57cec5SDimitry Andric   switch (fpAbi) {
3310b57cec5SDimitry Andric   case Mips::Val_GNU_MIPS_ABI_FP_ANY:
3320b57cec5SDimitry Andric     return "any";
3330b57cec5SDimitry Andric   case Mips::Val_GNU_MIPS_ABI_FP_DOUBLE:
3340b57cec5SDimitry Andric     return "-mdouble-float";
3350b57cec5SDimitry Andric   case Mips::Val_GNU_MIPS_ABI_FP_SINGLE:
3360b57cec5SDimitry Andric     return "-msingle-float";
3370b57cec5SDimitry Andric   case Mips::Val_GNU_MIPS_ABI_FP_SOFT:
3380b57cec5SDimitry Andric     return "-msoft-float";
3390b57cec5SDimitry Andric   case Mips::Val_GNU_MIPS_ABI_FP_OLD_64:
3400b57cec5SDimitry Andric     return "-mgp32 -mfp64 (old)";
3410b57cec5SDimitry Andric   case Mips::Val_GNU_MIPS_ABI_FP_XX:
3420b57cec5SDimitry Andric     return "-mfpxx";
3430b57cec5SDimitry Andric   case Mips::Val_GNU_MIPS_ABI_FP_64:
3440b57cec5SDimitry Andric     return "-mgp32 -mfp64";
3450b57cec5SDimitry Andric   case Mips::Val_GNU_MIPS_ABI_FP_64A:
3460b57cec5SDimitry Andric     return "-mgp32 -mfp64 -mno-odd-spreg";
3470b57cec5SDimitry Andric   default:
3480b57cec5SDimitry Andric     return "unknown";
3490b57cec5SDimitry Andric   }
3500b57cec5SDimitry Andric }
3510b57cec5SDimitry Andric 
getMipsFpAbiFlag(uint8_t oldFlag,uint8_t newFlag,StringRef fileName)3525ffd83dbSDimitry Andric uint8_t elf::getMipsFpAbiFlag(uint8_t oldFlag, uint8_t newFlag,
3535ffd83dbSDimitry Andric                               StringRef fileName) {
3540b57cec5SDimitry Andric   if (compareMipsFpAbi(newFlag, oldFlag) >= 0)
3550b57cec5SDimitry Andric     return newFlag;
3560b57cec5SDimitry Andric   if (compareMipsFpAbi(oldFlag, newFlag) < 0)
3570b57cec5SDimitry Andric     error(fileName + ": floating point ABI '" + getMipsFpAbiName(newFlag) +
3580b57cec5SDimitry Andric           "' is incompatible with target floating point ABI '" +
3590b57cec5SDimitry Andric           getMipsFpAbiName(oldFlag) + "'");
3600b57cec5SDimitry Andric   return oldFlag;
3610b57cec5SDimitry Andric }
3620b57cec5SDimitry Andric 
isN32Abi(const InputFile * f)3630b57cec5SDimitry Andric template <class ELFT> static bool isN32Abi(const InputFile *f) {
3640b57cec5SDimitry Andric   if (auto *ef = dyn_cast<ELFFileBase>(f))
365e8d8bef9SDimitry Andric     return ef->template getObj<ELFT>().getHeader().e_flags & EF_MIPS_ABI2;
3660b57cec5SDimitry Andric   return false;
3670b57cec5SDimitry Andric }
3680b57cec5SDimitry Andric 
isMipsN32Abi(const InputFile * f)3695ffd83dbSDimitry Andric bool elf::isMipsN32Abi(const InputFile *f) {
3700b57cec5SDimitry Andric   switch (config->ekind) {
3710b57cec5SDimitry Andric   case ELF32LEKind:
3720b57cec5SDimitry Andric     return isN32Abi<ELF32LE>(f);
3730b57cec5SDimitry Andric   case ELF32BEKind:
3740b57cec5SDimitry Andric     return isN32Abi<ELF32BE>(f);
3750b57cec5SDimitry Andric   case ELF64LEKind:
3760b57cec5SDimitry Andric     return isN32Abi<ELF64LE>(f);
3770b57cec5SDimitry Andric   case ELF64BEKind:
3780b57cec5SDimitry Andric     return isN32Abi<ELF64BE>(f);
3790b57cec5SDimitry Andric   default:
3800b57cec5SDimitry Andric     llvm_unreachable("unknown Config->EKind");
3810b57cec5SDimitry Andric   }
3820b57cec5SDimitry Andric }
3830b57cec5SDimitry Andric 
isMicroMips()3845ffd83dbSDimitry Andric bool elf::isMicroMips() { return config->eflags & EF_MIPS_MICROMIPS; }
3850b57cec5SDimitry Andric 
isMipsR6()3865ffd83dbSDimitry Andric bool elf::isMipsR6() {
3870b57cec5SDimitry Andric   uint32_t arch = config->eflags & EF_MIPS_ARCH;
3880b57cec5SDimitry Andric   return arch == EF_MIPS_ARCH_32R6 || arch == EF_MIPS_ARCH_64R6;
3890b57cec5SDimitry Andric }
3900b57cec5SDimitry Andric 
3915ffd83dbSDimitry Andric template uint32_t elf::calcMipsEFlags<ELF32LE>();
3925ffd83dbSDimitry Andric template uint32_t elf::calcMipsEFlags<ELF32BE>();
3935ffd83dbSDimitry Andric template uint32_t elf::calcMipsEFlags<ELF64LE>();
3945ffd83dbSDimitry Andric template uint32_t elf::calcMipsEFlags<ELF64BE>();
395