LLVM 18.0.0git
aarch32.h
Go to the documentation of this file.
1//===------ aarch32.h - Generic JITLink arm/thumb utilities -----*- C++ -*-===//
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//
9// Generic utilities for graphs representing arm/thumb objects.
10//
11//===----------------------------------------------------------------------===//
12
13#ifndef LLVM_EXECUTIONENGINE_JITLINK_AARCH32
14#define LLVM_EXECUTIONENGINE_JITLINK_AARCH32
15
16#include "TableManager.h"
20#include "llvm/Support/Error.h"
21
22namespace llvm {
23namespace jitlink {
24namespace aarch32 {
25
26/// Check whether the given target flags are set for this Symbol.
28
29/// JITLink-internal AArch32 fixup kinds
31
32 ///
33 /// Relocations of class Data respect target endianness (unless otherwise
34 /// specified)
35 ///
37
38 /// Relative 32-bit value relocation
40
41 /// Absolute 32-bit value relocation
43
45
46 ///
47 /// Relocations of class Arm (covers fixed-width 4-byte instruction subset)
48 ///
50
51 /// Write immediate value for unconditional PC-relative branch with link.
52 /// We patch the instruction opcode to account for an instruction-set state
53 /// switch: we use the bl instruction to stay in ARM and the blx instruction
54 /// to switch to Thumb.
56
57 /// Write immediate value for conditional PC-relative branch without link.
58 /// If the branch target is not ARM, we are forced to generate an explicit
59 /// interworking stub.
61
62 /// Write immediate value to the lower halfword of the destination register
64
65 /// Write immediate value to the top halfword of the destination register
67
69
70 ///
71 /// Relocations of class Thumb16 and Thumb32 (covers Thumb instruction subset)
72 ///
74
75 /// Write immediate value for unconditional PC-relative branch with link.
76 /// We patch the instruction opcode to account for an instruction-set state
77 /// switch: we use the bl instruction to stay in Thumb and the blx instruction
78 /// to switch to ARM.
80
81 /// Write immediate value for PC-relative branch without link. The instruction
82 /// can be made conditional by an IT block. If the branch target is not ARM,
83 /// we are forced to generate an explicit interworking stub.
85
86 /// Write immediate value to the lower halfword of the destination register
88
89 /// Write immediate value to the top halfword of the destination register
91
92 /// Write PC-relative immediate value to the lower halfword of the destination
93 /// register
95
96 /// Write PC-relative immediate value to the top halfword of the destination
97 /// register
99
102};
103
104/// Flags enum for AArch32-specific symbol properties
106 ThumbSymbol = 1 << 0,
107};
108
109/// Human-readable name for a given CPU architecture kind
111
112/// Get a human-readable name for the given AArch32 edge kind.
113const char *getEdgeKindName(Edge::Kind K);
114
115/// AArch32 uses stubs for a number of purposes, like branch range extension
116/// or interworking between Arm and Thumb instruction subsets.
117///
118/// Stub implementations vary depending on CPU architecture (v4, v6, v7),
119/// instruction subset and branch type (absolute/PC-relative).
120///
121/// For each kind of stub, the StubsFlavor defines one concrete form that is
122/// used throughout the LinkGraph.
123///
124/// Stubs are often called "veneers" in the official docs and online.
125///
129};
130
131/// JITLink sub-arch configuration for Arm CPU models
132struct ArmConfig {
133 bool J1J2BranchEncoding = false;
135};
136
137/// Obtain the sub-arch configuration for a given Arm CPU model.
139 ArmConfig ArmCfg;
140 switch (CPUArch) {
143 ArmCfg.J1J2BranchEncoding = true;
144 ArmCfg.Stubs = Thumbv7;
145 break;
146 default:
147 DEBUG_WITH_TYPE("jitlink", {
148 dbgs() << " Warning: ARM config not defined for CPU architecture "
149 << getCPUArchName(CPUArch);
150 });
151 break;
152 }
153 return ArmCfg;
154}
155
156/// Immutable pair of halfwords, Hi and Lo, with overflow check
157struct HalfWords {
158 constexpr HalfWords() : Hi(0), Lo(0) {}
159 constexpr HalfWords(uint32_t Hi, uint32_t Lo) : Hi(Hi), Lo(Lo) {
160 assert(isUInt<16>(Hi) && "Overflow in first half-word");
161 assert(isUInt<16>(Lo) && "Overflow in second half-word");
162 }
163 const uint16_t Hi; // First halfword
164 const uint16_t Lo; // Second halfword
165};
166
167/// FixupInfo base class is required for dynamic lookups.
170 virtual ~FixupInfoBase() {}
171};
172
173/// FixupInfo checks for Arm edge kinds work on 32-bit words
176};
177
178/// FixupInfo check for Thumb32 edge kinds work on a pair of 16-bit halfwords
181};
182
183/// Collection of named constants per fixup kind
184///
185/// Mandatory entries:
186/// Opcode - Values of the op-code bits in the instruction, with
187/// unaffected bits nulled
188/// OpcodeMask - Mask with all bits set that encode the op-code
189///
190/// Other common entries:
191/// ImmMask - Mask with all bits set that encode the immediate value
192/// RegMask - Mask with all bits set that encode the register
193///
194/// Specializations can add further custom fields without restrictions.
195///
196template <EdgeKind_aarch32 Kind> struct FixupInfo {};
197
198namespace {
199struct FixupInfoArmBranch : public FixupInfoArm {
200 static constexpr uint32_t Opcode = 0x0a000000;
201 static constexpr uint32_t ImmMask = 0x00ffffff;
202};
203} // namespace
204
205template <> struct FixupInfo<Arm_Jump24> : public FixupInfoArmBranch {
206 static constexpr uint32_t OpcodeMask = 0x0f000000;
207};
208
209template <> struct FixupInfo<Arm_Call> : public FixupInfoArmBranch {
210 static constexpr uint32_t OpcodeMask = 0x0e000000;
211 static constexpr uint32_t CondMask = 0xe0000000; // excluding BLX bit
212 static constexpr uint32_t Unconditional = 0xe0000000;
213 static constexpr uint32_t BitH = 0x01000000;
214 static constexpr uint32_t BitBlx = 0x10000000;
215};
216
217namespace {
218struct FixupInfoArmMov : public FixupInfoArm {
219 static constexpr uint32_t OpcodeMask = 0x0ff00000;
220 static constexpr uint32_t ImmMask = 0x000f0fff;
221 static constexpr uint32_t RegMask = 0x0000f000;
222};
223} // namespace
224
225template <> struct FixupInfo<Arm_MovtAbs> : public FixupInfoArmMov {
226 static constexpr uint32_t Opcode = 0x03400000;
227};
228
229template <> struct FixupInfo<Arm_MovwAbsNC> : public FixupInfoArmMov {
230 static constexpr uint32_t Opcode = 0x03000000;
231};
232
233template <> struct FixupInfo<Thumb_Jump24> : public FixupInfoThumb {
234 static constexpr HalfWords Opcode{0xf000, 0x9000};
235 static constexpr HalfWords OpcodeMask{0xf800, 0x9000};
236 static constexpr HalfWords ImmMask{0x07ff, 0x2fff};
237};
238
239template <> struct FixupInfo<Thumb_Call> : public FixupInfoThumb {
240 static constexpr HalfWords Opcode{0xf000, 0xc000};
241 static constexpr HalfWords OpcodeMask{0xf800, 0xc000};
242 static constexpr HalfWords ImmMask{0x07ff, 0x2fff};
243 static constexpr uint16_t LoBitH = 0x0001;
244 static constexpr uint16_t LoBitNoBlx = 0x1000;
245};
246
247namespace {
248struct FixupInfoThumbMov : public FixupInfoThumb {
249 static constexpr HalfWords OpcodeMask{0xfbf0, 0x8000};
250 static constexpr HalfWords ImmMask{0x040f, 0x70ff};
251 static constexpr HalfWords RegMask{0x0000, 0x0f00};
252};
253} // namespace
254
255template <> struct FixupInfo<Thumb_MovtAbs> : public FixupInfoThumbMov {
256 static constexpr HalfWords Opcode{0xf2c0, 0x0000};
257};
258
259template <> struct FixupInfo<Thumb_MovtPrel> : public FixupInfoThumbMov {
260 static constexpr HalfWords Opcode{0xf2c0, 0x0000};
261};
262
263template <> struct FixupInfo<Thumb_MovwAbsNC> : public FixupInfoThumbMov {
264 static constexpr HalfWords Opcode{0xf240, 0x0000};
265};
266
267template <> struct FixupInfo<Thumb_MovwPrelNC> : public FixupInfoThumbMov {
268 static constexpr HalfWords Opcode{0xf240, 0x0000};
269};
270
271/// Helper function to read the initial addend for Data-class relocations.
273 Edge::Kind Kind);
274
275/// Helper function to read the initial addend for Arm-class relocations.
277 Edge::Kind Kind);
278
279/// Helper function to read the initial addend for Thumb-class relocations.
281 Edge::Kind Kind, const ArmConfig &ArmCfg);
282
283/// Read the initial addend for a REL-type relocation. It's the value encoded
284/// in the immediate field of the fixup location by the compiler.
287 const ArmConfig &ArmCfg) {
288 if (Kind <= LastDataRelocation)
289 return readAddendData(G, B, Offset, Kind);
290
291 if (Kind <= LastArmRelocation)
292 return readAddendArm(G, B, Offset, Kind);
293
294 if (Kind <= LastThumbRelocation)
295 return readAddendThumb(G, B, Offset, Kind, ArmCfg);
296
297 llvm_unreachable("Relocation must be of class Data, Arm or Thumb");
298}
299
300/// Helper function to apply the fixup for Data-class relocations.
302
303/// Helper function to apply the fixup for Arm-class relocations.
305
306/// Helper function to apply the fixup for Thumb-class relocations.
308 const ArmConfig &ArmCfg);
309
310/// Apply fixup expression for edge to block content.
312 const ArmConfig &ArmCfg) {
313 Edge::Kind Kind = E.getKind();
314
315 if (Kind <= LastDataRelocation)
316 return applyFixupData(G, B, E);
317
318 if (Kind <= LastArmRelocation)
319 return applyFixupArm(G, B, E);
320
321 if (Kind <= LastThumbRelocation)
322 return applyFixupThumb(G, B, E, ArmCfg);
323
324 llvm_unreachable("Relocation must be of class Data, Arm or Thumb");
325}
326
327/// Stubs builder for a specific StubsFlavor
328///
329/// Right now we only have one default stub kind, but we want to extend this
330/// and allow creation of specific kinds in the future (e.g. branch range
331/// extension or interworking).
332///
333/// Let's keep it simple for the moment and not wire this through a GOT.
334///
335template <StubsFlavor Flavor>
336class StubsManager : public TableManager<StubsManager<Flavor>> {
337public:
338 StubsManager() = default;
339
340 /// Name of the object file section that will contain all our stubs.
342
343 /// Implements link-graph traversal via visitExistingEdges().
345 if (E.getTarget().isDefined())
346 return false;
347
348 switch (E.getKind()) {
349 case Thumb_Call:
350 case Thumb_Jump24: {
351 DEBUG_WITH_TYPE("jitlink", {
352 dbgs() << " Fixing " << G.getEdgeKindName(E.getKind()) << " edge at "
353 << B->getFixupAddress(E) << " (" << B->getAddress() << " + "
354 << formatv("{0:x}", E.getOffset()) << ")\n";
355 });
356 E.setTarget(this->getEntryForTarget(G, E.getTarget()));
357 return true;
358 }
359 }
360 return false;
361 }
362
363 /// Create a branch range extension stub for the class's flavor.
365
366private:
367 /// Create a new node in the link-graph for the given stub template.
368 template <size_t Size>
369 Block &addStub(LinkGraph &G, const uint8_t (&Code)[Size],
370 uint64_t Alignment) {
371 ArrayRef<char> Template(reinterpret_cast<const char *>(Code), Size);
372 return G.createContentBlock(getStubsSection(G), Template,
373 orc::ExecutorAddr(), Alignment, 0);
374 }
375
376 /// Get or create the object file section that will contain all our stubs.
377 Section &getStubsSection(LinkGraph &G) {
378 if (!StubsSection)
379 StubsSection = &G.createSection(getSectionName(),
381 return *StubsSection;
382 }
383
384 Section *StubsSection = nullptr;
385};
386
387/// Create a branch range extension stub with Thumb encoding for v7 CPUs.
388template <>
390
392 return "__llvm_jitlink_aarch32_STUBS_Thumbv7";
393}
394
395} // namespace aarch32
396} // namespace jitlink
397} // namespace llvm
398
399#endif // LLVM_EXECUTIONENGINE_JITLINK_AARCH32
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
#define DEBUG_WITH_TYPE(TYPE, X)
DEBUG_WITH_TYPE macro - This macro should be used by passes to emit debug information.
Definition: Debug.h:64
uint64_t Size
Symbol * Sym
Definition: ELF_riscv.cpp:477
#define G(x, y, z)
Definition: MD5.cpp:56
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
support::ulittle32_t & Wd
Definition: aarch32.cpp:226
static constexpr uint32_t RegMask
Definition: aarch32.h:221
static constexpr uint32_t OpcodeMask
Definition: aarch32.h:219
static constexpr uint32_t Opcode
Definition: aarch32.h:200
static constexpr uint32_t ImmMask
Definition: aarch32.h:201
ArrayRef - Represent a constant reference to an array (0 or more elements consecutively in memory),...
Definition: ArrayRef.h:41
Lightweight error class with error context and mandatory checking.
Definition: Error.h:160
Tagged union holding either a T or a Error.
Definition: Error.h:474
StringRef - Represent a constant reference to a string, i.e.
Definition: StringRef.h:50
Target - Wrapper for Target specific information.
Represents an address in the executor process.
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
This is an optimization pass for GlobalISel generic memory operations.
Definition: AddressRanges.h:18
@ Offset
Definition: DWP.cpp:440
auto formatv(const char *Fmt, Ts &&... Vals) -> formatv_object< decltype(std::make_tuple(detail::build_format_adapter(std::forward< Ts >(Vals))...))>
raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
Definition: Debug.cpp:163