[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