[llvm] 2820795 - [JITLink][Mips] Add ELF backend (#224578)

via llvm-commits llvm-commits at lists.llvm.org
Wed Sep 30 03:21:00 PDT 2026


Author: Jiaxun Yang
Date: 2026-09-30T11:20:49+01:00
New Revision: 2820795b027eb68e3c3a0f1ad1ddd36aaeb8730a

URL: https://github.com/llvm/llvm-project/commit/2820795b027eb68e3c3a0f1ad1ddd36aaeb8730a
DIFF: https://github.com/llvm/llvm-project/commit/2820795b027eb68e3c3a0f1ad1ddd36aaeb8730a.diff

LOG: [JITLink][Mips] Add ELF backend (#224578)

Add support for O32, N32, and N64 relocatable ELF objects in both byte
orders. Handle O32 implicit addends and HI/LO pairing, N32 relocation
groups, and N64 packed relocations. Preserve the MIPS64 ISA triple for
N32 while recording its four-byte pointer ABI in LinkGraph.

Implement absolute, PC-relative, GP/GOT, and compound fixups, GOT-backed
$t9 call stubs, and EH-frame support. Use MIPS-specific GOT keys for
target, addend, and exact/page entries, and collect GP-relative content
into one ordered region. Support standard MIPS ISAs, including release-6
stubs.

Integrate GD/LD TLS with ELFNixPlatform and add an assembly resolver
that reads the thread pointer with rdhwr before calling the existing C
implementation. Honor explicit MIPS relocation-model requests while
retaining the static default. JITLink remains opt-in and RuntimeDyld
remains the default.

Add focused relocation, ABI, GOT/stub, EH-frame, and TLS tests.

Assisted-by: chatgpt-5.6-sol

Added: 
    compiler-rt/lib/orc/elfnix_tls.mips.S
    compiler-rt/test/orc/TestCases/Linux/mips/Inputs/external-branch-stub-helper.c
    compiler-rt/test/orc/TestCases/Linux/mips/Inputs/external-branch-stub-main.c
    compiler-rt/test/orc/TestCases/Linux/mips/external-branch-stub.test
    compiler-rt/test/orc/TestCases/Linux/mips/lit.local.cfg.py
    compiler-rt/test/orc/TestCases/Linux/mips/trivial-tls.c
    llvm/include/llvm/ExecutionEngine/JITLink/ELF_mips.h
    llvm/include/llvm/ExecutionEngine/JITLink/mips.h
    llvm/lib/ExecutionEngine/JITLink/ELF_mips.cpp
    llvm/lib/ExecutionEngine/JITLink/mips.cpp
    llvm/test/ExecutionEngine/JITLink/Mips/ELF_abs16_data.s
    llvm/test/ExecutionEngine/JITLink/Mips/ELF_ehframe.s
    llvm/test/ExecutionEngine/JITLink/Mips/ELF_got_ordering.s
    llvm/test/ExecutionEngine/JITLink/Mips/ELF_invalid_abi.yaml
    llvm/test/ExecutionEngine/JITLink/Mips/ELF_micromips_unsupported.s
    llvm/test/ExecutionEngine/JITLink/Mips/ELF_minimal.s
    llvm/test/ExecutionEngine/JITLink/Mips/ELF_n64_compound_relocations.s
    llvm/test/ExecutionEngine/JITLink/Mips/ELF_pc16_errors.s
    llvm/test/ExecutionEngine/JITLink/Mips/ELF_pc18_aligned_base.s
    llvm/test/ExecutionEngine/JITLink/Mips/ELF_r6_external_branch_stub.s
    llvm/test/ExecutionEngine/JITLink/Mips/ELF_relocations.s
    llvm/test/ExecutionEngine/JITLink/Mips/ELF_unmatched_hi16.s
    llvm/test/ExecutionEngine/JITLink/Mips/ELF_unsupported_packed_relocation.yaml
    llvm/test/ExecutionEngine/JITLink/Mips/ELF_unsupported_tls.s
    llvm/test/ExecutionEngine/JITLink/Mips/lit.local.cfg
    llvm/unittests/ExecutionEngine/JITLink/MipsTests.cpp

Modified: 
    compiler-rt/cmake/Modules/AllSupportedArchDefs.cmake
    compiler-rt/lib/orc/CMakeLists.txt
    llvm/include/llvm/ExecutionEngine/JITLink/JITLink.h
    llvm/lib/ExecutionEngine/JITLink/CMakeLists.txt
    llvm/lib/ExecutionEngine/JITLink/COFFLinkGraphBuilder.cpp
    llvm/lib/ExecutionEngine/JITLink/ELF.cpp
    llvm/lib/ExecutionEngine/JITLink/ELFLinkGraphBuilder.h
    llvm/lib/ExecutionEngine/JITLink/JITLink.cpp
    llvm/lib/ExecutionEngine/JITLink/JITLinkMemoryManager.cpp
    llvm/lib/ExecutionEngine/JITLink/MachOLinkGraphBuilder.cpp
    llvm/lib/ExecutionEngine/JITLink/XCOFFLinkGraphBuilder.cpp
    llvm/lib/ExecutionEngine/Orc/COFFAutoImportGenerator.cpp
    llvm/lib/ExecutionEngine/Orc/COFFPlatform.cpp
    llvm/lib/ExecutionEngine/Orc/ELFNixPlatform.cpp
    llvm/lib/ExecutionEngine/Orc/ExecutionUtils.cpp
    llvm/lib/ExecutionEngine/Orc/JITLinkRedirectableSymbolManager.cpp
    llvm/lib/ExecutionEngine/Orc/JITLinkReentryTrampolines.cpp
    llvm/lib/ExecutionEngine/Orc/MachOPlatform.cpp
    llvm/lib/ExecutionEngine/Orc/SectCreate.cpp
    llvm/lib/Target/Mips/MipsTargetMachine.cpp
    llvm/unittests/ExecutionEngine/JITLink/AArch32ErrorTests.cpp
    llvm/unittests/ExecutionEngine/JITLink/AArch64Tests.cpp
    llvm/unittests/ExecutionEngine/JITLink/CMakeLists.txt
    llvm/unittests/ExecutionEngine/JITLink/COFFLinkGraphTests.cpp
    llvm/unittests/ExecutionEngine/JITLink/JITLinkTestUtils.cpp
    llvm/unittests/ExecutionEngine/JITLink/LinkGraphTests.cpp
    llvm/unittests/ExecutionEngine/JITLink/MachOLinkGraphTests.cpp
    llvm/unittests/ExecutionEngine/JITLink/MemoryManagerErrorTests.cpp
    llvm/unittests/ExecutionEngine/JITLink/StubsTests.cpp
    llvm/unittests/ExecutionEngine/JITLink/X86_64Tests.cpp
    llvm/unittests/ExecutionEngine/Orc/LinkGraphLinkingLayerTest.cpp
    llvm/unittests/ExecutionEngine/Orc/MemoryMapperTest.cpp
    llvm/unittests/ExecutionEngine/Orc/ObjectLinkingLayerTest.cpp
    llvm/unittests/ExecutionEngine/Orc/SharedMemoryMapperTest.cpp

Removed: 
    


################################################################################
diff  --git a/compiler-rt/cmake/Modules/AllSupportedArchDefs.cmake b/compiler-rt/cmake/Modules/AllSupportedArchDefs.cmake
index 8956ed2d305de..9ea6d294a3fe7 100644
--- a/compiler-rt/cmake/Modules/AllSupportedArchDefs.cmake
+++ b/compiler-rt/cmake/Modules/AllSupportedArchDefs.cmake
@@ -130,7 +130,7 @@ set(ALL_SHADOWCALLSTACK_SUPPORTED_ARCH ${ARM64} ${HEXAGON})
 
 if (UNIX)
   if (OS_NAME MATCHES "Linux")
-    set(ALL_ORC_SUPPORTED_ARCH ${X86_64} ${ARM64} ${ARM32} ${PPC64} ${LOONGARCH64} ${S390X})
+    set(ALL_ORC_SUPPORTED_ARCH ${X86_64} ${ARM64} ${ARM32} ${MIPS32} ${MIPS64} ${PPC64} ${LOONGARCH64} ${S390X})
   else()
     set(ALL_ORC_SUPPORTED_ARCH ${X86_64} ${ARM64} ${ARM32})
   endif()

diff  --git a/compiler-rt/lib/orc/CMakeLists.txt b/compiler-rt/lib/orc/CMakeLists.txt
index efaf0358bb7d8..56bd563493bc0 100644
--- a/compiler-rt/lib/orc/CMakeLists.txt
+++ b/compiler-rt/lib/orc/CMakeLists.txt
@@ -119,6 +119,7 @@ else() # not Apple
     set(ORC_ASM_SOURCES
       elfnix_tls.x86-64.S
       elfnix_tls.aarch64.S
+      elfnix_tls.mips.S
       elfnix_tls.ppc64.S
       elfnix_tls.systemz.S
       sysv_reenter.arm64.S

diff  --git a/compiler-rt/lib/orc/elfnix_tls.mips.S b/compiler-rt/lib/orc/elfnix_tls.mips.S
new file mode 100644
index 0000000000000..e86b79f5da668
--- /dev/null
+++ b/compiler-rt/lib/orc/elfnix_tls.mips.S
@@ -0,0 +1,62 @@
+//===-- orc_rt_elfnix_tls.mips.S --------------------------------*- ASM -*-===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of the ORC runtime support library.
+//
+//===----------------------------------------------------------------------===//
+
+#if defined(__mips__)
+
+#if _MIPS_SIM == _ABI64
+#define PTR_ADDIU daddiu
+#define PTR_LA dla
+#else
+#define PTR_ADDIU addiu
+#define PTR_LA la
+#endif
+
+        .text
+        .option pic2
+
+        // Returns the TLS address in $2, passing the thread pointer in $5.
+        .globl ___orc_rt_elfnix_tls_get_addr
+___orc_rt_elfnix_tls_get_addr:
+#if _MIPS_SIM == _ABIO32
+        .set noreorder
+        .cpload $25
+        .set reorder
+        PTR_ADDIU $sp, $sp, -24
+        sw $ra, 20($sp)
+#else
+        PTR_ADDIU $sp, $sp, -16
+        .cpsetup $25, 0, ___orc_rt_elfnix_tls_get_addr
+        sd $ra, 8($sp)
+#endif
+
+        .set push
+#if !defined(__mips_isa_rev) || __mips_isa_rev < 2
+        // Linux trap-and-emulates rdhwr on pre-r2 CPUs, so it is always valid.
+        .set mips32r2
+#endif
+        rdhwr $5, $29
+        .set pop
+
+        PTR_LA $25, __orc_rt_elfnix_tls_get_addr_impl
+        jalr $25
+
+#if _MIPS_SIM == _ABIO32
+        lw $ra, 20($sp)
+        PTR_ADDIU $sp, $sp, 24
+#else
+        .cpreturn
+        ld $ra, 8($sp)
+        PTR_ADDIU $sp, $sp, 16
+#endif
+        jr $ra
+
+#endif // defined(__mips__)

diff  --git a/compiler-rt/test/orc/TestCases/Linux/mips/Inputs/external-branch-stub-helper.c b/compiler-rt/test/orc/TestCases/Linux/mips/Inputs/external-branch-stub-helper.c
new file mode 100644
index 0000000000000..2b74503f8a7c0
--- /dev/null
+++ b/compiler-rt/test/orc/TestCases/Linux/mips/Inputs/external-branch-stub-helper.c
@@ -0,0 +1 @@
+int helper(int x) { return x + 5; }

diff  --git a/compiler-rt/test/orc/TestCases/Linux/mips/Inputs/external-branch-stub-main.c b/compiler-rt/test/orc/TestCases/Linux/mips/Inputs/external-branch-stub-main.c
new file mode 100644
index 0000000000000..16215b872d2bb
--- /dev/null
+++ b/compiler-rt/test/orc/TestCases/Linux/mips/Inputs/external-branch-stub-main.c
@@ -0,0 +1,3 @@
+extern int helper(int);
+
+int main(void) { return helper(37) != 42; }

diff  --git a/compiler-rt/test/orc/TestCases/Linux/mips/external-branch-stub.test b/compiler-rt/test/orc/TestCases/Linux/mips/external-branch-stub.test
new file mode 100644
index 0000000000000..c1b32ba3b58cf
--- /dev/null
+++ b/compiler-rt/test/orc/TestCases/Linux/mips/external-branch-stub.test
@@ -0,0 +1,8 @@
+// RUN: rm -rf %t && mkdir -p %t
+// RUN: %clang -O1 -fno-pic -mno-abicalls -fno-stack-protector -c -o %t/main.o %S/Inputs/external-branch-stub-main.c
+// RUN: %clang -O1 -fno-pic -mno-abicalls -fno-stack-protector -c -o %t/helper.o %S/Inputs/external-branch-stub-helper.c
+// RUN: %llvm_jitlink %t/main.o %t/helper.o
+
+// A cross-object non-PIC call uses R_MIPS_26 and requires a pointer-jump stub.
+// The stub must not assume that the executor's incoming $gp is the JIT graph's
+// _gp value.

diff  --git a/compiler-rt/test/orc/TestCases/Linux/mips/lit.local.cfg.py b/compiler-rt/test/orc/TestCases/Linux/mips/lit.local.cfg.py
new file mode 100644
index 0000000000000..fa6d0b3754074
--- /dev/null
+++ b/compiler-rt/test/orc/TestCases/Linux/mips/lit.local.cfg.py
@@ -0,0 +1,5 @@
+if config.root.host_arch not in ["mips", "mipsel", "mips64", "mips64el"]:
+    config.unsupported = True
+
+if config.target_arch not in ["mips", "mipsel", "mips64", "mips64el"]:
+    config.unsupported = True

diff  --git a/compiler-rt/test/orc/TestCases/Linux/mips/trivial-tls.c b/compiler-rt/test/orc/TestCases/Linux/mips/trivial-tls.c
new file mode 100644
index 0000000000000..7d04f33d11490
--- /dev/null
+++ b/compiler-rt/test/orc/TestCases/Linux/mips/trivial-tls.c
@@ -0,0 +1,14 @@
+// RUN: %clang -O1 -fPIC -fno-stack-protector -c -o %t %s
+// RUN: %llvm_jitlink %t
+// RUN: %clang -O1 -fPIC -fno-stack-protector -S -emit-llvm -o %t.ll %s
+// RUN: %lli_orc_jitlink -emulated-tls=false -relocation-model=pic %t.ll
+
+// Check general-dynamic and local-dynamic TLS in .tdata and .tbss.
+
+__thread __attribute__((tls_model("global-dynamic"))) int gd_data = 7;
+__thread __attribute__((tls_model("global-dynamic"))) int gd_bss;
+static __thread
+    __attribute__((tls_model("local-dynamic"))) volatile int ld_data = 11;
+static __thread __attribute__((tls_model("local-dynamic"))) volatile int ld_bss;
+
+int main(void) { return gd_data + gd_bss + ld_data + ld_bss - 18; }

diff  --git a/llvm/include/llvm/ExecutionEngine/JITLink/ELF_mips.h b/llvm/include/llvm/ExecutionEngine/JITLink/ELF_mips.h
new file mode 100644
index 0000000000000..7a7c72a351f26
--- /dev/null
+++ b/llvm/include/llvm/ExecutionEngine/JITLink/ELF_mips.h
@@ -0,0 +1,30 @@
+//===-- ELF_mips.h - JIT link functions for ELF/MIPS ---------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_EXECUTIONENGINE_JITLINK_ELF_MIPS_H
+#define LLVM_EXECUTIONENGINE_JITLINK_ELF_MIPS_H
+
+#include "llvm/ExecutionEngine/JITLink/JITLink.h"
+
+namespace llvm {
+namespace jitlink {
+
+/// Create a LinkGraph from an O32, N32, or N64 ELF/MIPS relocatable object.
+/// Both ELF byte orders are supported.
+LLVM_ABI Expected<std::unique_ptr<LinkGraph>>
+createLinkGraphFromELFObject_mips(MemoryBufferRef ObjectBuffer,
+                                  std::shared_ptr<orc::SymbolStringPool> SSP);
+
+/// JIT-link an ELF/MIPS graph.
+LLVM_ABI void link_ELF_mips(std::unique_ptr<LinkGraph> G,
+                            std::unique_ptr<JITLinkContext> Ctx);
+
+} // namespace jitlink
+} // namespace llvm
+
+#endif // LLVM_EXECUTIONENGINE_JITLINK_ELF_MIPS_H

diff  --git a/llvm/include/llvm/ExecutionEngine/JITLink/JITLink.h b/llvm/include/llvm/ExecutionEngine/JITLink/JITLink.h
index f6794636df1f8..70abc7a68478a 100644
--- a/llvm/include/llvm/ExecutionEngine/JITLink/JITLink.h
+++ b/llvm/include/llvm/ExecutionEngine/JITLink/JITLink.h
@@ -1027,14 +1027,11 @@ class LinkGraph {
   using GetEdgeKindNameFunction = const char *(*)(Edge::Kind);
 
   LinkGraph(std::string Name, std::shared_ptr<orc::SymbolStringPool> SSP,
-            Triple TT, SubtargetFeatures Features,
+            Triple TT, unsigned PointerSize, SubtargetFeatures Features,
             GetEdgeKindNameFunction GetEdgeKindName)
       : Name(std::move(Name)), SSP(std::move(SSP)), TT(std::move(TT)),
-        Features(std::move(Features)),
-        GetEdgeKindName(std::move(GetEdgeKindName)) {
-    assert(!(Triple::getArchPointerBitWidth(this->TT.getArch()) % 8) &&
-           "Arch bitwidth is not a multiple of 8");
-  }
+        PointerSize(PointerSize), Features(std::move(Features)),
+        GetEdgeKindName(std::move(GetEdgeKindName)) {}
 
   LinkGraph(const LinkGraph &) = delete;
   LinkGraph &operator=(const LinkGraph &) = delete;
@@ -1053,7 +1050,7 @@ class LinkGraph {
   const SubtargetFeatures &getFeatures() const { return Features; }
 
   /// Returns the pointer size for use in this graph.
-  unsigned getPointerSize() const { return TT.getArchPointerBitWidth() / 8; }
+  unsigned getPointerSize() const { return PointerSize; }
 
   /// Returns the endianness of content in this graph.
   llvm::endianness getEndianness() const {
@@ -1678,6 +1675,7 @@ class LinkGraph {
   std::string Name;
   std::shared_ptr<orc::SymbolStringPool> SSP;
   Triple TT;
+  unsigned PointerSize;
   SubtargetFeatures Features;
   GetEdgeKindNameFunction GetEdgeKindName = nullptr;
   DenseMap<StringRef, std::unique_ptr<Section>> Sections;

diff  --git a/llvm/include/llvm/ExecutionEngine/JITLink/mips.h b/llvm/include/llvm/ExecutionEngine/JITLink/mips.h
new file mode 100644
index 0000000000000..3fc4a6a31d9cb
--- /dev/null
+++ b/llvm/include/llvm/ExecutionEngine/JITLink/mips.h
@@ -0,0 +1,413 @@
+//===-- mips.h - Generic JITLink MIPS edge kinds and utilities -*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// Generic utilities for graphs representing MIPS objects.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_EXECUTIONENGINE_JITLINK_MIPS_H
+#define LLVM_EXECUTIONENGINE_JITLINK_MIPS_H
+
+#include "llvm/ExecutionEngine/JITLink/JITLink.h"
+#include "llvm/Support/Compiler.h"
+#include "llvm/Support/Endian.h"
+#include "llvm/Support/MathExtras.h"
+
+namespace llvm {
+namespace jitlink {
+namespace mips {
+
+/// MIPS fixup and table-request edge kinds.
+enum EdgeKind_mips : Edge::Kind {
+  /// Fixup <- Target + Addend, checked as an unsigned 32-bit pointer.
+  Pointer32 = Edge::FirstRelocation,
+  /// Fixup <- Target + Addend : uint64.
+  Pointer64,
+  /// Pointer containing the rounded 64-KiB page of Target + Addend.
+  PagePointer32,
+  PagePointer64,
+  /// Fixup <- Target - Fixup + Addend : int32.
+  Delta32,
+  /// Fixup <- Target - Fixup + Addend : int64.
+  Delta64,
+  /// Fixup <- Fixup - Target + Addend : int32 (used by .eh_frame).
+  NegDelta32,
+
+  /// Fixup[15:0] <- Target + Addend : int16.
+  Abs16,
+  /// Fixup[15:0] <- (Target + Addend + 0x8000) >> 16.
+  Hi16,
+  /// Fixup[15:0] <- Target + Addend.
+  Lo16,
+  /// Fixup[15:0] <- (Target + Addend + 0x80008000) >> 32.
+  Higher16,
+  /// Fixup[15:0] <- (Target + Addend + 0x800080008000) >> 48.
+  Highest16,
+
+  /// J/JAL target. The target must be aligned and in the same 256-MiB region.
+  Jump26,
+  /// Fixup[15:0] <- (Target - Fixup + Addend) >> 2 : int16.
+  PC16,
+  /// Fixup <- Target - Fixup + Addend : int32.
+  PC32,
+  /// Release-6 compact branch immediate fields.
+  PC18S3,
+  PC19S2,
+  PC21S2,
+  PC26S2,
+  /// Paired PC-relative high and low halves.
+  PCHi16,
+  PCLo16,
+  /// _gp_disp high/low expressions. The O32 low half uses Fixup - 4 as P.
+  GPDispHi16,
+  GPDispLo16,
+
+  /// Fixup <- Target + Addend - _gp.
+  GPRel16,
+  GPRel32,
+  GPRel64,
+  /// Fixup <- address of GOT entry - _gp.
+  GOTOffset16,
+  GOTOffsetHi16,
+  GOTOffsetLo16,
+  /// Low offset complementary to a rounded 64-KiB GOT page entry.
+  GOTPageOffset16,
+
+  /// Fixup <- Target + Addend - start-of-ORC-TLS-template.
+  DTPRelHi16,
+  DTPRelLo16,
+  DTPRel32,
+  DTPRel64,
+
+  /// Compound N32/N64 %neg(%gp_rel(Target + Addend)) fixups.
+  NegGPRelHi16,
+  NegGPRelLo16,
+
+  /// Create an exact-address GOT entry and rewrite to GOTOffset16.
+  RequestGOTAndTransformToOffset16,
+  /// Create a rounded 64-KiB page GOT entry and rewrite to GOTOffset16.
+  RequestGOTPageAndTransformToOffset16,
+  /// Create an exact-address GOT entry and rewrite to its high/low GP offset.
+  RequestGOTAndTransformToOffsetHi16,
+  RequestGOTAndTransformToOffsetLo16,
+  /// Create a two-word general/local-dynamic TLS descriptor.
+  RequestTLSGDAndTransformToOffset16,
+  RequestTLSLDMAndTransformToOffset16,
+};
+
+LLVM_ABI const char *getEdgeKindName(Edge::Kind K);
+
+/// Returns true if G uses the MIPS release-6 ISA.
+LLVM_ABI bool isR6(const LinkGraph &G);
+
+/// Returns Pointer32 or Pointer64, according to G's pointer ABI.
+LLVM_ABI Edge::Kind getPointerEdgeKind(const LinkGraph &G);
+
+constexpr unsigned InstructionSize = sizeof(uint32_t);
+constexpr unsigned GOTPageBits = 16;
+constexpr uint64_t GOTPageSize = UINT64_C(1) << GOTPageBits;
+constexpr uint64_t GOTPageMask = GOTPageSize - 1;
+constexpr uint64_t GOTPageBias = GOTPageSize / 2;
+constexpr unsigned JumpRegionBits = 28;
+constexpr uint64_t JumpRegionMask = ~maskTrailingOnes<uint64_t>(JumpRegionBits);
+
+inline uint16_t getLo16(uint64_t Value) { return static_cast<uint16_t>(Value); }
+
+inline uint16_t getHi16(uint64_t Value) {
+  return static_cast<uint16_t>((Value + GOTPageBias) >> 16);
+}
+
+inline uint16_t getHigher16(uint64_t Value) {
+  constexpr uint64_t Bias = GOTPageBias | (GOTPageBias << 16);
+  return static_cast<uint16_t>((Value + Bias) >> 32);
+}
+
+inline uint16_t getHighest16(uint64_t Value) {
+  constexpr uint64_t Bias =
+      GOTPageBias | (GOTPageBias << 16) | (GOTPageBias << 32);
+  return static_cast<uint16_t>((Value + Bias) >> 48);
+}
+
+inline uint64_t getGOTPage(uint64_t Value) {
+  return (Value + GOTPageBias) & ~GOTPageMask;
+}
+
+struct PCRelEncoding {
+  unsigned Bits;
+  unsigned Shift;
+  unsigned PCAlignment;
+};
+
+inline PCRelEncoding getPCRelEncoding(Edge::Kind Kind) {
+  switch (Kind) {
+  case PC16:
+    return {16, 2, 1};
+  case PC18S3:
+    return {18, 3, 8};
+  case PC19S2:
+    return {19, 2, 4};
+  case PC21S2:
+    return {21, 2, 1};
+  case PC26S2:
+    return {26, 2, 1};
+  default:
+    llvm_unreachable("not a MIPS immediate branch edge");
+  }
+}
+
+inline bool needsGP(Edge::Kind K) {
+  switch (K) {
+  case GPRel16:
+  case GPRel32:
+  case GPRel64:
+  case GOTOffset16:
+  case GOTOffsetHi16:
+  case GOTOffsetLo16:
+  case GPDispHi16:
+  case GPDispLo16:
+  case NegGPRelHi16:
+  case NegGPRelLo16:
+    return true;
+  default:
+    return false;
+  }
+}
+
+constexpr uint32_t InstructionImm16Mask = 0x0000ffffU;
+constexpr uint32_t InstructionImm26Mask = 0x03ffffffU;
+
+inline void writeMaskedInstruction32(char *Fixup, uint32_t Mask, uint32_t Value,
+                                     endianness Endianness) {
+  uint32_t Instruction = support::endian::read32(Fixup, Endianness);
+  support::endian::write32(Fixup, (Instruction & ~Mask) | (Value & Mask),
+                           Endianness);
+}
+
+inline void writeImmediate16(char *Fixup, uint16_t Value,
+                             endianness Endianness) {
+  writeMaskedInstruction32(Fixup, InstructionImm16Mask, Value, Endianness);
+}
+
+inline void writeImmediate26(char *Fixup, uint32_t Value,
+                             endianness Endianness) {
+  writeMaskedInstruction32(Fixup, InstructionImm26Mask, Value, Endianness);
+}
+
+/// Apply fixup expression for edge to block content.
+/// GPSymbol and TLSBaseSymbol supply the bases for GP-relative and DTP-relative
+/// edges. They may be null when the edge does not require the respective base.
+inline Error applyFixup(LinkGraph &G, Block &B, const Edge &E,
+                        const Symbol *GPSymbol, const Symbol *TLSBaseSymbol) {
+  char *Fixup = B.getAlreadyMutableContent().data() + E.getOffset();
+  uint64_t P = B.getFixupAddress(E).getValue();
+  uint64_t S = E.getTarget().getAddress().getValue();
+  int64_t A = E.getAddend();
+  uint64_t TargetAddress = S + A;
+  const endianness Endianness = G.getEndianness();
+
+  auto TLSBaseAddr = [&]() -> Expected<uint64_t> {
+    if (TLSBaseSymbol)
+      return TLSBaseSymbol->getAddress().getValue();
+    return make_error<JITLinkError>(
+        "MIPS DTPREL relocation requires a TLS template");
+  };
+  auto CheckSigned = [&](int64_t V, unsigned Bits) -> Error {
+    if (!isIntN(Bits, V))
+      return makeTargetOutOfRangeError(G, B, E);
+    return Error::success();
+  };
+  auto CheckAligned = [&](int64_t V, unsigned Align) -> Error {
+    if (V & (Align - 1))
+      return makeAlignmentError(orc::ExecutorAddr(P), V, Align, E);
+    return Error::success();
+  };
+
+  int64_t V = static_cast<int64_t>(TargetAddress);
+  std::optional<uint64_t> GP;
+  if (needsGP(E.getKind())) {
+    assert(GPSymbol && "missing MIPS GP symbol");
+    GP = GPSymbol->getAddress().getValue();
+  }
+
+  switch (E.getKind()) {
+  case Pointer32:
+    if (TargetAddress > UINT32_MAX)
+      return makeTargetOutOfRangeError(G, B, E);
+    support::endian::write32(Fixup, static_cast<uint32_t>(TargetAddress),
+                             Endianness);
+    break;
+  case Pointer64:
+    support::endian::write64(Fixup, TargetAddress, Endianness);
+    break;
+  case PagePointer32: {
+    uint64_t Page = getGOTPage(TargetAddress);
+    if (Page > UINT32_MAX)
+      return makeTargetOutOfRangeError(G, B, E);
+    support::endian::write32(Fixup, Page, Endianness);
+    break;
+  }
+  case PagePointer64:
+    support::endian::write64(Fixup, getGOTPage(TargetAddress), Endianness);
+    break;
+  case Delta32:
+  case PC32:
+    V = static_cast<int64_t>(TargetAddress - P);
+    if (auto Err = CheckSigned(V, 32))
+      return Err;
+    support::endian::write32(Fixup, V, Endianness);
+    break;
+  case Delta64:
+    support::endian::write64(Fixup, TargetAddress - P, Endianness);
+    break;
+  case NegDelta32:
+    V = static_cast<int64_t>(P - S + A);
+    if (auto Err = CheckSigned(V, 32))
+      return Err;
+    support::endian::write32(Fixup, V, Endianness);
+    break;
+  case Abs16:
+    if (auto Err = CheckSigned(V, 16))
+      return Err;
+    support::endian::write16(Fixup, V, Endianness);
+    break;
+  case Hi16:
+    writeImmediate16(Fixup, getHi16(TargetAddress), Endianness);
+    break;
+  case Lo16:
+    writeImmediate16(Fixup, getLo16(TargetAddress), Endianness);
+    break;
+  case Higher16:
+    writeImmediate16(Fixup, getHigher16(TargetAddress), Endianness);
+    break;
+  case Highest16:
+    writeImmediate16(Fixup, getHighest16(TargetAddress), Endianness);
+    break;
+  case Jump26: {
+    if (auto Err = CheckAligned(TargetAddress, InstructionSize))
+      return Err;
+    if (((P + InstructionSize) & JumpRegionMask) !=
+        (TargetAddress & JumpRegionMask))
+      return makeTargetOutOfRangeError(G, B, E);
+    writeImmediate26(Fixup, TargetAddress >> 2, Endianness);
+    break;
+  }
+  case PC16:
+  case PC18S3:
+  case PC19S2:
+  case PC21S2:
+  case PC26S2: {
+    PCRelEncoding Encoding = getPCRelEncoding(E.getKind());
+    uint64_t FixupPC = alignDown(P, Encoding.PCAlignment);
+    V = static_cast<int64_t>(TargetAddress - FixupPC);
+    if (auto Err = CheckAligned(V, 1U << Encoding.Shift))
+      return Err;
+    if (auto Err = CheckSigned(V, Encoding.Bits + Encoding.Shift))
+      return Err;
+    uint32_t Mask = maskTrailingOnes<uint32_t>(Encoding.Bits);
+    writeMaskedInstruction32(
+        Fixup, Mask, static_cast<uint64_t>(V) >> Encoding.Shift, Endianness);
+    break;
+  }
+  case PCHi16:
+    V = static_cast<int64_t>(TargetAddress - P);
+    writeImmediate16(Fixup, getHi16(V), Endianness);
+    break;
+  case PCLo16:
+    writeImmediate16(Fixup, getLo16(TargetAddress - P), Endianness);
+    break;
+  case GPDispHi16:
+    V = static_cast<int64_t>(*GP + A - P);
+    writeImmediate16(Fixup, getHi16(V), Endianness);
+    break;
+  case GPDispLo16:
+    // Both halves use the address of the high instruction as P.
+    writeImmediate16(Fixup, getLo16(*GP + A - P + InstructionSize), Endianness);
+    break;
+  case GPRel16:
+  case GOTOffset16:
+    V = static_cast<int64_t>(S + A - *GP);
+    if (auto Err = CheckSigned(V, 16))
+      return Err;
+    writeImmediate16(Fixup, V, Endianness);
+    break;
+  case GPRel32:
+    V = static_cast<int64_t>(S + A - *GP);
+    if (auto Err = CheckSigned(V, 32))
+      return Err;
+    support::endian::write32(Fixup, V, Endianness);
+    break;
+  case GPRel64:
+    support::endian::write64(Fixup, TargetAddress - *GP, Endianness);
+    break;
+  case GOTOffsetHi16:
+    V = static_cast<int64_t>(S + A - *GP);
+    writeImmediate16(Fixup, getHi16(V), Endianness);
+    break;
+  case GOTOffsetLo16:
+    writeImmediate16(Fixup, getLo16(TargetAddress - *GP), Endianness);
+    break;
+  case GOTPageOffset16: {
+    uint64_t Page = getGOTPage(TargetAddress);
+    writeImmediate16(Fixup, getLo16(TargetAddress - Page), Endianness);
+    break;
+  }
+  case DTPRelHi16:
+  case DTPRelLo16:
+  case DTPRel32:
+  case DTPRel64: {
+    auto BaseOrErr = TLSBaseAddr();
+    if (!BaseOrErr)
+      return BaseOrErr.takeError();
+    V = static_cast<int64_t>(S + A - *BaseOrErr);
+    if (E.getKind() == DTPRelHi16)
+      writeImmediate16(Fixup, getHi16(V), Endianness);
+    else if (E.getKind() == DTPRelLo16)
+      writeImmediate16(Fixup, getLo16(V), Endianness);
+    else if (E.getKind() == DTPRel32) {
+      if (auto Err = CheckSigned(V, 32))
+        return Err;
+      support::endian::write32(Fixup, V, Endianness);
+    } else
+      support::endian::write64(Fixup, V, Endianness);
+    break;
+  }
+  case NegGPRelHi16:
+  case NegGPRelLo16:
+    V = static_cast<int64_t>(*GP - S - A);
+    if (E.getKind() == NegGPRelHi16)
+      writeImmediate16(Fixup, getHi16(V), Endianness);
+    else
+      writeImmediate16(Fixup, getLo16(V), Endianness);
+    break;
+  default:
+    return make_error<JITLinkError>(
+        "In graph " + G.getName() + ", section " + B.getSection().getName() +
+        ": unsupported MIPS edge kind " + G.getEdgeKindName(E.getKind()));
+  }
+  return Error::success();
+}
+
+/// Returns zero-filled pointer contents in the graph's pointer width.
+LLVM_ABI ArrayRef<char> getPointerBlockContent(const LinkGraph &G);
+
+/// Creates an anonymous pointer, optionally initialized to InitialTarget.
+LLVM_ABI Symbol &createAnonymousPointer(LinkGraph &G, Section &PointerSection,
+                                        Symbol *InitialTarget = nullptr,
+                                        Edge::AddendT InitialAddend = 0);
+
+/// Creates a stub that materializes PointerSymbol, loads its value into $t9,
+/// and jumps to $t9. Release-6 graphs use the release-6 indirect-jump encoding.
+LLVM_ABI Symbol &createAnonymousPointerJumpStub(LinkGraph &G,
+                                                Section &StubSection,
+                                                Symbol &PointerSymbol);
+
+} // namespace mips
+} // namespace jitlink
+} // namespace llvm
+
+#endif // LLVM_EXECUTIONENGINE_JITLINK_MIPS_H

diff  --git a/llvm/lib/ExecutionEngine/JITLink/CMakeLists.txt b/llvm/lib/ExecutionEngine/JITLink/CMakeLists.txt
index c1456321327ef..8162d8ee18ec5 100644
--- a/llvm/lib/ExecutionEngine/JITLink/CMakeLists.txt
+++ b/llvm/lib/ExecutionEngine/JITLink/CMakeLists.txt
@@ -26,6 +26,7 @@ add_llvm_component_library(LLVMJITLink
   ELF_aarch64.cpp
   ELF_hexagon.cpp
   ELF_loongarch.cpp
+  ELF_mips.cpp
   ELF_ppc64.cpp
   ELF_riscv.cpp
   ELF_systemz.cpp
@@ -48,6 +49,7 @@ add_llvm_component_library(LLVMJITLink
   aarch64.cpp
   hexagon.cpp
   loongarch.cpp
+  mips.cpp
   ppc64.cpp
   riscv.cpp
   systemz.cpp

diff  --git a/llvm/lib/ExecutionEngine/JITLink/COFFLinkGraphBuilder.cpp b/llvm/lib/ExecutionEngine/JITLink/COFFLinkGraphBuilder.cpp
index 984ef81ae6c99..be0db894080ec 100644
--- a/llvm/lib/ExecutionEngine/JITLink/COFFLinkGraphBuilder.cpp
+++ b/llvm/lib/ExecutionEngine/JITLink/COFFLinkGraphBuilder.cpp
@@ -31,10 +31,10 @@ COFFLinkGraphBuilder::COFFLinkGraphBuilder(
     SubtargetFeatures Features,
     LinkGraph::GetEdgeKindNameFunction GetEdgeKindName)
     : Obj(Obj),
-      G(std::make_unique<LinkGraph>(Obj.getFileName().str(), std::move(SSP),
-                                    createTripleWithCOFFFormat(std::move(TT)),
-                                    std::move(Features),
-                                    std::move(GetEdgeKindName))) {
+      G(std::make_unique<LinkGraph>(
+          Obj.getFileName().str(), std::move(SSP),
+          createTripleWithCOFFFormat(std::move(TT)), Obj.getBytesInAddress(),
+          std::move(Features), std::move(GetEdgeKindName))) {
   LLVM_DEBUG({
     dbgs() << "Created COFFLinkGraphBuilder for \"" << Obj.getFileName()
            << "\"\n";

diff  --git a/llvm/lib/ExecutionEngine/JITLink/ELF.cpp b/llvm/lib/ExecutionEngine/JITLink/ELF.cpp
index c1b5b00bdac3b..bfee62dedf6c9 100644
--- a/llvm/lib/ExecutionEngine/JITLink/ELF.cpp
+++ b/llvm/lib/ExecutionEngine/JITLink/ELF.cpp
@@ -17,6 +17,7 @@
 #include "llvm/ExecutionEngine/JITLink/ELF_aarch64.h"
 #include "llvm/ExecutionEngine/JITLink/ELF_hexagon.h"
 #include "llvm/ExecutionEngine/JITLink/ELF_loongarch.h"
+#include "llvm/ExecutionEngine/JITLink/ELF_mips.h"
 #include "llvm/ExecutionEngine/JITLink/ELF_ppc64.h"
 #include "llvm/ExecutionEngine/JITLink/ELF_riscv.h"
 #include "llvm/ExecutionEngine/JITLink/ELF_systemz.h"
@@ -105,6 +106,8 @@ createLinkGraphFromELFObject(MemoryBufferRef ObjectBuffer,
   }
   case ELF::EM_LOONGARCH:
     return createLinkGraphFromELFObject_loongarch(ObjectBuffer, std::move(SSP));
+  case ELF::EM_MIPS:
+    return createLinkGraphFromELFObject_mips(ObjectBuffer, std::move(SSP));
   case ELF::EM_RISCV:
     return createLinkGraphFromELFObject_riscv(ObjectBuffer, std::move(SSP));
   case ELF::EM_S390:
@@ -142,6 +145,12 @@ void link_ELF(std::unique_ptr<LinkGraph> G,
   case Triple::loongarch64:
     link_ELF_loongarch(std::move(G), std::move(Ctx));
     return;
+  case Triple::mips:
+  case Triple::mipsel:
+  case Triple::mips64:
+  case Triple::mips64el:
+    link_ELF_mips(std::move(G), std::move(Ctx));
+    return;
   case Triple::ppc64:
     link_ELF_ppc64(std::move(G), std::move(Ctx));
     return;

diff  --git a/llvm/lib/ExecutionEngine/JITLink/ELFLinkGraphBuilder.h b/llvm/lib/ExecutionEngine/JITLink/ELFLinkGraphBuilder.h
index 8dd176cd07f92..1886b3e711807 100644
--- a/llvm/lib/ExecutionEngine/JITLink/ELFLinkGraphBuilder.h
+++ b/llvm/lib/ExecutionEngine/JITLink/ELFLinkGraphBuilder.h
@@ -194,8 +194,8 @@ ELFLinkGraphBuilder<ELFT>::ELFLinkGraphBuilder(
     SubtargetFeatures Features, StringRef FileName,
     LinkGraph::GetEdgeKindNameFunction GetEdgeKindName)
     : ELFLinkGraphBuilderBase(std::make_unique<LinkGraph>(
-          FileName.str(), std::move(SSP), std::move(TT), std::move(Features),
-          std::move(GetEdgeKindName))),
+          FileName.str(), std::move(SSP), std::move(TT), ELFT::Is64Bits ? 8 : 4,
+          std::move(Features), std::move(GetEdgeKindName))),
       Obj(Obj) {
   LLVM_DEBUG(
       { dbgs() << "Created ELFLinkGraphBuilder for \"" << FileName << "\""; });

diff  --git a/llvm/lib/ExecutionEngine/JITLink/ELF_mips.cpp b/llvm/lib/ExecutionEngine/JITLink/ELF_mips.cpp
new file mode 100644
index 0000000000000..020440568af35
--- /dev/null
+++ b/llvm/lib/ExecutionEngine/JITLink/ELF_mips.cpp
@@ -0,0 +1,912 @@
+//===-- ELF_mips.cpp - JIT linker implementation for ELF/MIPS ------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/ExecutionEngine/JITLink/ELF_mips.h"
+
+#include "EHFrameSupportImpl.h"
+#include "ELFLinkGraphBuilder.h"
+#include "JITLinkGeneric.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/BinaryFormat/ELF.h"
+#include "llvm/ExecutionEngine/JITLink/DWARFRecordSectionSplitter.h"
+#include "llvm/ExecutionEngine/JITLink/mips.h"
+#include "llvm/Object/ELF.h"
+#include "llvm/Object/ELFObjectFile.h"
+#include "llvm/Support/Endian.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/MathExtras.h"
+#include "llvm/Support/MipsABIFlags.h"
+#include "llvm/Support/raw_ostream.h"
+
+#include <tuple>
+
+#define DEBUG_TYPE "jitlink"
+
+using namespace llvm;
+using namespace llvm::jitlink;
+using namespace llvm::jitlink::mips;
+
+namespace {
+
+constexpr StringRef GOTSectionName = "$__GOT";
+constexpr StringRef StubsSectionName = "$__STUBS";
+constexpr StringRef TLSInfoSectionName = "$__TLSINFO";
+constexpr StringRef TLSBaseName = "__jitlink_mips_tls_base";
+constexpr StringRef GOTSymbolName = "_GLOBAL_OFFSET_TABLE_";
+constexpr StringRef GPName = "_gp";
+constexpr StringRef GPDispName = "_gp_disp";
+constexpr StringRef LocalGPName = "__gnu_local_gp";
+constexpr unsigned RelocationTypeBits = 8;
+constexpr unsigned MaxRelocationOperations = 3;
+constexpr int64_t CompactBranchPCBias = InstructionSize;
+// The MIPS psABI defines $gp as 0x7ff0 bytes past the GOT base.
+constexpr uint64_t GPAnchorOffset = 0x7ff0;
+
+enum class MipsABI { O32, N32, N64 };
+
+static Edge::Kind getPagePointerEdgeKind(const LinkGraph &G) {
+  return G.getPointerSize() == 8 ? PagePointer64 : PagePointer32;
+}
+
+template <unsigned Bits, unsigned Shift>
+static int64_t decodeInstructionImmediate(uint32_t Instruction) {
+  static_assert(Bits + Shift <= 32);
+  uint32_t Value = (Instruction & maskTrailingOnes<uint32_t>(Bits)) << Shift;
+  return SignExtend64<Bits + Shift>(Value);
+}
+
+static uint8_t getPackedRelocationField(uint32_t Packed, unsigned Index) {
+  return static_cast<uint8_t>((Packed >> (Index * RelocationTypeBits)) &
+                              maskTrailingOnes<uint32_t>(RelocationTypeBits));
+}
+
+static std::string getRelocationChainName(ArrayRef<uint8_t> Types) {
+  std::string Result;
+  raw_string_ostream OS(Result);
+  for (auto [Index, Type] : llvm::enumerate(Types)) {
+    if (Index)
+      OS << '/';
+    OS << object::getELFRelocationTypeName(ELF::EM_MIPS, Type);
+  }
+  return Result;
+}
+
+static unsigned getFixupSize(Edge::Kind K) {
+  switch (K) {
+  case Abs16:
+    return sizeof(uint16_t);
+  case Pointer64:
+  case PagePointer64:
+  case Delta64:
+  case GPRel64:
+  case DTPRel64:
+    return sizeof(uint64_t);
+  case Pointer32:
+  case PagePointer32:
+  case Delta32:
+  case NegDelta32:
+  case Hi16:
+  case Lo16:
+  case Higher16:
+  case Highest16:
+  case Jump26:
+  case PC16:
+  case PC32:
+  case PC18S3:
+  case PC19S2:
+  case PC21S2:
+  case PC26S2:
+  case PCHi16:
+  case PCLo16:
+  case GPDispHi16:
+  case GPDispLo16:
+  case GPRel16:
+  case GPRel32:
+  case GOTOffset16:
+  case GOTOffsetHi16:
+  case GOTOffsetLo16:
+  case GOTPageOffset16:
+  case DTPRelHi16:
+  case DTPRelLo16:
+  case DTPRel32:
+  case NegGPRelHi16:
+  case NegGPRelLo16:
+  case RequestGOTAndTransformToOffset16:
+  case RequestGOTPageAndTransformToOffset16:
+  case RequestGOTAndTransformToOffsetHi16:
+  case RequestGOTAndTransformToOffsetLo16:
+  case RequestTLSGDAndTransformToOffset16:
+  case RequestTLSLDMAndTransformToOffset16:
+    return sizeof(uint32_t);
+  default:
+    llvm_unreachable("not a MIPS relocation edge");
+  }
+}
+
+class ELFJITLinker_mips : public JITLinker<ELFJITLinker_mips> {
+  friend class JITLinker<ELFJITLinker_mips>;
+
+public:
+  ELFJITLinker_mips(std::unique_ptr<JITLinkContext> Ctx,
+                    std::unique_ptr<LinkGraph> G, PassConfiguration PassConfig)
+      : JITLinker(std::move(Ctx), std::move(G), std::move(PassConfig)) {
+    getPassConfig().PreFixupPasses.push_back([this](LinkGraph &G) {
+      GPSymbol = G.findDefinedSymbolByName(G.intern(GPName));
+      TLSBaseSymbol = G.findDefinedSymbolByName(G.intern(TLSBaseName));
+      return Error::success();
+    });
+  }
+
+private:
+  Symbol *GPSymbol = nullptr;
+  Symbol *TLSBaseSymbol = nullptr;
+
+  Error applyFixup(LinkGraph &G, Block &B, const Edge &E) const {
+    return mips::applyFixup(G, B, E, GPSymbol, TLSBaseSymbol);
+  }
+};
+
+template <typename ELFT>
+class ELFLinkGraphBuilder_mips : public ELFLinkGraphBuilder<ELFT> {
+  using Base = ELFLinkGraphBuilder<ELFT>;
+  using Rel = typename ELFT::Rel;
+  using Rela = typename ELFT::Rela;
+
+  struct Reloc {
+    uint64_t Offset;
+    uint32_t Symbol;
+    SmallVector<uint8_t, MaxRelocationOperations> Types;
+    int64_t Addend;
+  };
+
+public:
+  ELFLinkGraphBuilder_mips(StringRef FileName, const object::ELFFile<ELFT> &Obj,
+                           std::shared_ptr<orc::SymbolStringPool> SSP,
+                           Triple TT, SubtargetFeatures Features, MipsABI ABI)
+      : Base(Obj, std::move(SSP), std::move(TT), std::move(Features), FileName,
+             mips::getEdgeKindName),
+        ABI(ABI) {}
+
+private:
+  MipsABI ABI;
+
+  bool excludeSection(const typename ELFT::Shdr &Sec) const override {
+    return Sec.sh_type == ELF::SHT_MIPS_ABIFLAGS ||
+           Sec.sh_type == ELF::SHT_MIPS_REGINFO ||
+           Sec.sh_type == ELF::SHT_MIPS_OPTIONS;
+  }
+
+  Error error(const typename ELFT::Shdr &FixupSect, uint64_t Offset,
+              const Twine &Message) const {
+    auto Name = Base::Obj.getSectionName(FixupSect);
+    if (!Name)
+      return Name.takeError();
+    return make_error<JITLinkError>(Base::G->getName() + ": section " + *Name +
+                                    "+0x" + utohexstr(Offset) + ": " + Message);
+  }
+
+  Expected<int64_t> implicitAddend(const typename ELFT::Shdr &RelSect,
+                                   uint8_t Type, const Block &B,
+                                   uint64_t Offset) const {
+    if (Type == ELF::R_MIPS_NONE || Type == ELF::R_MIPS_JALR)
+      return 0;
+
+    unsigned FixupSize = Type == ELF::R_MIPS_16   ? sizeof(uint16_t)
+                         : Type == ELF::R_MIPS_64 ? sizeof(uint64_t)
+                                                  : sizeof(uint32_t);
+    if (Offset > B.getSize() || FixupSize > B.getSize() - Offset)
+      return error(RelSect, Offset,
+                   "relocation fixup extends past the end of its block");
+
+    const char *P = B.getContent().data() + Offset;
+    if (Type == ELF::R_MIPS_16)
+      return SignExtend64<16>(support::endian::read16<ELFT::Endianness>(P));
+
+    if (Type == ELF::R_MIPS_64)
+      return support::endian::read64<ELFT::Endianness>(P);
+
+    uint32_t W = support::endian::read32<ELFT::Endianness>(P);
+    switch (Type) {
+    case ELF::R_MIPS_32:
+    case ELF::R_MIPS_GPREL32:
+    case ELF::R_MIPS_PC32:
+    case ELF::R_MIPS_TLS_DTPREL32:
+      return SignExtend64<32>(W);
+    case ELF::R_MIPS_26:
+      return decodeInstructionImmediate<26, 2>(W);
+    case ELF::R_MIPS_HI16:
+    case ELF::R_MIPS_PCHI16:
+    case ELF::R_MIPS_GOT16:
+    case ELF::R_MIPS_GOT_HI16:
+    case ELF::R_MIPS_CALL_HI16:
+      return decodeInstructionImmediate<16, 16>(W);
+    case ELF::R_MIPS_PC16:
+      return decodeInstructionImmediate<16, 2>(W);
+    case ELF::R_MIPS_PC18_S3:
+      return decodeInstructionImmediate<18, 3>(W);
+    case ELF::R_MIPS_PC19_S2:
+      return decodeInstructionImmediate<19, 2>(W);
+    case ELF::R_MIPS_PC21_S2:
+      return decodeInstructionImmediate<21, 2>(W);
+    case ELF::R_MIPS_PC26_S2:
+      return decodeInstructionImmediate<26, 2>(W);
+    default:
+      return decodeInstructionImmediate<16, 0>(W);
+    }
+  }
+
+  static uint8_t matchingLow(uint8_t Type, bool IsLocal) {
+    switch (Type) {
+    case ELF::R_MIPS_HI16:
+      return ELF::R_MIPS_LO16;
+    case ELF::R_MIPS_PCHI16:
+      return ELF::R_MIPS_PCLO16;
+    case ELF::R_MIPS_GOT16:
+      return IsLocal ? ELF::R_MIPS_LO16 : ELF::R_MIPS_NONE;
+    default:
+      return ELF::R_MIPS_NONE;
+    }
+  }
+
+  Error validateSymbols() {
+    if (!Base::SymTabSec)
+      return Error::success();
+    auto Symbols = Base::Obj.symbols(Base::SymTabSec);
+    if (!Symbols)
+      return Symbols.takeError();
+    for (const auto &Sym : *Symbols)
+      if ((Sym.st_other & ELF::STO_MIPS_MICROMIPS) ||
+          (Sym.st_other & ELF::STO_MIPS_MIPS16) == ELF::STO_MIPS_MIPS16)
+        return make_error<JITLinkError>(
+            Base::G->getName() +
+            ": compact-mode MIPS16/microMIPS symbols are unsupported");
+    return Error::success();
+  }
+
+  Error collectRelocs(const typename ELFT::Shdr &RelSect, Block &B,
+                      SmallVectorImpl<Reloc> &Out) {
+    if (RelSect.sh_type == ELF::SHT_RELA) {
+      auto Rs = Base::Obj.relas(RelSect);
+      if (!Rs)
+        return Rs.takeError();
+      for (auto I = Rs->begin(), E = Rs->end(); I != E;) {
+        const Rela &R = *I++;
+        if (ABI == MipsABI::N32) {
+          Reloc RR{R.r_offset, R.getSymbol(false), {}, R.r_addend};
+          RR.Types.push_back(R.getType(false));
+          while (I != E && I->r_offset == R.r_offset) {
+            if (RR.Types.size() == MaxRelocationOperations)
+              return error(RelSect, R.r_offset,
+                           "more than three N32 relocation operations");
+            if (I->getSymbol(false) != 0)
+              return error(RelSect, R.r_offset,
+                           "non-zero symbol in a secondary N32 relocation");
+            RR.Types.push_back(I->getType(false));
+            ++I;
+          }
+          Out.push_back(std::move(RR));
+        } else {
+          uint32_t PackedType = R.getType(Base::Obj.isMips64EL());
+          Reloc RR{
+              R.r_offset, R.getSymbol(Base::Obj.isMips64EL()), {}, R.r_addend};
+          uint8_t T2 = getPackedRelocationField(PackedType, 1);
+          uint8_t T3 = getPackedRelocationField(PackedType, 2);
+          RR.Types.push_back(getPackedRelocationField(PackedType, 0));
+          if (T2 || T3)
+            RR.Types.push_back(T2);
+          if (T3)
+            RR.Types.push_back(T3);
+          uint8_t SSym = getPackedRelocationField(PackedType, 3);
+          if (SSym != ELF::RSS_UNDEF)
+            return error(RelSect, R.r_offset,
+                         "unsupported packed relocation special symbol " +
+                             Twine(SSym));
+          Out.push_back(std::move(RR));
+        }
+      }
+      return Error::success();
+    }
+
+    auto Rs = Base::Obj.rels(RelSect);
+    if (!Rs)
+      return Rs.takeError();
+    for (auto I = Rs->begin(), E = Rs->end(); I != E;) {
+      const Rel &R = *I++;
+      Reloc RR{R.r_offset, R.getSymbol(false), {}, 0};
+      RR.Types.push_back(R.getType(false));
+      if (ABI == MipsABI::N32) {
+        while (I != E && I->r_offset == R.r_offset) {
+          if (RR.Types.size() == MaxRelocationOperations)
+            return error(RelSect, R.r_offset,
+                         "more than three N32 relocation operations");
+          if (I->getSymbol(false) != 0)
+            return error(RelSect, R.r_offset,
+                         "non-zero symbol in a secondary N32 relocation");
+          RR.Types.push_back(I->getType(false));
+          ++I;
+        }
+      }
+      Out.push_back(std::move(RR));
+    }
+
+    for (size_t I = 0; I != Out.size(); ++I) {
+      auto &R = Out[I];
+      uint8_t FinalType = R.Types.back();
+      auto Addend = implicitAddend(RelSect, FinalType, B, R.Offset);
+      if (!Addend)
+        return Addend.takeError();
+      R.Addend = *Addend;
+      bool IsLocal = false;
+      if (auto *S = Base::getGraphSymbol(R.Symbol))
+        IsLocal = S->getScope() == Scope::Local;
+      uint8_t LowType = matchingLow(R.Types.front(), IsLocal);
+      if (LowType == ELF::R_MIPS_NONE)
+        continue;
+      bool Found = false;
+      for (size_t J = I + 1; J != Out.size(); ++J)
+        if (Out[J].Types.front() == LowType && Out[J].Symbol == R.Symbol) {
+          auto LowAddend = implicitAddend(RelSect, LowType, B, Out[J].Offset);
+          if (!LowAddend)
+            return LowAddend.takeError();
+          R.Addend += *LowAddend;
+          Found = true;
+          break;
+        }
+      if (!Found)
+        return error(RelSect, R.Offset,
+                     "unmatched " +
+                         Twine(object::getELFRelocationTypeName(
+                             ELF::EM_MIPS, R.Types.front())) +
+                         " relocation");
+    }
+    return Error::success();
+  }
+
+  Expected<Edge::Kind> edgeKind(const Reloc &R, Symbol &Target) const {
+    if (R.Types.size() > 1) {
+      if (R.Types.size() == 2 && R.Types[1] == ELF::R_MIPS_64) {
+        switch (R.Types[0]) {
+        case ELF::R_MIPS_32:
+        case ELF::R_MIPS_64:
+          return Pointer64;
+        case ELF::R_MIPS_PC32:
+          return Delta64;
+        case ELF::R_MIPS_GPREL32:
+          return GPRel64;
+        default:
+          break;
+        }
+      }
+      if (R.Types.size() == 3 && R.Types[0] == ELF::R_MIPS_GPREL16 &&
+          R.Types[1] == ELF::R_MIPS_SUB && R.Types[2] == ELF::R_MIPS_HI16)
+        return NegGPRelHi16;
+      if (R.Types.size() == 3 && R.Types[0] == ELF::R_MIPS_GPREL16 &&
+          R.Types[1] == ELF::R_MIPS_SUB && R.Types[2] == ELF::R_MIPS_LO16)
+        return NegGPRelLo16;
+      return make_error<JITLinkError>("unsupported packed MIPS relocation " +
+                                      getRelocationChainName(R.Types));
+    }
+
+    StringRef Name = Target.hasName() ? *Target.getName() : StringRef();
+    switch (R.Types.front()) {
+    case ELF::R_MIPS_16:
+      return Abs16;
+    case ELF::R_MIPS_32:
+      return Pointer32;
+    case ELF::R_MIPS_64:
+      return Pointer64;
+    case ELF::R_MIPS_HI16:
+      return Name == GPDispName ? GPDispHi16 : Hi16;
+    case ELF::R_MIPS_LO16:
+      return Name == GPDispName ? GPDispLo16 : Lo16;
+    case ELF::R_MIPS_HIGHER:
+      return Higher16;
+    case ELF::R_MIPS_HIGHEST:
+      return Highest16;
+    case ELF::R_MIPS_26:
+      return Jump26;
+    case ELF::R_MIPS_PC16:
+      return PC16;
+    case ELF::R_MIPS_PC32:
+      return PC32;
+    case ELF::R_MIPS_PC18_S3:
+      return PC18S3;
+    case ELF::R_MIPS_PC19_S2:
+      return PC19S2;
+    case ELF::R_MIPS_PC21_S2:
+      return PC21S2;
+    case ELF::R_MIPS_PC26_S2:
+      return PC26S2;
+    case ELF::R_MIPS_PCHI16:
+      return PCHi16;
+    case ELF::R_MIPS_PCLO16:
+      return PCLo16;
+    case ELF::R_MIPS_GPREL16:
+      return GPRel16;
+    case ELF::R_MIPS_GPREL32:
+      return GPRel32;
+    case ELF::R_MIPS_GOT16:
+      return Target.getScope() == Scope::Local
+                 ? RequestGOTPageAndTransformToOffset16
+                 : RequestGOTAndTransformToOffset16;
+    case ELF::R_MIPS_CALL16:
+    case ELF::R_MIPS_GOT_DISP:
+      return RequestGOTAndTransformToOffset16;
+    case ELF::R_MIPS_GOT_PAGE:
+      return RequestGOTPageAndTransformToOffset16;
+    case ELF::R_MIPS_GOT_OFST:
+      return GOTPageOffset16;
+    case ELF::R_MIPS_GOT_HI16:
+    case ELF::R_MIPS_CALL_HI16:
+      return RequestGOTAndTransformToOffsetHi16;
+    case ELF::R_MIPS_GOT_LO16:
+    case ELF::R_MIPS_CALL_LO16:
+      return RequestGOTAndTransformToOffsetLo16;
+    case ELF::R_MIPS_TLS_GD:
+      return RequestTLSGDAndTransformToOffset16;
+    case ELF::R_MIPS_TLS_LDM:
+      return RequestTLSLDMAndTransformToOffset16;
+    case ELF::R_MIPS_TLS_DTPREL_HI16:
+      return DTPRelHi16;
+    case ELF::R_MIPS_TLS_DTPREL_LO16:
+      return DTPRelLo16;
+    case ELF::R_MIPS_TLS_DTPREL32:
+      return DTPRel32;
+    case ELF::R_MIPS_TLS_DTPREL64:
+      return DTPRel64;
+    case ELF::R_MIPS_TLS_GOTTPREL:
+    case ELF::R_MIPS_TLS_TPREL32:
+    case ELF::R_MIPS_TLS_TPREL64:
+    case ELF::R_MIPS_TLS_TPREL_HI16:
+    case ELF::R_MIPS_TLS_TPREL_LO16:
+      return make_error<JITLinkError>(
+          "initial/local-exec MIPS TLS relocations are unsupported");
+    default:
+      return make_error<JITLinkError>("unsupported MIPS relocation " +
+                                      Twine(object::getELFRelocationTypeName(
+                                          ELF::EM_MIPS, R.Types.front())));
+    }
+  }
+
+  Error addRelocations() override {
+    if (auto Err = validateSymbols())
+      return Err;
+    for (const auto &RelSect : Base::Sections) {
+      if (RelSect.sh_type != ELF::SHT_REL && RelSect.sh_type != ELF::SHT_RELA)
+        continue;
+      if ((ABI != MipsABI::O32) != (RelSect.sh_type == ELF::SHT_RELA))
+        return make_error<JITLinkError>(
+            Base::G->getName() +
+            ": invalid MIPS relocation-section format for ABI");
+      auto FixupSect = Base::Obj.getSection(RelSect.sh_info);
+      if (!FixupSect)
+        return FixupSect.takeError();
+      Block *B = Base::getGraphBlock(RelSect.sh_info);
+      if (!B)
+        continue;
+      SmallVector<Reloc> Rs;
+      if (auto Err = collectRelocs(RelSect, *B, Rs))
+        return Err;
+      for (const Reloc &R : Rs) {
+        uint8_t Primary = R.Types.front();
+        if (Primary == ELF::R_MIPS_NONE || Primary == ELF::R_MIPS_JALR)
+          continue;
+        Symbol *Target = Base::getGraphSymbol(R.Symbol);
+        if (!Target)
+          return error(**FixupSect, R.Offset,
+                       "relocation references missing symbol index " +
+                           Twine(R.Symbol));
+        auto Kind = edgeKind(R, *Target);
+        if (!Kind)
+          return joinErrors(
+              error(**FixupSect, R.Offset, "cannot lower relocation"),
+              Kind.takeError());
+        auto FixupAddress = orc::ExecutorAddr((*FixupSect)->sh_addr) + R.Offset;
+        Edge::OffsetT Offset = FixupAddress - B->getAddress();
+        unsigned FixupSize = getFixupSize(*Kind);
+        if (Offset > B->getSize() || FixupSize > B->getSize() - Offset)
+          return error(**FixupSect, R.Offset,
+                       "relocation fixup extends past the end of its block");
+        B->addEdge(*Kind, Offset, *Target, R.Addend);
+      }
+    }
+    return Error::success();
+  }
+};
+
+static Symbol &getOrCreateTLSBase(LinkGraph &G) {
+  auto Name = G.intern(TLSBaseName);
+  if (auto *S = G.findDefinedSymbolByName(Name))
+    return *S;
+  Section *TLS = G.findSectionByName(".tdata");
+  if (!TLS || TLS->empty())
+    TLS = G.findSectionByName(".tbss");
+  if (!TLS || TLS->empty()) {
+    auto &S =
+        G.createSection(".tdata", orc::MemProt::Read | orc::MemProt::Write);
+    auto &B = G.createMutableContentBlock(S, 0, orc::ExecutorAddr(), 1, 0);
+    return G.addDefinedSymbol(B, 0, Name, 0, Linkage::Strong, Scope::Local,
+                              false, true);
+  }
+  auto &B = **TLS->blocks().begin();
+  return G.addDefinedSymbol(B, 0, Name, 0, Linkage::Strong, Scope::Local, false,
+                            true);
+}
+
+class MipsTableManager {
+public:
+  explicit MipsTableManager(LinkGraph &G) : G(G) {}
+
+  bool visitEdge(LinkGraph &, Block *, Edge &E) {
+    switch (E.getKind()) {
+    case RequestGOTAndTransformToOffset16:
+      rewriteGOT(E, GOTEntryKind::Exact, GOTOffset16);
+      return true;
+    case RequestGOTPageAndTransformToOffset16:
+      rewriteGOT(E, GOTEntryKind::Page, GOTOffset16);
+      return true;
+    case RequestGOTAndTransformToOffsetHi16:
+      rewriteGOT(E, GOTEntryKind::Exact, GOTOffsetHi16);
+      return true;
+    case RequestGOTAndTransformToOffsetLo16:
+      rewriteGOT(E, GOTEntryKind::Exact, GOTOffsetLo16);
+      return true;
+    case RequestTLSGDAndTransformToOffset16:
+      rewriteTLS(E, TLSDescriptorKind::GeneralDynamic);
+      return true;
+    case RequestTLSLDMAndTransformToOffset16:
+      rewriteTLS(E, TLSDescriptorKind::LocalDynamic);
+      return true;
+    case Jump26:
+      if (!E.getTarget().isDefined()) {
+        rewriteBranchToStub(E);
+        return true;
+      }
+      return false;
+    case PC26S2:
+      if (mips::isR6(G) && !E.getTarget().isDefined()) {
+        rewriteBranchToStub(E);
+        return true;
+      }
+      return false;
+    default:
+      return false;
+    }
+  }
+
+private:
+  enum class GOTEntryKind { Exact, Page };
+  enum class TLSDescriptorKind { GeneralDynamic, LocalDynamic };
+
+  using GOTKey = std::tuple<Symbol *, int64_t, GOTEntryKind>;
+  using StubKey = std::tuple<Symbol *, int64_t>;
+  LinkGraph &G;
+  DenseMap<GOTKey, Symbol *> GOTEntries;
+  DenseMap<StubKey, Symbol *> Stubs;
+  DenseMap<std::pair<Symbol *, int64_t>, Symbol *> TLSGDEntries;
+  Symbol *TLSLDMEntry = nullptr;
+
+  Section &getSection(StringRef Name, orc::MemProt Prot) {
+    if (auto *S = G.findSectionByName(Name))
+      return *S;
+    return G.createSection(Name, Prot);
+  }
+
+  Symbol &getGOT(Symbol &Target, int64_t Addend, GOTEntryKind Kind) {
+    GOTKey Key{&Target, Addend, Kind};
+    auto I = GOTEntries.find(Key);
+    if (I != GOTEntries.end())
+      return *I->second;
+    auto &Sec =
+        getSection(GOTSectionName, orc::MemProt::Read | orc::MemProt::Write);
+    auto &Entry = mips::createAnonymousPointer(G, Sec);
+    Edge::Kind PointerKind = Kind == GOTEntryKind::Page
+                                 ? getPagePointerEdgeKind(G)
+                                 : mips::getPointerEdgeKind(G);
+    Entry.getBlock().addEdge(PointerKind, 0, Target, Addend);
+    GOTEntries[Key] = &Entry;
+    return Entry;
+  }
+
+  void rewriteGOT(Edge &E, GOTEntryKind EntryKind, Edge::Kind NewKind) {
+    Symbol &Entry = getGOT(E.getTarget(), E.getAddend(), EntryKind);
+    E.setKind(NewKind);
+    E.setTarget(Entry);
+    E.setAddend(0);
+  }
+
+  Symbol &createTLSInfo(Symbol &Target, int64_t Addend) {
+    auto &Sec = getSection(TLSInfoSectionName,
+                           orc::MemProt::Read | orc::MemProt::Write);
+    auto &B =
+        G.createMutableContentBlock(Sec, 2 * G.getPointerSize(),
+                                    orc::ExecutorAddr(), G.getPointerSize(), 0);
+    B.addEdge(mips::getPointerEdgeKind(G), G.getPointerSize(), Target, Addend);
+    return G.addAnonymousSymbol(B, 0, B.getSize(), false, false);
+  }
+
+  void rewriteTLS(Edge &E, TLSDescriptorKind Kind) {
+    Symbol *Entry = nullptr;
+    if (Kind == TLSDescriptorKind::LocalDynamic) {
+      if (!TLSLDMEntry)
+        TLSLDMEntry = &createTLSInfo(getOrCreateTLSBase(G), 0);
+      Entry = TLSLDMEntry;
+    } else {
+      auto Key = std::make_pair(&E.getTarget(), E.getAddend());
+      auto I = TLSGDEntries.find(Key);
+      if (I == TLSGDEntries.end())
+        I = TLSGDEntries
+                .try_emplace(Key, &createTLSInfo(E.getTarget(), E.getAddend()))
+                .first;
+      Entry = I->second;
+    }
+    E.setKind(GOTOffset16);
+    E.setTarget(*Entry);
+    E.setAddend(0);
+  }
+
+  void rewriteBranchToStub(Edge &E) {
+    // PC26_S2 uses PC + 4; JITLink edges use the fixup address.
+    int64_t PointerAddend = E.getAddend();
+    int64_t BranchAddend = 0;
+    if (E.getKind() == PC26S2) {
+      PointerAddend += CompactBranchPCBias;
+      BranchAddend = -CompactBranchPCBias;
+    }
+
+    StubKey Key{&E.getTarget(), PointerAddend};
+    auto I = Stubs.find(Key);
+    if (I == Stubs.end()) {
+      auto &Ptr = getGOT(E.getTarget(), PointerAddend, GOTEntryKind::Exact);
+      auto &Sec =
+          getSection(StubsSectionName, orc::MemProt::Read | orc::MemProt::Exec);
+      I = Stubs
+              .try_emplace(Key,
+                           &mips::createAnonymousPointerJumpStub(G, Sec, Ptr))
+              .first;
+    }
+    E.setTarget(*I->second);
+    E.setAddend(BranchAddend);
+  }
+};
+
+static Error buildTables(LinkGraph &G) {
+  MipsTableManager Tables(G);
+  visitExistingEdges(G, Tables);
+  return Error::success();
+}
+
+static Symbol &defineMagic(LinkGraph &G, Block &Anchor, StringRef Name,
+                           uint64_t Offset) {
+  auto N = G.intern(Name);
+  if (auto *S = G.findDefinedSymbolByName(N)) {
+    S->setLive(true);
+    return *S;
+  }
+  if (auto *S = G.findExternalSymbolByName(N)) {
+    G.makeDefined(*S, Anchor, Offset, 0, Linkage::Strong, Scope::Local, true);
+    return *S;
+  }
+  return G.addDefinedSymbol(Anchor, Offset, N, 0, Linkage::Strong, Scope::Local,
+                            false, true);
+}
+
+static void prepareGPRegion(LinkGraph &G,
+                            ArrayRef<std::string> GPRelSectionNames) {
+  Section *GOT = G.findSectionByName(GOTSectionName);
+  if (!GOT)
+    GOT = &G.createSection(GOTSectionName,
+                           orc::MemProt::Read | orc::MemProt::Write);
+  // Keep the reserved GP window as content so it can share the GOT section.
+  auto &Anchor = G.createMutableContentBlock(
+      *GOT, GPAnchorOffset, orc::ExecutorAddr(), G.getPointerSize(), 0);
+  defineMagic(G, Anchor, GOTSymbolName, 0);
+  defineMagic(G, Anchor, GPName, GPAnchorOffset);
+  defineMagic(G, Anchor, GPDispName, GPAnchorOffset);
+  defineMagic(G, Anchor, LocalGPName, GPAnchorOffset);
+
+  for (const std::string &Name : GPRelSectionNames)
+    if (auto *S = G.findSectionByName(Name)) {
+      SmallVector<Block *> Blocks(S->blocks().begin(), S->blocks().end());
+      for (auto *B : Blocks)
+        G.transferBlock(*B, *GOT);
+    }
+}
+
+static Error orderGPRegion(LinkGraph &G) {
+  auto *GOT = G.findSectionByName(GOTSectionName);
+  if (!GOT)
+    return Error::success();
+
+  if (auto *TLSInfo = G.findSectionByName(TLSInfoSectionName))
+    G.mergeSections(*GOT, *TLSInfo);
+
+  auto *GOTBase = G.findDefinedSymbolByName(G.intern(GOTSymbolName));
+  assert(GOTBase && &GOTBase->getBlock().getSection() == GOT &&
+         GOTBase->getOffset() == 0 && "invalid MIPS GOT base");
+
+  // BasicLayout orders equal-address blocks by size. Give synthesized entries
+  // the anchor's end address to keep the reserved GP window first.
+  Block &Anchor = GOTBase->getBlock();
+  Anchor.setAddress(orc::ExecutorAddr());
+  for (auto *B : GOT->blocks())
+    if (B != &Anchor)
+      B->setAddress(orc::ExecutorAddr(Anchor.getSize()));
+
+  return Error::success();
+}
+
+template <typename ELFT>
+Error validateABIFlags(const object::ELFFile<ELFT> &Obj, MipsABI ABI,
+                       StringRef FileName) {
+  auto Sections = Obj.sections();
+  if (!Sections)
+    return Sections.takeError();
+  const typename ELFT::Shdr *ABIFlagsSec = nullptr;
+  for (const auto &Sec : *Sections)
+    if (Sec.sh_type == ELF::SHT_MIPS_ABIFLAGS) {
+      if (ABIFlagsSec)
+        return make_error<JITLinkError>(FileName.str() +
+                                        ": multiple .MIPS.abiflags sections");
+      ABIFlagsSec = &Sec;
+    }
+  if (!ABIFlagsSec)
+    return Error::success();
+  auto Contents = Obj.template getSectionContentsAsArray<char>(*ABIFlagsSec);
+  if (!Contents)
+    return Contents.takeError();
+  if (Contents->size() != sizeof(object::Elf_Mips_ABIFlags<ELFT>))
+    return make_error<JITLinkError>(FileName.str() +
+                                    ": invalid .MIPS.abiflags size");
+  const auto &AF = *reinterpret_cast<const object::Elf_Mips_ABIFlags<ELFT> *>(
+      Contents->data());
+  if (AF.version != 0)
+    return make_error<JITLinkError>(FileName.str() +
+                                    ": unsupported .MIPS.abiflags version");
+  if ((ABI == MipsABI::N32 || ABI == MipsABI::N64) &&
+      AF.gpr_size != Mips::AFL_REG_64)
+    return make_error<JITLinkError>(
+        FileName.str() + ": N32/N64 requires 64-bit general registers");
+  if (static_cast<uint32_t>(AF.ases) &
+      (Mips::AFL_ASE_MIPS16 | Mips::AFL_ASE_MICROMIPS))
+    return make_error<JITLinkError>(
+        FileName.str() +
+        ": MIPS16 and microMIPS ABI flags are unsupported by JITLink");
+  return Error::success();
+}
+
+template <typename ELFT>
+Expected<std::unique_ptr<LinkGraph>>
+buildGraph(object::ELFObjectFile<ELFT> &ObjFile,
+           std::shared_ptr<orc::SymbolStringPool> SSP, MipsABI ABI, Triple TT,
+           SubtargetFeatures Features) {
+  auto &Obj = ObjFile.getELFFile();
+  if (auto Err = validateABIFlags(Obj, ABI, ObjFile.getFileName()))
+    return std::move(Err);
+  ELFLinkGraphBuilder_mips<ELFT> Builder(ObjFile.getFileName(), Obj,
+                                         std::move(SSP), std::move(TT),
+                                         std::move(Features), ABI);
+  auto G = Builder.buildGraph();
+  if (!G)
+    return G.takeError();
+
+  SmallVector<std::string> GPRelSections;
+  auto Sections = Obj.sections();
+  if (!Sections)
+    return Sections.takeError();
+  for (const auto &Sec : *Sections)
+    if (Sec.sh_flags & ELF::SHF_MIPS_GPREL) {
+      auto Name = Obj.getSectionName(Sec);
+      if (!Name)
+        return Name.takeError();
+      GPRelSections.push_back(Name->str());
+    }
+  prepareGPRegion(**G, GPRelSections);
+  return G;
+}
+
+static Expected<MipsABI> validateHeader(const object::ELFObjectFileBase &Obj,
+                                        uint8_t ELFClass, StringRef FileName) {
+  uint32_t Flags = Obj.getPlatformFlags();
+  if (Flags & (ELF::EF_MIPS_ARCH_ASE_M16 | ELF::EF_MIPS_MICROMIPS))
+    return make_error<JITLinkError>(
+        FileName.str() +
+        ": MIPS16 and microMIPS objects are unsupported by JITLink");
+
+  uint32_t ABIFlag = Flags & ELF::EF_MIPS_ABI;
+  if (ELFClass == ELF::ELFCLASS64) {
+    if ((Flags & ELF::EF_MIPS_ABI2) || ABIFlag != 0)
+      return make_error<JITLinkError>(
+          FileName.str() + ": inconsistent MIPS N64 ELF class/ABI flags");
+    return MipsABI::N64;
+  }
+  if (Flags & ELF::EF_MIPS_ABI2) {
+    if (ABIFlag != 0)
+      return make_error<JITLinkError>(
+          FileName.str() + ": inconsistent MIPS N32 ELF class/ABI flags");
+    return MipsABI::N32;
+  }
+  if (ABIFlag != 0 && ABIFlag != ELF::EF_MIPS_ABI_O32)
+    return make_error<JITLinkError>(FileName.str() +
+                                    ": unsupported 32-bit MIPS ABI flags");
+  return MipsABI::O32;
+}
+
+} // namespace
+
+namespace llvm {
+namespace jitlink {
+
+Expected<std::unique_ptr<LinkGraph>>
+createLinkGraphFromELFObject_mips(MemoryBufferRef ObjectBuffer,
+                                  std::shared_ptr<orc::SymbolStringPool> SSP) {
+  StringRef FileName = ObjectBuffer.getBufferIdentifier();
+  auto ELFObj = object::ObjectFile::createELFObjectFile(ObjectBuffer);
+  if (!ELFObj)
+    return ELFObj.takeError();
+  auto &Base = cast<object::ELFObjectFileBase>(**ELFObj);
+  assert(Base.getEMachine() == ELF::EM_MIPS && "expected an ELF/MIPS object");
+
+  StringRef Buf = ObjectBuffer.getBuffer();
+  uint8_t Class = Buf[ELF::EI_CLASS];
+  uint8_t Data = Buf[ELF::EI_DATA];
+  auto ABI = validateHeader(Base, Class, FileName);
+  if (!ABI)
+    return ABI.takeError();
+  auto Features = Base.getFeatures();
+  if (!Features)
+    return Features.takeError();
+
+  Triple TT = Base.makeTriple();
+  if (*ABI == MipsABI::N32) {
+    TT.setArch(Data == ELF::ELFDATA2LSB ? Triple::mips64el : Triple::mips64);
+    TT.setEnvironment(Triple::GNUABIN32);
+  }
+
+  if (Class == ELF::ELFCLASS32 && Data == ELF::ELFDATA2LSB)
+    return buildGraph(cast<object::ELFObjectFile<object::ELF32LE>>(**ELFObj),
+                      std::move(SSP), *ABI, TT, std::move(*Features));
+  if (Class == ELF::ELFCLASS32 && Data == ELF::ELFDATA2MSB)
+    return buildGraph(cast<object::ELFObjectFile<object::ELF32BE>>(**ELFObj),
+                      std::move(SSP), *ABI, TT, std::move(*Features));
+  if (Class == ELF::ELFCLASS64 && Data == ELF::ELFDATA2LSB)
+    return buildGraph(cast<object::ELFObjectFile<object::ELF64LE>>(**ELFObj),
+                      std::move(SSP), *ABI, TT, std::move(*Features));
+  if (Class == ELF::ELFCLASS64 && Data == ELF::ELFDATA2MSB)
+    return buildGraph(cast<object::ELFObjectFile<object::ELF64BE>>(**ELFObj),
+                      std::move(SSP), *ABI, TT, std::move(*Features));
+  llvm_unreachable("invalid ELF/MIPS class or byte order");
+}
+
+void link_ELF_mips(std::unique_ptr<LinkGraph> G,
+                   std::unique_ptr<JITLinkContext> Ctx) {
+  PassConfiguration Config;
+  const Triple &TT = G->getTargetTriple();
+  if (Ctx->shouldAddDefaultTargetPasses(TT)) {
+    Config.PrePrunePasses.push_back(DWARFRecordSectionSplitter(".eh_frame"));
+    Config.PrePrunePasses.push_back(
+        EHFrameEdgeFixer(".eh_frame", G->getPointerSize(), Pointer32, Pointer64,
+                         Delta32, Delta64, NegDelta32));
+    Config.PrePrunePasses.push_back(EHFrameNullTerminator(".eh_frame"));
+    if (auto MarkLive = Ctx->getMarkLivePass(TT))
+      Config.PrePrunePasses.push_back(std::move(MarkLive));
+    else
+      Config.PrePrunePasses.push_back(markAllSymbolsLive);
+    Config.PostPrunePasses.push_back(buildTables);
+  }
+  if (auto Err = Ctx->modifyPassConfig(*G, Config))
+    return Ctx->notifyFailed(std::move(Err));
+  if (Ctx->shouldAddDefaultTargetPasses(TT))
+    Config.PostPrunePasses.push_back(orderGPRegion);
+  ELFJITLinker_mips::link(std::move(Ctx), std::move(G), std::move(Config));
+}
+
+} // namespace jitlink
+} // namespace llvm

diff  --git a/llvm/lib/ExecutionEngine/JITLink/JITLink.cpp b/llvm/lib/ExecutionEngine/JITLink/JITLink.cpp
index 329414a5e1275..9176417ea92f4 100644
--- a/llvm/lib/ExecutionEngine/JITLink/JITLink.cpp
+++ b/llvm/lib/ExecutionEngine/JITLink/JITLink.cpp
@@ -16,6 +16,7 @@
 #include "llvm/ExecutionEngine/JITLink/XCOFF.h"
 #include "llvm/ExecutionEngine/JITLink/aarch64.h"
 #include "llvm/ExecutionEngine/JITLink/loongarch.h"
+#include "llvm/ExecutionEngine/JITLink/mips.h"
 #include "llvm/ExecutionEngine/JITLink/ppc64.h"
 #include "llvm/ExecutionEngine/JITLink/systemz.h"
 #include "llvm/ExecutionEngine/JITLink/x86.h"
@@ -481,6 +482,11 @@ AnonymousPointerCreator getAnonymousPointerCreator(const Triple &TT) {
   case Triple::loongarch32:
   case Triple::loongarch64:
     return loongarch::createAnonymousPointer;
+  case Triple::mips:
+  case Triple::mipsel:
+  case Triple::mips64:
+  case Triple::mips64el:
+    return mips::createAnonymousPointer;
   case Triple::systemz:
     return systemz::createAnonymousPointer;
   case Triple::ppc64:
@@ -502,6 +508,11 @@ PointerJumpStubCreator getPointerJumpStubCreator(const Triple &TT) {
   case Triple::loongarch32:
   case Triple::loongarch64:
     return loongarch::createAnonymousPointerJumpStub;
+  case Triple::mips:
+  case Triple::mipsel:
+  case Triple::mips64:
+  case Triple::mips64el:
+    return mips::createAnonymousPointerJumpStub;
   case Triple::systemz:
     return systemz::createAnonymousPointerJumpStub;
   case Triple::ppc64:
@@ -537,9 +548,10 @@ absoluteSymbolsLinkGraph(Triple TT, std::shared_ptr<orc::SymbolStringPool> SSP,
                          orc::SymbolMap Symbols) {
   static std::atomic<uint64_t> Counter = {0};
   auto Index = Counter.fetch_add(1, std::memory_order_relaxed);
+  unsigned PointerSize = TT.getArchPointerBitWidth() / 8;
   auto G = std::make_unique<LinkGraph>(
       "<Absolute Symbols " + std::to_string(Index) + ">", std::move(SSP),
-      std::move(TT), SubtargetFeatures(), getGenericEdgeKindName);
+      std::move(TT), PointerSize, SubtargetFeatures(), getGenericEdgeKindName);
   for (auto &[Name, Def] : Symbols) {
     auto &Sym =
         G->addAbsoluteSymbol(*Name, Def.getAddress(), /*Size=*/0,

diff  --git a/llvm/lib/ExecutionEngine/JITLink/JITLinkMemoryManager.cpp b/llvm/lib/ExecutionEngine/JITLink/JITLinkMemoryManager.cpp
index fa04976f06b5a..aabe0ce0953a6 100644
--- a/llvm/lib/ExecutionEngine/JITLink/JITLinkMemoryManager.cpp
+++ b/llvm/lib/ExecutionEngine/JITLink/JITLinkMemoryManager.cpp
@@ -157,9 +157,10 @@ void SimpleSegmentAlloc::Create(JITLinkMemoryManager &MemMgr,
       "__---.finalize", "__R--.finalize", "__-W-.finalize", "__RW-.finalize",
       "__--X.finalize", "__R-X.finalize", "__-WX.finalize", "__RWX.finalize"};
 
-  auto G =
-      std::make_unique<LinkGraph>("", std::move(SSP), std::move(TT),
-                                  SubtargetFeatures(), getGenericEdgeKindName);
+  unsigned PointerSize = TT.getArchPointerBitWidth() / 8;
+  auto G = std::make_unique<LinkGraph>("", std::move(SSP), std::move(TT),
+                                       PointerSize, SubtargetFeatures(),
+                                       getGenericEdgeKindName);
   orc::AllocGroupSmallMap<Block *> ContentBlocks;
 
   orc::ExecutorAddr NextAddr(0x100000);

diff  --git a/llvm/lib/ExecutionEngine/JITLink/MachOLinkGraphBuilder.cpp b/llvm/lib/ExecutionEngine/JITLink/MachOLinkGraphBuilder.cpp
index 4212efd256cbe..dfcb85a90955f 100644
--- a/llvm/lib/ExecutionEngine/JITLink/MachOLinkGraphBuilder.cpp
+++ b/llvm/lib/ExecutionEngine/JITLink/MachOLinkGraphBuilder.cpp
@@ -52,10 +52,10 @@ MachOLinkGraphBuilder::MachOLinkGraphBuilder(
     std::shared_ptr<orc::SymbolStringPool> SSP, Triple TT,
     SubtargetFeatures Features,
     LinkGraph::GetEdgeKindNameFunction GetEdgeKindName)
-    : Obj(Obj),
-      G(std::make_unique<LinkGraph>(
-          std::string(Obj.getFileName()), std::move(SSP), std::move(TT),
-          std::move(Features), std::move(GetEdgeKindName))) {
+    : Obj(Obj), G(std::make_unique<LinkGraph>(
+                    std::string(Obj.getFileName()), std::move(SSP),
+                    std::move(TT), Obj.getBytesInAddress(), std::move(Features),
+                    std::move(GetEdgeKindName))) {
   auto &MachHeader = Obj.getHeader64();
   SubsectionsViaSymbols = MachHeader.flags & MachO::MH_SUBSECTIONS_VIA_SYMBOLS;
 }

diff  --git a/llvm/lib/ExecutionEngine/JITLink/XCOFFLinkGraphBuilder.cpp b/llvm/lib/ExecutionEngine/JITLink/XCOFFLinkGraphBuilder.cpp
index f0a14c6b1c24c..4cf63d709e2e8 100644
--- a/llvm/lib/ExecutionEngine/JITLink/XCOFFLinkGraphBuilder.cpp
+++ b/llvm/lib/ExecutionEngine/JITLink/XCOFFLinkGraphBuilder.cpp
@@ -35,10 +35,10 @@ XCOFFLinkGraphBuilder::XCOFFLinkGraphBuilder(
     std::shared_ptr<orc::SymbolStringPool> SSP, Triple TT,
     SubtargetFeatures Features,
     LinkGraph::GetEdgeKindNameFunction GetEdgeKindName)
-    : Obj(Obj),
-      G(std::make_unique<LinkGraph>(
-          std::string(Obj.getFileName()), std::move(SSP), std::move(TT),
-          std::move(Features), std::move(GetEdgeKindName))) {}
+    : Obj(Obj), G(std::make_unique<LinkGraph>(
+                    std::string(Obj.getFileName()), std::move(SSP),
+                    std::move(TT), Obj.getBytesInAddress(), std::move(Features),
+                    std::move(GetEdgeKindName))) {}
 
 #ifndef NDEBUG
 static llvm::StringRef getStorageClassString(XCOFF::StorageClass SC) {

diff  --git a/llvm/lib/ExecutionEngine/JITLink/mips.cpp b/llvm/lib/ExecutionEngine/JITLink/mips.cpp
new file mode 100644
index 0000000000000..6ded7c08a3f49
--- /dev/null
+++ b/llvm/lib/ExecutionEngine/JITLink/mips.cpp
@@ -0,0 +1,226 @@
+//===-- mips.cpp - Generic JITLink MIPS edge kinds and utilities ----------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/ExecutionEngine/JITLink/mips.h"
+
+#include "llvm/ADT/STLExtras.h"
+
+namespace llvm {
+namespace jitlink {
+namespace mips {
+
+namespace {
+
+constexpr unsigned HalfwordBits = 16;
+constexpr unsigned MaxPointerJumpStubInstructions = 9;
+
+enum class Register : uint32_t {
+  Zero = 0,
+  T9 = 25,
+};
+
+enum class Opcode : uint32_t {
+  Addiu = 0x09,
+  Lui = 0x0f,
+  Daddiu = 0x19,
+  Lw = 0x23,
+  Ld = 0x37,
+};
+
+enum class Function : uint32_t {
+  Jr = 0x08,
+  Jalr = 0x09,
+  Dsll = 0x38,
+};
+
+constexpr unsigned OpcodeShift = 26;
+constexpr unsigned RSShift = 21;
+constexpr unsigned RTShift = 16;
+constexpr unsigned RDShift = 11;
+constexpr unsigned ShiftAmountShift = 6;
+
+constexpr uint32_t encodeIType(Opcode Op, Register RS, Register RT) {
+  return (static_cast<uint32_t>(Op) << OpcodeShift) |
+         (static_cast<uint32_t>(RS) << RSShift) |
+         (static_cast<uint32_t>(RT) << RTShift);
+}
+
+constexpr uint32_t encodeRType(Function Fn, Register RS, Register RT,
+                               Register RD, unsigned ShiftAmount = 0) {
+  return (static_cast<uint32_t>(RS) << RSShift) |
+         (static_cast<uint32_t>(RT) << RTShift) |
+         (static_cast<uint32_t>(RD) << RDShift) |
+         (ShiftAmount << ShiftAmountShift) | static_cast<uint32_t>(Fn);
+}
+
+constexpr uint32_t encodeLui(Register RT) {
+  return encodeIType(Opcode::Lui, Register::Zero, RT);
+}
+
+constexpr uint32_t encodeAddiu(Register RT, Register RS) {
+  return encodeIType(Opcode::Addiu, RS, RT);
+}
+
+constexpr uint32_t encodeDaddiu(Register RT, Register RS) {
+  return encodeIType(Opcode::Daddiu, RS, RT);
+}
+
+constexpr uint32_t encodeLoadPointer32(Register RT, Register Base) {
+  return encodeIType(Opcode::Lw, Base, RT);
+}
+
+constexpr uint32_t encodeLoadPointer64(Register RT, Register Base) {
+  return encodeIType(Opcode::Ld, Base, RT);
+}
+
+constexpr uint32_t encodeDsll(Register RD, Register RT, unsigned ShiftAmount) {
+  return encodeRType(Function::Dsll, Register::Zero, RT, RD, ShiftAmount);
+}
+
+constexpr uint32_t encodeIndirectJump(Register Target, bool R6) {
+  // JALR with $zero is the release-6 no-link compact jump.
+  return encodeRType(R6 ? Function::Jalr : Function::Jr, Target, Register::Zero,
+                     Register::Zero);
+}
+
+constexpr uint32_t encodeNop() { return 0; }
+
+struct StubFixup {
+  Edge::Kind Kind;
+  unsigned InstructionIndex;
+};
+
+constexpr StubFixup Pointer32StubFixups[] = {{Hi16, 0}, {Lo16, 1}};
+constexpr StubFixup Pointer64StubFixups[] = {
+    {Highest16, 0}, {Higher16, 1}, {Hi16, 3}, {Lo16, 5}};
+
+} // namespace
+
+const char *getEdgeKindName(Edge::Kind K) {
+  switch (K) {
+#define KIND_NAME(K)                                                           \
+  case K:                                                                      \
+    return #K
+    KIND_NAME(Pointer32);
+    KIND_NAME(Pointer64);
+    KIND_NAME(PagePointer32);
+    KIND_NAME(PagePointer64);
+    KIND_NAME(Delta32);
+    KIND_NAME(Delta64);
+    KIND_NAME(NegDelta32);
+    KIND_NAME(Abs16);
+    KIND_NAME(Hi16);
+    KIND_NAME(Lo16);
+    KIND_NAME(Higher16);
+    KIND_NAME(Highest16);
+    KIND_NAME(Jump26);
+    KIND_NAME(PC16);
+    KIND_NAME(PC32);
+    KIND_NAME(PC18S3);
+    KIND_NAME(PC19S2);
+    KIND_NAME(PC21S2);
+    KIND_NAME(PC26S2);
+    KIND_NAME(PCHi16);
+    KIND_NAME(PCLo16);
+    KIND_NAME(GPDispHi16);
+    KIND_NAME(GPDispLo16);
+    KIND_NAME(GPRel16);
+    KIND_NAME(GPRel32);
+    KIND_NAME(GPRel64);
+    KIND_NAME(GOTOffset16);
+    KIND_NAME(GOTOffsetHi16);
+    KIND_NAME(GOTOffsetLo16);
+    KIND_NAME(GOTPageOffset16);
+    KIND_NAME(DTPRelHi16);
+    KIND_NAME(DTPRelLo16);
+    KIND_NAME(DTPRel32);
+    KIND_NAME(DTPRel64);
+    KIND_NAME(NegGPRelHi16);
+    KIND_NAME(NegGPRelLo16);
+    KIND_NAME(RequestGOTAndTransformToOffset16);
+    KIND_NAME(RequestGOTPageAndTransformToOffset16);
+    KIND_NAME(RequestGOTAndTransformToOffsetHi16);
+    KIND_NAME(RequestGOTAndTransformToOffsetLo16);
+    KIND_NAME(RequestTLSGDAndTransformToOffset16);
+    KIND_NAME(RequestTLSLDMAndTransformToOffset16);
+#undef KIND_NAME
+  default:
+    return getGenericEdgeKindName(K);
+  }
+}
+
+static const char NullPointerContent[sizeof(uint64_t)] = {};
+
+bool isR6(const LinkGraph &G) {
+  const auto &Features = G.getFeatures().getFeatures();
+  return llvm::is_contained(Features, "+mips32r6") ||
+         llvm::is_contained(Features, "+mips64r6");
+}
+
+Edge::Kind getPointerEdgeKind(const LinkGraph &G) {
+  return G.getPointerSize() == 8 ? Pointer64 : Pointer32;
+}
+
+ArrayRef<char> getPointerBlockContent(const LinkGraph &G) {
+  return {NullPointerContent, G.getPointerSize()};
+}
+
+Symbol &createAnonymousPointer(LinkGraph &G, Section &PointerSection,
+                               Symbol *InitialTarget,
+                               Edge::AddendT InitialAddend) {
+  auto &B = G.createContentBlock(PointerSection, getPointerBlockContent(G),
+                                 orc::ExecutorAddr(), G.getPointerSize(), 0);
+  if (InitialTarget)
+    B.addEdge(getPointerEdgeKind(G), 0, *InitialTarget, InitialAddend);
+  return G.addAnonymousSymbol(B, 0, G.getPointerSize(), false, false);
+}
+
+Symbol &createAnonymousPointerJumpStub(LinkGraph &G, Section &StubSection,
+                                       Symbol &PointerSymbol) {
+  // Non-PIC callers do not enter with this graph's $gp.
+  unsigned PointerSize = G.getPointerSize();
+
+  SmallVector<uint32_t, MaxPointerJumpStubInstructions> Instructions;
+  ArrayRef<StubFixup> Fixups;
+  if (PointerSize == 8) {
+    Instructions = {
+        encodeLui(Register::T9),
+        encodeDaddiu(Register::T9, Register::T9),
+        encodeDsll(Register::T9, Register::T9, HalfwordBits),
+        encodeDaddiu(Register::T9, Register::T9),
+        encodeDsll(Register::T9, Register::T9, HalfwordBits),
+        encodeDaddiu(Register::T9, Register::T9),
+        encodeLoadPointer64(Register::T9, Register::T9),
+    };
+    Fixups = Pointer64StubFixups;
+  } else {
+    Instructions = {
+        encodeLui(Register::T9),
+        encodeAddiu(Register::T9, Register::T9),
+        encodeLoadPointer32(Register::T9, Register::T9),
+    };
+    Fixups = Pointer32StubFixups;
+  }
+  Instructions.push_back(encodeIndirectJump(Register::T9, isR6(G)));
+  Instructions.push_back(encodeNop());
+
+  auto Content = G.allocateBuffer(Instructions.size() * InstructionSize);
+  for (auto [Index, Instruction] : llvm::enumerate(Instructions))
+    support::endian::write32(Content.data() + Index * InstructionSize,
+                             Instruction, G.getEndianness());
+
+  auto &B = G.createContentBlock(StubSection, Content, orc::ExecutorAddr(),
+                                 alignof(uint32_t), 0);
+  for (const StubFixup &F : Fixups)
+    B.addEdge(F.Kind, F.InstructionIndex * InstructionSize, PointerSymbol, 0);
+  return G.addAnonymousSymbol(B, 0, Content.size(), true, false);
+}
+
+} // namespace mips
+} // namespace jitlink
+} // namespace llvm

diff  --git a/llvm/lib/ExecutionEngine/Orc/COFFAutoImportGenerator.cpp b/llvm/lib/ExecutionEngine/Orc/COFFAutoImportGenerator.cpp
index 9474945f50b77..90cd4d9593730 100644
--- a/llvm/lib/ExecutionEngine/Orc/COFFAutoImportGenerator.cpp
+++ b/llvm/lib/ExecutionEngine/Orc/COFFAutoImportGenerator.cpp
@@ -99,7 +99,8 @@ COFFAutoImportGenerator::createStubsGraph(const SymbolMap &Resolved) {
   Triple TT = ES.getTargetTriple();
 
   auto G = std::make_unique<jitlink::LinkGraph>(
-      "<AUTOIMPORT_STUBS>", ES.getSymbolStringPool(), TT, SubtargetFeatures(),
+      "<AUTOIMPORT_STUBS>", ES.getSymbolStringPool(), TT,
+      TT.getArchPointerBitWidth() / 8, SubtargetFeatures(),
       jitlink::getGenericEdgeKindName);
   jitlink::Section &Sec =
       G->createSection(getSectionName(), MemProt::Read | MemProt::Exec);

diff  --git a/llvm/lib/ExecutionEngine/Orc/COFFPlatform.cpp b/llvm/lib/ExecutionEngine/Orc/COFFPlatform.cpp
index b88f82f0599f9..4f777e95224d4 100644
--- a/llvm/lib/ExecutionEngine/Orc/COFFPlatform.cpp
+++ b/llvm/lib/ExecutionEngine/Orc/COFFPlatform.cpp
@@ -81,8 +81,9 @@ class COFFHeaderMaterializationUnit : public MaterializationUnit {
   void materialize(std::unique_ptr<MaterializationResponsibility> R) override {
     auto G = std::make_unique<jitlink::LinkGraph>(
         "<COFFHeaderMU>", CP.getExecutionSession().getSymbolStringPool(),
-        CP.getExecutionSession().getTargetTriple(), SubtargetFeatures(),
-        jitlink::getGenericEdgeKindName);
+        CP.getExecutionSession().getTargetTriple(),
+        CP.getExecutionSession().getTargetTriple().getArchPointerBitWidth() / 8,
+        SubtargetFeatures(), jitlink::getGenericEdgeKindName);
     auto &HeaderSection = G->createSection("__header", MemProt::Read);
     auto &HeaderBlock = createHeaderBlock(*G, HeaderSection);
 

diff  --git a/llvm/lib/ExecutionEngine/Orc/ELFNixPlatform.cpp b/llvm/lib/ExecutionEngine/Orc/ELFNixPlatform.cpp
index 5a8e37a5898ba..af80b2de80eec 100644
--- a/llvm/lib/ExecutionEngine/Orc/ELFNixPlatform.cpp
+++ b/llvm/lib/ExecutionEngine/Orc/ELFNixPlatform.cpp
@@ -11,6 +11,7 @@
 
 #include "llvm/ExecutionEngine/JITLink/aarch64.h"
 #include "llvm/ExecutionEngine/JITLink/loongarch.h"
+#include "llvm/ExecutionEngine/JITLink/mips.h"
 #include "llvm/ExecutionEngine/JITLink/ppc64.h"
 #include "llvm/ExecutionEngine/JITLink/systemz.h"
 #include "llvm/ExecutionEngine/JITLink/x86_64.h"
@@ -19,6 +20,7 @@
 #include "llvm/ExecutionEngine/Orc/Shared/ObjectFormats.h"
 #include "llvm/ExecutionEngine/Orc/Shared/OrcRTBridge.h"
 #include "llvm/Support/Debug.h"
+#include "llvm/Support/Endian.h"
 #include <optional>
 
 #define DEBUG_TYPE "orc"
@@ -56,7 +58,8 @@ std::unique_ptr<jitlink::LinkGraph> createPlatformGraph(ELFNixPlatform &MOP,
   auto &ES = MOP.getExecutionSession();
   return std::make_unique<jitlink::LinkGraph>(
       std::move(Name), ES.getSymbolStringPool(), ES.getTargetTriple(),
-      SubtargetFeatures(), jitlink::getGenericEdgeKindName);
+      ES.getTargetTriple().getArchPointerBitWidth() / 8, SubtargetFeatures(),
+      jitlink::getGenericEdgeKindName);
 }
 
 // Creates a Bootstrap-Complete LinkGraph to run deferred actions.
@@ -149,6 +152,7 @@ class DSOHandleMaterializationUnit : public MaterializationUnit {
     auto &ES = ENP.getExecutionSession();
 
     jitlink::Edge::Kind EdgeKind;
+    unsigned PointerSize = ES.getTargetTriple().getArchPointerBitWidth() / 8;
 
     switch (ES.getTargetTriple().getArch()) {
     case Triple::x86_64:
@@ -166,6 +170,18 @@ class DSOHandleMaterializationUnit : public MaterializationUnit {
     case Triple::loongarch64:
       EdgeKind = jitlink::loongarch::Pointer64;
       break;
+    case Triple::mips:
+    case Triple::mipsel:
+      EdgeKind = jitlink::mips::Pointer32;
+      break;
+    case Triple::mips64:
+    case Triple::mips64el:
+      if (ES.getTargetTriple().isABIN32()) {
+        EdgeKind = jitlink::mips::Pointer32;
+        PointerSize = 4;
+      } else
+        EdgeKind = jitlink::mips::Pointer64;
+      break;
     case Triple::systemz:
       EdgeKind = jitlink::systemz::Pointer64;
       break;
@@ -176,7 +192,7 @@ class DSOHandleMaterializationUnit : public MaterializationUnit {
     // void *__dso_handle = &__dso_handle;
     auto G = std::make_unique<jitlink::LinkGraph>(
         "<DSOHandleMU>", ES.getSymbolStringPool(), ES.getTargetTriple(),
-        SubtargetFeatures(), jitlink::getGenericEdgeKindName);
+        PointerSize, SubtargetFeatures(), jitlink::getGenericEdgeKindName);
     auto &DSOHandleSection =
         G->createSection(".data.__dso_handle", MemProt::Read);
     auto &DSOHandleBlock = G->createContentBlock(
@@ -385,6 +401,10 @@ bool ELFNixPlatform::supportedTarget(const Triple &TT) {
   case Triple::ppc64le:
   case Triple::loongarch64:
   case Triple::systemz:
+  case Triple::mips:
+  case Triple::mipsel:
+  case Triple::mips64:
+  case Triple::mips64el:
     return true;
   default:
     return false;
@@ -1219,16 +1239,18 @@ Error ELFNixPlatform::ELFNixPlatformPlugin::fixTLVSectionsAndEdges(
         return KeyOrErr.takeError();
     }
 
-    uint64_t PlatformKeyBits =
-        support::endian::byte_swap(*Key, G.getEndianness());
-
     for (auto *B : TLSInfoEntrySection->blocks()) {
       // FIXME: The TLS descriptor byte length may 
diff erent with 
diff erent
       // ISA
       assert(B->getSize() == (G.getPointerSize() * 2) &&
              "TLS descriptor must be 2 words length");
       auto TLSInfoEntryContent = B->getMutableContent(G);
-      memcpy(TLSInfoEntryContent.data(), &PlatformKeyBits, G.getPointerSize());
+      if (G.getPointerSize() == 4)
+        support::endian::write<uint32_t>(TLSInfoEntryContent.data(), *Key,
+                                         G.getEndianness());
+      else
+        support::endian::write<uint64_t>(TLSInfoEntryContent.data(), *Key,
+                                         G.getEndianness());
     }
   }
 

diff  --git a/llvm/lib/ExecutionEngine/Orc/ExecutionUtils.cpp b/llvm/lib/ExecutionEngine/Orc/ExecutionUtils.cpp
index 2af8463840534..f0f584c553c69 100644
--- a/llvm/lib/ExecutionEngine/Orc/ExecutionUtils.cpp
+++ b/llvm/lib/ExecutionEngine/Orc/ExecutionUtils.cpp
@@ -566,7 +566,8 @@ DLLImportDefinitionGenerator::createStubsGraph(const SymbolMap &Resolved) {
         inconvertibleErrorCode());
 
   auto G = std::make_unique<jitlink::LinkGraph>(
-      "<DLLIMPORT_STUBS>", ES.getSymbolStringPool(), TT, SubtargetFeatures(),
+      "<DLLIMPORT_STUBS>", ES.getSymbolStringPool(), TT,
+      TT.getArchPointerBitWidth() / 8, SubtargetFeatures(),
       jitlink::getGenericEdgeKindName);
   jitlink::Section &Sec =
       G->createSection(getSectionName(), MemProt::Read | MemProt::Exec);

diff  --git a/llvm/lib/ExecutionEngine/Orc/JITLinkRedirectableSymbolManager.cpp b/llvm/lib/ExecutionEngine/Orc/JITLinkRedirectableSymbolManager.cpp
index 0a25bb0622933..2c2d14cf278ec 100644
--- a/llvm/lib/ExecutionEngine/Orc/JITLinkRedirectableSymbolManager.cpp
+++ b/llvm/lib/ExecutionEngine/Orc/JITLinkRedirectableSymbolManager.cpp
@@ -26,7 +26,8 @@ void JITLinkRedirectableSymbolManager::emitRedirectableSymbols(
   auto &ES = ObjLinkingLayer.getExecutionSession();
   auto G = std::make_unique<jitlink::LinkGraph>(
       ("<indirect stubs graph #" + Twine(++StubGraphIdx) + ">").str(),
-      ES.getSymbolStringPool(), ES.getTargetTriple(), SubtargetFeatures(),
+      ES.getSymbolStringPool(), ES.getTargetTriple(),
+      ES.getTargetTriple().getArchPointerBitWidth() / 8, SubtargetFeatures(),
       jitlink::getGenericEdgeKindName);
   auto &PointerSection =
       G->createSection(StubPtrSectionName, MemProt::Write | MemProt::Read);

diff  --git a/llvm/lib/ExecutionEngine/Orc/JITLinkReentryTrampolines.cpp b/llvm/lib/ExecutionEngine/Orc/JITLinkReentryTrampolines.cpp
index d305342e6fed8..d56db2d453544 100644
--- a/llvm/lib/ExecutionEngine/Orc/JITLinkReentryTrampolines.cpp
+++ b/llvm/lib/ExecutionEngine/Orc/JITLinkReentryTrampolines.cpp
@@ -129,7 +129,8 @@ void JITLinkReentryTrampolines::emit(ResourceTrackerSP RT,
 
   auto G = std::make_unique<jitlink::LinkGraph>(
       (*ReentryGraphSym).str(), ES.getSymbolStringPool(), ES.getTargetTriple(),
-      SubtargetFeatures(), jitlink::getGenericEdgeKindName);
+      ES.getTargetTriple().getArchPointerBitWidth() / 8, SubtargetFeatures(),
+      jitlink::getGenericEdgeKindName);
 
   auto &ReentryFnSym = G->addExternalSymbol(ReentryFnName, 0, false);
 

diff  --git a/llvm/lib/ExecutionEngine/Orc/MachOPlatform.cpp b/llvm/lib/ExecutionEngine/Orc/MachOPlatform.cpp
index fc4f2c86361f9..4f980eb4e5468 100644
--- a/llvm/lib/ExecutionEngine/Orc/MachOPlatform.cpp
+++ b/llvm/lib/ExecutionEngine/Orc/MachOPlatform.cpp
@@ -110,7 +110,8 @@ std::unique_ptr<jitlink::LinkGraph> createPlatformGraph(MachOPlatform &MOP,
   auto &ES = MOP.getExecutionSession();
   return std::make_unique<jitlink::LinkGraph>(
       std::move(Name), ES.getSymbolStringPool(), ES.getTargetTriple(),
-      SubtargetFeatures(), jitlink::getGenericEdgeKindName);
+      ES.getTargetTriple().getArchPointerBitWidth() / 8, SubtargetFeatures(),
+      jitlink::getGenericEdgeKindName);
 }
 
 // Creates a Bootstrap-Complete LinkGraph to run deferred actions.

diff  --git a/llvm/lib/ExecutionEngine/Orc/SectCreate.cpp b/llvm/lib/ExecutionEngine/Orc/SectCreate.cpp
index 1e889e141ef96..56a53e5afd9c8 100644
--- a/llvm/lib/ExecutionEngine/Orc/SectCreate.cpp
+++ b/llvm/lib/ExecutionEngine/Orc/SectCreate.cpp
@@ -16,10 +16,10 @@ namespace llvm::orc {
 
 void SectCreateMaterializationUnit::materialize(
     std::unique_ptr<MaterializationResponsibility> R) {
+  auto &ES = ObjLinkingLayer.getExecutionSession();
   auto G = std::make_unique<LinkGraph>(
-      "orc_sectcreate_" + SectName,
-      ObjLinkingLayer.getExecutionSession().getSymbolStringPool(),
-      ObjLinkingLayer.getExecutionSession().getTargetTriple(),
+      "orc_sectcreate_" + SectName, ES.getSymbolStringPool(),
+      ES.getTargetTriple(), ES.getTargetTriple().getArchPointerBitWidth() / 8,
       SubtargetFeatures(), getGenericEdgeKindName);
 
   auto &Sect = G->createSection(SectName, MP);

diff  --git a/llvm/lib/Target/Mips/MipsTargetMachine.cpp b/llvm/lib/Target/Mips/MipsTargetMachine.cpp
index 041a7be78d4ad..25d7c22454ecf 100644
--- a/llvm/lib/Target/Mips/MipsTargetMachine.cpp
+++ b/llvm/lib/Target/Mips/MipsTargetMachine.cpp
@@ -84,11 +84,8 @@ createTLOF(const Triple &TT, bool UseSmallSection) {
   return std::make_unique<MipsTargetObjectFile>(UseSmallSection);
 }
 
-static Reloc::Model getEffectiveRelocModel(bool JIT,
-                                           std::optional<Reloc::Model> RM) {
-  if (!RM || JIT)
-    return Reloc::Static;
-  return *RM;
+static Reloc::Model getEffectiveRelocModel(std::optional<Reloc::Model> RM) {
+  return RM.value_or(Reloc::Static);
 }
 
 // On function prologue, the stack is created by decrementing
@@ -101,10 +98,10 @@ MipsTargetMachine::MipsTargetMachine(const Target &T, const Triple &TT,
                                      const TargetOptions &Options,
                                      std::optional<Reloc::Model> RM,
                                      std::optional<CodeModel::Model> CM,
-                                     CodeGenOptLevel OL, bool JIT,
+                                     CodeGenOptLevel OL, bool /*JIT*/,
                                      bool isLittle)
     : CodeGenTargetMachineImpl(T, TT, CPU, FS, Options,
-                               getEffectiveRelocModel(JIT, RM),
+                               getEffectiveRelocModel(RM),
                                getEffectiveCodeModel(CM, CodeModel::Small), OL),
       isLittle(isLittle),
       DefaultSubtarget(TT, CPU, FS, Options.MCOptions.getABIName(), isLittle,

diff  --git a/llvm/test/ExecutionEngine/JITLink/Mips/ELF_abs16_data.s b/llvm/test/ExecutionEngine/JITLink/Mips/ELF_abs16_data.s
new file mode 100644
index 0000000000000..647cd1d9c0d57
--- /dev/null
+++ b/llvm/test/ExecutionEngine/JITLink/Mips/ELF_abs16_data.s
@@ -0,0 +1,27 @@
+# RUN: rm -rf %t && mkdir -p %t
+# RUN: llvm-mc -triple=mipsel-unknown-linux-gnu -mcpu=mips1 -filetype=obj %s -o %t/o32el.o
+# RUN: llvm-mc -triple=mips-unknown-linux-gnu -mcpu=mips1 -filetype=obj %s -o %t/o32be.o
+# RUN: llvm-mc -triple=mips64el-unknown-linux-gnuabi64 -mcpu=mips64 -filetype=obj %s -o %t/n64el.o
+# RUN: llvm-mc -triple=mips64-unknown-linux-gnuabi64 -mcpu=mips64 -filetype=obj %s -o %t/n64be.o
+# RUN: llvm-jitlink -noexec --abs=small_abs=0x1234 -check=%s %t/o32el.o
+# RUN: llvm-jitlink -noexec --abs=small_abs=0x1234 -check=%s %t/o32be.o
+# RUN: llvm-jitlink -noexec --abs=small_abs=0x1234 -check=%s %t/n64el.o
+# RUN: llvm-jitlink -noexec --abs=small_abs=0x1234 -check=%s %t/n64be.o
+
+        .set noreorder
+        .text
+        .globl main
+        .type main, at function
+main:
+        jr $ra
+        nop
+        .size main, .-main
+
+        .data
+        .globl half_pointer
+half_pointer:
+        .2byte small_abs
+        .2byte 0xbeef
+
+# jitlink-check: *{2}half_pointer = 0x1234
+# jitlink-check: *{2}(half_pointer + 2) = 0xbeef

diff  --git a/llvm/test/ExecutionEngine/JITLink/Mips/ELF_ehframe.s b/llvm/test/ExecutionEngine/JITLink/Mips/ELF_ehframe.s
new file mode 100644
index 0000000000000..3673c528f8046
--- /dev/null
+++ b/llvm/test/ExecutionEngine/JITLink/Mips/ELF_ehframe.s
@@ -0,0 +1,55 @@
+# REQUIRES: asserts
+# RUN: rm -rf %t && mkdir -p %t
+# RUN: llvm-mc -triple=mipsel-unknown-linux-gnu -mcpu=mips32r2 -filetype=obj %s -o %t/o32el.o
+# RUN: llvm-mc -triple=mips-unknown-linux-gnu -mcpu=mips32r2 -filetype=obj %s -o %t/o32be.o
+# RUN: llvm-mc -triple=mips64el-unknown-linux-gnuabi64 -mcpu=mips64r2 -filetype=obj %s -o %t/n64el.o
+# RUN: llvm-mc -triple=mips64-unknown-linux-gnuabi64 -mcpu=mips64r2 -filetype=obj %s -o %t/n64be.o
+# RUN: llvm-jitlink -num-threads=0 -debug-only=jitlink -noexec -phony-externals \
+# RUN:   -slab-address=0x10000000 -slab-allocate=128Kb -slab-page-size=4096 \
+# RUN:   %t/o32el.o 2>&1 | FileCheck %s
+# RUN: llvm-jitlink -num-threads=0 -debug-only=jitlink -noexec -phony-externals \
+# RUN:   -slab-address=0x10000000 -slab-allocate=128Kb -slab-page-size=4096 \
+# RUN:   %t/o32be.o 2>&1 | FileCheck %s
+# RUN: llvm-jitlink -num-threads=0 -debug-only=jitlink -noexec -phony-externals \
+# RUN:   -slab-address=0x10000000 -slab-allocate=128Kb -slab-page-size=4096 \
+# RUN:   %t/n64el.o 2>&1 | FileCheck %s
+# RUN: llvm-jitlink -num-threads=0 -debug-only=jitlink -noexec -phony-externals \
+# RUN:   -slab-address=0x10000000 -slab-allocate=128Kb -slab-page-size=4096 \
+# RUN:   %t/n64be.o 2>&1 | FileCheck %s
+
+# CHECK: DWARFRecordSectionSplitter: Processing .eh_frame...
+# CHECK: Processing CFI record at
+# CHECK: Processing CFI record at
+# CHECK: Processing CFI record at
+# CHECK: EHFrameEdgeFixer: Processing .eh_frame in "{{.*}}"...
+# CHECK: Record is CIE
+# CHECK: Record is FDE
+# CHECK: Adding edge at {{.*}} to CIE at: {{.*}}
+# CHECK: Existing edge at {{.*}} to PC begin at {{.*}}
+# CHECK: Adding keep-alive edge from target at {{.*}} to FDE at {{.*}}
+# CHECK: Record is FDE
+# CHECK: Adding edge at {{.*}} to CIE at: {{.*}}
+# CHECK: Existing edge at {{.*}} to PC begin at {{.*}}
+# CHECK: Adding keep-alive edge from target at {{.*}} to FDE at {{.*}}
+
+        .set noreorder
+        .text
+        .globl main
+        .type main, at function
+main:
+        .cfi_startproc
+        nop
+        jr $ra
+        nop
+        .cfi_endproc
+        .size main, .-main
+
+        .globl dup
+        .type dup, at function
+dup:
+        .cfi_startproc
+        nop
+        jr $ra
+        nop
+        .cfi_endproc
+        .size dup, .-dup

diff  --git a/llvm/test/ExecutionEngine/JITLink/Mips/ELF_got_ordering.s b/llvm/test/ExecutionEngine/JITLink/Mips/ELF_got_ordering.s
new file mode 100644
index 0000000000000..debd866510642
--- /dev/null
+++ b/llvm/test/ExecutionEngine/JITLink/Mips/ELF_got_ordering.s
@@ -0,0 +1,55 @@
+# RUN: rm -rf %t && mkdir -p %t
+# RUN: llvm-mc -triple=mipsel-unknown-linux-gnu -mcpu=mips32r2 -filetype=obj %s -o %t/o32el.o
+# RUN: llvm-mc -triple=mips-unknown-linux-gnu -mcpu=mips32r2 -filetype=obj %s -o %t/o32be.o
+# RUN: llvm-mc -triple=mips64el-unknown-linux-gnuabi64 -mcpu=mips64r2 -defsym PTR64=1 -filetype=obj %s -o %t/n64el.o
+# RUN: llvm-mc -triple=mips64-unknown-linux-gnuabi64 -mcpu=mips64r2 -defsym PTR64=1 -filetype=obj %s -o %t/n64be.o
+# RUN: llvm-jitlink -noexec -slab-address=0x10000000 -slab-allocate=128Kb -slab-page-size=4096 -check=%s -check-name=check-o32el --abs=ext0=0x20000000 --abs=ext1=0x20000004 --abs=ext2=0x20000008 --abs=ext3=0x2000000c --abs=ext4=0x20000010 --abs=ext5=0x20000014 --abs=ext6=0x20000018 --abs=ext7=0x2000001c %t/o32el.o
+# RUN: llvm-jitlink -noexec -slab-address=0x10000000 -slab-allocate=128Kb -slab-page-size=4096 -check=%s -check-name=check-o32be --abs=ext0=0x20000000 --abs=ext1=0x20000004 --abs=ext2=0x20000008 --abs=ext3=0x2000000c --abs=ext4=0x20000010 --abs=ext5=0x20000014 --abs=ext6=0x20000018 --abs=ext7=0x2000001c %t/o32be.o
+# RUN: llvm-jitlink -noexec -slab-address=0x10000000 -slab-allocate=128Kb -slab-page-size=4096 -check=%s -check-name=check-n64el --abs=ext0=0x20000000 --abs=ext1=0x20000004 --abs=ext2=0x20000008 --abs=ext3=0x2000000c --abs=ext4=0x20000010 --abs=ext5=0x20000014 --abs=ext6=0x20000018 --abs=ext7=0x2000001c %t/n64el.o
+# RUN: llvm-jitlink -noexec -slab-address=0x10000000 -slab-allocate=128Kb -slab-page-size=4096 -check=%s -check-name=check-n64be --abs=ext0=0x20000000 --abs=ext1=0x20000004 --abs=ext2=0x20000008 --abs=ext3=0x2000000c --abs=ext4=0x20000010 --abs=ext5=0x20000014 --abs=ext6=0x20000018 --abs=ext7=0x2000001c %t/n64be.o
+
+# Regression test for GP-region ordering. More than four pointer-sized entries
+# used to be sorted before the 0x7ff0-byte GOT prefix, placing the first entry
+# below the signed 16-bit range of _gp.
+
+        .set noreorder
+        .text
+        .globl main
+        .type main, at function
+main:
+        jr $ra
+        nop
+
+        .globl load_got
+        .type load_got, at function
+load_got:
+        .ifdef PTR64
+        ld $2, %got(ext0)($gp)
+        ld $3, %got(ext1)($gp)
+        ld $4, %got(ext2)($gp)
+        ld $5, %got(ext3)($gp)
+        ld $6, %got(ext4)($gp)
+        ld $7, %got(ext5)($gp)
+        ld $8, %got(ext6)($gp)
+        ld $9, %got(ext7)($gp)
+        .else
+        lw $2, %got(ext0)($gp)
+        lw $3, %got(ext1)($gp)
+        lw $4, %got(ext2)($gp)
+        lw $5, %got(ext3)($gp)
+        lw $6, %got(ext4)($gp)
+        lw $7, %got(ext5)($gp)
+        lw $8, %got(ext6)($gp)
+        lw $9, %got(ext7)($gp)
+        .endif
+        jr $ra
+        nop
+
+# check-o32el: *{4}(got_addr(o32el.o, ext0)) = 0x20000000
+# check-o32el: *{4}(got_addr(o32el.o, ext7)) = 0x2000001c
+# check-o32be: *{4}(got_addr(o32be.o, ext0)) = 0x20000000
+# check-o32be: *{4}(got_addr(o32be.o, ext7)) = 0x2000001c
+# check-n64el: *{8}(got_addr(n64el.o, ext0)) = 0x20000000
+# check-n64el: *{8}(got_addr(n64el.o, ext7)) = 0x2000001c
+# check-n64be: *{8}(got_addr(n64be.o, ext0)) = 0x20000000
+# check-n64be: *{8}(got_addr(n64be.o, ext7)) = 0x2000001c

diff  --git a/llvm/test/ExecutionEngine/JITLink/Mips/ELF_invalid_abi.yaml b/llvm/test/ExecutionEngine/JITLink/Mips/ELF_invalid_abi.yaml
new file mode 100644
index 0000000000000..d252511e3f91c
--- /dev/null
+++ b/llvm/test/ExecutionEngine/JITLink/Mips/ELF_invalid_abi.yaml
@@ -0,0 +1,25 @@
+# RUN: yaml2obj %s -o %t.o
+# RUN: not llvm-jitlink -noexec %t.o 2>&1 | FileCheck %s
+
+# CHECK: inconsistent MIPS N64 ELF class/ABI flags
+
+--- !ELF
+FileHeader:
+  Class:   ELFCLASS64
+  Data:    ELFDATA2LSB
+  Type:    ET_REL
+  Machine: EM_MIPS
+  Flags:   [ EF_MIPS_ABI2, EF_MIPS_ARCH_64R2 ]
+Sections:
+  - Name:         .text
+    Type:         SHT_PROGBITS
+    Flags:        [ SHF_ALLOC, SHF_EXECINSTR ]
+    AddressAlign: 4
+    Size:         4
+Symbols:
+  - Name:    main
+    Type:    STT_FUNC
+    Binding: STB_GLOBAL
+    Section: .text
+    Size:    4
+...

diff  --git a/llvm/test/ExecutionEngine/JITLink/Mips/ELF_micromips_unsupported.s b/llvm/test/ExecutionEngine/JITLink/Mips/ELF_micromips_unsupported.s
new file mode 100644
index 0000000000000..e0640333b079e
--- /dev/null
+++ b/llvm/test/ExecutionEngine/JITLink/Mips/ELF_micromips_unsupported.s
@@ -0,0 +1,12 @@
+# RUN: llvm-mc -triple=mipsel-unknown-linux-gnu -mcpu=mips32r2 -mattr=+micromips -filetype=obj %s -o %t.o
+# RUN: not llvm-jitlink -noexec %t.o 2>&1 | FileCheck %s
+# RUN: llvm-mc -triple=mipsel-unknown-linux-gnu -mcpu=mips32r2 -mattr=+mips16 -filetype=obj %s -o %t.mips16.o
+# RUN: not llvm-jitlink -noexec %t.mips16.o 2>&1 | FileCheck %s
+
+        .set noreorder
+        .text
+        .globl main
+main:
+        nop
+
+# CHECK: MIPS16 and microMIPS{{.*}}unsupported by JITLink

diff  --git a/llvm/test/ExecutionEngine/JITLink/Mips/ELF_minimal.s b/llvm/test/ExecutionEngine/JITLink/Mips/ELF_minimal.s
new file mode 100644
index 0000000000000..7de91963753a5
--- /dev/null
+++ b/llvm/test/ExecutionEngine/JITLink/Mips/ELF_minimal.s
@@ -0,0 +1,24 @@
+# RUN: rm -rf %t && mkdir -p %t
+# RUN: llvm-mc -triple=mipsel-unknown-linux-gnu -mcpu=mips1 -filetype=obj %s -o %t/mips1el.o
+# RUN: llvm-mc -triple=mips-unknown-linux-gnu -mcpu=mips1 -filetype=obj %s -o %t/mips1be.o
+# RUN: llvm-mc -triple=mips64el-unknown-linux-gnuabi64 -mcpu=mips64 -filetype=obj %s -o %t/mips64el.o
+# RUN: llvm-mc -triple=mips64-unknown-linux-gnuabi64 -mcpu=mips64 -filetype=obj %s -o %t/mips64be.o
+# RUN: llvm-jitlink -noexec -slab-address=0x10000000 -slab-allocate=128Kb -slab-page-size=4096 %t/mips1el.o
+# RUN: llvm-jitlink -noexec -slab-address=0x10000000 -slab-allocate=128Kb -slab-page-size=4096 %t/mips1be.o
+# RUN: llvm-jitlink -noexec -slab-address=0x10000000 -slab-allocate=128Kb -slab-page-size=4096 %t/mips64el.o
+# RUN: llvm-jitlink -noexec -slab-address=0x10000000 -slab-allocate=128Kb -slab-page-size=4096 %t/mips64be.o
+
+        .set noreorder
+        .text
+        .globl main
+        .type main, at function
+main:
+        lui $2, %hi(data)
+        addiu $2, $2, %lo(data)
+        jr $ra
+        nop
+        .size main, .-main
+
+        .data
+data:
+        .word 42

diff  --git a/llvm/test/ExecutionEngine/JITLink/Mips/ELF_n64_compound_relocations.s b/llvm/test/ExecutionEngine/JITLink/Mips/ELF_n64_compound_relocations.s
new file mode 100644
index 0000000000000..fd0dd20288955
--- /dev/null
+++ b/llvm/test/ExecutionEngine/JITLink/Mips/ELF_n64_compound_relocations.s
@@ -0,0 +1,31 @@
+# RUN: rm -rf %t && mkdir -p %t
+# RUN: llvm-mc -triple=mips64el-unknown-linux-gnuabi64 -mcpu=mips64 -filetype=obj %s -o %t/le.o
+# RUN: llvm-mc -triple=mips64-unknown-linux-gnuabi64 -mcpu=mips64 -filetype=obj %s -o %t/be.o
+# RUN: llvm-jitlink -noexec -slab-address=0x10000000 -slab-allocate=128Kb -slab-page-size=4096 -check=%s %t/le.o
+# RUN: llvm-jitlink -noexec -slab-address=0x10000000 -slab-allocate=128Kb -slab-page-size=4096 -check=%s %t/be.o
+
+        .set noreorder
+        .text
+        .globl main
+        .type main, at function
+main:
+        jr $ra
+        nop
+        .size main, .-main
+
+        .data
+        .p2align 3
+        .globl target
+target:
+        .8byte 0
+
+        .globl gp_value
+gp_value:
+        .gpdword target
+
+        .globl delta_value
+delta_value:
+        .8byte target - .
+
+# jitlink-check: *{8}gp_value = target - _gp
+# jitlink-check: *{8}delta_value = target - delta_value

diff  --git a/llvm/test/ExecutionEngine/JITLink/Mips/ELF_pc16_errors.s b/llvm/test/ExecutionEngine/JITLink/Mips/ELF_pc16_errors.s
new file mode 100644
index 0000000000000..954f26faa6bd2
--- /dev/null
+++ b/llvm/test/ExecutionEngine/JITLink/Mips/ELF_pc16_errors.s
@@ -0,0 +1,13 @@
+# RUN: llvm-mc -triple=mipsel-unknown-linux-gnu -mcpu=mips32r2 -filetype=obj %s -o %t.o
+# RUN: not llvm-jitlink -noexec --abs=far_target=0x30000000 -slab-address=0x10000000 -slab-allocate=128Kb -slab-page-size=4096 %t.o 2>&1 | FileCheck %s --check-prefix=RANGE
+# RUN: not llvm-jitlink -noexec --abs=far_target=0x10008002 -slab-address=0x10000000 -slab-allocate=128Kb -slab-page-size=4096 %t.o 2>&1 | FileCheck %s --check-prefix=ALIGN
+
+        .set noreorder
+        .text
+        .globl main
+main:
+        beq $zero, $zero, far_target
+        nop
+
+# RANGE: is out of range of PC16 fixup
+# ALIGN: improper alignment for relocation

diff  --git a/llvm/test/ExecutionEngine/JITLink/Mips/ELF_pc18_aligned_base.s b/llvm/test/ExecutionEngine/JITLink/Mips/ELF_pc18_aligned_base.s
new file mode 100644
index 0000000000000..52e04d784e4d5
--- /dev/null
+++ b/llvm/test/ExecutionEngine/JITLink/Mips/ELF_pc18_aligned_base.s
@@ -0,0 +1,25 @@
+# RUN: rm -rf %t && mkdir -p %t
+# RUN: llvm-mc -triple=mips64el-unknown-linux-gnuabi64 -mcpu=mips64r6 -filetype=obj %s -o %t/le.o
+# RUN: llvm-mc -triple=mips64-unknown-linux-gnuabi64 -mcpu=mips64r6 -filetype=obj %s -o %t/be.o
+# RUN: llvm-jitlink -noexec -slab-address=0x10000000 -slab-allocate=128Kb -slab-page-size=4096 -check=%s %t/le.o
+# RUN: llvm-jitlink -noexec -slab-address=0x10000000 -slab-allocate=128Kb -slab-page-size=4096 -check=%s %t/be.o
+
+        .set noreorder
+        .text
+        .globl main
+        .type main, at function
+main:
+        nop
+        .globl load_pc
+load_pc:
+        ldpc $2, target
+        jrc $ra
+        .size main, .-main
+
+        .section .rodata,"a", at progbits
+        .p2align 3
+target:
+        .8byte 42
+
+# R_MIPS_PC18_S3 uses the containing 8-byte bundle as its PC base.
+# jitlink-check: (*{4}load_pc) & 0x3ffff = ((target - (load_pc & 0xfffffffffffffff8)) >> 3) & 0x3ffff

diff  --git a/llvm/test/ExecutionEngine/JITLink/Mips/ELF_r6_external_branch_stub.s b/llvm/test/ExecutionEngine/JITLink/Mips/ELF_r6_external_branch_stub.s
new file mode 100644
index 0000000000000..e529aa5c37d1d
--- /dev/null
+++ b/llvm/test/ExecutionEngine/JITLink/Mips/ELF_r6_external_branch_stub.s
@@ -0,0 +1,30 @@
+# RUN: rm -rf %t && mkdir -p %t
+# RUN: llvm-mc -triple=mipsel-unknown-linux-gnu -mcpu=mips32r6 -filetype=obj %s -o %t/o32el.o
+# RUN: llvm-mc -triple=mips-unknown-linux-gnu -mcpu=mips32r6 -filetype=obj %s -o %t/o32be.o
+# RUN: llvm-mc -triple=mips64el-unknown-linux-gnuabi64 -mcpu=mips64r6 -filetype=obj %s -o %t/n64el.o
+# RUN: llvm-mc -triple=mips64-unknown-linux-gnuabi64 -mcpu=mips64r6 -filetype=obj %s -o %t/n64be.o
+# RUN: llvm-jitlink -noexec -slab-address=0x10000000 -slab-allocate=128Kb -slab-page-size=4096 -check=%s -check-name=check-o32el --abs=external_func=0x30000000 %t/o32el.o
+# RUN: llvm-jitlink -noexec -slab-address=0x10000000 -slab-allocate=128Kb -slab-page-size=4096 -check=%s -check-name=check-o32be --abs=external_func=0x30000000 %t/o32be.o
+# RUN: llvm-jitlink -noexec -slab-address=0x10000000 -slab-allocate=128Kb -slab-page-size=4096 -check=%s -check-name=check-n64el --abs=external_func=0x30000000 %t/n64el.o
+# RUN: llvm-jitlink -noexec -slab-address=0x10000000 -slab-allocate=128Kb -slab-page-size=4096 -check=%s -check-name=check-n64be --abs=external_func=0x30000000 %t/n64be.o
+
+        .set noreorder
+        .text
+        .globl main
+        .type main, at function
+main:
+        balc external_func
+        jrc $ra
+        .size main, .-main
+
+# R_MIPS_PC26_S2 carries an addend of -4 because its architectural base is
+# the instruction following the branch. An out-of-range absolute call must be
+# redirected to a reachable stub, whose pointer entry contains the callee.
+# check-o32el: decode_operand(main, 0) = stub_addr(o32el.o, external_func) - main
+# check-o32el: *{4}(got_addr(o32el.o, external_func)) = external_func
+# check-o32be: decode_operand(main, 0) = stub_addr(o32be.o, external_func) - main
+# check-o32be: *{4}(got_addr(o32be.o, external_func)) = external_func
+# check-n64el: decode_operand(main, 0) = stub_addr(n64el.o, external_func) - main
+# check-n64el: *{8}(got_addr(n64el.o, external_func)) = external_func
+# check-n64be: decode_operand(main, 0) = stub_addr(n64be.o, external_func) - main
+# check-n64be: *{8}(got_addr(n64be.o, external_func)) = external_func

diff  --git a/llvm/test/ExecutionEngine/JITLink/Mips/ELF_relocations.s b/llvm/test/ExecutionEngine/JITLink/Mips/ELF_relocations.s
new file mode 100644
index 0000000000000..0d0e23eb478f0
--- /dev/null
+++ b/llvm/test/ExecutionEngine/JITLink/Mips/ELF_relocations.s
@@ -0,0 +1,54 @@
+# RUN: rm -rf %t && mkdir -p %t
+# RUN: llvm-mc -triple=mipsel-unknown-linux-gnu -mcpu=mips32r2 -filetype=obj %s -o %t/o32el.o
+# RUN: llvm-mc -triple=mips-unknown-linux-gnu -mcpu=mips32r2 -filetype=obj %s -o %t/o32be.o
+# RUN: llvm-mc -triple=mips64el-unknown-linux-gnuabin32 -mcpu=mips64r2 -filetype=obj %s -o %t/n32el.o
+# RUN: llvm-mc -triple=mips64-unknown-linux-gnuabin32 -mcpu=mips64r2 -filetype=obj %s -o %t/n32be.o
+# RUN: llvm-mc -triple=mips64el-unknown-linux-gnuabi64 -mcpu=mips64r2 -defsym PTR64=1 -filetype=obj %s -o %t/n64el.o
+# RUN: llvm-mc -triple=mips64-unknown-linux-gnuabi64 -mcpu=mips64r2 -defsym PTR64=1 -filetype=obj %s -o %t/n64be.o
+# RUN: llvm-jitlink -noexec -slab-address 0x10000000 -slab-allocate 128Kb -slab-page-size 4096 -check %s -check-name=jitlink-check-32 %t/o32el.o
+# RUN: llvm-jitlink -noexec -slab-address 0x10000000 -slab-allocate 128Kb -slab-page-size 4096 -check %s -check-name=jitlink-check-32 %t/o32be.o
+# RUN: llvm-jitlink -noexec -slab-address 0x10000000 -slab-allocate 128Kb -slab-page-size 4096 -check %s -check-name=jitlink-check-32 %t/n32el.o
+# RUN: llvm-jitlink -noexec -slab-address 0x10000000 -slab-allocate 128Kb -slab-page-size 4096 -check %s -check-name=jitlink-check-32 %t/n32be.o
+# RUN: llvm-jitlink -noexec -slab-address 0x10000000 -slab-allocate 128Kb -slab-page-size 4096 -check %s -check-name=jitlink-check-64 %t/n64el.o
+# RUN: llvm-jitlink -noexec -slab-address 0x10000000 -slab-allocate 128Kb -slab-page-size 4096 -check %s -check-name=jitlink-check-64 %t/n64be.o
+
+        .set noreorder
+        .text
+        .globl main
+        .type main, at function
+main:
+        .cfi_startproc
+        jr $ra
+        nop
+        .cfi_endproc
+        .size main, .-main
+
+# jitlink-check-32: decode_operand(load_address, 1) = (target + 0x8008)[31:16]
+# jitlink-check-32: decode_operand(load_address + 4, 2)[15:0] = (target + 8)[15:0]
+# jitlink-check-64: decode_operand(load_address, 1) = (target + 0x8008)[31:16]
+# jitlink-check-64: decode_operand(load_address + 4, 2)[15:0] = (target + 8)[15:0]
+        .globl load_address
+        .type load_address, at function
+load_address:
+        lui $4, %hi(target + 8)
+        addiu $4, $4, %lo(target + 8)
+        jr $ra
+        nop
+        .size load_address, .-load_address
+
+        .data
+        .p2align 3
+        .globl target
+target:
+        .8byte 0x1122334455667788
+
+        .globl target_pointer
+target_pointer:
+        .ifdef PTR64
+        .8byte target + 4
+        .else
+        .4byte target + 4
+        .endif
+
+# jitlink-check-32: *{4}(target_pointer) = target + 4
+# jitlink-check-64: *{8}(target_pointer) = target + 4

diff  --git a/llvm/test/ExecutionEngine/JITLink/Mips/ELF_unmatched_hi16.s b/llvm/test/ExecutionEngine/JITLink/Mips/ELF_unmatched_hi16.s
new file mode 100644
index 0000000000000..92200c22c8594
--- /dev/null
+++ b/llvm/test/ExecutionEngine/JITLink/Mips/ELF_unmatched_hi16.s
@@ -0,0 +1,15 @@
+# RUN: llvm-mc -triple=mipsel-unknown-linux-gnu -mcpu=mips32r2 -filetype=obj %s -o %t.o
+# RUN: not llvm-jitlink -noexec %t.o 2>&1 | FileCheck %s
+
+        .text
+        .globl main
+main:
+        lui $2, %hi(target)
+        jr $ra
+        nop
+
+        .data
+target:
+        .word 0
+
+# CHECK: unmatched R_MIPS_HI16 relocation

diff  --git a/llvm/test/ExecutionEngine/JITLink/Mips/ELF_unsupported_packed_relocation.yaml b/llvm/test/ExecutionEngine/JITLink/Mips/ELF_unsupported_packed_relocation.yaml
new file mode 100644
index 0000000000000..c747050170b1d
--- /dev/null
+++ b/llvm/test/ExecutionEngine/JITLink/Mips/ELF_unsupported_packed_relocation.yaml
@@ -0,0 +1,35 @@
+# RUN: yaml2obj %s -o %t.o
+# RUN: not llvm-jitlink -noexec %t.o 2>&1 | FileCheck %s
+
+# CHECK: unsupported packed MIPS relocation
+
+--- !ELF
+FileHeader:
+  Class:   ELFCLASS64
+  Data:    ELFDATA2LSB
+  Type:    ET_REL
+  Machine: EM_MIPS
+  Flags:   [ EF_MIPS_ARCH_64R2 ]
+Sections:
+  - Name:         .text
+    Type:         SHT_PROGBITS
+    Flags:        [ SHF_ALLOC, SHF_EXECINSTR ]
+    AddressAlign: 4
+    Size:         4
+  - Name:         .rela.text
+    Type:         SHT_RELA
+    Flags:        [ SHF_INFO_LINK ]
+    Info:         .text
+    AddressAlign: 8
+    Relocations:
+      - Offset: 0
+        Symbol: main
+        Type:   R_MIPS_GPREL16
+        Type2:  R_MIPS_LO16
+Symbols:
+  - Name:    main
+    Type:    STT_FUNC
+    Binding: STB_GLOBAL
+    Section: .text
+    Size:    4
+...

diff  --git a/llvm/test/ExecutionEngine/JITLink/Mips/ELF_unsupported_tls.s b/llvm/test/ExecutionEngine/JITLink/Mips/ELF_unsupported_tls.s
new file mode 100644
index 0000000000000..2ff49a028c4f9
--- /dev/null
+++ b/llvm/test/ExecutionEngine/JITLink/Mips/ELF_unsupported_tls.s
@@ -0,0 +1,15 @@
+# RUN: llvm-mc -triple=mipsel-unknown-linux-gnu -mcpu=mips32r2 -filetype=obj %s -o %t.o
+# RUN: not llvm-jitlink -noexec %t.o 2>&1 | FileCheck %s
+
+        .text
+        .globl main
+main:
+        lw $2, %gottprel(tls_var)($gp)
+        jr $ra
+        nop
+
+        .section .tbss,"awT", at nobits
+tls_var:
+        .space 4
+
+# CHECK: initial/local-exec MIPS TLS relocations are unsupported

diff  --git a/llvm/test/ExecutionEngine/JITLink/Mips/lit.local.cfg b/llvm/test/ExecutionEngine/JITLink/Mips/lit.local.cfg
new file mode 100644
index 0000000000000..b997811996b31
--- /dev/null
+++ b/llvm/test/ExecutionEngine/JITLink/Mips/lit.local.cfg
@@ -0,0 +1,2 @@
+if not "Mips" in config.root.targets:
+    config.unsupported = True

diff  --git a/llvm/unittests/ExecutionEngine/JITLink/AArch32ErrorTests.cpp b/llvm/unittests/ExecutionEngine/JITLink/AArch32ErrorTests.cpp
index 6e9957f53a357..1706e6f3873e9 100644
--- a/llvm/unittests/ExecutionEngine/JITLink/AArch32ErrorTests.cpp
+++ b/llvm/unittests/ExecutionEngine/JITLink/AArch32ErrorTests.cpp
@@ -20,7 +20,7 @@ using namespace llvm::support::endian;
 
 auto G = std::make_unique<LinkGraph>(
     "foo", std::make_shared<orc::SymbolStringPool>(),
-    Triple("armv7-linux-gnueabi"), SubtargetFeatures(),
+    Triple("armv7-linux-gnueabi"), 4, SubtargetFeatures(),
     aarch32::getEdgeKindName);
 auto &Sec =
     G->createSection("__data", orc::MemProt::Read | orc::MemProt::Write);
@@ -49,7 +49,7 @@ class AArch32Errors : public testing::Test {
   void SetUp() override {
     G = std::make_unique<LinkGraph>(
         "foo", std::make_shared<orc::SymbolStringPool>(),
-        Triple("armv7-linux-gnueabi"), SubtargetFeatures(),
+        Triple("armv7-linux-gnueabi"), 4, SubtargetFeatures(),
         aarch32::getEdgeKindName);
     S = &G->createSection("__data", orc::MemProt::Read | orc::MemProt::Write);
   }

diff  --git a/llvm/unittests/ExecutionEngine/JITLink/AArch64Tests.cpp b/llvm/unittests/ExecutionEngine/JITLink/AArch64Tests.cpp
index 34918ead5b49b..eaa7f005b9f97 100644
--- a/llvm/unittests/ExecutionEngine/JITLink/AArch64Tests.cpp
+++ b/llvm/unittests/ExecutionEngine/JITLink/AArch64Tests.cpp
@@ -17,7 +17,7 @@ using namespace llvm::jitlink::aarch64;
 
 TEST(AArch64, EmptyLinkGraph) {
   LinkGraph G("foo", std::make_shared<orc::SymbolStringPool>(),
-              Triple("arm64-apple-darwin"), SubtargetFeatures(),
+              Triple("arm64-apple-darwin"), 8, SubtargetFeatures(),
               getEdgeKindName);
   EXPECT_EQ(G.getName(), "foo");
   EXPECT_EQ(G.getTargetTriple().str(), "arm64-apple-darwin");
@@ -31,7 +31,7 @@ TEST(AArch64, EmptyLinkGraph) {
 
 TEST(AArch64, GOTAndStubs) {
   LinkGraph G("foo", std::make_shared<orc::SymbolStringPool>(),
-              Triple("arm64-apple-darwin"), SubtargetFeatures(),
+              Triple("arm64-apple-darwin"), 8, SubtargetFeatures(),
               getEdgeKindName);
 
   auto &External = G.addExternalSymbol("external", 0, false);

diff  --git a/llvm/unittests/ExecutionEngine/JITLink/CMakeLists.txt b/llvm/unittests/ExecutionEngine/JITLink/CMakeLists.txt
index 04fdf1f4e57c3..d8811fc773394 100644
--- a/llvm/unittests/ExecutionEngine/JITLink/CMakeLists.txt
+++ b/llvm/unittests/ExecutionEngine/JITLink/CMakeLists.txt
@@ -18,6 +18,7 @@ add_llvm_unittest(JITLinkTests
     LinkGraphTests.cpp
     MachOLinkGraphTests.cpp
     MemoryManagerErrorTests.cpp
+    MipsTests.cpp
     StubsTests.cpp
     X86_64Tests.cpp
   )

diff  --git a/llvm/unittests/ExecutionEngine/JITLink/COFFLinkGraphTests.cpp b/llvm/unittests/ExecutionEngine/JITLink/COFFLinkGraphTests.cpp
index a2cf73e3fa99f..0243602c59b5c 100644
--- a/llvm/unittests/ExecutionEngine/JITLink/COFFLinkGraphTests.cpp
+++ b/llvm/unittests/ExecutionEngine/JITLink/COFFLinkGraphTests.cpp
@@ -18,7 +18,7 @@ using namespace llvm::jitlink;
 
 TEST(COFFLinkGraphTest, GetImageBaseSymbolReturnsNullWhenMissing) {
   LinkGraph G("foo", std::make_shared<orc::SymbolStringPool>(),
-              Triple("x86_64-pc-windows-msvc"), SubtargetFeatures(),
+              Triple("x86_64-pc-windows-msvc"), 8, SubtargetFeatures(),
               getGenericEdgeKindName);
 
   GetImageBaseSymbol GetIB;
@@ -27,7 +27,7 @@ TEST(COFFLinkGraphTest, GetImageBaseSymbolReturnsNullWhenMissing) {
 
 TEST(COFFLinkGraphTest, GetImageBaseSymbolFindsExternal) {
   LinkGraph G("foo", std::make_shared<orc::SymbolStringPool>(),
-              Triple("x86_64-pc-windows-msvc"), SubtargetFeatures(),
+              Triple("x86_64-pc-windows-msvc"), 8, SubtargetFeatures(),
               getGenericEdgeKindName);
 
   auto &ExtSym = G.addExternalSymbol(G.intern("__ImageBase"), 0, false);
@@ -37,7 +37,7 @@ TEST(COFFLinkGraphTest, GetImageBaseSymbolFindsExternal) {
 
 TEST(COFFLinkGraphTest, GetImageBaseSymbolFindsAbsolute) {
   LinkGraph G("foo", std::make_shared<orc::SymbolStringPool>(),
-              Triple("x86_64-pc-windows-msvc"), SubtargetFeatures(),
+              Triple("x86_64-pc-windows-msvc"), 8, SubtargetFeatures(),
               getGenericEdgeKindName);
 
   auto &AbsSym =
@@ -49,7 +49,7 @@ TEST(COFFLinkGraphTest, GetImageBaseSymbolFindsAbsolute) {
 
 TEST(COFFLinkGraphTest, GetImageBaseSymbolFindsDefined) {
   LinkGraph G("foo", std::make_shared<orc::SymbolStringPool>(),
-              Triple("x86_64-pc-windows-msvc"), SubtargetFeatures(),
+              Triple("x86_64-pc-windows-msvc"), 8, SubtargetFeatures(),
               getGenericEdgeKindName);
 
   auto &Sec =
@@ -65,7 +65,7 @@ TEST(COFFLinkGraphTest, GetImageBaseSymbolFindsDefined) {
 
 TEST(COFFLinkGraphTest, GetImageBaseSymbolCachesResult) {
   LinkGraph G("foo", std::make_shared<orc::SymbolStringPool>(),
-              Triple("x86_64-pc-windows-msvc"), SubtargetFeatures(),
+              Triple("x86_64-pc-windows-msvc"), 8, SubtargetFeatures(),
               getGenericEdgeKindName);
 
   auto &ExtSym = G.addExternalSymbol(G.intern("__ImageBase"), 0, false);
@@ -79,7 +79,7 @@ TEST(COFFLinkGraphTest, GetImageBaseSymbolCachesResult) {
 
 TEST(COFFLinkGraphTest, GetImageBaseSymbolReset) {
   LinkGraph G("foo", std::make_shared<orc::SymbolStringPool>(),
-              Triple("x86_64-pc-windows-msvc"), SubtargetFeatures(),
+              Triple("x86_64-pc-windows-msvc"), 8, SubtargetFeatures(),
               getGenericEdgeKindName);
 
   GetImageBaseSymbol GetIB;
@@ -98,7 +98,7 @@ TEST(COFFLinkGraphTest, GetImageBaseSymbolReset) {
 
 TEST(COFFLinkGraphTest, GetImageBaseSymbolCustomName) {
   LinkGraph G("foo", std::make_shared<orc::SymbolStringPool>(),
-              Triple("x86_64-pc-windows-msvc"), SubtargetFeatures(),
+              Triple("x86_64-pc-windows-msvc"), 8, SubtargetFeatures(),
               getGenericEdgeKindName);
 
   G.addExternalSymbol(G.intern("__ImageBase"), 0, false);

diff  --git a/llvm/unittests/ExecutionEngine/JITLink/JITLinkTestUtils.cpp b/llvm/unittests/ExecutionEngine/JITLink/JITLinkTestUtils.cpp
index 2d0801fb6ac67..d9e96783e3a8a 100644
--- a/llvm/unittests/ExecutionEngine/JITLink/JITLinkTestUtils.cpp
+++ b/llvm/unittests/ExecutionEngine/JITLink/JITLinkTestUtils.cpp
@@ -94,7 +94,7 @@ TEST(JITLinkMocks, SmokeTest) {
   // successfully.
   auto G = std::make_unique<LinkGraph>(
       "foo", std::make_shared<orc::SymbolStringPool>(),
-      Triple("x86_64-apple-darwin"), SubtargetFeatures(),
+      Triple("x86_64-apple-darwin"), 8, SubtargetFeatures(),
       getGenericEdgeKindName);
 
   ArrayRef<char> Content = "hello, world!";

diff  --git a/llvm/unittests/ExecutionEngine/JITLink/LinkGraphTests.cpp b/llvm/unittests/ExecutionEngine/JITLink/LinkGraphTests.cpp
index c760873493528..3ab07a6cd1615 100644
--- a/llvm/unittests/ExecutionEngine/JITLink/LinkGraphTests.cpp
+++ b/llvm/unittests/ExecutionEngine/JITLink/LinkGraphTests.cpp
@@ -22,7 +22,7 @@ using namespace llvm::jitlink;
 TEST(LinkGraphTest, Construction) {
   // Check that LinkGraph construction works as expected.
   LinkGraph G("foo", std::make_shared<orc::SymbolStringPool>(),
-              Triple("x86_64-apple-darwin"), SubtargetFeatures(),
+              Triple("x86_64-apple-darwin"), 8, SubtargetFeatures(),
               getGenericEdgeKindName);
   EXPECT_EQ(G.getName(), "foo");
   EXPECT_EQ(G.getTargetTriple().str(), "x86_64-apple-darwin");
@@ -37,7 +37,7 @@ TEST(LinkGraphTest, Construction) {
 TEST(LinkGraphTest, AddressAccess) {
   // Check that we can get addresses for blocks, symbols, and edges.
   LinkGraph G("foo", std::make_shared<orc::SymbolStringPool>(),
-              Triple("x86_64-apple-darwin"), SubtargetFeatures(),
+              Triple("x86_64-apple-darwin"), 8, SubtargetFeatures(),
               getGenericEdgeKindName);
 
   auto &Sec1 =
@@ -57,7 +57,7 @@ TEST(LinkGraphTest, AddressAccess) {
 TEST(LinkGraphTest, DefinedSymbolProperties) {
   // Check that Section::empty behaves as expected.
   LinkGraph G("foo", std::make_shared<orc::SymbolStringPool>(),
-              Triple("x86_64-apple-darwin"), SubtargetFeatures(),
+              Triple("x86_64-apple-darwin"), 8, SubtargetFeatures(),
               getGenericEdgeKindName);
   auto &Sec =
       G.createSection("__data", orc::MemProt::Read | orc::MemProt::Write);
@@ -87,7 +87,7 @@ TEST(LinkGraphTest, DefinedSymbolProperties) {
 TEST(LinkGraphTest, SectionEmpty) {
   // Check that Section::empty behaves as expected.
   LinkGraph G("foo", std::make_shared<orc::SymbolStringPool>(),
-              Triple("x86_64-apple-darwin"), SubtargetFeatures(),
+              Triple("x86_64-apple-darwin"), 8, SubtargetFeatures(),
               getGenericEdgeKindName);
   auto &Sec1 =
       G.createSection("__data.1", orc::MemProt::Read | orc::MemProt::Write);
@@ -106,7 +106,7 @@ TEST(LinkGraphTest, SectionEmpty) {
 TEST(LinkGraphTest, BlockAndSymbolIteration) {
   // Check that we can iterate over blocks within Sections and across sections.
   LinkGraph G("foo", std::make_shared<orc::SymbolStringPool>(),
-              Triple("x86_64-apple-darwin"), SubtargetFeatures(),
+              Triple("x86_64-apple-darwin"), 8, SubtargetFeatures(),
               getGenericEdgeKindName);
   auto &Sec1 =
       G.createSection("__data.1", orc::MemProt::Read | orc::MemProt::Write);
@@ -160,7 +160,7 @@ TEST(LinkGraphTest, BlockAndSymbolIteration) {
 TEST(LinkGraphTest, EdgeIteration) {
   // Check that we can iterate over blocks within Sections and across sections.
   LinkGraph G("foo", std::make_shared<orc::SymbolStringPool>(),
-              Triple("x86_64-apple-darwin"), SubtargetFeatures(),
+              Triple("x86_64-apple-darwin"), 8, SubtargetFeatures(),
               getGenericEdgeKindName);
   auto &Sec1 =
       G.createSection("__data.1", orc::MemProt::Read | orc::MemProt::Write);
@@ -190,7 +190,7 @@ TEST(LinkGraphTest, EdgeIteration) {
 TEST(LinkGraphTest, ContentAccessAndUpdate) {
   // Check that we can make a defined symbol external.
   LinkGraph G("foo", std::make_shared<orc::SymbolStringPool>(),
-              Triple("x86_64-apple-darwin"), SubtargetFeatures(),
+              Triple("x86_64-apple-darwin"), 8, SubtargetFeatures(),
               getGenericEdgeKindName);
   auto &Sec =
       G.createSection("__data", orc::MemProt::Read | orc::MemProt::Write);
@@ -280,7 +280,7 @@ TEST(LinkGraphTest, ContentAccessAndUpdate) {
 TEST(LinkGraphTest, FindSymbolsByName) {
   // Check that we can make defined and absolute symbols external.
   LinkGraph G("foo", std::make_shared<orc::SymbolStringPool>(),
-              Triple("x86_64-apple-darwin"), SubtargetFeatures(),
+              Triple("x86_64-apple-darwin"), 8, SubtargetFeatures(),
               getGenericEdgeKindName);
   auto &Sec =
       G.createSection("__data", orc::MemProt::Read | orc::MemProt::Write);
@@ -325,7 +325,7 @@ TEST(LinkGraphTest, FindSymbolsByName) {
 TEST(LinkGraphTest, MakeExternal) {
   // Check that we can make defined and absolute symbols external.
   LinkGraph G("foo", std::make_shared<orc::SymbolStringPool>(),
-              Triple("x86_64-apple-darwin"), SubtargetFeatures(),
+              Triple("x86_64-apple-darwin"), 8, SubtargetFeatures(),
               getGenericEdgeKindName);
   auto &Sec =
       G.createSection("__data", orc::MemProt::Read | orc::MemProt::Write);
@@ -396,7 +396,7 @@ TEST(LinkGraphTest, MakeExternal) {
 TEST(LinkGraphTest, MakeAbsolute) {
   // Check that we can make defined and external symbols absolute.
   LinkGraph G("foo", std::make_shared<orc::SymbolStringPool>(),
-              Triple("x86_64-apple-darwin"), SubtargetFeatures(),
+              Triple("x86_64-apple-darwin"), 8, SubtargetFeatures(),
               getGenericEdgeKindName);
   auto &Sec =
       G.createSection("__data", orc::MemProt::Read | orc::MemProt::Write);
@@ -466,7 +466,7 @@ TEST(LinkGraphTest, MakeAbsolute) {
 TEST(LinkGraphTest, MakeDefined) {
   // Check that we can make an external symbol defined.
   LinkGraph G("foo", std::make_shared<orc::SymbolStringPool>(),
-              Triple("x86_64-apple-darwin"), SubtargetFeatures(),
+              Triple("x86_64-apple-darwin"), 8, SubtargetFeatures(),
               getGenericEdgeKindName);
   auto &Sec =
       G.createSection("__data", orc::MemProt::Read | orc::MemProt::Write);
@@ -515,7 +515,7 @@ TEST(LinkGraphTest, MakeDefined) {
 TEST(LinkGraphTest, TransferDefinedSymbol) {
   // Check that we can transfer a defined symbol from one block to another.
   LinkGraph G("foo", std::make_shared<orc::SymbolStringPool>(),
-              Triple("x86_64-apple-darwin"), SubtargetFeatures(),
+              Triple("x86_64-apple-darwin"), 8, SubtargetFeatures(),
               getGenericEdgeKindName);
   auto &Sec =
       G.createSection("__data", orc::MemProt::Read | orc::MemProt::Write);
@@ -551,7 +551,7 @@ TEST(LinkGraphTest, TransferDefinedSymbolAcrossSections) {
   // Check that we can transfer a defined symbol from an existing block in one
   // section to another.
   LinkGraph G("foo", std::make_shared<orc::SymbolStringPool>(),
-              Triple("x86_64-apple-darwin"), SubtargetFeatures(),
+              Triple("x86_64-apple-darwin"), 8, SubtargetFeatures(),
               getGenericEdgeKindName);
   auto &Sec1 =
       G.createSection("__data.1", orc::MemProt::Read | orc::MemProt::Write);
@@ -586,7 +586,7 @@ TEST(LinkGraphTest, TransferBlock) {
   // Check that we can transfer a block (and all associated symbols) from one
   // section to another.
   LinkGraph G("foo", std::make_shared<orc::SymbolStringPool>(),
-              Triple("x86_64-apple-darwin"), SubtargetFeatures(),
+              Triple("x86_64-apple-darwin"), 8, SubtargetFeatures(),
               getGenericEdgeKindName);
   auto &Sec1 =
       G.createSection("__data.1", orc::MemProt::Read | orc::MemProt::Write);
@@ -635,7 +635,7 @@ TEST(LinkGraphTest, MergeSections) {
   // Check that we can transfer a block (and all associated symbols) from one
   // section to another.
   LinkGraph G("foo", std::make_shared<orc::SymbolStringPool>(),
-              Triple("x86_64-apple-darwin"), SubtargetFeatures(),
+              Triple("x86_64-apple-darwin"), 8, SubtargetFeatures(),
               getGenericEdgeKindName);
   auto &Sec1 =
       G.createSection("__data.1", orc::MemProt::Read | orc::MemProt::Write);
@@ -722,7 +722,7 @@ TEST(LinkGraphTest, MergeSections) {
 TEST(LinkGraphTest, SplitBlock) {
   // Check that the LinkGraph::splitBlock test works as expected.
   LinkGraph G("foo", std::make_shared<orc::SymbolStringPool>(),
-              Triple("x86_64-apple-darwin"), SubtargetFeatures(),
+              Triple("x86_64-apple-darwin"), 8, SubtargetFeatures(),
               getGenericEdgeKindName);
   auto &Sec =
       G.createSection("__data", orc::MemProt::Read | orc::MemProt::Write);
@@ -835,7 +835,7 @@ TEST(LinkGraphTest, SplitBlock) {
 
 TEST(LinkGraphTest, GraphAllocationMethods) {
   LinkGraph G("foo", std::make_shared<orc::SymbolStringPool>(),
-              Triple("x86_64-apple-darwin"), SubtargetFeatures(),
+              Triple("x86_64-apple-darwin"), 8, SubtargetFeatures(),
               getGenericEdgeKindName);
 
   // Test allocation of sized, uninitialized buffer.
@@ -857,7 +857,7 @@ TEST(LinkGraphTest, GraphAllocationMethods) {
 TEST(LinkGraphTest, IsCStringBlockTest) {
   // Check that the LinkGraph::splitBlock test works as expected.
   LinkGraph G("foo", std::make_shared<orc::SymbolStringPool>(),
-              Triple("x86_64-apple-darwin"), SubtargetFeatures(),
+              Triple("x86_64-apple-darwin"), 8, SubtargetFeatures(),
               getGenericEdgeKindName);
   auto &Sec =
       G.createSection("__data", orc::MemProt::Read | orc::MemProt::Write);
@@ -882,7 +882,7 @@ TEST(LinkGraphTest, IsCStringBlockTest) {
 
 TEST(LinkGraphTest, BasicLayoutHonorsNoAlloc) {
   LinkGraph G("foo", std::make_shared<orc::SymbolStringPool>(),
-              Triple("x86_64-apple-darwin"), SubtargetFeatures(),
+              Triple("x86_64-apple-darwin"), 8, SubtargetFeatures(),
               getGenericEdgeKindName);
 
   // Create a regular section and block.

diff  --git a/llvm/unittests/ExecutionEngine/JITLink/MachOLinkGraphTests.cpp b/llvm/unittests/ExecutionEngine/JITLink/MachOLinkGraphTests.cpp
index 173ec14fe260f..6ccbd20a351f2 100644
--- a/llvm/unittests/ExecutionEngine/JITLink/MachOLinkGraphTests.cpp
+++ b/llvm/unittests/ExecutionEngine/JITLink/MachOLinkGraphTests.cpp
@@ -22,7 +22,7 @@ using namespace llvm::jitlink;
 TEST(MachOLinkGraphTest, GetStandardSections) {
   // Check that LinkGraph construction works as expected.
   LinkGraph G("foo", std::make_shared<orc::SymbolStringPool>(),
-              Triple("arm64-apple-darwin"), SubtargetFeatures(),
+              Triple("arm64-apple-darwin"), 8, SubtargetFeatures(),
               getGenericEdgeKindName);
 
   auto &Data = getMachODefaultRWDataSection(G);

diff  --git a/llvm/unittests/ExecutionEngine/JITLink/MemoryManagerErrorTests.cpp b/llvm/unittests/ExecutionEngine/JITLink/MemoryManagerErrorTests.cpp
index 48a38aefe4e6d..998e81b70e5f8 100644
--- a/llvm/unittests/ExecutionEngine/JITLink/MemoryManagerErrorTests.cpp
+++ b/llvm/unittests/ExecutionEngine/JITLink/MemoryManagerErrorTests.cpp
@@ -20,7 +20,7 @@ TEST(MemoryManagerErrorTest, ErrorOnFirstAllocate) {
   // Check that we can get addresses for blocks, symbols, and edges.
   auto G = std::make_unique<LinkGraph>(
       "foo", std::make_shared<orc::SymbolStringPool>(),
-      Triple("x86_64-apple-darwin"), SubtargetFeatures(),
+      Triple("x86_64-apple-darwin"), 8, SubtargetFeatures(),
       getGenericEdgeKindName);
 
   ArrayRef<char> Content = "hello, world!";

diff  --git a/llvm/unittests/ExecutionEngine/JITLink/MipsTests.cpp b/llvm/unittests/ExecutionEngine/JITLink/MipsTests.cpp
new file mode 100644
index 0000000000000..b0869d16790c7
--- /dev/null
+++ b/llvm/unittests/ExecutionEngine/JITLink/MipsTests.cpp
@@ -0,0 +1,72 @@
+//===-- MipsTests.cpp - Tests for MIPS JITLink utilities ------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/ExecutionEngine/JITLink/mips.h"
+#include "gtest/gtest.h"
+
+using namespace llvm;
+using namespace llvm::jitlink;
+
+TEST(MipsJITLinkTest, N32PointerSize) {
+  LinkGraph G("n32", std::make_shared<orc::SymbolStringPool>(),
+              Triple("mips64el-unknown-linux-gnuabin32"), 4,
+              SubtargetFeatures(), mips::getEdgeKindName);
+  EXPECT_EQ(G.getPointerSize(), 4U);
+  EXPECT_EQ(G.getEndianness(), endianness::little);
+  EXPECT_EQ(mips::getPointerEdgeKind(G), mips::Pointer32);
+}
+
+TEST(MipsJITLinkTest, GOTAndStubs) {
+  LinkGraph G("mips-r6", std::make_shared<orc::SymbolStringPool>(),
+              Triple("mipsel-unknown-linux"), 4, SubtargetFeatures("+mips32r6"),
+              mips::getEdgeKindName);
+  auto &GOT =
+      G.createSection("$__GOT", orc::MemProt::Read | orc::MemProt::Write);
+  auto &Stubs =
+      G.createSection("$__STUBS", orc::MemProt::Read | orc::MemProt::Exec);
+  auto &Target = G.addAbsoluteSymbol("target", orc::ExecutorAddr(0x12345678), 0,
+                                     Linkage::Strong, Scope::Local, false);
+  auto &Pointer = mips::createAnonymousPointer(G, GOT, &Target, 4);
+  ASSERT_EQ(Pointer.getBlock().edges_size(), 1U);
+  auto &PointerEdge = *Pointer.getBlock().edges().begin();
+  EXPECT_EQ(PointerEdge.getKind(), mips::Pointer32);
+  EXPECT_EQ(&PointerEdge.getTarget(), &Target);
+  EXPECT_EQ(PointerEdge.getAddend(), 4);
+
+  auto &Stub = mips::createAnonymousPointerJumpStub(G, Stubs, Pointer);
+  ASSERT_EQ(Stub.getSize(), 20U);
+  ASSERT_EQ(Stub.getBlock().edges_size(), 2U);
+  auto StubEdge = Stub.getBlock().edges().begin();
+  EXPECT_EQ(StubEdge->getKind(), mips::Hi16);
+  EXPECT_EQ(&StubEdge->getTarget(), &Pointer);
+  ++StubEdge;
+  EXPECT_EQ(StubEdge->getKind(), mips::Lo16);
+  EXPECT_EQ(&StubEdge->getTarget(), &Pointer);
+
+  LinkGraph G64("mips64be-r2", std::make_shared<orc::SymbolStringPool>(),
+                Triple("mips64-unknown-linux-gnuabi64"), 8,
+                SubtargetFeatures("+mips64r2"), mips::getEdgeKindName);
+  auto &GOT64 =
+      G64.createSection("$__GOT", orc::MemProt::Read | orc::MemProt::Write);
+  auto &Stubs64 =
+      G64.createSection("$__STUBS", orc::MemProt::Read | orc::MemProt::Exec);
+  auto &Target64 =
+      G64.addAbsoluteSymbol("target", orc::ExecutorAddr(0x123456789abcdef0ULL),
+                            0, Linkage::Strong, Scope::Local, false);
+  auto &Pointer64 = mips::createAnonymousPointer(G64, GOT64, &Target64);
+  EXPECT_EQ(Pointer64.getBlock().edges().begin()->getKind(), mips::Pointer64);
+
+  auto &Stub64 = mips::createAnonymousPointerJumpStub(G64, Stubs64, Pointer64);
+  ASSERT_EQ(Stub64.getSize(), 36U);
+  ASSERT_EQ(Stub64.getBlock().edges_size(), 4U);
+  auto I = Stub64.getBlock().edges().begin();
+  EXPECT_EQ((I++)->getKind(), mips::Highest16);
+  EXPECT_EQ((I++)->getKind(), mips::Higher16);
+  EXPECT_EQ((I++)->getKind(), mips::Hi16);
+  EXPECT_EQ(I->getKind(), mips::Lo16);
+}

diff  --git a/llvm/unittests/ExecutionEngine/JITLink/StubsTests.cpp b/llvm/unittests/ExecutionEngine/JITLink/StubsTests.cpp
index 8473c71ef0ce3..df16806a2938f 100644
--- a/llvm/unittests/ExecutionEngine/JITLink/StubsTests.cpp
+++ b/llvm/unittests/ExecutionEngine/JITLink/StubsTests.cpp
@@ -58,7 +58,7 @@ TEST(StubsTest, StubsGeneration_x86_64) {
   const char PointerJumpStubContent[6] = {
       static_cast<char>(0xFFu), 0x25, 0x00, 0x00, 0x00, 0x00};
   LinkGraph G("foo", std::make_shared<orc::SymbolStringPool>(),
-              Triple("x86_64-apple-darwin"), SubtargetFeatures(),
+              Triple("x86_64-apple-darwin"), 8, SubtargetFeatures(),
               getGenericEdgeKindName);
   auto [PointerSym, StubSym] = GenerateStub(G, 8U, x86_64::Pointer64);
 
@@ -79,7 +79,7 @@ TEST(StubsTest, StubsGeneration_aarch64) {
       0x00, 0x02, 0x1f, (char)0xd6u  // BR  x16
   };
   LinkGraph G("foo", std::make_shared<orc::SymbolStringPool>(),
-              Triple("aarch64-linux-gnu"), SubtargetFeatures(),
+              Triple("aarch64-linux-gnu"), 8, SubtargetFeatures(),
               getGenericEdgeKindName);
   auto [PointerSym, StubSym] = GenerateStub(G, 8U, aarch64::Pointer64);
 
@@ -100,7 +100,7 @@ TEST(StubsTest, StubsGeneration_x86) {
   const char PointerJumpStubContent[6] = {
       static_cast<char>(0xFFu), 0x25, 0x00, 0x00, 0x00, 0x00};
   LinkGraph G("foo", std::make_shared<orc::SymbolStringPool>(),
-              Triple("i386-unknown-linux-gnu"), SubtargetFeatures(),
+              Triple("i386-unknown-linux-gnu"), 4, SubtargetFeatures(),
               getGenericEdgeKindName);
   auto [PointerSym, StubSym] = GenerateStub(G, 4U, x86::Pointer32);
 
@@ -130,7 +130,7 @@ TEST(StubsTest, StubsGeneration_loongarch32) {
       0x4c // jr $t8
   };
   LinkGraph G("foo", std::make_shared<orc::SymbolStringPool>(),
-              Triple("loongarch32"), SubtargetFeatures(),
+              Triple("loongarch32"), 4, SubtargetFeatures(),
               getGenericEdgeKindName);
   auto [PointerSym, StubSym] = GenerateStub(G, 4U, loongarch::Pointer32);
 
@@ -164,7 +164,7 @@ TEST(StubsTest, StubsGeneration_loongarch64) {
   };
 
   LinkGraph G("foo", std::make_shared<orc::SymbolStringPool>(),
-              Triple("loongarch64"), SubtargetFeatures(),
+              Triple("loongarch64"), 8, SubtargetFeatures(),
               getGenericEdgeKindName);
   auto [PointerSym, StubSym] = GenerateStub(G, 8U, loongarch::Pointer64);
 

diff  --git a/llvm/unittests/ExecutionEngine/JITLink/X86_64Tests.cpp b/llvm/unittests/ExecutionEngine/JITLink/X86_64Tests.cpp
index 8c79f0a8a9ee1..5b4b706905163 100644
--- a/llvm/unittests/ExecutionEngine/JITLink/X86_64Tests.cpp
+++ b/llvm/unittests/ExecutionEngine/JITLink/X86_64Tests.cpp
@@ -17,7 +17,7 @@ using namespace llvm::jitlink::x86_64;
 
 TEST(X86_64, EmptyLinkGraph) {
   LinkGraph G("foo", std::make_shared<orc::SymbolStringPool>(),
-              Triple("x86_64-apple-darwin"), SubtargetFeatures(),
+              Triple("x86_64-apple-darwin"), 8, SubtargetFeatures(),
               getEdgeKindName);
   EXPECT_EQ(G.getName(), "foo");
   EXPECT_EQ(G.getTargetTriple().str(), "x86_64-apple-darwin");
@@ -31,7 +31,7 @@ TEST(X86_64, EmptyLinkGraph) {
 
 TEST(X86_64, GOTAndStubs) {
   LinkGraph G("foo", std::make_shared<orc::SymbolStringPool>(),
-              Triple("x86_64-apple-darwin"), SubtargetFeatures(),
+              Triple("x86_64-apple-darwin"), 8, SubtargetFeatures(),
               getEdgeKindName);
 
   auto &External = G.addExternalSymbol("external", 0, false);

diff  --git a/llvm/unittests/ExecutionEngine/Orc/LinkGraphLinkingLayerTest.cpp b/llvm/unittests/ExecutionEngine/Orc/LinkGraphLinkingLayerTest.cpp
index 913cb0b702a41..98ed4c3a6484b 100644
--- a/llvm/unittests/ExecutionEngine/Orc/LinkGraphLinkingLayerTest.cpp
+++ b/llvm/unittests/ExecutionEngine/Orc/LinkGraphLinkingLayerTest.cpp
@@ -32,7 +32,7 @@ class LinkGraphLinkingLayerTests : public testing::Test {
   static std::unique_ptr<LinkGraph> makeGraph(StringRef Name = "test") {
     return std::make_unique<LinkGraph>(
         Name.str(), std::make_shared<SymbolStringPool>(),
-        Triple("x86_64-apple-darwin"), SubtargetFeatures(),
+        Triple("x86_64-apple-darwin"), 8, SubtargetFeatures(),
         getGenericEdgeKindName);
   }
 };

diff  --git a/llvm/unittests/ExecutionEngine/Orc/MemoryMapperTest.cpp b/llvm/unittests/ExecutionEngine/Orc/MemoryMapperTest.cpp
index b4051790c3511..a54424fc9085b 100644
--- a/llvm/unittests/ExecutionEngine/Orc/MemoryMapperTest.cpp
+++ b/llvm/unittests/ExecutionEngine/Orc/MemoryMapperTest.cpp
@@ -68,7 +68,7 @@ TEST(MemoryMapperTest, InitializeDeinitialize) {
     std::unique_ptr<MemoryMapper> Mapper =
         cantFail(InProcessMemoryMapper::Create());
     jitlink::LinkGraph G("G", std::make_shared<SymbolStringPool>(),
-                         Triple("x86_64-apple-darwin"), SubtargetFeatures(),
+                         Triple("x86_64-apple-darwin"), 8, SubtargetFeatures(),
                          jitlink::getGenericEdgeKindName);
 
     // We will do two separate allocations

diff  --git a/llvm/unittests/ExecutionEngine/Orc/ObjectLinkingLayerTest.cpp b/llvm/unittests/ExecutionEngine/Orc/ObjectLinkingLayerTest.cpp
index 4a12a45df95bb..0db37d7203fbd 100644
--- a/llvm/unittests/ExecutionEngine/Orc/ObjectLinkingLayerTest.cpp
+++ b/llvm/unittests/ExecutionEngine/Orc/ObjectLinkingLayerTest.cpp
@@ -48,7 +48,7 @@ class ObjectLinkingLayerTest : public testing::Test {
 
 TEST_F(ObjectLinkingLayerTest, AddLinkGraph) {
   auto G = std::make_unique<LinkGraph>(
-      "foo", ES.getSymbolStringPool(), Triple("x86_64-apple-darwin"),
+      "foo", ES.getSymbolStringPool(), Triple("x86_64-apple-darwin"), 8,
       SubtargetFeatures(), x86_64::getEdgeKindName);
 
   auto &Sec1 = G->createSection("__data", MemProt::Read | MemProt::Write);
@@ -75,7 +75,7 @@ TEST_F(ObjectLinkingLayerTest, ResourceTracker) {
   std::vector<ResourceTrackerSP> Trackers;
   for (unsigned I = 0; I < 64; I++) {
     auto G = std::make_unique<LinkGraph>(
-        "foo", ES.getSymbolStringPool(), Triple("x86_64-apple-darwin"),
+        "foo", ES.getSymbolStringPool(), Triple("x86_64-apple-darwin"), 8,
         SubtargetFeatures(), x86_64::getEdgeKindName);
 
     auto &Sec1 = G->createSection("__data", MemProt::Read | MemProt::Write);
@@ -142,7 +142,7 @@ TEST_F(ObjectLinkingLayerTest, ClaimLateDefinedWeakSymbols) {
 
   ObjLinkingLayer.addPlugin(std::make_unique<TestPlugin>());
   auto G = std::make_unique<LinkGraph>(
-      "foo", ES.getSymbolStringPool(), Triple("x86_64-apple-darwin"),
+      "foo", ES.getSymbolStringPool(), Triple("x86_64-apple-darwin"), 8,
       SubtargetFeatures(), getGenericEdgeKindName);
 
   auto &DataSec = G->createSection("__data", MemProt::Read | MemProt::Write);
@@ -195,7 +195,7 @@ TEST_F(ObjectLinkingLayerTest, HandleErrorDuringPostAllocationPass) {
 
   ObjLinkingLayer.addPlugin(std::make_unique<TestPlugin>());
   auto G = std::make_unique<LinkGraph>(
-      "foo", ES.getSymbolStringPool(), Triple("x86_64-apple-darwin"),
+      "foo", ES.getSymbolStringPool(), Triple("x86_64-apple-darwin"), 8,
       SubtargetFeatures(), getGenericEdgeKindName);
 
   auto &DataSec = G->createSection("__data", MemProt::Read | MemProt::Write);
@@ -249,7 +249,7 @@ TEST_F(ObjectLinkingLayerTest, AddAndRemovePlugins) {
 
   {
     auto G1 = std::make_unique<LinkGraph>(
-        "G1", ES.getSymbolStringPool(), Triple("x86_64-apple-darwin"),
+        "G1", ES.getSymbolStringPool(), Triple("x86_64-apple-darwin"), 8,
         SubtargetFeatures(), x86_64::getEdgeKindName);
 
     auto &DataSec = G1->createSection("__data", MemProt::Read | MemProt::Write);
@@ -267,7 +267,7 @@ TEST_F(ObjectLinkingLayerTest, AddAndRemovePlugins) {
 
   {
     auto G2 = std::make_unique<LinkGraph>(
-        "G2", ES.getSymbolStringPool(), Triple("x86_64-apple-darwin"),
+        "G2", ES.getSymbolStringPool(), Triple("x86_64-apple-darwin"), 8,
         SubtargetFeatures(), x86_64::getEdgeKindName);
 
     auto &DataSec = G2->createSection("__data", MemProt::Read | MemProt::Write);

diff  --git a/llvm/unittests/ExecutionEngine/Orc/SharedMemoryMapperTest.cpp b/llvm/unittests/ExecutionEngine/Orc/SharedMemoryMapperTest.cpp
index 753f8836acbd6..0b47d178247b0 100644
--- a/llvm/unittests/ExecutionEngine/Orc/SharedMemoryMapperTest.cpp
+++ b/llvm/unittests/ExecutionEngine/Orc/SharedMemoryMapperTest.cpp
@@ -85,7 +85,7 @@ TEST(SharedMemoryMapperTest, MemReserveInitializeDeinitializeRelease) {
     auto PageSize = Mapper->getPageSize();
     size_t ReqSize = PageSize;
     jitlink::LinkGraph G("G", std::make_shared<SymbolStringPool>(),
-                         Triple("x86_64-apple-darwin"), SubtargetFeatures(),
+                         Triple("x86_64-apple-darwin"), 8, SubtargetFeatures(),
                          jitlink::getGenericEdgeKindName);
 
     Mapper->reserve(ReqSize, [&](Expected<ExecutorAddrRange> Result) {


        


More information about the llvm-commits mailing list