LLVM 24.0.0git
mips.cpp
Go to the documentation of this file.
1//===-- mips.cpp - Generic JITLink MIPS edge kinds and utilities ----------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
10
11#include "llvm/ADT/STLExtras.h"
12
13namespace llvm {
14namespace jitlink {
15namespace mips {
16
17namespace {
18
19constexpr unsigned HalfwordBits = 16;
20constexpr unsigned MaxPointerJumpStubInstructions = 9;
21
22enum class Register : uint32_t {
23 Zero = 0,
24 T9 = 25,
25};
26
27enum class Opcode : uint32_t {
28 Addiu = 0x09,
29 Lui = 0x0f,
30 Daddiu = 0x19,
31 Lw = 0x23,
32 Ld = 0x37,
33};
34
35enum class Function : uint32_t {
36 Jr = 0x08,
37 Jalr = 0x09,
38 Dsll = 0x38,
39};
40
41constexpr unsigned OpcodeShift = 26;
42constexpr unsigned RSShift = 21;
43constexpr unsigned RTShift = 16;
44constexpr unsigned RDShift = 11;
45constexpr unsigned ShiftAmountShift = 6;
46
47constexpr uint32_t encodeIType(Opcode Op, Register RS, Register RT) {
48 return (static_cast<uint32_t>(Op) << OpcodeShift) |
49 (static_cast<uint32_t>(RS) << RSShift) |
50 (static_cast<uint32_t>(RT) << RTShift);
51}
52
53constexpr uint32_t encodeRType(Function Fn, Register RS, Register RT,
54 Register RD, unsigned ShiftAmount = 0) {
55 return (static_cast<uint32_t>(RS) << RSShift) |
56 (static_cast<uint32_t>(RT) << RTShift) |
57 (static_cast<uint32_t>(RD) << RDShift) |
58 (ShiftAmount << ShiftAmountShift) | static_cast<uint32_t>(Fn);
59}
60
61constexpr uint32_t encodeLui(Register RT) {
62 return encodeIType(Opcode::Lui, Register::Zero, RT);
63}
64
65constexpr uint32_t encodeAddiu(Register RT, Register RS) {
66 return encodeIType(Opcode::Addiu, RS, RT);
67}
68
69constexpr uint32_t encodeDaddiu(Register RT, Register RS) {
70 return encodeIType(Opcode::Daddiu, RS, RT);
71}
72
73constexpr uint32_t encodeLoadPointer32(Register RT, Register Base) {
74 return encodeIType(Opcode::Lw, Base, RT);
75}
76
77constexpr uint32_t encodeLoadPointer64(Register RT, Register Base) {
78 return encodeIType(Opcode::Ld, Base, RT);
79}
80
81constexpr uint32_t encodeDsll(Register RD, Register RT, unsigned ShiftAmount) {
82 return encodeRType(Function::Dsll, Register::Zero, RT, RD, ShiftAmount);
83}
84
85constexpr uint32_t encodeIndirectJump(Register Target, bool R6) {
86 // JALR with $zero is the release-6 no-link compact jump.
87 return encodeRType(R6 ? Function::Jalr : Function::Jr, Target, Register::Zero,
88 Register::Zero);
89}
90
91constexpr uint32_t encodeNop() { return 0; }
92
93struct StubFixup {
94 Edge::Kind Kind;
95 unsigned InstructionIndex;
96};
97
98constexpr StubFixup Pointer32StubFixups[] = {{Hi16, 0}, {Lo16, 1}};
99constexpr StubFixup Pointer64StubFixups[] = {
100 {Highest16, 0}, {Higher16, 1}, {Hi16, 3}, {Lo16, 5}};
101
102} // namespace
103
156
157static const char NullPointerContent[sizeof(uint64_t)] = {};
158
159bool isR6(const LinkGraph &G) {
160 const auto &Features = G.getFeatures().getFeatures();
161 return llvm::is_contained(Features, "+mips32r6") ||
162 llvm::is_contained(Features, "+mips64r6");
163}
164
165Edge::Kind getPointerEdgeKind(const LinkGraph &G) {
166 return G.getPointerSize() == 8 ? Pointer64 : Pointer32;
167}
168
170 return {NullPointerContent, G.getPointerSize()};
171}
172
174 Symbol *InitialTarget,
175 Edge::AddendT InitialAddend) {
176 auto &B = G.createContentBlock(PointerSection, getPointerBlockContent(G),
177 orc::ExecutorAddr(), G.getPointerSize(), 0);
178 if (InitialTarget)
179 B.addEdge(getPointerEdgeKind(G), 0, *InitialTarget, InitialAddend);
180 return G.addAnonymousSymbol(B, 0, G.getPointerSize(), false, false);
181}
182
184 Symbol &PointerSymbol) {
185 // Non-PIC callers do not enter with this graph's $gp.
186 unsigned PointerSize = G.getPointerSize();
187
189 ArrayRef<StubFixup> Fixups;
190 if (PointerSize == 8) {
191 Instructions = {
192 encodeLui(Register::T9),
193 encodeDaddiu(Register::T9, Register::T9),
194 encodeDsll(Register::T9, Register::T9, HalfwordBits),
195 encodeDaddiu(Register::T9, Register::T9),
196 encodeDsll(Register::T9, Register::T9, HalfwordBits),
197 encodeDaddiu(Register::T9, Register::T9),
198 encodeLoadPointer64(Register::T9, Register::T9),
199 };
200 Fixups = Pointer64StubFixups;
201 } else {
202 Instructions = {
203 encodeLui(Register::T9),
204 encodeAddiu(Register::T9, Register::T9),
205 encodeLoadPointer32(Register::T9, Register::T9),
206 };
207 Fixups = Pointer32StubFixups;
208 }
209 Instructions.push_back(encodeIndirectJump(Register::T9, isR6(G)));
210 Instructions.push_back(encodeNop());
211
212 auto Content = G.allocateBuffer(Instructions.size() * InstructionSize);
213 for (auto [Index, Instruction] : llvm::enumerate(Instructions))
214 support::endian::write32(Content.data() + Index * InstructionSize,
215 Instruction, G.getEndianness());
216
217 auto &B = G.createContentBlock(StubSection, Content, orc::ExecutorAddr(),
218 alignof(uint32_t), 0);
219 for (const StubFixup &F : Fixups)
220 B.addEdge(F.Kind, F.InstructionIndex * InstructionSize, PointerSymbol, 0);
221 return G.addAnonymousSymbol(B, 0, Content.size(), true, false);
222}
223
224} // namespace mips
225} // namespace jitlink
226} // namespace llvm
unsigned uint64_t
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
#define F(x, y, z)
Definition MD5.cpp:54
#define G(x, y, z)
Definition MD5.cpp:55
#define R6(n)
Promote Memory to Register
Definition Mem2Reg.cpp:110
This file contains some templates that are useful if you are working with the STL at all.
Represent a constant reference to an array (0 or more elements consecutively in memory),...
Definition ArrayRef.h:40
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
Represents an address in the executor process.
#define KIND_NAME(K)
@ OpcodeShift
Opcode.
void write32(void *P, uint32_t V, endianness E)
Definition Endian.h:435
This is an optimization pass for GlobalISel generic memory operations.
auto enumerate(FirstRange &&First, RestRanges &&...Rest)
Given two or more input ranges, returns a new range whose values are tuples (A, B,...
Definition STLExtras.h:2570
DWARFExpression::Operation Op
bool is_contained(R &&Range, const E &Element)
Returns true if Element is found in Range.
Definition STLExtras.h:1963