Skip to content

[clang][MIPS] Add support for mipsel-windows-* targets #107744

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 13 commits into from

Conversation

hpoussin
Copy link
Contributor

@hpoussin hpoussin commented Sep 8, 2024

  • Add support for Windows MIPS relocations types
  • Support reading MIPS COFF files in objdump
  • Support generating MIPS COFF files in yaml2obj
  • Support generating MIPS COFF files in llvm-lib
  • Support generating MIPS COFF files in llvm-dlltool
  • Support generating MIPS COFF files in clang

Compiler and library creation have been cross-tested with Microsoft counterparts.
Linker part is not yet ready (although available in my mips-pe branch).

By using Microsoft linker (or my work-in-process work on lld), I get working executables.
clang-20-mips

Windows NT/MIPS and Windows CE/MIPS always used COFF format.
Copy link

github-actions bot commented Sep 8, 2024

Thank you for submitting a Pull Request (PR) to the LLVM Project!

This PR will be automatically labeled and the relevant teams will be notified.

If you wish to, you can add reviewers by using the "Reviewers" section on this page.

If this is not working for you, it is probably because you do not have write permissions for the repository. In which case you can instead tag reviewers by name in a comment by using @ followed by their GitHub username.

If you have received no comments on your PR for a week, you can request a review by "ping"ing the PR by adding a comment “Ping”. The common courtesy "ping" rate is once a week. Please remember that you are asking for valuable time from other developers.

If you have further questions, they may be answered by the LLVM GitHub User Guide.

You can also ask questions in a comment on this PR, on the LLVM Discord or on the forums.

Add the MIPS COFF relocation types. They will be needed to add support for
MIPS Windows object file.
…MIPS COFF relocations

llvm-objdump can now parse MIPS COFF files.
Also change MipsAsmPrinter::emitStartOfAsmFile to emit ELF-related
sections only when using ELF output file format.
Also add support for new relocation types required by debug information.
Implement GNU and MSVC variants.
When using them, _WIN32 and _M_MRX000/_MIPS_ macros are correctly defined.
'mipspe' name was chosen by binutils, when the project was able to create
executables for Windows CE/MIPS.
@llvmbot
Copy link
Member

llvmbot commented Sep 8, 2024

@llvm/pr-subscribers-lld-coff
@llvm/pr-subscribers-mc
@llvm/pr-subscribers-llvm-binary-utilities

@llvm/pr-subscribers-objectyaml

Author: None (hpoussin)

Changes
  • Add support for Windows MIPS relocations types
  • Support reading MIPS COFF files in objdump
  • Support generating MIPS COFF files in yaml2obj
  • Support generating MIPS COFF files in llvm-lib
  • Support generating MIPS COFF files in llvm-dlltool
  • Support generating MIPS COFF files in clang

Compiler and library creation have been cross-tested with Microsoft counterparts.
Linker part is not yet ready (although available in my mips-pe branch).

By using Microsoft linker (or my work-in-process work on lld), I get working executables.
clang-20-mips


Patch is 33.84 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/107744.diff

26 Files Affected:

  • (modified) lld/COFF/Config.h (+1)
  • (modified) llvm/include/llvm/BinaryFormat/COFF.h (+18)
  • (modified) llvm/include/llvm/Object/WindowsMachineFlag.h (+2)
  • (modified) llvm/include/llvm/ObjectYAML/COFFYAML.h (+5)
  • (modified) llvm/lib/MC/WinCOFFObjectWriter.cpp (+15-2)
  • (modified) llvm/lib/Object/COFFObjectFile.cpp (+26)
  • (modified) llvm/lib/Object/WindowsMachineFlag.cpp (+4)
  • (modified) llvm/lib/Object/WindowsResource.cpp (+3)
  • (modified) llvm/lib/ObjectYAML/COFFYAML.cpp (+23)
  • (modified) llvm/lib/ObjectYAML/CodeViewYAMLSymbols.cpp (+3)
  • (modified) llvm/lib/Target/Mips/MCTargetDesc/CMakeLists.txt (+2)
  • (modified) llvm/lib/Target/Mips/MCTargetDesc/MipsAsmBackend.cpp (+21)
  • (modified) llvm/lib/Target/Mips/MCTargetDesc/MipsMCAsmInfo.cpp (+25-3)
  • (modified) llvm/lib/Target/Mips/MCTargetDesc/MipsMCAsmInfo.h (+18-3)
  • (modified) llvm/lib/Target/Mips/MCTargetDesc/MipsMCTargetDesc.cpp (+19-1)
  • (modified) llvm/lib/Target/Mips/MCTargetDesc/MipsMCTargetDesc.h (+15)
  • (added) llvm/lib/Target/Mips/MCTargetDesc/MipsWinCOFFObjectWriter.cpp (+58)
  • (added) llvm/lib/Target/Mips/MCTargetDesc/MipsWinCOFFStreamer.cpp (+33)
  • (modified) llvm/lib/Target/Mips/MipsAsmPrinter.cpp (+59-56)
  • (modified) llvm/lib/Target/Mips/MipsTargetMachine.cpp (+7-1)
  • (modified) llvm/lib/TargetParser/Triple.cpp (+5-1)
  • (added) llvm/test/MC/Mips/coff-basic.ll (+8)
  • (added) llvm/test/MC/Mips/coff-relocs.ll (+46)
  • (added) llvm/test/Object/Inputs/COFF/mipsel.yaml (+8)
  • (modified) llvm/test/Object/objdump-section-content.test (+4)
  • (modified) llvm/unittests/TargetParser/TripleTest.cpp (+3)
diff --git a/lld/COFF/Config.h b/lld/COFF/Config.h
index 947f3fead54e03..a7984753c7e917 100644
--- a/lld/COFF/Config.h
+++ b/lld/COFF/Config.h
@@ -40,6 +40,7 @@ static const auto ARM64EC = llvm::COFF::IMAGE_FILE_MACHINE_ARM64EC;
 static const auto ARM64X = llvm::COFF::IMAGE_FILE_MACHINE_ARM64X;
 static const auto ARMNT = llvm::COFF::IMAGE_FILE_MACHINE_ARMNT;
 static const auto I386 = llvm::COFF::IMAGE_FILE_MACHINE_I386;
+static const auto MIPS = llvm::COFF::IMAGE_FILE_MACHINE_R4000;
 
 enum class ExportSource {
   Unset,
diff --git a/llvm/include/llvm/BinaryFormat/COFF.h b/llvm/include/llvm/BinaryFormat/COFF.h
index 3fc543f73c49db..bbc5264d17872a 100644
--- a/llvm/include/llvm/BinaryFormat/COFF.h
+++ b/llvm/include/llvm/BinaryFormat/COFF.h
@@ -417,6 +417,24 @@ enum RelocationTypesARM64 : unsigned {
   IMAGE_REL_ARM64_REL32 = 0x0011,
 };
 
+enum RelocationTypesMips : unsigned {
+  IMAGE_REL_MIPS_ABSOLUTE = 0x0000,
+  IMAGE_REL_MIPS_REFHALF = 0x0001,
+  IMAGE_REL_MIPS_REFWORD = 0x0002,
+  IMAGE_REL_MIPS_JMPADDR = 0x0003,
+  IMAGE_REL_MIPS_REFHI = 0x0004,
+  IMAGE_REL_MIPS_REFLO = 0x0005,
+  IMAGE_REL_MIPS_GPREL = 0x0006,
+  IMAGE_REL_MIPS_LITERAL = 0x0007,
+  IMAGE_REL_MIPS_SECTION = 0x000A,
+  IMAGE_REL_MIPS_SECREL = 0x000B,
+  IMAGE_REL_MIPS_SECRELLO = 0x000C,
+  IMAGE_REL_MIPS_SECRELHI = 0x000D,
+  IMAGE_REL_MIPS_JMPADDR16 = 0x0010,
+  IMAGE_REL_MIPS_REFWORDNB = 0x0022,
+  IMAGE_REL_MIPS_PAIR = 0x0025,
+};
+
 enum DynamicRelocationType : unsigned {
   IMAGE_DYNAMIC_RELOCATION_GUARD_RF_PROLOGUE = 1,
   IMAGE_DYNAMIC_RELOCATION_GUARD_RF_EPILOGUE = 2,
diff --git a/llvm/include/llvm/Object/WindowsMachineFlag.h b/llvm/include/llvm/Object/WindowsMachineFlag.h
index 1cb408ed13d420..ce5b356f8bfeed 100644
--- a/llvm/include/llvm/Object/WindowsMachineFlag.h
+++ b/llvm/include/llvm/Object/WindowsMachineFlag.h
@@ -43,6 +43,8 @@ template <typename T> Triple::ArchType getMachineArchType(T machine) {
   case COFF::IMAGE_FILE_MACHINE_ARM64EC:
   case COFF::IMAGE_FILE_MACHINE_ARM64X:
     return llvm::Triple::ArchType::aarch64;
+  case COFF::IMAGE_FILE_MACHINE_R4000:
+    return llvm::Triple::ArchType::mipsel;
   default:
     return llvm::Triple::ArchType::UnknownArch;
   }
diff --git a/llvm/include/llvm/ObjectYAML/COFFYAML.h b/llvm/include/llvm/ObjectYAML/COFFYAML.h
index 2f9a1aae0eb05a..f7797fc7f67bcd 100644
--- a/llvm/include/llvm/ObjectYAML/COFFYAML.h
+++ b/llvm/include/llvm/ObjectYAML/COFFYAML.h
@@ -179,6 +179,11 @@ struct ScalarEnumerationTraits<COFF::RelocationTypeAMD64> {
   static void enumeration(IO &IO, COFF::RelocationTypeAMD64 &Value);
 };
 
+template <>
+struct ScalarEnumerationTraits<COFF::RelocationTypesMips> {
+  static void enumeration(IO &IO, COFF::RelocationTypesMips &Value);
+};
+
 template <>
 struct ScalarEnumerationTraits<COFF::RelocationTypesARM> {
   static void enumeration(IO &IO, COFF::RelocationTypesARM &Value);
diff --git a/llvm/lib/MC/WinCOFFObjectWriter.cpp b/llvm/lib/MC/WinCOFFObjectWriter.cpp
index 62f53423126ea9..d5a30d332d2b92 100644
--- a/llvm/lib/MC/WinCOFFObjectWriter.cpp
+++ b/llvm/lib/MC/WinCOFFObjectWriter.cpp
@@ -773,7 +773,10 @@ void WinCOFFWriter::assignFileOffsets(MCAssembler &Asm) {
 
       for (auto &Relocation : Sec->Relocations) {
         assert(Relocation.Symb->getIndex() != -1);
-        Relocation.Data.SymbolTableIndex = Relocation.Symb->getIndex();
+        if (Header.Machine != COFF::IMAGE_FILE_MACHINE_R4000 ||
+            Relocation.Data.Type != COFF::IMAGE_REL_MIPS_PAIR) {
+          Relocation.Data.SymbolTableIndex = Relocation.Symb->getIndex();
+        }
       }
     }
 
@@ -967,8 +970,18 @@ void WinCOFFWriter::recordRelocation(MCAssembler &Asm,
   if (Fixup.getKind() == FK_SecRel_2)
     FixedValue = 0;
 
-  if (OWriter.TargetObjectWriter->recordRelocation(Fixup))
+  if (OWriter.TargetObjectWriter->recordRelocation(Fixup)) {
     Sec->Relocations.push_back(Reloc);
+    if (Header.Machine == COFF::IMAGE_FILE_MACHINE_R4000 &&
+        (Reloc.Data.Type == COFF::IMAGE_REL_MIPS_REFHI ||
+         Reloc.Data.Type == COFF::IMAGE_REL_MIPS_SECRELHI)) {
+      // IMAGE_REL_MIPS_REFHI and IMAGE_REL_MIPS_SECRELHI *must*
+      // be followed by IMAGE_REL_MIPS_PAIR
+      auto RelocPair = Reloc;
+      RelocPair.Data.Type = COFF::IMAGE_REL_MIPS_PAIR;
+      Sec->Relocations.push_back(RelocPair);
+    }
+  }
 }
 
 static std::time_t getTime() {
diff --git a/llvm/lib/Object/COFFObjectFile.cpp b/llvm/lib/Object/COFFObjectFile.cpp
index 5fdf3baf8c02cc..ad15d42135b319 100644
--- a/llvm/lib/Object/COFFObjectFile.cpp
+++ b/llvm/lib/Object/COFFObjectFile.cpp
@@ -1132,6 +1132,8 @@ StringRef COFFObjectFile::getFileFormatName() const {
     return "COFF-ARM64EC";
   case COFF::IMAGE_FILE_MACHINE_ARM64X:
     return "COFF-ARM64X";
+  case COFF::IMAGE_FILE_MACHINE_R4000:
+    return "COFF-R4000";
   default:
     return "COFF-<unknown arch>";
   }
@@ -1465,6 +1467,27 @@ StringRef COFFObjectFile::getRelocationTypeName(uint16_t Type) const {
       return "Unknown";
     }
     break;
+  case Triple::mipsel:
+    switch (Type) {
+    LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_MIPS_ABSOLUTE);
+    LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_MIPS_REFHALF);
+    LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_MIPS_REFWORD);
+    LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_MIPS_JMPADDR);
+    LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_MIPS_REFHI);
+    LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_MIPS_REFLO);
+    LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_MIPS_GPREL);
+    LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_MIPS_LITERAL);
+    LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_MIPS_SECTION);
+    LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_MIPS_SECREL);
+    LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_MIPS_SECRELLO);
+    LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_MIPS_SECRELHI);
+    LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_MIPS_JMPADDR16);
+    LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_MIPS_REFWORDNB);
+    LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_MIPS_PAIR);
+    default:
+      return "Unknown";
+    }
+    break;
   default:
     return "Unknown";
   }
@@ -2326,6 +2349,9 @@ ResourceSectionRef::getContents(const coff_resource_data_entry &Entry) {
     case Triple::aarch64:
       RVAReloc = COFF::IMAGE_REL_ARM64_ADDR32NB;
       break;
+    case Triple::mipsel:
+      RVAReloc = COFF::IMAGE_REL_MIPS_REFWORDNB;
+      break;
     default:
       return createStringError(object_error::parse_failed,
                                "unsupported architecture");
diff --git a/llvm/lib/Object/WindowsMachineFlag.cpp b/llvm/lib/Object/WindowsMachineFlag.cpp
index b9f818775768a2..bade2d4f0f6a74 100644
--- a/llvm/lib/Object/WindowsMachineFlag.cpp
+++ b/llvm/lib/Object/WindowsMachineFlag.cpp
@@ -28,6 +28,8 @@ COFF::MachineTypes llvm::getMachineType(StringRef S) {
       .Case("arm64", COFF::IMAGE_FILE_MACHINE_ARM64)
       .Case("arm64ec", COFF::IMAGE_FILE_MACHINE_ARM64EC)
       .Case("arm64x", COFF::IMAGE_FILE_MACHINE_ARM64X)
+      .Case("mips", COFF::IMAGE_FILE_MACHINE_R4000) // also handle mips (big-endian) because we want to support '/machine:MIPS'
+      .Case("mipsel", COFF::IMAGE_FILE_MACHINE_R4000)
       .Default(COFF::IMAGE_FILE_MACHINE_UNKNOWN);
 }
 
@@ -45,6 +47,8 @@ StringRef llvm::machineToStr(COFF::MachineTypes MT) {
     return "x64";
   case COFF::IMAGE_FILE_MACHINE_I386:
     return "x86";
+  case COFF::IMAGE_FILE_MACHINE_R4000:
+    return "mipsel";
   default:
     llvm_unreachable("unknown machine type");
   }
diff --git a/llvm/lib/Object/WindowsResource.cpp b/llvm/lib/Object/WindowsResource.cpp
index 306e8ec542068b..211e581a7da6a9 100644
--- a/llvm/lib/Object/WindowsResource.cpp
+++ b/llvm/lib/Object/WindowsResource.cpp
@@ -992,6 +992,9 @@ void WindowsResourceCOFFWriter::writeFirstSectionRelocations() {
     case Triple::aarch64:
       Reloc->Type = COFF::IMAGE_REL_ARM64_ADDR32NB;
       break;
+    case Triple::mipsel:
+      Reloc->Type = COFF::IMAGE_REL_MIPS_REFWORDNB;
+      break;
     default:
       llvm_unreachable("unknown machine type");
     }
diff --git a/llvm/lib/ObjectYAML/COFFYAML.cpp b/llvm/lib/ObjectYAML/COFFYAML.cpp
index e14e1b5e467b41..53ea40a0354cea 100644
--- a/llvm/lib/ObjectYAML/COFFYAML.cpp
+++ b/llvm/lib/ObjectYAML/COFFYAML.cpp
@@ -183,6 +183,25 @@ void ScalarEnumerationTraits<COFF::RelocationTypeAMD64>::enumeration(
   ECase(IMAGE_REL_AMD64_SSPAN32);
 }
 
+void ScalarEnumerationTraits<COFF::RelocationTypesMips>::enumeration(
+    IO &IO, COFF::RelocationTypesMips &Value) {
+  ECase(IMAGE_REL_MIPS_ABSOLUTE);
+  ECase(IMAGE_REL_MIPS_REFHALF);
+  ECase(IMAGE_REL_MIPS_REFWORD);
+  ECase(IMAGE_REL_MIPS_JMPADDR);
+  ECase(IMAGE_REL_MIPS_REFHI);
+  ECase(IMAGE_REL_MIPS_REFLO);
+  ECase(IMAGE_REL_MIPS_GPREL);
+  ECase(IMAGE_REL_MIPS_LITERAL);
+  ECase(IMAGE_REL_MIPS_SECTION);
+  ECase(IMAGE_REL_MIPS_SECREL);
+  ECase(IMAGE_REL_MIPS_SECRELLO);
+  ECase(IMAGE_REL_MIPS_SECRELHI);
+  ECase(IMAGE_REL_MIPS_JMPADDR16);
+  ECase(IMAGE_REL_MIPS_REFWORDNB);
+  ECase(IMAGE_REL_MIPS_PAIR);
+}
+
 void ScalarEnumerationTraits<COFF::RelocationTypesARM>::enumeration(
     IO &IO, COFF::RelocationTypesARM &Value) {
   ECase(IMAGE_REL_ARM_ABSOLUTE);
@@ -427,6 +446,10 @@ void MappingTraits<COFFYAML::Relocation>::mapping(IO &IO,
     MappingNormalization<NType<COFF::RelocationTypeAMD64>, uint16_t> NT(
         IO, Rel.Type);
     IO.mapRequired("Type", NT->Type);
+  } else if (H.Machine == COFF::IMAGE_FILE_MACHINE_R4000) {
+    MappingNormalization<NType<COFF::RelocationTypesMips>, uint16_t> NT(
+        IO, Rel.Type);
+    IO.mapRequired("Type", NT->Type);
   } else if (H.Machine == COFF::IMAGE_FILE_MACHINE_ARMNT) {
     MappingNormalization<NType<COFF::RelocationTypesARM>, uint16_t> NT(
         IO, Rel.Type);
diff --git a/llvm/lib/ObjectYAML/CodeViewYAMLSymbols.cpp b/llvm/lib/ObjectYAML/CodeViewYAMLSymbols.cpp
index e1d2700623ec3c..26d71e624aee5b 100644
--- a/llvm/lib/ObjectYAML/CodeViewYAMLSymbols.cpp
+++ b/llvm/lib/ObjectYAML/CodeViewYAMLSymbols.cpp
@@ -171,6 +171,9 @@ void ScalarEnumerationTraits<RegisterId>::enumeration(IO &io, RegisterId &Reg) {
   case COFF::IMAGE_FILE_MACHINE_ARM64X:
     CpuType = CPUType::ARM64;
     break;
+  case COFF::IMAGE_FILE_MACHINE_R4000:
+    CpuType = CPUType::MIPSIII;
+    break;
   }
 
   if (CpuType)
diff --git a/llvm/lib/Target/Mips/MCTargetDesc/CMakeLists.txt b/llvm/lib/Target/Mips/MCTargetDesc/CMakeLists.txt
index 97a6f886d114ec..d3f16e5042c3ac 100644
--- a/llvm/lib/Target/Mips/MCTargetDesc/CMakeLists.txt
+++ b/llvm/lib/Target/Mips/MCTargetDesc/CMakeLists.txt
@@ -12,6 +12,8 @@ add_llvm_component_library(LLVMMipsDesc
   MipsNaClELFStreamer.cpp
   MipsOptionRecord.cpp
   MipsTargetStreamer.cpp
+  MipsWinCOFFObjectWriter.cpp
+  MipsWinCOFFStreamer.cpp
 
   LINK_COMPONENTS
   CodeGenTypes
diff --git a/llvm/lib/Target/Mips/MCTargetDesc/MipsAsmBackend.cpp b/llvm/lib/Target/Mips/MCTargetDesc/MipsAsmBackend.cpp
index f8172e576ce4c1..16318cffd7470e 100644
--- a/llvm/lib/Target/Mips/MCTargetDesc/MipsAsmBackend.cpp
+++ b/llvm/lib/Target/Mips/MCTargetDesc/MipsAsmBackend.cpp
@@ -597,10 +597,31 @@ bool MipsAsmBackend::isMicroMips(const MCSymbol *Sym) const {
   return false;
 }
 
+namespace {
+
+class WindowsMipsAsmBackend : public MipsAsmBackend {
+public:
+  WindowsMipsAsmBackend(const Target &T, const MCRegisterInfo &MRI,
+                        const MCSubtargetInfo &STI)
+    : MipsAsmBackend(T, MRI, STI.getTargetTriple(), STI.getCPU(), false) {
+  }
+
+  std::unique_ptr<MCObjectTargetWriter>
+  createObjectTargetWriter() const override {
+    return createMipsWinCOFFObjectWriter();
+  }
+};
+
+} // end anonymous namespace
+
 MCAsmBackend *llvm::createMipsAsmBackend(const Target &T,
                                          const MCSubtargetInfo &STI,
                                          const MCRegisterInfo &MRI,
                                          const MCTargetOptions &Options) {
+  const Triple &TheTriple = STI.getTargetTriple();
+  if (TheTriple.isOSWindows())
+    return new WindowsMipsAsmBackend(T, MRI, STI);
+
   MipsABIInfo ABI = MipsABIInfo::computeTargetABI(STI.getTargetTriple(),
                                                   STI.getCPU(), Options);
   return new MipsAsmBackend(T, MRI, STI.getTargetTriple(), STI.getCPU(),
diff --git a/llvm/lib/Target/Mips/MCTargetDesc/MipsMCAsmInfo.cpp b/llvm/lib/Target/Mips/MCTargetDesc/MipsMCAsmInfo.cpp
index f89c78e75d3ee7..960256bc38f244 100644
--- a/llvm/lib/Target/Mips/MCTargetDesc/MipsMCAsmInfo.cpp
+++ b/llvm/lib/Target/Mips/MCTargetDesc/MipsMCAsmInfo.cpp
@@ -16,10 +16,10 @@
 
 using namespace llvm;
 
-void MipsMCAsmInfo::anchor() { }
+void MipsELFMCAsmInfo::anchor() { }
 
-MipsMCAsmInfo::MipsMCAsmInfo(const Triple &TheTriple,
-                             const MCTargetOptions &Options) {
+MipsELFMCAsmInfo::MipsELFMCAsmInfo(const Triple &TheTriple,
+                                   const MCTargetOptions &Options) {
   IsLittleEndian = TheTriple.isLittleEndian();
 
   MipsABIInfo ABI = MipsABIInfo::computeTargetABI(TheTriple, "", Options);
@@ -51,3 +51,25 @@ MipsMCAsmInfo::MipsMCAsmInfo(const Triple &TheTriple,
   DwarfRegNumForCFI = true;
   HasMipsExpressions = true;
 }
+
+void MipsCOFFMCAsmInfoMicrosoft::anchor() { }
+
+MipsCOFFMCAsmInfoMicrosoft::MipsCOFFMCAsmInfoMicrosoft() {
+  WinEHEncodingType = WinEH::EncodingType::Itanium;
+  CommentString = ";";
+
+  ExceptionsType = ExceptionHandling::WinEH;
+
+  AllowAtInName = true;
+}
+
+void MipsCOFFMCAsmInfoGNU::anchor() { }
+
+MipsCOFFMCAsmInfoGNU::MipsCOFFMCAsmInfoGNU() {
+  HasSingleParameterDotFile = true;
+  WinEHEncodingType = WinEH::EncodingType::Itanium;
+
+  ExceptionsType = ExceptionHandling::WinEH;
+
+  AllowAtInName = true;
+}
diff --git a/llvm/lib/Target/Mips/MCTargetDesc/MipsMCAsmInfo.h b/llvm/lib/Target/Mips/MCTargetDesc/MipsMCAsmInfo.h
index d8bfe58d24a838..96348b17e57696 100644
--- a/llvm/lib/Target/Mips/MCTargetDesc/MipsMCAsmInfo.h
+++ b/llvm/lib/Target/Mips/MCTargetDesc/MipsMCAsmInfo.h
@@ -13,17 +13,32 @@
 #ifndef LLVM_LIB_TARGET_MIPS_MCTARGETDESC_MIPSMCASMINFO_H
 #define LLVM_LIB_TARGET_MIPS_MCTARGETDESC_MIPSMCASMINFO_H
 
+#include "llvm/MC/MCAsmInfoCOFF.h"
 #include "llvm/MC/MCAsmInfoELF.h"
 
 namespace llvm {
 class Triple;
 
-class MipsMCAsmInfo : public MCAsmInfoELF {
+class MipsELFMCAsmInfo : public MCAsmInfoELF {
   void anchor() override;
 
 public:
-  explicit MipsMCAsmInfo(const Triple &TheTriple,
-                         const MCTargetOptions &Options);
+  explicit MipsELFMCAsmInfo(const Triple &TheTriple,
+                            const MCTargetOptions &Options);
+};
+
+class MipsCOFFMCAsmInfoMicrosoft : public MCAsmInfoMicrosoft {
+  void anchor() override;
+
+public:
+  explicit MipsCOFFMCAsmInfoMicrosoft();
+};
+
+class MipsCOFFMCAsmInfoGNU : public MCAsmInfoGNUCOFF {
+  void anchor() override;
+
+public:
+  explicit MipsCOFFMCAsmInfoGNU();
 };
 
 } // namespace llvm
diff --git a/llvm/lib/Target/Mips/MCTargetDesc/MipsMCTargetDesc.cpp b/llvm/lib/Target/Mips/MCTargetDesc/MipsMCTargetDesc.cpp
index ca95f67174da1e..378cc12388bae3 100644
--- a/llvm/lib/Target/Mips/MCTargetDesc/MipsMCTargetDesc.cpp
+++ b/llvm/lib/Target/Mips/MCTargetDesc/MipsMCTargetDesc.cpp
@@ -45,6 +45,13 @@ using namespace llvm;
 #define GET_REGINFO_MC_DESC
 #include "MipsGenRegisterInfo.inc"
 
+namespace {
+class MipsWinCOFFTargetStreamer : public MipsTargetStreamer {
+public:
+  MipsWinCOFFTargetStreamer(MCStreamer &S) : MipsTargetStreamer(S) {}
+};
+} // end namespace
+
 /// Select the Mips CPU for the given triple and cpu name.
 StringRef MIPS_MC::selectMipsCPU(const Triple &TT, StringRef CPU) {
   if (CPU.empty() || CPU == "generic") {
@@ -84,7 +91,14 @@ static MCSubtargetInfo *createMipsMCSubtargetInfo(const Triple &TT,
 static MCAsmInfo *createMipsMCAsmInfo(const MCRegisterInfo &MRI,
                                       const Triple &TT,
                                       const MCTargetOptions &Options) {
-  MCAsmInfo *MAI = new MipsMCAsmInfo(TT, Options);
+  MCAsmInfo *MAI;
+
+  if (TT.isWindowsMSVCEnvironment())
+    MAI = new MipsCOFFMCAsmInfoMicrosoft();
+  else if (TT.isOSWindows())
+    MAI = new MipsCOFFMCAsmInfoGNU();
+  else
+    MAI = new MipsELFMCAsmInfo(TT, Options);
 
   unsigned SP = MRI.getDwarfRegNum(Mips::SP, true);
   MCCFIInstruction Inst = MCCFIInstruction::createDefCfaRegister(nullptr, SP);
@@ -127,6 +141,8 @@ static MCTargetStreamer *createMipsNullTargetStreamer(MCStreamer &S) {
 
 static MCTargetStreamer *
 createMipsObjectTargetStreamer(MCStreamer &S, const MCSubtargetInfo &STI) {
+  if (STI.getTargetTriple().isOSBinFormatCOFF())
+    return new MipsWinCOFFTargetStreamer(S);
   return new MipsTargetELFStreamer(S, STI);
 }
 
@@ -186,6 +202,8 @@ extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeMipsTargetMC() {
     TargetRegistry::RegisterNullTargetStreamer(*T,
                                                createMipsNullTargetStreamer);
 
+    TargetRegistry::RegisterCOFFStreamer(*T, createMipsWinCOFFStreamer);
+
     // Register the MC subtarget info.
     TargetRegistry::RegisterMCSubtargetInfo(*T, createMipsMCSubtargetInfo);
 
diff --git a/llvm/lib/Target/Mips/MCTargetDesc/MipsMCTargetDesc.h b/llvm/lib/Target/Mips/MCTargetDesc/MipsMCTargetDesc.h
index d51f3b9abcfd1b..a02e4fa2208880 100644
--- a/llvm/lib/Target/Mips/MCTargetDesc/MipsMCTargetDesc.h
+++ b/llvm/lib/Target/Mips/MCTargetDesc/MipsMCTargetDesc.h
@@ -23,7 +23,9 @@ class MCCodeEmitter;
 class MCContext;
 class MCInstrInfo;
 class MCObjectTargetWriter;
+class MCObjectWriter;
 class MCRegisterInfo;
+class MCStreamer;
 class MCSubtargetInfo;
 class MCTargetOptions;
 class StringRef;
@@ -39,8 +41,21 @@ MCAsmBackend *createMipsAsmBackend(const Target &T, const MCSubtargetInfo &STI,
                                    const MCRegisterInfo &MRI,
                                    const MCTargetOptions &Options);
 
+/// Construct an MIPS Windows COFF machine code streamer which will generate
+/// PE/COFF format object files.
+///
+/// Takes ownership of \p AB and \p CE.
+MCStreamer *createMipsWinCOFFStreamer(MCContext &C,
+                                      std::unique_ptr<MCAsmBackend> &&AB,
+                                      std::unique_ptr<MCObjectWriter> &&OW,
+                                      std::unique_ptr<MCCodeEmitter> &&CE);
+
+/// Construct a Mips ELF object writer.
 std::unique_ptr<MCObjectTargetWriter>
 createMipsELFObjectWriter(const Triple &TT, bool IsN32);
+/// Construct a Mips Win COFF object writer.
+std::unique_ptr<MCObjectTargetWriter>
+createMipsWinCOFFObjectWriter();
 
 namespace MIPS_MC {
 StringRef selectMipsCPU(const Triple &TT, StringRef CPU);
diff --git a/llvm/lib/Target/Mips/MCTargetDesc/MipsWinCOFFObjectWriter.cpp b/llvm/lib/Target/Mips/MCTargetDesc/MipsWinCOFFObjectWriter.cpp
new file mode 100644
index 00000000000000..d014cc1b0c1b55
--- /dev/null
+++ b/llvm/lib/Target/Mips/MCTargetDesc/MipsWinCOFFObjectWriter.cpp
@@ -0,0 +1,58 @@
+//===-- MipsWinCOFFObjectWriter.cpp - Mips Win COFF Writer -----------------===//
+//
+// 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 "MCTargetDesc/MipsFixupKinds.h"
+#include "MCTargetDesc/MipsMCTargetDesc.h"
+#include "llvm/BinaryFormat/COFF.h"
+#include "llvm/MC/MCContext.h"
+#include "llvm/MC/MCWinCOFFObjectWriter.h"
+
+using namespace llvm;
+
+namespace {
+
+class MipsWinCOFFObjectWriter : public MCWinCOFFObjectTargetWriter {
+public:
+  MipsWinCOFFObjectWriter();
+
+  unsigned getRelocType(MCContext &Ctx, const MCValue &Target,
+                        const MCFixup &Fixup, bool IsCrossSection,
+                        const MCAsmBackend &MAB) const override;
+};
+
+} // end anonymous namespace
+
+MipsWinCOFFObjectWriter::MipsWinCOFFObjectWriter()
+    : MCWinCOFFObjectTargetWriter(COFF::IMAGE_FILE_MACHINE_R4000) {}
+
+unsigned MipsWinCOFFObjectWriter::getRelocType(MCContext &Ctx,
+                                               const MCValue &Target,
+                                               const MCFixup &Fixup,
+                                               bool IsCrossSection,
+                                               const MCAsmBackend &MAB) const {
+  unsigned FixupKind = Fixup.getKind();
+
+  switch (FixupKind) {
+  case FK_Data_4:
+    return COFF::IMAGE_REL_MIPS_...
[truncated]

@llvmbot
Copy link
Member

llvmbot commented Sep 8, 2024

@llvm/pr-subscribers-platform-windows

Author: None (hpoussin)

Changes
  • Add support for Windows MIPS relocations types
  • Support reading MIPS COFF files in objdump
  • Support generating MIPS COFF files in yaml2obj
  • Support generating MIPS COFF files in llvm-lib
  • Support generating MIPS COFF files in llvm-dlltool
  • Support generating MIPS COFF files in clang

Compiler and library creation have been cross-tested with Microsoft counterparts.
Linker part is not yet ready (although available in my mips-pe branch).

By using Microsoft linker (or my work-in-process work on lld), I get working executables.
clang-20-mips


Patch is 33.84 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/107744.diff

26 Files Affected:

  • (modified) lld/COFF/Config.h (+1)
  • (modified) llvm/include/llvm/BinaryFormat/COFF.h (+18)
  • (modified) llvm/include/llvm/Object/WindowsMachineFlag.h (+2)
  • (modified) llvm/include/llvm/ObjectYAML/COFFYAML.h (+5)
  • (modified) llvm/lib/MC/WinCOFFObjectWriter.cpp (+15-2)
  • (modified) llvm/lib/Object/COFFObjectFile.cpp (+26)
  • (modified) llvm/lib/Object/WindowsMachineFlag.cpp (+4)
  • (modified) llvm/lib/Object/WindowsResource.cpp (+3)
  • (modified) llvm/lib/ObjectYAML/COFFYAML.cpp (+23)
  • (modified) llvm/lib/ObjectYAML/CodeViewYAMLSymbols.cpp (+3)
  • (modified) llvm/lib/Target/Mips/MCTargetDesc/CMakeLists.txt (+2)
  • (modified) llvm/lib/Target/Mips/MCTargetDesc/MipsAsmBackend.cpp (+21)
  • (modified) llvm/lib/Target/Mips/MCTargetDesc/MipsMCAsmInfo.cpp (+25-3)
  • (modified) llvm/lib/Target/Mips/MCTargetDesc/MipsMCAsmInfo.h (+18-3)
  • (modified) llvm/lib/Target/Mips/MCTargetDesc/MipsMCTargetDesc.cpp (+19-1)
  • (modified) llvm/lib/Target/Mips/MCTargetDesc/MipsMCTargetDesc.h (+15)
  • (added) llvm/lib/Target/Mips/MCTargetDesc/MipsWinCOFFObjectWriter.cpp (+58)
  • (added) llvm/lib/Target/Mips/MCTargetDesc/MipsWinCOFFStreamer.cpp (+33)
  • (modified) llvm/lib/Target/Mips/MipsAsmPrinter.cpp (+59-56)
  • (modified) llvm/lib/Target/Mips/MipsTargetMachine.cpp (+7-1)
  • (modified) llvm/lib/TargetParser/Triple.cpp (+5-1)
  • (added) llvm/test/MC/Mips/coff-basic.ll (+8)
  • (added) llvm/test/MC/Mips/coff-relocs.ll (+46)
  • (added) llvm/test/Object/Inputs/COFF/mipsel.yaml (+8)
  • (modified) llvm/test/Object/objdump-section-content.test (+4)
  • (modified) llvm/unittests/TargetParser/TripleTest.cpp (+3)
diff --git a/lld/COFF/Config.h b/lld/COFF/Config.h
index 947f3fead54e03..a7984753c7e917 100644
--- a/lld/COFF/Config.h
+++ b/lld/COFF/Config.h
@@ -40,6 +40,7 @@ static const auto ARM64EC = llvm::COFF::IMAGE_FILE_MACHINE_ARM64EC;
 static const auto ARM64X = llvm::COFF::IMAGE_FILE_MACHINE_ARM64X;
 static const auto ARMNT = llvm::COFF::IMAGE_FILE_MACHINE_ARMNT;
 static const auto I386 = llvm::COFF::IMAGE_FILE_MACHINE_I386;
+static const auto MIPS = llvm::COFF::IMAGE_FILE_MACHINE_R4000;
 
 enum class ExportSource {
   Unset,
diff --git a/llvm/include/llvm/BinaryFormat/COFF.h b/llvm/include/llvm/BinaryFormat/COFF.h
index 3fc543f73c49db..bbc5264d17872a 100644
--- a/llvm/include/llvm/BinaryFormat/COFF.h
+++ b/llvm/include/llvm/BinaryFormat/COFF.h
@@ -417,6 +417,24 @@ enum RelocationTypesARM64 : unsigned {
   IMAGE_REL_ARM64_REL32 = 0x0011,
 };
 
+enum RelocationTypesMips : unsigned {
+  IMAGE_REL_MIPS_ABSOLUTE = 0x0000,
+  IMAGE_REL_MIPS_REFHALF = 0x0001,
+  IMAGE_REL_MIPS_REFWORD = 0x0002,
+  IMAGE_REL_MIPS_JMPADDR = 0x0003,
+  IMAGE_REL_MIPS_REFHI = 0x0004,
+  IMAGE_REL_MIPS_REFLO = 0x0005,
+  IMAGE_REL_MIPS_GPREL = 0x0006,
+  IMAGE_REL_MIPS_LITERAL = 0x0007,
+  IMAGE_REL_MIPS_SECTION = 0x000A,
+  IMAGE_REL_MIPS_SECREL = 0x000B,
+  IMAGE_REL_MIPS_SECRELLO = 0x000C,
+  IMAGE_REL_MIPS_SECRELHI = 0x000D,
+  IMAGE_REL_MIPS_JMPADDR16 = 0x0010,
+  IMAGE_REL_MIPS_REFWORDNB = 0x0022,
+  IMAGE_REL_MIPS_PAIR = 0x0025,
+};
+
 enum DynamicRelocationType : unsigned {
   IMAGE_DYNAMIC_RELOCATION_GUARD_RF_PROLOGUE = 1,
   IMAGE_DYNAMIC_RELOCATION_GUARD_RF_EPILOGUE = 2,
diff --git a/llvm/include/llvm/Object/WindowsMachineFlag.h b/llvm/include/llvm/Object/WindowsMachineFlag.h
index 1cb408ed13d420..ce5b356f8bfeed 100644
--- a/llvm/include/llvm/Object/WindowsMachineFlag.h
+++ b/llvm/include/llvm/Object/WindowsMachineFlag.h
@@ -43,6 +43,8 @@ template <typename T> Triple::ArchType getMachineArchType(T machine) {
   case COFF::IMAGE_FILE_MACHINE_ARM64EC:
   case COFF::IMAGE_FILE_MACHINE_ARM64X:
     return llvm::Triple::ArchType::aarch64;
+  case COFF::IMAGE_FILE_MACHINE_R4000:
+    return llvm::Triple::ArchType::mipsel;
   default:
     return llvm::Triple::ArchType::UnknownArch;
   }
diff --git a/llvm/include/llvm/ObjectYAML/COFFYAML.h b/llvm/include/llvm/ObjectYAML/COFFYAML.h
index 2f9a1aae0eb05a..f7797fc7f67bcd 100644
--- a/llvm/include/llvm/ObjectYAML/COFFYAML.h
+++ b/llvm/include/llvm/ObjectYAML/COFFYAML.h
@@ -179,6 +179,11 @@ struct ScalarEnumerationTraits<COFF::RelocationTypeAMD64> {
   static void enumeration(IO &IO, COFF::RelocationTypeAMD64 &Value);
 };
 
+template <>
+struct ScalarEnumerationTraits<COFF::RelocationTypesMips> {
+  static void enumeration(IO &IO, COFF::RelocationTypesMips &Value);
+};
+
 template <>
 struct ScalarEnumerationTraits<COFF::RelocationTypesARM> {
   static void enumeration(IO &IO, COFF::RelocationTypesARM &Value);
diff --git a/llvm/lib/MC/WinCOFFObjectWriter.cpp b/llvm/lib/MC/WinCOFFObjectWriter.cpp
index 62f53423126ea9..d5a30d332d2b92 100644
--- a/llvm/lib/MC/WinCOFFObjectWriter.cpp
+++ b/llvm/lib/MC/WinCOFFObjectWriter.cpp
@@ -773,7 +773,10 @@ void WinCOFFWriter::assignFileOffsets(MCAssembler &Asm) {
 
       for (auto &Relocation : Sec->Relocations) {
         assert(Relocation.Symb->getIndex() != -1);
-        Relocation.Data.SymbolTableIndex = Relocation.Symb->getIndex();
+        if (Header.Machine != COFF::IMAGE_FILE_MACHINE_R4000 ||
+            Relocation.Data.Type != COFF::IMAGE_REL_MIPS_PAIR) {
+          Relocation.Data.SymbolTableIndex = Relocation.Symb->getIndex();
+        }
       }
     }
 
@@ -967,8 +970,18 @@ void WinCOFFWriter::recordRelocation(MCAssembler &Asm,
   if (Fixup.getKind() == FK_SecRel_2)
     FixedValue = 0;
 
-  if (OWriter.TargetObjectWriter->recordRelocation(Fixup))
+  if (OWriter.TargetObjectWriter->recordRelocation(Fixup)) {
     Sec->Relocations.push_back(Reloc);
+    if (Header.Machine == COFF::IMAGE_FILE_MACHINE_R4000 &&
+        (Reloc.Data.Type == COFF::IMAGE_REL_MIPS_REFHI ||
+         Reloc.Data.Type == COFF::IMAGE_REL_MIPS_SECRELHI)) {
+      // IMAGE_REL_MIPS_REFHI and IMAGE_REL_MIPS_SECRELHI *must*
+      // be followed by IMAGE_REL_MIPS_PAIR
+      auto RelocPair = Reloc;
+      RelocPair.Data.Type = COFF::IMAGE_REL_MIPS_PAIR;
+      Sec->Relocations.push_back(RelocPair);
+    }
+  }
 }
 
 static std::time_t getTime() {
diff --git a/llvm/lib/Object/COFFObjectFile.cpp b/llvm/lib/Object/COFFObjectFile.cpp
index 5fdf3baf8c02cc..ad15d42135b319 100644
--- a/llvm/lib/Object/COFFObjectFile.cpp
+++ b/llvm/lib/Object/COFFObjectFile.cpp
@@ -1132,6 +1132,8 @@ StringRef COFFObjectFile::getFileFormatName() const {
     return "COFF-ARM64EC";
   case COFF::IMAGE_FILE_MACHINE_ARM64X:
     return "COFF-ARM64X";
+  case COFF::IMAGE_FILE_MACHINE_R4000:
+    return "COFF-R4000";
   default:
     return "COFF-<unknown arch>";
   }
@@ -1465,6 +1467,27 @@ StringRef COFFObjectFile::getRelocationTypeName(uint16_t Type) const {
       return "Unknown";
     }
     break;
+  case Triple::mipsel:
+    switch (Type) {
+    LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_MIPS_ABSOLUTE);
+    LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_MIPS_REFHALF);
+    LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_MIPS_REFWORD);
+    LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_MIPS_JMPADDR);
+    LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_MIPS_REFHI);
+    LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_MIPS_REFLO);
+    LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_MIPS_GPREL);
+    LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_MIPS_LITERAL);
+    LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_MIPS_SECTION);
+    LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_MIPS_SECREL);
+    LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_MIPS_SECRELLO);
+    LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_MIPS_SECRELHI);
+    LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_MIPS_JMPADDR16);
+    LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_MIPS_REFWORDNB);
+    LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_MIPS_PAIR);
+    default:
+      return "Unknown";
+    }
+    break;
   default:
     return "Unknown";
   }
@@ -2326,6 +2349,9 @@ ResourceSectionRef::getContents(const coff_resource_data_entry &Entry) {
     case Triple::aarch64:
       RVAReloc = COFF::IMAGE_REL_ARM64_ADDR32NB;
       break;
+    case Triple::mipsel:
+      RVAReloc = COFF::IMAGE_REL_MIPS_REFWORDNB;
+      break;
     default:
       return createStringError(object_error::parse_failed,
                                "unsupported architecture");
diff --git a/llvm/lib/Object/WindowsMachineFlag.cpp b/llvm/lib/Object/WindowsMachineFlag.cpp
index b9f818775768a2..bade2d4f0f6a74 100644
--- a/llvm/lib/Object/WindowsMachineFlag.cpp
+++ b/llvm/lib/Object/WindowsMachineFlag.cpp
@@ -28,6 +28,8 @@ COFF::MachineTypes llvm::getMachineType(StringRef S) {
       .Case("arm64", COFF::IMAGE_FILE_MACHINE_ARM64)
       .Case("arm64ec", COFF::IMAGE_FILE_MACHINE_ARM64EC)
       .Case("arm64x", COFF::IMAGE_FILE_MACHINE_ARM64X)
+      .Case("mips", COFF::IMAGE_FILE_MACHINE_R4000) // also handle mips (big-endian) because we want to support '/machine:MIPS'
+      .Case("mipsel", COFF::IMAGE_FILE_MACHINE_R4000)
       .Default(COFF::IMAGE_FILE_MACHINE_UNKNOWN);
 }
 
@@ -45,6 +47,8 @@ StringRef llvm::machineToStr(COFF::MachineTypes MT) {
     return "x64";
   case COFF::IMAGE_FILE_MACHINE_I386:
     return "x86";
+  case COFF::IMAGE_FILE_MACHINE_R4000:
+    return "mipsel";
   default:
     llvm_unreachable("unknown machine type");
   }
diff --git a/llvm/lib/Object/WindowsResource.cpp b/llvm/lib/Object/WindowsResource.cpp
index 306e8ec542068b..211e581a7da6a9 100644
--- a/llvm/lib/Object/WindowsResource.cpp
+++ b/llvm/lib/Object/WindowsResource.cpp
@@ -992,6 +992,9 @@ void WindowsResourceCOFFWriter::writeFirstSectionRelocations() {
     case Triple::aarch64:
       Reloc->Type = COFF::IMAGE_REL_ARM64_ADDR32NB;
       break;
+    case Triple::mipsel:
+      Reloc->Type = COFF::IMAGE_REL_MIPS_REFWORDNB;
+      break;
     default:
       llvm_unreachable("unknown machine type");
     }
diff --git a/llvm/lib/ObjectYAML/COFFYAML.cpp b/llvm/lib/ObjectYAML/COFFYAML.cpp
index e14e1b5e467b41..53ea40a0354cea 100644
--- a/llvm/lib/ObjectYAML/COFFYAML.cpp
+++ b/llvm/lib/ObjectYAML/COFFYAML.cpp
@@ -183,6 +183,25 @@ void ScalarEnumerationTraits<COFF::RelocationTypeAMD64>::enumeration(
   ECase(IMAGE_REL_AMD64_SSPAN32);
 }
 
+void ScalarEnumerationTraits<COFF::RelocationTypesMips>::enumeration(
+    IO &IO, COFF::RelocationTypesMips &Value) {
+  ECase(IMAGE_REL_MIPS_ABSOLUTE);
+  ECase(IMAGE_REL_MIPS_REFHALF);
+  ECase(IMAGE_REL_MIPS_REFWORD);
+  ECase(IMAGE_REL_MIPS_JMPADDR);
+  ECase(IMAGE_REL_MIPS_REFHI);
+  ECase(IMAGE_REL_MIPS_REFLO);
+  ECase(IMAGE_REL_MIPS_GPREL);
+  ECase(IMAGE_REL_MIPS_LITERAL);
+  ECase(IMAGE_REL_MIPS_SECTION);
+  ECase(IMAGE_REL_MIPS_SECREL);
+  ECase(IMAGE_REL_MIPS_SECRELLO);
+  ECase(IMAGE_REL_MIPS_SECRELHI);
+  ECase(IMAGE_REL_MIPS_JMPADDR16);
+  ECase(IMAGE_REL_MIPS_REFWORDNB);
+  ECase(IMAGE_REL_MIPS_PAIR);
+}
+
 void ScalarEnumerationTraits<COFF::RelocationTypesARM>::enumeration(
     IO &IO, COFF::RelocationTypesARM &Value) {
   ECase(IMAGE_REL_ARM_ABSOLUTE);
@@ -427,6 +446,10 @@ void MappingTraits<COFFYAML::Relocation>::mapping(IO &IO,
     MappingNormalization<NType<COFF::RelocationTypeAMD64>, uint16_t> NT(
         IO, Rel.Type);
     IO.mapRequired("Type", NT->Type);
+  } else if (H.Machine == COFF::IMAGE_FILE_MACHINE_R4000) {
+    MappingNormalization<NType<COFF::RelocationTypesMips>, uint16_t> NT(
+        IO, Rel.Type);
+    IO.mapRequired("Type", NT->Type);
   } else if (H.Machine == COFF::IMAGE_FILE_MACHINE_ARMNT) {
     MappingNormalization<NType<COFF::RelocationTypesARM>, uint16_t> NT(
         IO, Rel.Type);
diff --git a/llvm/lib/ObjectYAML/CodeViewYAMLSymbols.cpp b/llvm/lib/ObjectYAML/CodeViewYAMLSymbols.cpp
index e1d2700623ec3c..26d71e624aee5b 100644
--- a/llvm/lib/ObjectYAML/CodeViewYAMLSymbols.cpp
+++ b/llvm/lib/ObjectYAML/CodeViewYAMLSymbols.cpp
@@ -171,6 +171,9 @@ void ScalarEnumerationTraits<RegisterId>::enumeration(IO &io, RegisterId &Reg) {
   case COFF::IMAGE_FILE_MACHINE_ARM64X:
     CpuType = CPUType::ARM64;
     break;
+  case COFF::IMAGE_FILE_MACHINE_R4000:
+    CpuType = CPUType::MIPSIII;
+    break;
   }
 
   if (CpuType)
diff --git a/llvm/lib/Target/Mips/MCTargetDesc/CMakeLists.txt b/llvm/lib/Target/Mips/MCTargetDesc/CMakeLists.txt
index 97a6f886d114ec..d3f16e5042c3ac 100644
--- a/llvm/lib/Target/Mips/MCTargetDesc/CMakeLists.txt
+++ b/llvm/lib/Target/Mips/MCTargetDesc/CMakeLists.txt
@@ -12,6 +12,8 @@ add_llvm_component_library(LLVMMipsDesc
   MipsNaClELFStreamer.cpp
   MipsOptionRecord.cpp
   MipsTargetStreamer.cpp
+  MipsWinCOFFObjectWriter.cpp
+  MipsWinCOFFStreamer.cpp
 
   LINK_COMPONENTS
   CodeGenTypes
diff --git a/llvm/lib/Target/Mips/MCTargetDesc/MipsAsmBackend.cpp b/llvm/lib/Target/Mips/MCTargetDesc/MipsAsmBackend.cpp
index f8172e576ce4c1..16318cffd7470e 100644
--- a/llvm/lib/Target/Mips/MCTargetDesc/MipsAsmBackend.cpp
+++ b/llvm/lib/Target/Mips/MCTargetDesc/MipsAsmBackend.cpp
@@ -597,10 +597,31 @@ bool MipsAsmBackend::isMicroMips(const MCSymbol *Sym) const {
   return false;
 }
 
+namespace {
+
+class WindowsMipsAsmBackend : public MipsAsmBackend {
+public:
+  WindowsMipsAsmBackend(const Target &T, const MCRegisterInfo &MRI,
+                        const MCSubtargetInfo &STI)
+    : MipsAsmBackend(T, MRI, STI.getTargetTriple(), STI.getCPU(), false) {
+  }
+
+  std::unique_ptr<MCObjectTargetWriter>
+  createObjectTargetWriter() const override {
+    return createMipsWinCOFFObjectWriter();
+  }
+};
+
+} // end anonymous namespace
+
 MCAsmBackend *llvm::createMipsAsmBackend(const Target &T,
                                          const MCSubtargetInfo &STI,
                                          const MCRegisterInfo &MRI,
                                          const MCTargetOptions &Options) {
+  const Triple &TheTriple = STI.getTargetTriple();
+  if (TheTriple.isOSWindows())
+    return new WindowsMipsAsmBackend(T, MRI, STI);
+
   MipsABIInfo ABI = MipsABIInfo::computeTargetABI(STI.getTargetTriple(),
                                                   STI.getCPU(), Options);
   return new MipsAsmBackend(T, MRI, STI.getTargetTriple(), STI.getCPU(),
diff --git a/llvm/lib/Target/Mips/MCTargetDesc/MipsMCAsmInfo.cpp b/llvm/lib/Target/Mips/MCTargetDesc/MipsMCAsmInfo.cpp
index f89c78e75d3ee7..960256bc38f244 100644
--- a/llvm/lib/Target/Mips/MCTargetDesc/MipsMCAsmInfo.cpp
+++ b/llvm/lib/Target/Mips/MCTargetDesc/MipsMCAsmInfo.cpp
@@ -16,10 +16,10 @@
 
 using namespace llvm;
 
-void MipsMCAsmInfo::anchor() { }
+void MipsELFMCAsmInfo::anchor() { }
 
-MipsMCAsmInfo::MipsMCAsmInfo(const Triple &TheTriple,
-                             const MCTargetOptions &Options) {
+MipsELFMCAsmInfo::MipsELFMCAsmInfo(const Triple &TheTriple,
+                                   const MCTargetOptions &Options) {
   IsLittleEndian = TheTriple.isLittleEndian();
 
   MipsABIInfo ABI = MipsABIInfo::computeTargetABI(TheTriple, "", Options);
@@ -51,3 +51,25 @@ MipsMCAsmInfo::MipsMCAsmInfo(const Triple &TheTriple,
   DwarfRegNumForCFI = true;
   HasMipsExpressions = true;
 }
+
+void MipsCOFFMCAsmInfoMicrosoft::anchor() { }
+
+MipsCOFFMCAsmInfoMicrosoft::MipsCOFFMCAsmInfoMicrosoft() {
+  WinEHEncodingType = WinEH::EncodingType::Itanium;
+  CommentString = ";";
+
+  ExceptionsType = ExceptionHandling::WinEH;
+
+  AllowAtInName = true;
+}
+
+void MipsCOFFMCAsmInfoGNU::anchor() { }
+
+MipsCOFFMCAsmInfoGNU::MipsCOFFMCAsmInfoGNU() {
+  HasSingleParameterDotFile = true;
+  WinEHEncodingType = WinEH::EncodingType::Itanium;
+
+  ExceptionsType = ExceptionHandling::WinEH;
+
+  AllowAtInName = true;
+}
diff --git a/llvm/lib/Target/Mips/MCTargetDesc/MipsMCAsmInfo.h b/llvm/lib/Target/Mips/MCTargetDesc/MipsMCAsmInfo.h
index d8bfe58d24a838..96348b17e57696 100644
--- a/llvm/lib/Target/Mips/MCTargetDesc/MipsMCAsmInfo.h
+++ b/llvm/lib/Target/Mips/MCTargetDesc/MipsMCAsmInfo.h
@@ -13,17 +13,32 @@
 #ifndef LLVM_LIB_TARGET_MIPS_MCTARGETDESC_MIPSMCASMINFO_H
 #define LLVM_LIB_TARGET_MIPS_MCTARGETDESC_MIPSMCASMINFO_H
 
+#include "llvm/MC/MCAsmInfoCOFF.h"
 #include "llvm/MC/MCAsmInfoELF.h"
 
 namespace llvm {
 class Triple;
 
-class MipsMCAsmInfo : public MCAsmInfoELF {
+class MipsELFMCAsmInfo : public MCAsmInfoELF {
   void anchor() override;
 
 public:
-  explicit MipsMCAsmInfo(const Triple &TheTriple,
-                         const MCTargetOptions &Options);
+  explicit MipsELFMCAsmInfo(const Triple &TheTriple,
+                            const MCTargetOptions &Options);
+};
+
+class MipsCOFFMCAsmInfoMicrosoft : public MCAsmInfoMicrosoft {
+  void anchor() override;
+
+public:
+  explicit MipsCOFFMCAsmInfoMicrosoft();
+};
+
+class MipsCOFFMCAsmInfoGNU : public MCAsmInfoGNUCOFF {
+  void anchor() override;
+
+public:
+  explicit MipsCOFFMCAsmInfoGNU();
 };
 
 } // namespace llvm
diff --git a/llvm/lib/Target/Mips/MCTargetDesc/MipsMCTargetDesc.cpp b/llvm/lib/Target/Mips/MCTargetDesc/MipsMCTargetDesc.cpp
index ca95f67174da1e..378cc12388bae3 100644
--- a/llvm/lib/Target/Mips/MCTargetDesc/MipsMCTargetDesc.cpp
+++ b/llvm/lib/Target/Mips/MCTargetDesc/MipsMCTargetDesc.cpp
@@ -45,6 +45,13 @@ using namespace llvm;
 #define GET_REGINFO_MC_DESC
 #include "MipsGenRegisterInfo.inc"
 
+namespace {
+class MipsWinCOFFTargetStreamer : public MipsTargetStreamer {
+public:
+  MipsWinCOFFTargetStreamer(MCStreamer &S) : MipsTargetStreamer(S) {}
+};
+} // end namespace
+
 /// Select the Mips CPU for the given triple and cpu name.
 StringRef MIPS_MC::selectMipsCPU(const Triple &TT, StringRef CPU) {
   if (CPU.empty() || CPU == "generic") {
@@ -84,7 +91,14 @@ static MCSubtargetInfo *createMipsMCSubtargetInfo(const Triple &TT,
 static MCAsmInfo *createMipsMCAsmInfo(const MCRegisterInfo &MRI,
                                       const Triple &TT,
                                       const MCTargetOptions &Options) {
-  MCAsmInfo *MAI = new MipsMCAsmInfo(TT, Options);
+  MCAsmInfo *MAI;
+
+  if (TT.isWindowsMSVCEnvironment())
+    MAI = new MipsCOFFMCAsmInfoMicrosoft();
+  else if (TT.isOSWindows())
+    MAI = new MipsCOFFMCAsmInfoGNU();
+  else
+    MAI = new MipsELFMCAsmInfo(TT, Options);
 
   unsigned SP = MRI.getDwarfRegNum(Mips::SP, true);
   MCCFIInstruction Inst = MCCFIInstruction::createDefCfaRegister(nullptr, SP);
@@ -127,6 +141,8 @@ static MCTargetStreamer *createMipsNullTargetStreamer(MCStreamer &S) {
 
 static MCTargetStreamer *
 createMipsObjectTargetStreamer(MCStreamer &S, const MCSubtargetInfo &STI) {
+  if (STI.getTargetTriple().isOSBinFormatCOFF())
+    return new MipsWinCOFFTargetStreamer(S);
   return new MipsTargetELFStreamer(S, STI);
 }
 
@@ -186,6 +202,8 @@ extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeMipsTargetMC() {
     TargetRegistry::RegisterNullTargetStreamer(*T,
                                                createMipsNullTargetStreamer);
 
+    TargetRegistry::RegisterCOFFStreamer(*T, createMipsWinCOFFStreamer);
+
     // Register the MC subtarget info.
     TargetRegistry::RegisterMCSubtargetInfo(*T, createMipsMCSubtargetInfo);
 
diff --git a/llvm/lib/Target/Mips/MCTargetDesc/MipsMCTargetDesc.h b/llvm/lib/Target/Mips/MCTargetDesc/MipsMCTargetDesc.h
index d51f3b9abcfd1b..a02e4fa2208880 100644
--- a/llvm/lib/Target/Mips/MCTargetDesc/MipsMCTargetDesc.h
+++ b/llvm/lib/Target/Mips/MCTargetDesc/MipsMCTargetDesc.h
@@ -23,7 +23,9 @@ class MCCodeEmitter;
 class MCContext;
 class MCInstrInfo;
 class MCObjectTargetWriter;
+class MCObjectWriter;
 class MCRegisterInfo;
+class MCStreamer;
 class MCSubtargetInfo;
 class MCTargetOptions;
 class StringRef;
@@ -39,8 +41,21 @@ MCAsmBackend *createMipsAsmBackend(const Target &T, const MCSubtargetInfo &STI,
                                    const MCRegisterInfo &MRI,
                                    const MCTargetOptions &Options);
 
+/// Construct an MIPS Windows COFF machine code streamer which will generate
+/// PE/COFF format object files.
+///
+/// Takes ownership of \p AB and \p CE.
+MCStreamer *createMipsWinCOFFStreamer(MCContext &C,
+                                      std::unique_ptr<MCAsmBackend> &&AB,
+                                      std::unique_ptr<MCObjectWriter> &&OW,
+                                      std::unique_ptr<MCCodeEmitter> &&CE);
+
+/// Construct a Mips ELF object writer.
 std::unique_ptr<MCObjectTargetWriter>
 createMipsELFObjectWriter(const Triple &TT, bool IsN32);
+/// Construct a Mips Win COFF object writer.
+std::unique_ptr<MCObjectTargetWriter>
+createMipsWinCOFFObjectWriter();
 
 namespace MIPS_MC {
 StringRef selectMipsCPU(const Triple &TT, StringRef CPU);
diff --git a/llvm/lib/Target/Mips/MCTargetDesc/MipsWinCOFFObjectWriter.cpp b/llvm/lib/Target/Mips/MCTargetDesc/MipsWinCOFFObjectWriter.cpp
new file mode 100644
index 00000000000000..d014cc1b0c1b55
--- /dev/null
+++ b/llvm/lib/Target/Mips/MCTargetDesc/MipsWinCOFFObjectWriter.cpp
@@ -0,0 +1,58 @@
+//===-- MipsWinCOFFObjectWriter.cpp - Mips Win COFF Writer -----------------===//
+//
+// 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 "MCTargetDesc/MipsFixupKinds.h"
+#include "MCTargetDesc/MipsMCTargetDesc.h"
+#include "llvm/BinaryFormat/COFF.h"
+#include "llvm/MC/MCContext.h"
+#include "llvm/MC/MCWinCOFFObjectWriter.h"
+
+using namespace llvm;
+
+namespace {
+
+class MipsWinCOFFObjectWriter : public MCWinCOFFObjectTargetWriter {
+public:
+  MipsWinCOFFObjectWriter();
+
+  unsigned getRelocType(MCContext &Ctx, const MCValue &Target,
+                        const MCFixup &Fixup, bool IsCrossSection,
+                        const MCAsmBackend &MAB) const override;
+};
+
+} // end anonymous namespace
+
+MipsWinCOFFObjectWriter::MipsWinCOFFObjectWriter()
+    : MCWinCOFFObjectTargetWriter(COFF::IMAGE_FILE_MACHINE_R4000) {}
+
+unsigned MipsWinCOFFObjectWriter::getRelocType(MCContext &Ctx,
+                                               const MCValue &Target,
+                                               const MCFixup &Fixup,
+                                               bool IsCrossSection,
+                                               const MCAsmBackend &MAB) const {
+  unsigned FixupKind = Fixup.getKind();
+
+  switch (FixupKind) {
+  case FK_Data_4:
+    return COFF::IMAGE_REL_MIPS_...
[truncated]

@llvmbot
Copy link
Member

llvmbot commented Sep 8, 2024

@llvm/pr-subscribers-lld

Author: None (hpoussin)

Changes
  • Add support for Windows MIPS relocations types
  • Support reading MIPS COFF files in objdump
  • Support generating MIPS COFF files in yaml2obj
  • Support generating MIPS COFF files in llvm-lib
  • Support generating MIPS COFF files in llvm-dlltool
  • Support generating MIPS COFF files in clang

Compiler and library creation have been cross-tested with Microsoft counterparts.
Linker part is not yet ready (although available in my mips-pe branch).

By using Microsoft linker (or my work-in-process work on lld), I get working executables.
clang-20-mips


Patch is 33.84 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/107744.diff

26 Files Affected:

  • (modified) lld/COFF/Config.h (+1)
  • (modified) llvm/include/llvm/BinaryFormat/COFF.h (+18)
  • (modified) llvm/include/llvm/Object/WindowsMachineFlag.h (+2)
  • (modified) llvm/include/llvm/ObjectYAML/COFFYAML.h (+5)
  • (modified) llvm/lib/MC/WinCOFFObjectWriter.cpp (+15-2)
  • (modified) llvm/lib/Object/COFFObjectFile.cpp (+26)
  • (modified) llvm/lib/Object/WindowsMachineFlag.cpp (+4)
  • (modified) llvm/lib/Object/WindowsResource.cpp (+3)
  • (modified) llvm/lib/ObjectYAML/COFFYAML.cpp (+23)
  • (modified) llvm/lib/ObjectYAML/CodeViewYAMLSymbols.cpp (+3)
  • (modified) llvm/lib/Target/Mips/MCTargetDesc/CMakeLists.txt (+2)
  • (modified) llvm/lib/Target/Mips/MCTargetDesc/MipsAsmBackend.cpp (+21)
  • (modified) llvm/lib/Target/Mips/MCTargetDesc/MipsMCAsmInfo.cpp (+25-3)
  • (modified) llvm/lib/Target/Mips/MCTargetDesc/MipsMCAsmInfo.h (+18-3)
  • (modified) llvm/lib/Target/Mips/MCTargetDesc/MipsMCTargetDesc.cpp (+19-1)
  • (modified) llvm/lib/Target/Mips/MCTargetDesc/MipsMCTargetDesc.h (+15)
  • (added) llvm/lib/Target/Mips/MCTargetDesc/MipsWinCOFFObjectWriter.cpp (+58)
  • (added) llvm/lib/Target/Mips/MCTargetDesc/MipsWinCOFFStreamer.cpp (+33)
  • (modified) llvm/lib/Target/Mips/MipsAsmPrinter.cpp (+59-56)
  • (modified) llvm/lib/Target/Mips/MipsTargetMachine.cpp (+7-1)
  • (modified) llvm/lib/TargetParser/Triple.cpp (+5-1)
  • (added) llvm/test/MC/Mips/coff-basic.ll (+8)
  • (added) llvm/test/MC/Mips/coff-relocs.ll (+46)
  • (added) llvm/test/Object/Inputs/COFF/mipsel.yaml (+8)
  • (modified) llvm/test/Object/objdump-section-content.test (+4)
  • (modified) llvm/unittests/TargetParser/TripleTest.cpp (+3)
diff --git a/lld/COFF/Config.h b/lld/COFF/Config.h
index 947f3fead54e03..a7984753c7e917 100644
--- a/lld/COFF/Config.h
+++ b/lld/COFF/Config.h
@@ -40,6 +40,7 @@ static const auto ARM64EC = llvm::COFF::IMAGE_FILE_MACHINE_ARM64EC;
 static const auto ARM64X = llvm::COFF::IMAGE_FILE_MACHINE_ARM64X;
 static const auto ARMNT = llvm::COFF::IMAGE_FILE_MACHINE_ARMNT;
 static const auto I386 = llvm::COFF::IMAGE_FILE_MACHINE_I386;
+static const auto MIPS = llvm::COFF::IMAGE_FILE_MACHINE_R4000;
 
 enum class ExportSource {
   Unset,
diff --git a/llvm/include/llvm/BinaryFormat/COFF.h b/llvm/include/llvm/BinaryFormat/COFF.h
index 3fc543f73c49db..bbc5264d17872a 100644
--- a/llvm/include/llvm/BinaryFormat/COFF.h
+++ b/llvm/include/llvm/BinaryFormat/COFF.h
@@ -417,6 +417,24 @@ enum RelocationTypesARM64 : unsigned {
   IMAGE_REL_ARM64_REL32 = 0x0011,
 };
 
+enum RelocationTypesMips : unsigned {
+  IMAGE_REL_MIPS_ABSOLUTE = 0x0000,
+  IMAGE_REL_MIPS_REFHALF = 0x0001,
+  IMAGE_REL_MIPS_REFWORD = 0x0002,
+  IMAGE_REL_MIPS_JMPADDR = 0x0003,
+  IMAGE_REL_MIPS_REFHI = 0x0004,
+  IMAGE_REL_MIPS_REFLO = 0x0005,
+  IMAGE_REL_MIPS_GPREL = 0x0006,
+  IMAGE_REL_MIPS_LITERAL = 0x0007,
+  IMAGE_REL_MIPS_SECTION = 0x000A,
+  IMAGE_REL_MIPS_SECREL = 0x000B,
+  IMAGE_REL_MIPS_SECRELLO = 0x000C,
+  IMAGE_REL_MIPS_SECRELHI = 0x000D,
+  IMAGE_REL_MIPS_JMPADDR16 = 0x0010,
+  IMAGE_REL_MIPS_REFWORDNB = 0x0022,
+  IMAGE_REL_MIPS_PAIR = 0x0025,
+};
+
 enum DynamicRelocationType : unsigned {
   IMAGE_DYNAMIC_RELOCATION_GUARD_RF_PROLOGUE = 1,
   IMAGE_DYNAMIC_RELOCATION_GUARD_RF_EPILOGUE = 2,
diff --git a/llvm/include/llvm/Object/WindowsMachineFlag.h b/llvm/include/llvm/Object/WindowsMachineFlag.h
index 1cb408ed13d420..ce5b356f8bfeed 100644
--- a/llvm/include/llvm/Object/WindowsMachineFlag.h
+++ b/llvm/include/llvm/Object/WindowsMachineFlag.h
@@ -43,6 +43,8 @@ template <typename T> Triple::ArchType getMachineArchType(T machine) {
   case COFF::IMAGE_FILE_MACHINE_ARM64EC:
   case COFF::IMAGE_FILE_MACHINE_ARM64X:
     return llvm::Triple::ArchType::aarch64;
+  case COFF::IMAGE_FILE_MACHINE_R4000:
+    return llvm::Triple::ArchType::mipsel;
   default:
     return llvm::Triple::ArchType::UnknownArch;
   }
diff --git a/llvm/include/llvm/ObjectYAML/COFFYAML.h b/llvm/include/llvm/ObjectYAML/COFFYAML.h
index 2f9a1aae0eb05a..f7797fc7f67bcd 100644
--- a/llvm/include/llvm/ObjectYAML/COFFYAML.h
+++ b/llvm/include/llvm/ObjectYAML/COFFYAML.h
@@ -179,6 +179,11 @@ struct ScalarEnumerationTraits<COFF::RelocationTypeAMD64> {
   static void enumeration(IO &IO, COFF::RelocationTypeAMD64 &Value);
 };
 
+template <>
+struct ScalarEnumerationTraits<COFF::RelocationTypesMips> {
+  static void enumeration(IO &IO, COFF::RelocationTypesMips &Value);
+};
+
 template <>
 struct ScalarEnumerationTraits<COFF::RelocationTypesARM> {
   static void enumeration(IO &IO, COFF::RelocationTypesARM &Value);
diff --git a/llvm/lib/MC/WinCOFFObjectWriter.cpp b/llvm/lib/MC/WinCOFFObjectWriter.cpp
index 62f53423126ea9..d5a30d332d2b92 100644
--- a/llvm/lib/MC/WinCOFFObjectWriter.cpp
+++ b/llvm/lib/MC/WinCOFFObjectWriter.cpp
@@ -773,7 +773,10 @@ void WinCOFFWriter::assignFileOffsets(MCAssembler &Asm) {
 
       for (auto &Relocation : Sec->Relocations) {
         assert(Relocation.Symb->getIndex() != -1);
-        Relocation.Data.SymbolTableIndex = Relocation.Symb->getIndex();
+        if (Header.Machine != COFF::IMAGE_FILE_MACHINE_R4000 ||
+            Relocation.Data.Type != COFF::IMAGE_REL_MIPS_PAIR) {
+          Relocation.Data.SymbolTableIndex = Relocation.Symb->getIndex();
+        }
       }
     }
 
@@ -967,8 +970,18 @@ void WinCOFFWriter::recordRelocation(MCAssembler &Asm,
   if (Fixup.getKind() == FK_SecRel_2)
     FixedValue = 0;
 
-  if (OWriter.TargetObjectWriter->recordRelocation(Fixup))
+  if (OWriter.TargetObjectWriter->recordRelocation(Fixup)) {
     Sec->Relocations.push_back(Reloc);
+    if (Header.Machine == COFF::IMAGE_FILE_MACHINE_R4000 &&
+        (Reloc.Data.Type == COFF::IMAGE_REL_MIPS_REFHI ||
+         Reloc.Data.Type == COFF::IMAGE_REL_MIPS_SECRELHI)) {
+      // IMAGE_REL_MIPS_REFHI and IMAGE_REL_MIPS_SECRELHI *must*
+      // be followed by IMAGE_REL_MIPS_PAIR
+      auto RelocPair = Reloc;
+      RelocPair.Data.Type = COFF::IMAGE_REL_MIPS_PAIR;
+      Sec->Relocations.push_back(RelocPair);
+    }
+  }
 }
 
 static std::time_t getTime() {
diff --git a/llvm/lib/Object/COFFObjectFile.cpp b/llvm/lib/Object/COFFObjectFile.cpp
index 5fdf3baf8c02cc..ad15d42135b319 100644
--- a/llvm/lib/Object/COFFObjectFile.cpp
+++ b/llvm/lib/Object/COFFObjectFile.cpp
@@ -1132,6 +1132,8 @@ StringRef COFFObjectFile::getFileFormatName() const {
     return "COFF-ARM64EC";
   case COFF::IMAGE_FILE_MACHINE_ARM64X:
     return "COFF-ARM64X";
+  case COFF::IMAGE_FILE_MACHINE_R4000:
+    return "COFF-R4000";
   default:
     return "COFF-<unknown arch>";
   }
@@ -1465,6 +1467,27 @@ StringRef COFFObjectFile::getRelocationTypeName(uint16_t Type) const {
       return "Unknown";
     }
     break;
+  case Triple::mipsel:
+    switch (Type) {
+    LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_MIPS_ABSOLUTE);
+    LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_MIPS_REFHALF);
+    LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_MIPS_REFWORD);
+    LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_MIPS_JMPADDR);
+    LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_MIPS_REFHI);
+    LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_MIPS_REFLO);
+    LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_MIPS_GPREL);
+    LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_MIPS_LITERAL);
+    LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_MIPS_SECTION);
+    LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_MIPS_SECREL);
+    LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_MIPS_SECRELLO);
+    LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_MIPS_SECRELHI);
+    LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_MIPS_JMPADDR16);
+    LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_MIPS_REFWORDNB);
+    LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_MIPS_PAIR);
+    default:
+      return "Unknown";
+    }
+    break;
   default:
     return "Unknown";
   }
@@ -2326,6 +2349,9 @@ ResourceSectionRef::getContents(const coff_resource_data_entry &Entry) {
     case Triple::aarch64:
       RVAReloc = COFF::IMAGE_REL_ARM64_ADDR32NB;
       break;
+    case Triple::mipsel:
+      RVAReloc = COFF::IMAGE_REL_MIPS_REFWORDNB;
+      break;
     default:
       return createStringError(object_error::parse_failed,
                                "unsupported architecture");
diff --git a/llvm/lib/Object/WindowsMachineFlag.cpp b/llvm/lib/Object/WindowsMachineFlag.cpp
index b9f818775768a2..bade2d4f0f6a74 100644
--- a/llvm/lib/Object/WindowsMachineFlag.cpp
+++ b/llvm/lib/Object/WindowsMachineFlag.cpp
@@ -28,6 +28,8 @@ COFF::MachineTypes llvm::getMachineType(StringRef S) {
       .Case("arm64", COFF::IMAGE_FILE_MACHINE_ARM64)
       .Case("arm64ec", COFF::IMAGE_FILE_MACHINE_ARM64EC)
       .Case("arm64x", COFF::IMAGE_FILE_MACHINE_ARM64X)
+      .Case("mips", COFF::IMAGE_FILE_MACHINE_R4000) // also handle mips (big-endian) because we want to support '/machine:MIPS'
+      .Case("mipsel", COFF::IMAGE_FILE_MACHINE_R4000)
       .Default(COFF::IMAGE_FILE_MACHINE_UNKNOWN);
 }
 
@@ -45,6 +47,8 @@ StringRef llvm::machineToStr(COFF::MachineTypes MT) {
     return "x64";
   case COFF::IMAGE_FILE_MACHINE_I386:
     return "x86";
+  case COFF::IMAGE_FILE_MACHINE_R4000:
+    return "mipsel";
   default:
     llvm_unreachable("unknown machine type");
   }
diff --git a/llvm/lib/Object/WindowsResource.cpp b/llvm/lib/Object/WindowsResource.cpp
index 306e8ec542068b..211e581a7da6a9 100644
--- a/llvm/lib/Object/WindowsResource.cpp
+++ b/llvm/lib/Object/WindowsResource.cpp
@@ -992,6 +992,9 @@ void WindowsResourceCOFFWriter::writeFirstSectionRelocations() {
     case Triple::aarch64:
       Reloc->Type = COFF::IMAGE_REL_ARM64_ADDR32NB;
       break;
+    case Triple::mipsel:
+      Reloc->Type = COFF::IMAGE_REL_MIPS_REFWORDNB;
+      break;
     default:
       llvm_unreachable("unknown machine type");
     }
diff --git a/llvm/lib/ObjectYAML/COFFYAML.cpp b/llvm/lib/ObjectYAML/COFFYAML.cpp
index e14e1b5e467b41..53ea40a0354cea 100644
--- a/llvm/lib/ObjectYAML/COFFYAML.cpp
+++ b/llvm/lib/ObjectYAML/COFFYAML.cpp
@@ -183,6 +183,25 @@ void ScalarEnumerationTraits<COFF::RelocationTypeAMD64>::enumeration(
   ECase(IMAGE_REL_AMD64_SSPAN32);
 }
 
+void ScalarEnumerationTraits<COFF::RelocationTypesMips>::enumeration(
+    IO &IO, COFF::RelocationTypesMips &Value) {
+  ECase(IMAGE_REL_MIPS_ABSOLUTE);
+  ECase(IMAGE_REL_MIPS_REFHALF);
+  ECase(IMAGE_REL_MIPS_REFWORD);
+  ECase(IMAGE_REL_MIPS_JMPADDR);
+  ECase(IMAGE_REL_MIPS_REFHI);
+  ECase(IMAGE_REL_MIPS_REFLO);
+  ECase(IMAGE_REL_MIPS_GPREL);
+  ECase(IMAGE_REL_MIPS_LITERAL);
+  ECase(IMAGE_REL_MIPS_SECTION);
+  ECase(IMAGE_REL_MIPS_SECREL);
+  ECase(IMAGE_REL_MIPS_SECRELLO);
+  ECase(IMAGE_REL_MIPS_SECRELHI);
+  ECase(IMAGE_REL_MIPS_JMPADDR16);
+  ECase(IMAGE_REL_MIPS_REFWORDNB);
+  ECase(IMAGE_REL_MIPS_PAIR);
+}
+
 void ScalarEnumerationTraits<COFF::RelocationTypesARM>::enumeration(
     IO &IO, COFF::RelocationTypesARM &Value) {
   ECase(IMAGE_REL_ARM_ABSOLUTE);
@@ -427,6 +446,10 @@ void MappingTraits<COFFYAML::Relocation>::mapping(IO &IO,
     MappingNormalization<NType<COFF::RelocationTypeAMD64>, uint16_t> NT(
         IO, Rel.Type);
     IO.mapRequired("Type", NT->Type);
+  } else if (H.Machine == COFF::IMAGE_FILE_MACHINE_R4000) {
+    MappingNormalization<NType<COFF::RelocationTypesMips>, uint16_t> NT(
+        IO, Rel.Type);
+    IO.mapRequired("Type", NT->Type);
   } else if (H.Machine == COFF::IMAGE_FILE_MACHINE_ARMNT) {
     MappingNormalization<NType<COFF::RelocationTypesARM>, uint16_t> NT(
         IO, Rel.Type);
diff --git a/llvm/lib/ObjectYAML/CodeViewYAMLSymbols.cpp b/llvm/lib/ObjectYAML/CodeViewYAMLSymbols.cpp
index e1d2700623ec3c..26d71e624aee5b 100644
--- a/llvm/lib/ObjectYAML/CodeViewYAMLSymbols.cpp
+++ b/llvm/lib/ObjectYAML/CodeViewYAMLSymbols.cpp
@@ -171,6 +171,9 @@ void ScalarEnumerationTraits<RegisterId>::enumeration(IO &io, RegisterId &Reg) {
   case COFF::IMAGE_FILE_MACHINE_ARM64X:
     CpuType = CPUType::ARM64;
     break;
+  case COFF::IMAGE_FILE_MACHINE_R4000:
+    CpuType = CPUType::MIPSIII;
+    break;
   }
 
   if (CpuType)
diff --git a/llvm/lib/Target/Mips/MCTargetDesc/CMakeLists.txt b/llvm/lib/Target/Mips/MCTargetDesc/CMakeLists.txt
index 97a6f886d114ec..d3f16e5042c3ac 100644
--- a/llvm/lib/Target/Mips/MCTargetDesc/CMakeLists.txt
+++ b/llvm/lib/Target/Mips/MCTargetDesc/CMakeLists.txt
@@ -12,6 +12,8 @@ add_llvm_component_library(LLVMMipsDesc
   MipsNaClELFStreamer.cpp
   MipsOptionRecord.cpp
   MipsTargetStreamer.cpp
+  MipsWinCOFFObjectWriter.cpp
+  MipsWinCOFFStreamer.cpp
 
   LINK_COMPONENTS
   CodeGenTypes
diff --git a/llvm/lib/Target/Mips/MCTargetDesc/MipsAsmBackend.cpp b/llvm/lib/Target/Mips/MCTargetDesc/MipsAsmBackend.cpp
index f8172e576ce4c1..16318cffd7470e 100644
--- a/llvm/lib/Target/Mips/MCTargetDesc/MipsAsmBackend.cpp
+++ b/llvm/lib/Target/Mips/MCTargetDesc/MipsAsmBackend.cpp
@@ -597,10 +597,31 @@ bool MipsAsmBackend::isMicroMips(const MCSymbol *Sym) const {
   return false;
 }
 
+namespace {
+
+class WindowsMipsAsmBackend : public MipsAsmBackend {
+public:
+  WindowsMipsAsmBackend(const Target &T, const MCRegisterInfo &MRI,
+                        const MCSubtargetInfo &STI)
+    : MipsAsmBackend(T, MRI, STI.getTargetTriple(), STI.getCPU(), false) {
+  }
+
+  std::unique_ptr<MCObjectTargetWriter>
+  createObjectTargetWriter() const override {
+    return createMipsWinCOFFObjectWriter();
+  }
+};
+
+} // end anonymous namespace
+
 MCAsmBackend *llvm::createMipsAsmBackend(const Target &T,
                                          const MCSubtargetInfo &STI,
                                          const MCRegisterInfo &MRI,
                                          const MCTargetOptions &Options) {
+  const Triple &TheTriple = STI.getTargetTriple();
+  if (TheTriple.isOSWindows())
+    return new WindowsMipsAsmBackend(T, MRI, STI);
+
   MipsABIInfo ABI = MipsABIInfo::computeTargetABI(STI.getTargetTriple(),
                                                   STI.getCPU(), Options);
   return new MipsAsmBackend(T, MRI, STI.getTargetTriple(), STI.getCPU(),
diff --git a/llvm/lib/Target/Mips/MCTargetDesc/MipsMCAsmInfo.cpp b/llvm/lib/Target/Mips/MCTargetDesc/MipsMCAsmInfo.cpp
index f89c78e75d3ee7..960256bc38f244 100644
--- a/llvm/lib/Target/Mips/MCTargetDesc/MipsMCAsmInfo.cpp
+++ b/llvm/lib/Target/Mips/MCTargetDesc/MipsMCAsmInfo.cpp
@@ -16,10 +16,10 @@
 
 using namespace llvm;
 
-void MipsMCAsmInfo::anchor() { }
+void MipsELFMCAsmInfo::anchor() { }
 
-MipsMCAsmInfo::MipsMCAsmInfo(const Triple &TheTriple,
-                             const MCTargetOptions &Options) {
+MipsELFMCAsmInfo::MipsELFMCAsmInfo(const Triple &TheTriple,
+                                   const MCTargetOptions &Options) {
   IsLittleEndian = TheTriple.isLittleEndian();
 
   MipsABIInfo ABI = MipsABIInfo::computeTargetABI(TheTriple, "", Options);
@@ -51,3 +51,25 @@ MipsMCAsmInfo::MipsMCAsmInfo(const Triple &TheTriple,
   DwarfRegNumForCFI = true;
   HasMipsExpressions = true;
 }
+
+void MipsCOFFMCAsmInfoMicrosoft::anchor() { }
+
+MipsCOFFMCAsmInfoMicrosoft::MipsCOFFMCAsmInfoMicrosoft() {
+  WinEHEncodingType = WinEH::EncodingType::Itanium;
+  CommentString = ";";
+
+  ExceptionsType = ExceptionHandling::WinEH;
+
+  AllowAtInName = true;
+}
+
+void MipsCOFFMCAsmInfoGNU::anchor() { }
+
+MipsCOFFMCAsmInfoGNU::MipsCOFFMCAsmInfoGNU() {
+  HasSingleParameterDotFile = true;
+  WinEHEncodingType = WinEH::EncodingType::Itanium;
+
+  ExceptionsType = ExceptionHandling::WinEH;
+
+  AllowAtInName = true;
+}
diff --git a/llvm/lib/Target/Mips/MCTargetDesc/MipsMCAsmInfo.h b/llvm/lib/Target/Mips/MCTargetDesc/MipsMCAsmInfo.h
index d8bfe58d24a838..96348b17e57696 100644
--- a/llvm/lib/Target/Mips/MCTargetDesc/MipsMCAsmInfo.h
+++ b/llvm/lib/Target/Mips/MCTargetDesc/MipsMCAsmInfo.h
@@ -13,17 +13,32 @@
 #ifndef LLVM_LIB_TARGET_MIPS_MCTARGETDESC_MIPSMCASMINFO_H
 #define LLVM_LIB_TARGET_MIPS_MCTARGETDESC_MIPSMCASMINFO_H
 
+#include "llvm/MC/MCAsmInfoCOFF.h"
 #include "llvm/MC/MCAsmInfoELF.h"
 
 namespace llvm {
 class Triple;
 
-class MipsMCAsmInfo : public MCAsmInfoELF {
+class MipsELFMCAsmInfo : public MCAsmInfoELF {
   void anchor() override;
 
 public:
-  explicit MipsMCAsmInfo(const Triple &TheTriple,
-                         const MCTargetOptions &Options);
+  explicit MipsELFMCAsmInfo(const Triple &TheTriple,
+                            const MCTargetOptions &Options);
+};
+
+class MipsCOFFMCAsmInfoMicrosoft : public MCAsmInfoMicrosoft {
+  void anchor() override;
+
+public:
+  explicit MipsCOFFMCAsmInfoMicrosoft();
+};
+
+class MipsCOFFMCAsmInfoGNU : public MCAsmInfoGNUCOFF {
+  void anchor() override;
+
+public:
+  explicit MipsCOFFMCAsmInfoGNU();
 };
 
 } // namespace llvm
diff --git a/llvm/lib/Target/Mips/MCTargetDesc/MipsMCTargetDesc.cpp b/llvm/lib/Target/Mips/MCTargetDesc/MipsMCTargetDesc.cpp
index ca95f67174da1e..378cc12388bae3 100644
--- a/llvm/lib/Target/Mips/MCTargetDesc/MipsMCTargetDesc.cpp
+++ b/llvm/lib/Target/Mips/MCTargetDesc/MipsMCTargetDesc.cpp
@@ -45,6 +45,13 @@ using namespace llvm;
 #define GET_REGINFO_MC_DESC
 #include "MipsGenRegisterInfo.inc"
 
+namespace {
+class MipsWinCOFFTargetStreamer : public MipsTargetStreamer {
+public:
+  MipsWinCOFFTargetStreamer(MCStreamer &S) : MipsTargetStreamer(S) {}
+};
+} // end namespace
+
 /// Select the Mips CPU for the given triple and cpu name.
 StringRef MIPS_MC::selectMipsCPU(const Triple &TT, StringRef CPU) {
   if (CPU.empty() || CPU == "generic") {
@@ -84,7 +91,14 @@ static MCSubtargetInfo *createMipsMCSubtargetInfo(const Triple &TT,
 static MCAsmInfo *createMipsMCAsmInfo(const MCRegisterInfo &MRI,
                                       const Triple &TT,
                                       const MCTargetOptions &Options) {
-  MCAsmInfo *MAI = new MipsMCAsmInfo(TT, Options);
+  MCAsmInfo *MAI;
+
+  if (TT.isWindowsMSVCEnvironment())
+    MAI = new MipsCOFFMCAsmInfoMicrosoft();
+  else if (TT.isOSWindows())
+    MAI = new MipsCOFFMCAsmInfoGNU();
+  else
+    MAI = new MipsELFMCAsmInfo(TT, Options);
 
   unsigned SP = MRI.getDwarfRegNum(Mips::SP, true);
   MCCFIInstruction Inst = MCCFIInstruction::createDefCfaRegister(nullptr, SP);
@@ -127,6 +141,8 @@ static MCTargetStreamer *createMipsNullTargetStreamer(MCStreamer &S) {
 
 static MCTargetStreamer *
 createMipsObjectTargetStreamer(MCStreamer &S, const MCSubtargetInfo &STI) {
+  if (STI.getTargetTriple().isOSBinFormatCOFF())
+    return new MipsWinCOFFTargetStreamer(S);
   return new MipsTargetELFStreamer(S, STI);
 }
 
@@ -186,6 +202,8 @@ extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeMipsTargetMC() {
     TargetRegistry::RegisterNullTargetStreamer(*T,
                                                createMipsNullTargetStreamer);
 
+    TargetRegistry::RegisterCOFFStreamer(*T, createMipsWinCOFFStreamer);
+
     // Register the MC subtarget info.
     TargetRegistry::RegisterMCSubtargetInfo(*T, createMipsMCSubtargetInfo);
 
diff --git a/llvm/lib/Target/Mips/MCTargetDesc/MipsMCTargetDesc.h b/llvm/lib/Target/Mips/MCTargetDesc/MipsMCTargetDesc.h
index d51f3b9abcfd1b..a02e4fa2208880 100644
--- a/llvm/lib/Target/Mips/MCTargetDesc/MipsMCTargetDesc.h
+++ b/llvm/lib/Target/Mips/MCTargetDesc/MipsMCTargetDesc.h
@@ -23,7 +23,9 @@ class MCCodeEmitter;
 class MCContext;
 class MCInstrInfo;
 class MCObjectTargetWriter;
+class MCObjectWriter;
 class MCRegisterInfo;
+class MCStreamer;
 class MCSubtargetInfo;
 class MCTargetOptions;
 class StringRef;
@@ -39,8 +41,21 @@ MCAsmBackend *createMipsAsmBackend(const Target &T, const MCSubtargetInfo &STI,
                                    const MCRegisterInfo &MRI,
                                    const MCTargetOptions &Options);
 
+/// Construct an MIPS Windows COFF machine code streamer which will generate
+/// PE/COFF format object files.
+///
+/// Takes ownership of \p AB and \p CE.
+MCStreamer *createMipsWinCOFFStreamer(MCContext &C,
+                                      std::unique_ptr<MCAsmBackend> &&AB,
+                                      std::unique_ptr<MCObjectWriter> &&OW,
+                                      std::unique_ptr<MCCodeEmitter> &&CE);
+
+/// Construct a Mips ELF object writer.
 std::unique_ptr<MCObjectTargetWriter>
 createMipsELFObjectWriter(const Triple &TT, bool IsN32);
+/// Construct a Mips Win COFF object writer.
+std::unique_ptr<MCObjectTargetWriter>
+createMipsWinCOFFObjectWriter();
 
 namespace MIPS_MC {
 StringRef selectMipsCPU(const Triple &TT, StringRef CPU);
diff --git a/llvm/lib/Target/Mips/MCTargetDesc/MipsWinCOFFObjectWriter.cpp b/llvm/lib/Target/Mips/MCTargetDesc/MipsWinCOFFObjectWriter.cpp
new file mode 100644
index 00000000000000..d014cc1b0c1b55
--- /dev/null
+++ b/llvm/lib/Target/Mips/MCTargetDesc/MipsWinCOFFObjectWriter.cpp
@@ -0,0 +1,58 @@
+//===-- MipsWinCOFFObjectWriter.cpp - Mips Win COFF Writer -----------------===//
+//
+// 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 "MCTargetDesc/MipsFixupKinds.h"
+#include "MCTargetDesc/MipsMCTargetDesc.h"
+#include "llvm/BinaryFormat/COFF.h"
+#include "llvm/MC/MCContext.h"
+#include "llvm/MC/MCWinCOFFObjectWriter.h"
+
+using namespace llvm;
+
+namespace {
+
+class MipsWinCOFFObjectWriter : public MCWinCOFFObjectTargetWriter {
+public:
+  MipsWinCOFFObjectWriter();
+
+  unsigned getRelocType(MCContext &Ctx, const MCValue &Target,
+                        const MCFixup &Fixup, bool IsCrossSection,
+                        const MCAsmBackend &MAB) const override;
+};
+
+} // end anonymous namespace
+
+MipsWinCOFFObjectWriter::MipsWinCOFFObjectWriter()
+    : MCWinCOFFObjectTargetWriter(COFF::IMAGE_FILE_MACHINE_R4000) {}
+
+unsigned MipsWinCOFFObjectWriter::getRelocType(MCContext &Ctx,
+                                               const MCValue &Target,
+                                               const MCFixup &Fixup,
+                                               bool IsCrossSection,
+                                               const MCAsmBackend &MAB) const {
+  unsigned FixupKind = Fixup.getKind();
+
+  switch (FixupKind) {
+  case FK_Data_4:
+    return COFF::IMAGE_REL_MIPS_...
[truncated]

@hpoussin hpoussin force-pushed the clang-mips-coff branch 2 times, most recently from b02203d to 38bcda6 Compare September 8, 2024 19:38
@mstorsjo
Copy link
Member

mstorsjo commented Sep 8, 2024

Overall, thanks for the PR - this looks very exciting to me!

First off, I think it'd be good to set the scope for this. This is one of the historical Windows architectures, supported in early versions of NT and CE. As such, it probably has mostly hobbyist value at this point. However that shouldn't really be an issue for LLVM - I don't foresee this to add very much maintainance burden (as this isn't a new target per se, but mostly scattered COFF specific conditions), and is quite interesting for Windows target completeness. The main extra "burden" may be that people interested in testing all Windows configurations now should enable another target backend.

As for getting changes properly reviewed and merged; within LLVM, each PR, once merged, results in one commit. So for a longer patch series like this, one would need to do some sort of set of stacked PRs. (Or as a simpler version, one can make one branch per commit, i.e. one for commit 1, one for commits 1+2, one for commits 1+2+3 etc, and just point out the dependencies in each PR.)

In practice, I guess we can do some sort of pre-review within this PR, and for the commits that look fine, you can file individual PRs, avoiding needing to have 13 outstanding stacked PRs at once.

CCing a couple people who may be interested in commenting on things, @rnk @zmodem @cjacek @efriedma-quic.

@hpoussin
Copy link
Contributor Author

hpoussin commented Sep 8, 2024

I need a little bit help to understand why Linux buildbot succeeds, while Windows one fails.

@dpaoliello
Copy link
Contributor

I need a little bit help to understand why Linux buildbot succeeds, while Windows one fails.

Looks like an AV in some of the tests. If you open up the log for the Windows build you can see things like:

FAIL: LLVM :: MC/Mips/forbidden-slot.s (35919 of 54904)
******************** TEST 'LLVM :: MC/Mips/forbidden-slot.s' FAILED ********************
Exit Code: 3221225477
Command Output (stdout):
--
# RUN: at line 1
c:\ws\src\build\bin\llvm-mc.exe -assemble -mcpu=mips64r6 -arch=mips64el -filetype=obj C:\ws\src\llvm\test\MC\Mips\forbidden-slot.s -o tmp.o
# executed command: 'c:\ws\src\build\bin\llvm-mc.exe' -assemble -mcpu=mips64r6 -arch=mips64el -filetype=obj 'C:\ws\src\llvm\test\MC\Mips\forbidden-slot.s' -o tmp.o
# .---command stderr------------
# | PLEASE submit a bug report to https://github.com/llvm/llvm-project/issues/ and include the crash backtrace.
# | Stack dump:
# | 0.	Program arguments: c:\\ws\\src\\build\\bin\\llvm-mc.exe -assemble -mcpu=mips64r6 -arch=mips64el -filetype=obj C:\\ws\\src\\llvm\\test\\MC\\Mips\\forbidden-slot.s -o tmp.o
# | Exception Code: 0xC0000005
# |  #0 0x00007ff657a1bc59 (c:\ws\src\build\bin\llvm-mc.exe+0x8abc59)
# |  #1 0x00007ff657a1cc49 (c:\ws\src\build\bin\llvm-mc.exe+0x8acc49)
# |  #2 0x00007ff657a1d86c (c:\ws\src\build\bin\llvm-mc.exe+0x8ad86c)
# |  #3 0x00007ff657a1d749 (c:\ws\src\build\bin\llvm-mc.exe+0x8ad749)
# |  #4 0x00007ff657a077e5 (c:\ws\src\build\bin\llvm-mc.exe+0x8977e5)
# |  #5 0x00007ff657a05d7e (c:\ws\src\build\bin\llvm-mc.exe+0x895d7e)
# |  #6 0x00007ff657a71fcc (c:\ws\src\build\bin\llvm-mc.exe+0x901fcc)
# |  #7 0x00007ff65717feb5 (c:\ws\src\build\bin\llvm-mc.exe+0xfeb5)
# |  #8 0x00007ff65718326b (c:\ws\src\build\bin\llvm-mc.exe+0x1326b)
# |  #9 0x00007ff657b77910 (c:\ws\src\build\bin\llvm-mc.exe+0xa07910)
# | #10 0x00007ffad8a07ac4 (C:\Windows\System32\KERNEL32.DLL+0x17ac4)
# | #11 0x00007ffae696a4e1 (C:\Windows\SYSTEM32\ntdll.dll+0x5a4e1)
# `-----------------------------
# error: command failed with exit status: 0xc0000005
--
********************

You can follow the instructions on the LLVM docs on how to run a single test: https://llvm.org/docs/TestingGuide.html#unit-and-regression-tests

Assuming that you don't have llvm-lit on your path, you can run it like this:

python .\build\bin\llvm-lit.py -s -v .\llvm\test\MC\Mips\forbidden-slot.s

The test failure also shows the exact command that was run (in this case c:\ws\src\build\bin\llvm-mc.exe -assemble -mcpu=mips64r6 -arch=mips64el -filetype=obj C:\ws\src\llvm\test\MC\Mips\forbidden-slot.s -o tmp.o), so you can retry that under a debugger, assuming that you've enabled debug symbols when building LLVM.

@hpoussin
Copy link
Contributor Author

hpoussin commented Sep 9, 2024

I browsed through the first couple commits and added a couple pointers. Overall it looks reasonable, but things can probably be split up into even smaller commits for atomicity, which also would make it clearer where we'd want more test coverage.

Thanks for the review. I'll take it into account when creating PRs for each part.

Copy link

⚠️ C/C++ code formatter, clang-format found issues in your code. ⚠️

You can test this locally with the following command:
git-clang-format --diff ebf0599314e17c3ab89f303d452811b1db3e6d1e 9deeff4e9136c88813f26e83241328eb680938c6 --extensions h,c,cpp -- llvm/lib/Target/Mips/MCTargetDesc/MipsWinCOFFObjectWriter.cpp llvm/lib/Target/Mips/MCTargetDesc/MipsWinCOFFStreamer.cpp clang/lib/Basic/Targets.cpp clang/lib/Basic/Targets/Mips.cpp clang/lib/Basic/Targets/Mips.h clang/lib/CodeGen/CodeGenModule.cpp clang/lib/CodeGen/TargetInfo.h clang/lib/CodeGen/Targets/Mips.cpp clang/lib/Driver/ToolChains/MinGW.cpp clang/test/CodeGen/pragma-comment.c clang/test/Preprocessor/predefined-win-macros.c lld/COFF/Config.h llvm/include/llvm/BinaryFormat/COFF.h llvm/include/llvm/Object/WindowsMachineFlag.h llvm/include/llvm/ObjectYAML/COFFYAML.h llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp llvm/lib/MC/WinCOFFObjectWriter.cpp llvm/lib/Object/COFFImportFile.cpp llvm/lib/Object/COFFObjectFile.cpp llvm/lib/Object/WindowsMachineFlag.cpp llvm/lib/Object/WindowsResource.cpp llvm/lib/ObjectYAML/COFFYAML.cpp llvm/lib/ObjectYAML/CodeViewYAMLSymbols.cpp llvm/lib/Target/Mips/MCTargetDesc/MipsAsmBackend.cpp llvm/lib/Target/Mips/MCTargetDesc/MipsBaseInfo.h llvm/lib/Target/Mips/MCTargetDesc/MipsMCAsmInfo.cpp llvm/lib/Target/Mips/MCTargetDesc/MipsMCAsmInfo.h llvm/lib/Target/Mips/MCTargetDesc/MipsMCTargetDesc.cpp llvm/lib/Target/Mips/MCTargetDesc/MipsMCTargetDesc.h llvm/lib/Target/Mips/MipsAsmPrinter.cpp llvm/lib/Target/Mips/MipsISelLowering.cpp llvm/lib/Target/Mips/MipsISelLowering.h llvm/lib/Target/Mips/MipsMCInstLower.cpp llvm/lib/Target/Mips/MipsRegisterInfo.cpp llvm/lib/Target/Mips/MipsSubtarget.h llvm/lib/Target/Mips/MipsTargetMachine.cpp llvm/lib/TargetParser/Triple.cpp llvm/lib/ToolDrivers/llvm-dlltool/DlltoolDriver.cpp llvm/lib/ToolDrivers/llvm-lib/LibDriver.cpp llvm/unittests/TargetParser/TripleTest.cpp
View the diff from clang-format here.
diff --git a/clang/lib/Basic/Targets/Mips.cpp b/clang/lib/Basic/Targets/Mips.cpp
index 858cdd1c6f..d56995e3cc 100644
--- a/clang/lib/Basic/Targets/Mips.cpp
+++ b/clang/lib/Basic/Targets/Mips.cpp
@@ -307,11 +307,10 @@ bool MipsTargetInfo::validateTarget(DiagnosticsEngine &Diags) const {
 
 WindowsMipsTargetInfo::WindowsMipsTargetInfo(const llvm::Triple &Triple,
                                              const TargetOptions &Opts)
-    : WindowsTargetInfo<MipsTargetInfo>(Triple, Opts), Triple(Triple) {
-}
+    : WindowsTargetInfo<MipsTargetInfo>(Triple, Opts), Triple(Triple) {}
 
-void WindowsMipsTargetInfo::getVisualStudioDefines(const LangOptions &Opts,
-                                                   MacroBuilder &Builder) const {
+void WindowsMipsTargetInfo::getVisualStudioDefines(
+    const LangOptions &Opts, MacroBuilder &Builder) const {
   Builder.defineMacro("_M_MRX000", "4000");
 }
 
diff --git a/clang/lib/Basic/Targets/Mips.h b/clang/lib/Basic/Targets/Mips.h
index b138710bb8..f3bc0ee6d0 100644
--- a/clang/lib/Basic/Targets/Mips.h
+++ b/clang/lib/Basic/Targets/Mips.h
@@ -479,7 +479,8 @@ public:
 };
 
 // MIPS MinGW target
-class LLVM_LIBRARY_VISIBILITY MinGWMipsTargetInfo : public WindowsMipsTargetInfo {
+class LLVM_LIBRARY_VISIBILITY MinGWMipsTargetInfo
+    : public WindowsMipsTargetInfo {
 public:
   MinGWMipsTargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts);
 
diff --git a/clang/lib/CodeGen/Targets/Mips.cpp b/clang/lib/CodeGen/Targets/Mips.cpp
index e7601564f6..771a85c84b 100644
--- a/clang/lib/CodeGen/Targets/Mips.cpp
+++ b/clang/lib/CodeGen/Targets/Mips.cpp
@@ -109,7 +109,7 @@ public:
 class WindowsMIPSTargetCodeGenInfo : public MIPSTargetCodeGenInfo {
 public:
   WindowsMIPSTargetCodeGenInfo(CodeGenTypes &CGT, bool IsO32)
-        : MIPSTargetCodeGenInfo(CGT, IsO32) {}
+      : MIPSTargetCodeGenInfo(CGT, IsO32) {}
 
   void getDependentLibraryOption(llvm::StringRef Lib,
                                  llvm::SmallString<24> &Opt) const override {
@@ -117,8 +117,7 @@ public:
     Opt += qualifyWindowsLibrary(Lib);
   }
 
-  void getDetectMismatchOption(llvm::StringRef Name,
-                               llvm::StringRef Value,
+  void getDetectMismatchOption(llvm::StringRef Name, llvm::StringRef Value,
                                llvm::SmallString<32> &Opt) const override {
     Opt = "/FAILIFMISMATCH:\"" + Name.str() + "=" + Value.str() + "\"";
   }
diff --git a/llvm/include/llvm/ObjectYAML/COFFYAML.h b/llvm/include/llvm/ObjectYAML/COFFYAML.h
index f7797fc7f6..c22d4e7f0b 100644
--- a/llvm/include/llvm/ObjectYAML/COFFYAML.h
+++ b/llvm/include/llvm/ObjectYAML/COFFYAML.h
@@ -179,8 +179,7 @@ struct ScalarEnumerationTraits<COFF::RelocationTypeAMD64> {
   static void enumeration(IO &IO, COFF::RelocationTypeAMD64 &Value);
 };
 
-template <>
-struct ScalarEnumerationTraits<COFF::RelocationTypesMips> {
+template <> struct ScalarEnumerationTraits<COFF::RelocationTypesMips> {
   static void enumeration(IO &IO, COFF::RelocationTypesMips &Value);
 };
 
diff --git a/llvm/lib/Object/COFFObjectFile.cpp b/llvm/lib/Object/COFFObjectFile.cpp
index ad15d42135..f80a78d53a 100644
--- a/llvm/lib/Object/COFFObjectFile.cpp
+++ b/llvm/lib/Object/COFFObjectFile.cpp
@@ -1469,21 +1469,21 @@ StringRef COFFObjectFile::getRelocationTypeName(uint16_t Type) const {
     break;
   case Triple::mipsel:
     switch (Type) {
-    LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_MIPS_ABSOLUTE);
-    LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_MIPS_REFHALF);
-    LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_MIPS_REFWORD);
-    LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_MIPS_JMPADDR);
-    LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_MIPS_REFHI);
-    LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_MIPS_REFLO);
-    LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_MIPS_GPREL);
-    LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_MIPS_LITERAL);
-    LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_MIPS_SECTION);
-    LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_MIPS_SECREL);
-    LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_MIPS_SECRELLO);
-    LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_MIPS_SECRELHI);
-    LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_MIPS_JMPADDR16);
-    LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_MIPS_REFWORDNB);
-    LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_MIPS_PAIR);
+      LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_MIPS_ABSOLUTE);
+      LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_MIPS_REFHALF);
+      LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_MIPS_REFWORD);
+      LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_MIPS_JMPADDR);
+      LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_MIPS_REFHI);
+      LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_MIPS_REFLO);
+      LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_MIPS_GPREL);
+      LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_MIPS_LITERAL);
+      LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_MIPS_SECTION);
+      LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_MIPS_SECREL);
+      LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_MIPS_SECRELLO);
+      LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_MIPS_SECRELHI);
+      LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_MIPS_JMPADDR16);
+      LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_MIPS_REFWORDNB);
+      LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_MIPS_PAIR);
     default:
       return "Unknown";
     }
diff --git a/llvm/lib/Object/WindowsMachineFlag.cpp b/llvm/lib/Object/WindowsMachineFlag.cpp
index bade2d4f0f..c9e950f753 100644
--- a/llvm/lib/Object/WindowsMachineFlag.cpp
+++ b/llvm/lib/Object/WindowsMachineFlag.cpp
@@ -28,7 +28,10 @@ COFF::MachineTypes llvm::getMachineType(StringRef S) {
       .Case("arm64", COFF::IMAGE_FILE_MACHINE_ARM64)
       .Case("arm64ec", COFF::IMAGE_FILE_MACHINE_ARM64EC)
       .Case("arm64x", COFF::IMAGE_FILE_MACHINE_ARM64X)
-      .Case("mips", COFF::IMAGE_FILE_MACHINE_R4000) // also handle mips (big-endian) because we want to support '/machine:MIPS'
+      .Case("mips",
+            COFF::IMAGE_FILE_MACHINE_R4000) // also handle mips (big-endian)
+                                            // because we want to support
+                                            // '/machine:MIPS'
       .Case("mipsel", COFF::IMAGE_FILE_MACHINE_R4000)
       .Default(COFF::IMAGE_FILE_MACHINE_UNKNOWN);
 }
diff --git a/llvm/lib/Target/Mips/MCTargetDesc/MipsAsmBackend.cpp b/llvm/lib/Target/Mips/MCTargetDesc/MipsAsmBackend.cpp
index 16318cffd7..8acee578a5 100644
--- a/llvm/lib/Target/Mips/MCTargetDesc/MipsAsmBackend.cpp
+++ b/llvm/lib/Target/Mips/MCTargetDesc/MipsAsmBackend.cpp
@@ -603,8 +603,7 @@ class WindowsMipsAsmBackend : public MipsAsmBackend {
 public:
   WindowsMipsAsmBackend(const Target &T, const MCRegisterInfo &MRI,
                         const MCSubtargetInfo &STI)
-    : MipsAsmBackend(T, MRI, STI.getTargetTriple(), STI.getCPU(), false) {
-  }
+      : MipsAsmBackend(T, MRI, STI.getTargetTriple(), STI.getCPU(), false) {}
 
   std::unique_ptr<MCObjectTargetWriter>
   createObjectTargetWriter() const override {
diff --git a/llvm/lib/Target/Mips/MCTargetDesc/MipsBaseInfo.h b/llvm/lib/Target/Mips/MCTargetDesc/MipsBaseInfo.h
index b9a2af3341..11852681be 100644
--- a/llvm/lib/Target/Mips/MCTargetDesc/MipsBaseInfo.h
+++ b/llvm/lib/Target/Mips/MCTargetDesc/MipsBaseInfo.h
@@ -27,118 +27,118 @@ namespace llvm {
 ///
 namespace MipsII {
   /// Target Operand Flag enum.
-  enum TOF {
-    //===------------------------------------------------------------------===//
-    // Mips Specific MachineOperand flags.
-
-    MO_NO_FLAG,
-
-    /// MO_GOT - Represents the offset into the global offset table at which
-    /// the address the relocation entry symbol resides during execution.
-    MO_GOT,
-
-    /// MO_GOT_CALL - Represents the offset into the global offset table at
-    /// which the address of a call site relocation entry symbol resides
-    /// during execution. This is different from the above since this flag
-    /// can only be present in call instructions.
-    MO_GOT_CALL,
-
-    /// MO_GPREL - Represents the offset from the current gp value to be used
-    /// for the relocatable object file being produced.
-    MO_GPREL,
-
-    /// MO_ABS_HI/LO - Represents the hi or low part of an absolute symbol
-    /// address.
-    MO_ABS_HI,
-    MO_ABS_LO,
-
-    /// MO_TLSGD - Represents the offset into the global offset table at which
-    // the module ID and TSL block offset reside during execution (General
-    // Dynamic TLS).
-    MO_TLSGD,
-
-    /// MO_TLSLDM - Represents the offset into the global offset table at which
-    // the module ID and TSL block offset reside during execution (Local
-    // Dynamic TLS).
-    MO_TLSLDM,
-    MO_DTPREL_HI,
-    MO_DTPREL_LO,
-
-    /// MO_GOTTPREL - Represents the offset from the thread pointer (Initial
-    // Exec TLS).
-    MO_GOTTPREL,
-
-    /// MO_TPREL_HI/LO - Represents the hi and low part of the offset from
-    // the thread pointer (Local Exec TLS).
-    MO_TPREL_HI,
-    MO_TPREL_LO,
-
-    // N32/64 Flags.
-    MO_GPOFF_HI,
-    MO_GPOFF_LO,
-    MO_GOT_DISP,
-    MO_GOT_PAGE,
-    MO_GOT_OFST,
-
-    /// MO_HIGHER/HIGHEST - Represents the highest or higher half word of a
-    /// 64-bit symbol address.
-    MO_HIGHER,
-    MO_HIGHEST,
-
-    /// MO_GOT_HI16/LO16, MO_CALL_HI16/LO16 - Relocations used for large GOTs.
-    MO_GOT_HI16,
-    MO_GOT_LO16,
-    MO_CALL_HI16,
-    MO_CALL_LO16,
-
-    /// Helper operand used to generate R_MIPS_JALR
-    MO_JALR,
-
-    /// MO_DLLIMPORT - On a symbol operand "FOO", this indicates that the
-    /// reference is actually to the "__imp_FOO" symbol.  This is used for
-    /// dllimport linkage on windows.
-    MO_DLLIMPORT = 0x20,
-  };
-
-  enum {
-    //===------------------------------------------------------------------===//
-    // Instruction encodings.  These are the standard/most common forms for
-    // Mips instructions.
-    //
-
-    // Pseudo - This represents an instruction that is a pseudo instruction
-    // or one that has not been implemented yet.  It is illegal to code generate
-    // it, but tolerated for intermediate implementation stages.
-    Pseudo   = 0,
-
-    /// FrmR - This form is for instructions of the format R.
-    FrmR  = 1,
-    /// FrmI - This form is for instructions of the format I.
-    FrmI  = 2,
-    /// FrmJ - This form is for instructions of the format J.
-    FrmJ  = 3,
-    /// FrmFR - This form is for instructions of the format FR.
-    FrmFR = 4,
-    /// FrmFI - This form is for instructions of the format FI.
-    FrmFI = 5,
-    /// FrmOther - This form is for instructions that have no specific format.
-    FrmOther = 6,
-
-    FormMask = 15,
-    /// IsCTI - Instruction is a Control Transfer Instruction.
-    IsCTI = 1 << 4,
-    /// HasForbiddenSlot - Instruction has a forbidden slot.
-    HasForbiddenSlot = 1 << 5,
-    /// HasFCCRegOperand - Instruction uses an $fcc<x> register.
-    HasFCCRegOperand = 1 << 6
-
-  };
-
-  enum OperandType : unsigned {
-    OPERAND_FIRST_MIPS_MEM_IMM = MCOI::OPERAND_FIRST_TARGET,
-    OPERAND_MEM_SIMM9 = OPERAND_FIRST_MIPS_MEM_IMM,
-    OPERAND_LAST_MIPS_MEM_IMM = OPERAND_MEM_SIMM9
-  };
+enum TOF {
+  //===------------------------------------------------------------------===//
+  // Mips Specific MachineOperand flags.
+
+  MO_NO_FLAG,
+
+  /// MO_GOT - Represents the offset into the global offset table at which
+  /// the address the relocation entry symbol resides during execution.
+  MO_GOT,
+
+  /// MO_GOT_CALL - Represents the offset into the global offset table at
+  /// which the address of a call site relocation entry symbol resides
+  /// during execution. This is different from the above since this flag
+  /// can only be present in call instructions.
+  MO_GOT_CALL,
+
+  /// MO_GPREL - Represents the offset from the current gp value to be used
+  /// for the relocatable object file being produced.
+  MO_GPREL,
+
+  /// MO_ABS_HI/LO - Represents the hi or low part of an absolute symbol
+  /// address.
+  MO_ABS_HI,
+  MO_ABS_LO,
+
+  /// MO_TLSGD - Represents the offset into the global offset table at which
+  // the module ID and TSL block offset reside during execution (General
+  // Dynamic TLS).
+  MO_TLSGD,
+
+  /// MO_TLSLDM - Represents the offset into the global offset table at which
+  // the module ID and TSL block offset reside during execution (Local
+  // Dynamic TLS).
+  MO_TLSLDM,
+  MO_DTPREL_HI,
+  MO_DTPREL_LO,
+
+  /// MO_GOTTPREL - Represents the offset from the thread pointer (Initial
+  // Exec TLS).
+  MO_GOTTPREL,
+
+  /// MO_TPREL_HI/LO - Represents the hi and low part of the offset from
+  // the thread pointer (Local Exec TLS).
+  MO_TPREL_HI,
+  MO_TPREL_LO,
+
+  // N32/64 Flags.
+  MO_GPOFF_HI,
+  MO_GPOFF_LO,
+  MO_GOT_DISP,
+  MO_GOT_PAGE,
+  MO_GOT_OFST,
+
+  /// MO_HIGHER/HIGHEST - Represents the highest or higher half word of a
+  /// 64-bit symbol address.
+  MO_HIGHER,
+  MO_HIGHEST,
+
+  /// MO_GOT_HI16/LO16, MO_CALL_HI16/LO16 - Relocations used for large GOTs.
+  MO_GOT_HI16,
+  MO_GOT_LO16,
+  MO_CALL_HI16,
+  MO_CALL_LO16,
+
+  /// Helper operand used to generate R_MIPS_JALR
+  MO_JALR,
+
+  /// MO_DLLIMPORT - On a symbol operand "FOO", this indicates that the
+  /// reference is actually to the "__imp_FOO" symbol.  This is used for
+  /// dllimport linkage on windows.
+  MO_DLLIMPORT = 0x20,
+};
+
+enum {
+  //===------------------------------------------------------------------===//
+  // Instruction encodings.  These are the standard/most common forms for
+  // Mips instructions.
+  //
+
+  // Pseudo - This represents an instruction that is a pseudo instruction
+  // or one that has not been implemented yet.  It is illegal to code generate
+  // it, but tolerated for intermediate implementation stages.
+  Pseudo = 0,
+
+  /// FrmR - This form is for instructions of the format R.
+  FrmR = 1,
+  /// FrmI - This form is for instructions of the format I.
+  FrmI = 2,
+  /// FrmJ - This form is for instructions of the format J.
+  FrmJ = 3,
+  /// FrmFR - This form is for instructions of the format FR.
+  FrmFR = 4,
+  /// FrmFI - This form is for instructions of the format FI.
+  FrmFI = 5,
+  /// FrmOther - This form is for instructions that have no specific format.
+  FrmOther = 6,
+
+  FormMask = 15,
+  /// IsCTI - Instruction is a Control Transfer Instruction.
+  IsCTI = 1 << 4,
+  /// HasForbiddenSlot - Instruction has a forbidden slot.
+  HasForbiddenSlot = 1 << 5,
+  /// HasFCCRegOperand - Instruction uses an $fcc<x> register.
+  HasFCCRegOperand = 1 << 6
+
+};
+
+enum OperandType : unsigned {
+  OPERAND_FIRST_MIPS_MEM_IMM = MCOI::OPERAND_FIRST_TARGET,
+  OPERAND_MEM_SIMM9 = OPERAND_FIRST_MIPS_MEM_IMM,
+  OPERAND_LAST_MIPS_MEM_IMM = OPERAND_MEM_SIMM9
+};
 }
 
 inline static MCRegister getMSARegFromFReg(MCRegister Reg) {
diff --git a/llvm/lib/Target/Mips/MCTargetDesc/MipsMCAsmInfo.cpp b/llvm/lib/Target/Mips/MCTargetDesc/MipsMCAsmInfo.cpp
index 960256bc38..60567e2f1d 100644
--- a/llvm/lib/Target/Mips/MCTargetDesc/MipsMCAsmInfo.cpp
+++ b/llvm/lib/Target/Mips/MCTargetDesc/MipsMCAsmInfo.cpp
@@ -16,7 +16,7 @@
 
 using namespace llvm;
 
-void MipsELFMCAsmInfo::anchor() { }
+void MipsELFMCAsmInfo::anchor() {}
 
 MipsELFMCAsmInfo::MipsELFMCAsmInfo(const Triple &TheTriple,
                                    const MCTargetOptions &Options) {
@@ -52,7 +52,7 @@ MipsELFMCAsmInfo::MipsELFMCAsmInfo(const Triple &TheTriple,
   HasMipsExpressions = true;
 }
 
-void MipsCOFFMCAsmInfoMicrosoft::anchor() { }
+void MipsCOFFMCAsmInfoMicrosoft::anchor() {}
 
 MipsCOFFMCAsmInfoMicrosoft::MipsCOFFMCAsmInfoMicrosoft() {
   WinEHEncodingType = WinEH::EncodingType::Itanium;
@@ -63,7 +63,7 @@ MipsCOFFMCAsmInfoMicrosoft::MipsCOFFMCAsmInfoMicrosoft() {
   AllowAtInName = true;
 }
 
-void MipsCOFFMCAsmInfoGNU::anchor() { }
+void MipsCOFFMCAsmInfoGNU::anchor() {}
 
 MipsCOFFMCAsmInfoGNU::MipsCOFFMCAsmInfoGNU() {
   HasSingleParameterDotFile = true;
diff --git a/llvm/lib/Target/Mips/MCTargetDesc/MipsMCTargetDesc.h b/llvm/lib/Target/Mips/MCTargetDesc/MipsMCTargetDesc.h
index 114fec0ccc..f3e3e6e8d1 100644
--- a/llvm/lib/Target/Mips/MCTargetDesc/MipsMCTargetDesc.h
+++ b/llvm/lib/Target/Mips/MCTargetDesc/MipsMCTargetDesc.h
@@ -54,8 +54,7 @@ MCStreamer *createMipsWinCOFFStreamer(MCContext &C,
 std::unique_ptr<MCObjectTargetWriter>
 createMipsELFObjectWriter(const Triple &TT, bool IsN32);
 /// Construct a Mips Win COFF object writer.
-std::unique_ptr<MCObjectTargetWriter>
-createMipsWinCOFFObjectWriter();
+std::unique_ptr<MCObjectTargetWriter> createMipsWinCOFFObjectWriter();
 
 namespace MIPS_MC {
 void initLLVMToCVRegMapping(MCRegisterInfo *MRI);
diff --git a/llvm/lib/Target/Mips/MCTargetDesc/MipsWinCOFFObjectWriter.cpp b/llvm/lib/Target/Mips/MCTargetDesc/MipsWinCOFFObjectWriter.cpp
index 17c21bc8b1..58a1a02874 100644
--- a/llvm/lib/Target/Mips/MCTargetDesc/MipsWinCOFFObjectWriter.cpp
+++ b/llvm/lib/Target/Mips/MCTargetDesc/MipsWinCOFFObjectWriter.cpp
@@ -1,4 +1,5 @@
-//===-- MipsWinCOFFObjectWriter.cpp - Mips Win COFF Writer -----------------===//
+//===-- MipsWinCOFFObjectWriter.cpp - Mips Win COFF Writer
+//-----------------===//
 //
 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
 // See https://llvm.org/LICENSE.txt for license information.
@@ -56,7 +57,6 @@ unsigned MipsWinCOFFObjectWriter::getRelocType(MCContext &Ctx,
   }
 }
 
-std::unique_ptr<MCObjectTargetWriter>
-llvm::createMipsWinCOFFObjectWriter() {
+std::unique_ptr<MCObjectTargetWriter> llvm::createMipsWinCOFFObjectWriter() {
   return std::make_unique<MipsWinCOFFObjectWriter>();
 }
diff --git a/llvm/lib/Target/Mips/MCTargetDesc/MipsWinCOFFStreamer.cpp b/llvm/lib/Target/Mips/MCTargetDesc/MipsWinCOFFStreamer.cpp
index 77044a0ff3..47edddd29e 100644
--- a/llvm/lib/Target/Mips/MCTargetDesc/MipsWinCOFFStreamer.cpp
+++ b/llvm/lib/Target/Mips/MCTargetDesc/MipsWinCOFFStreamer.cpp
@@ -25,9 +25,9 @@ public:
 };
 } // namespace
 
-MCStreamer *llvm::createMipsWinCOFFStreamer(MCContext &C,
-                                            std::unique_ptr<MCAsmBackend> &&AB,
-                                            std::unique_ptr<MCObjectWriter> &&OW,
-                                            std::unique_ptr<MCCodeEmitter> &&CE) {
-  return new MipsWinCOFFStreamer(C, std::move(AB), std::move(CE), std::move(OW));
+MCStreamer *llvm::createMipsWinCOFFStreamer(
+    MCContext &C, std::unique_ptr<MCAsmBackend> &&AB,
+    std::unique_ptr<MCObjectWriter> &&OW, std::unique_ptr<MCCodeEmitter> &&CE) {
+  return new MipsWinCOFFStreamer(C, std::move(AB), std::move(CE),
+                                 std::move(OW));
 }
diff --git a/llvm/lib/Target/Mips/MipsAsmPrinter.cpp b/llvm/lib/Target/Mips/MipsAsmPrinter.cpp
index 89b79693a8..8a788f3aef 100644
--- a/llvm/lib/Target/Mips/MipsAsmPrinter.cpp
+++ b/llvm/lib/Target/Mips/MipsAsmPrinter.cpp
@@ -756,7 +756,8 @@ void MipsAsmPrinter::emitStartOfAsmFile(Module &M) {
     // for a feature string that doesn't match the default one.
     StringRef CPU = MIPS_MC::selectMipsCPU(TT, TM.getTargetCPU());
     const MipsTargetMachine &MTM = static_cast<const MipsTargetMachine &>(TM);
-    const MipsSubtarget STI(TT, CPU, FS, MTM.isLittleEndian(), MTM, std::nullopt);
+    const MipsSubtarget STI(TT, CPU, FS, MTM.isLittleEndian(), MTM,
+                            std::nullopt);
 
     bool IsABICalls = STI.isABICalls();
     const MipsABIInfo &ABI = MTM.getABI();
@@ -778,16 +779,15 @@ void MipsAsmPrinter::emitStartOfAsmFile(Module &M) {
     // NaN: At the moment we only support:
     // 1. .nan legacy (default)
     // 2. .nan 2008
-    STI.isNaN2008() ? TS.emitDirectiveNaN2008()
-                    : TS.emitDirectiveNaNLegacy();
+    STI.isNaN2008() ? TS.emitDirectiveNaN2008() : TS.emitDirectiveNaNLegacy();
 
     // TODO: handle O64 ABI
 
     TS.updateABIInfo(STI);
 
-    // We should always emit a '.module fp=...' but binutils 2.24 does not accept
-    // it. We therefore emit it when it contradicts the ABI defaults (-mfpxx or
-    // -mfp64) and omit it otherwise.
+    // We should always emit a '.module fp=...' but binutils 2.24 does not
+    // accept it. We therefore emit it when it contradicts the ABI defaults
+    // (-mfpxx or -mfp64) and omit it otherwise.
     if ((ABI.IsO32() && (STI.isABI_FPXX() || STI.isFP64bit())) ||
         STI.useSoftFloat())
       TS.emitDirectiveModuleFP();
diff --git a/llvm/lib/Target/Mips/MipsISelLowering.cpp b/llvm/lib/Target/Mips/MipsISelLowering.cpp
index 94cadfffa8..c3c43e8f7e 100644
--- a/llvm/lib/Target/Mips/MipsISelLowering.cpp
+++ b/llvm/lib/Target/Mips/MipsISelLowering.cpp
@@ -2109,8 +2109,8 @@ SDValue MipsTargetLowering::lowerGlobalAddress(SDValue Op,
     assert(Subtarget.isTargetWindows() &&
            "Windows is the only supported COFF target");
     return getDllimportVariable(
-        N, SDLoc(N), Ty, DAG,
-        DAG.getEntryNode(), MachinePointerInfo::getGOT(DAG.getMachineFunction()));
+        N, SDLoc(N), Ty, DAG, DAG.getEntryNode(),
+        MachinePointerInfo::getGOT(DAG.getMachineFunction()));
   }
 
   if (!isPositionIndependent()) {
@@ -3468,12 +3468,13 @@ MipsTargetLowering::LowerCall(TargetLowering::CallLoweringInfo &CLI,
   }
 
   if (GlobalAddressSDNode *G = dyn_cast<GlobalAddressSDNode>(Callee)) {
-    if (Subtarget.isTargetCOFF() && G->getGlobal()->hasDLLImportStorageClass()) {
+    if (Subtarget.isTargetCOFF() &&
+        G->getGlobal()->hasDLLImportStorageClass()) {
       assert(Subtarget.isTargetWindows() &&
              "Windows is the only supported COFF target");
       auto PtrInfo = MachinePointerInfo();
-      Callee = DAG.getLoad(Ty, DL, Chain, getDllimportSymbol(G, SDLoc(G), Ty, DAG),
-                           PtrInfo);
+      Callee = DAG.getLoad(Ty, DL, Chain,
+                           getDllimportSymbol(G, SDLoc(G), Ty, DAG), PtrInfo);
     } else if (IsPIC) {
       const GlobalValue *Val = G->getGlobal();
       InternalLinkage = Val->hasInternalLinkage();
diff --git a/llvm/lib/Target/Mips/MipsISelLowering.h b/llvm/lib/Target/Mips/MipsISelLowering.h
index 12dfa6bc1c..52d2fc02fd 100644
--- a/llvm/lib/Target/Mips/MipsISelLowering.h
+++ b/llvm/lib/Target/Mips/MipsISelLowering.h
@@ -490,12 +490,14 @@ class TargetRegisterClass;
     //
     // (lw (add (shl(%high(sym), 16), %low(sym)))
     template <class NodeTy>
-    SDValue getDllimportSymbol(NodeTy *N, const SDLoc &DL, EVT Ty, SelectionDAG &DAG) const {
-        SDValue Hi = getTargetNode(N, Ty, DAG, MipsII::MO_ABS_HI | MipsII::MO_DLLIMPORT);
-        SDValue Lo = getTargetNode(N, Ty, DAG, MipsII::MO_ABS_LO | MipsII::MO_DLLIMPORT);
-        return DAG.getNode(ISD::ADD, DL, Ty,
-                           DAG.getNode(MipsISD::Lo, DL, Ty, Lo),
-                           DAG.getNode(MipsISD::Hi, DL, Ty, Hi));
+    SDValue getDllimportSymbol(NodeTy *N, const SDLoc &DL, EVT Ty,
+                               SelectionDAG &DAG) const {
+      SDValue Hi =
+          getTargetNode(N, Ty, DAG, MipsII::MO_ABS_HI | MipsII::MO_DLLIMPORT);
+      SDValue Lo =
+          getTargetNode(N, Ty, DAG, MipsII::MO_ABS_LO | MipsII::MO_DLLIMPORT);
+      return DAG.getNode(ISD::ADD, DL, Ty, DAG.getNode(MipsISD::Lo, DL, Ty, Lo),
+                         DAG.getNode(MipsISD::Hi, DL, Ty, Hi));
     }
 
     // This method creates the following nodes, which are necessary for
@@ -503,12 +505,11 @@ class TargetRegisterClass;
     //
     // (lw (lw (add (shl(%high(sym), 16), %low(sym))))
     template <class NodeTy>
-    SDValue getDllimportVariable(NodeTy *N, const SDLoc &DL, EVT Ty, SelectionDAG &DAG,
-                                 SDValue Chain,
+    SDValue getDllimportVariable(NodeTy *N, const SDLoc &DL, EVT Ty,
+                                 SelectionDAG &DAG, SDValue Chain,
                                  const MachinePointerInfo &PtrInfo) const {
-        return DAG.getLoad(Ty, DL, Chain,
-                           getDllimportSymbol(N, DL, Ty, DAG),
-                           PtrInfo);
+      return DAG.getLoad(Ty, DL, Chain, getDllimportSymbol(N, DL, Ty, DAG),
+                         PtrInfo);
     }
 
     /// This function fills Ops, which is the list of operands that will later
diff --git a/llvm/lib/Target/Mips/MipsMCInstLower.cpp b/llvm/lib/Target/Mips/MipsMCInstLower.cpp
index 667cf26b60..e01d0d1e65 100644
--- a/llvm/lib/Target/Mips/MipsMCInstLower.cpp
+++ b/llvm/lib/Target/Mips/MipsMCInstLower.cpp
@@ -48,7 +48,7 @@ MCOperand MipsMCInstLower::LowerSymbolOperand(const MachineOperand &MO,
     TargetFlags &= ~MipsII::MO_DLLIMPORT;
   }
 
-  switch(TargetFlags) {
+  switch (TargetFlags) {
   default:
     llvm_unreachable("Invalid target flag!");
   case MipsII::MO_NO_FLAG:
diff --git a/llvm/unittests/TargetParser/TripleTest.cpp b/llvm/unittests/TargetParser/TripleTest.cpp
index 1beb520889..18a8a52fe0 100644
--- a/llvm/unittests/TargetParser/TripleTest.cpp
+++ b/llvm/unittests/TargetParser/TripleTest.cpp
@@ -2303,8 +2303,10 @@ TEST(TripleTest, NormalizeWindows) {
 
   EXPECT_TRUE(Triple("x86_64-pc-win32").isWindowsMSVCEnvironment());
 
-  EXPECT_TRUE(Triple(Triple::normalize("mipsel-windows-msvccoff")).isOSBinFormatCOFF());
-  EXPECT_TRUE(Triple(Triple::normalize("mipsel-windows-msvc")).isOSBinFormatCOFF());
+  EXPECT_TRUE(
+      Triple(Triple::normalize("mipsel-windows-msvccoff")).isOSBinFormatCOFF());
+  EXPECT_TRUE(
+      Triple(Triple::normalize("mipsel-windows-msvc")).isOSBinFormatCOFF());
 }
 
 TEST(TripleTest, NormalizeAndroid) {

@efriedma-quic
Copy link
Collaborator

In terms of maintenance, I'm not too concerned about the bits outside the MIPS backend; the constants and stuff are mostly boilerplate that doesn't require any particular Mips-specific expertise to understand.

For the Mips backend itself, I would ask the Mips backend code maintainer... but we don't have a maintainer for Mips. And we don't have any buildbots. I'm really not sure about adding complexity to a backend which is already suffering from a lack of anyone that has any experience with it. (People familiar with other backends can sort of step in to review changes to Mips, but it's hard to do a good review for anything non-trivial.)


Is there any documentation for calling conventions/exception-handling/etc. for Mips? Do we need to distinguish Windows NT Mips from Windows CE Mips?

@mstorsjo
Copy link
Member

For the Mips backend itself, I would ask the Mips backend code maintainer... but we don't have a maintainer for Mips. And we don't have any buildbots. I'm really not sure about adding complexity to a backend which is already suffering from a lack of anyone that has any experience with it. (People familiar with other backends can sort of step in to review changes to Mips, but it's hard to do a good review for anything non-trivial.)

FWIW, I've seen @wzssyqa do some amount of work around MIPS, should we ask them about whether want to take up the role as MIPS backend maintainer?

@hpoussin
Copy link
Contributor Author

Is there any documentation for calling conventions/exception-handling/etc. for Mips? Do we need to distinguish Windows NT Mips from Windows CE Mips?

Official Microsoft documentation for Windows CE MIPS is on MSDN
Raymond Chen described MIPS on his blog, including calling convention.

He also noted that:
The documentation was originally written for Windows CE, but I figure they are still true for Windows NT, because why not reuse the compiler you already have?

@mstorsjo
Copy link
Member

For the Mips backend itself, I would ask the Mips backend code maintainer... but we don't have a maintainer for Mips. And we don't have any buildbots. I'm really not sure about adding complexity to a backend which is already suffering from a lack of anyone that has any experience with it. (People familiar with other backends can sort of step in to review changes to Mips, but it's hard to do a good review for anything non-trivial.)

FWIW, I've seen @wzssyqa do some amount of work around MIPS, should we ask them about whether want to take up the role as MIPS backend maintainer?

Ping @wzssyqa - what's your take on this, both about the maintainance state of the MIPS target overall, and if you have concerns around accepting patches in this area?

@mstorsjo
Copy link
Member

For the Mips backend itself, I would ask the Mips backend code maintainer... but we don't have a maintainer for Mips. And we don't have any buildbots. I'm really not sure about adding complexity to a backend which is already suffering from a lack of anyone that has any experience with it. (People familiar with other backends can sort of step in to review changes to Mips, but it's hard to do a good review for anything non-trivial.)

FWIW, I've seen @wzssyqa do some amount of work around MIPS, should we ask them about whether want to take up the role as MIPS backend maintainer?

Ping @wzssyqa - what's your take on this, both about the maintainance state of the MIPS target overall, and if you have concerns around accepting patches in this area?

Ping @wzssyqa, can you comment on the above?

{codeview::RegisterId::MIPS_RA, Mips::RA},
{codeview::RegisterId::MIPS_LO, Mips::HI0},
{codeview::RegisterId::MIPS_HI, Mips::LO0},
//{codeview::RegisterId::MIPS_Fir, Mips::},
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As per my observation, FIR is FCR0, Psr is COP012 (CP0.Status), Fsr is FCR31.

@FlyGoat
Copy link

FlyGoat commented Oct 14, 2024

I'm going to help @wzssyqa reviewing MIPS backend changes as I worked on MIPS EFI stuff, and I'm fairly familiar with MIPS PE/COFF implementation details.

@FlyGoat
Copy link

FlyGoat commented Oct 14, 2024

Is there any documentation for calling conventions/exception-handling/etc. for Mips? Do we need to distinguish Windows NT Mips from Windows CE Mips?

Official Microsoft documentation for Windows CE MIPS is on MSDN Raymond Chen described MIPS on his blog, including calling convention.

He also noted that: The documentation was originally written for Windows CE, but I figure they are still true for Windows NT, because why not reuse the compiler you already have?

FYI the only practical difference between NT and CE toolchain is that CE toolchain do support n32 ABI \QMn32. But I guess that's trivial here.

@hpoussin
Copy link
Contributor Author

I'm going to help @wzssyqa reviewing MIPS backend changes as I worked on MIPS EFI stuff, and I'm fairly familiar with MIPS PE/COFF implementation details.

Thanks!
Can you check PR #107809 and PR #107814? Those seem quite trivial.

wzssyqa pushed a commit that referenced this pull request Oct 15, 2024
Windows NT/MIPS and Windows CE/MIPS always used COFF format.

This is an extract of PR #107744.
wzssyqa pushed a commit that referenced this pull request Oct 15, 2024
Add the MIPS COFF relocation types. They will be needed to add support
for MIPS Windows object file.

This is an extract of PR
#107744.
DanielCChen pushed a commit to DanielCChen/llvm-project that referenced this pull request Oct 16, 2024
Windows NT/MIPS and Windows CE/MIPS always used COFF format.

This is an extract of PR llvm#107744.
DanielCChen pushed a commit to DanielCChen/llvm-project that referenced this pull request Oct 16, 2024
Add the MIPS COFF relocation types. They will be needed to add support
for MIPS Windows object file.

This is an extract of PR
llvm#107744.
@hpoussin
Copy link
Contributor Author

@hpoussin hpoussin closed this Jan 21, 2025
@hpoussin hpoussin deleted the clang-mips-coff branch February 2, 2025 19:13
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants