LLVM 19.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
44 /// Relative 31-bit value relocation that preserves the most-significant bit
46
47 /// Create GOT entry and store offset
49
51
52 ///
53 /// Relocations of class Arm (covers fixed-width 4-byte instruction subset)
54 ///
56
57 /// Write immediate value for unconditional PC-relative branch with link.
58 /// We patch the instruction opcode to account for an instruction-set state
59 /// switch: we use the bl instruction to stay in ARM and the blx instruction
60 /// to switch to Thumb.
62
63 /// Write immediate value for conditional PC-relative branch without link.
64 /// If the branch target is not ARM, we are forced to generate an explicit
65 /// interworking stub.
67
68 /// Write immediate value to the lower halfword of the destination register
70
71 /// Write immediate value to the top halfword of the destination register
73
75
76 ///
77 /// Relocations of class Thumb16 and Thumb32 (covers Thumb instruction subset)
78 ///
80
81 /// Write immediate value for unconditional PC-relative branch with link.
82 /// We patch the instruction opcode to account for an instruction-set state
83 /// switch: we use the bl instruction to stay in Thumb and the blx instruction
84 /// to switch to ARM.
86
87 /// Write immediate value for PC-relative branch without link. The instruction
88 /// can be made conditional by an IT block. If the branch target is not ARM,
89 /// we are forced to generate an explicit interworking stub.
91
92 /// Write immediate value to the lower halfword of the destination register
94
95 /// Write immediate value to the top halfword of the destination register
97
98 /// Write PC-relative immediate value to the lower halfword of the destination
99 /// register
101
102 /// Write PC-relative immediate value to the top halfword of the destination
103 /// register
105
107
108 /// No-op relocation
110
112};
113
114/// Flags enum for AArch32-specific symbol properties
116 ThumbSymbol = 1 << 0,
117};
118
119/// Human-readable name for a given CPU architecture kind
121
122/// Get a human-readable name for the given AArch32 edge kind.
123const char *getEdgeKindName(Edge::Kind K);
124
125/// AArch32 uses stubs for a number of purposes, like branch range extension
126/// or interworking between Arm and Thumb instruction subsets.
127///
128/// Stub implementations vary depending on CPU architecture (v4, v6, v7),
129/// instruction subset and branch type (absolute/PC-relative).
130///
131/// For each kind of stub, the StubsFlavor defines one concrete form that is
132/// used throughout the LinkGraph.
133///
134/// Stubs are often called "veneers" in the official docs and online.
135///
136enum class StubsFlavor {
137 Undefined = 0,
138 pre_v7,
139 v7,
140};
141
142/// JITLink sub-arch configuration for Arm CPU models
143struct ArmConfig {
144 bool J1J2BranchEncoding = false;
146 // In the long term, we might want a linker switch like --target1-rel
147 bool Target1Rel = false;
148};
149
150/// Obtain the sub-arch configuration for a given Arm CPU model.
152 ArmConfig ArmCfg;
153 if (CPUArch == ARMBuildAttrs::v7 || CPUArch >= ARMBuildAttrs::v7E_M) {
154 ArmCfg.J1J2BranchEncoding = true;
155 ArmCfg.Stubs = StubsFlavor::v7;
156 } else {
157 ArmCfg.J1J2BranchEncoding = false;
158 ArmCfg.Stubs = StubsFlavor::pre_v7;
159 }
160 return ArmCfg;
161}
162
163/// Immutable pair of halfwords, Hi and Lo, with overflow check
164struct HalfWords {
165 constexpr HalfWords() : Hi(0), Lo(0) {}
166 constexpr HalfWords(uint32_t Hi, uint32_t Lo) : Hi(Hi), Lo(Lo) {
167 assert(isUInt<16>(Hi) && "Overflow in first half-word");
168 assert(isUInt<16>(Lo) && "Overflow in second half-word");
169 }
170 const uint16_t Hi; // First halfword
171 const uint16_t Lo; // Second halfword
172};
173
174/// FixupInfo base class is required for dynamic lookups.
177 virtual ~FixupInfoBase() {}
178};
179
180/// FixupInfo checks for Arm edge kinds work on 32-bit words
183};
184
185/// FixupInfo check for Thumb32 edge kinds work on a pair of 16-bit halfwords
188};
189
190/// Collection of named constants per fixup kind
191///
192/// Mandatory entries:
193/// Opcode - Values of the op-code bits in the instruction, with
194/// unaffected bits nulled
195/// OpcodeMask - Mask with all bits set that encode the op-code
196///
197/// Other common entries:
198/// ImmMask - Mask with all bits set that encode the immediate value
199/// RegMask - Mask with all bits set that encode the register
200///
201/// Specializations can add further custom fields without restrictions.
202///
203template <EdgeKind_aarch32 Kind> struct FixupInfo {};
204
206 static constexpr uint32_t Opcode = 0x0a000000;
207 static constexpr uint32_t ImmMask = 0x00ffffff;
208};
209
210template <> struct FixupInfo<Arm_Jump24> : public FixupInfoArmBranch {
211 static constexpr uint32_t OpcodeMask = 0x0f000000;
212};
213
214template <> struct FixupInfo<Arm_Call> : public FixupInfoArmBranch {
215 static constexpr uint32_t OpcodeMask = 0x0e000000;
216 static constexpr uint32_t CondMask = 0xe0000000; // excluding BLX bit
217 static constexpr uint32_t Unconditional = 0xe0000000;
218 static constexpr uint32_t BitH = 0x01000000;
219 static constexpr uint32_t BitBlx = 0x10000000;
220};
221
223 static constexpr uint32_t OpcodeMask = 0x0ff00000;
224 static constexpr uint32_t ImmMask = 0x000f0fff;
225 static constexpr uint32_t RegMask = 0x0000f000;
226};
227
228template <> struct FixupInfo<Arm_MovtAbs> : public FixupInfoArmMov {
229 static constexpr uint32_t Opcode = 0x03400000;
230};
231
232template <> struct FixupInfo<Arm_MovwAbsNC> : public FixupInfoArmMov {
233 static constexpr uint32_t Opcode = 0x03000000;
234};
235
236template <> struct FixupInfo<Thumb_Jump24> : public FixupInfoThumb {
237 static constexpr HalfWords Opcode{0xf000, 0x9000};
238 static constexpr HalfWords OpcodeMask{0xf800, 0x9000};
239 static constexpr HalfWords ImmMask{0x07ff, 0x2fff};
240};
241
242template <> struct FixupInfo<Thumb_Call> : public FixupInfoThumb {
243 static constexpr HalfWords Opcode{0xf000, 0xc000};
244 static constexpr HalfWords OpcodeMask{0xf800, 0xc000};
245 static constexpr HalfWords ImmMask{0x07ff, 0x2fff};
246 static constexpr uint16_t LoBitH = 0x0001;
247 static constexpr uint16_t LoBitNoBlx = 0x1000;
248};
249
251 static constexpr HalfWords OpcodeMask{0xfbf0, 0x8000};
252 static constexpr HalfWords ImmMask{0x040f, 0x70ff};
253 static constexpr HalfWords RegMask{0x0000, 0x0f00};
254};
255
256template <> struct FixupInfo<Thumb_MovtAbs> : public FixupInfoThumbMov {
257 static constexpr HalfWords Opcode{0xf2c0, 0x0000};
258};
259
260template <> struct FixupInfo<Thumb_MovtPrel> : public FixupInfoThumbMov {
261 static constexpr HalfWords Opcode{0xf2c0, 0x0000};
262};
263
264template <> struct FixupInfo<Thumb_MovwAbsNC> : public FixupInfoThumbMov {
265 static constexpr HalfWords Opcode{0xf240, 0x0000};
266};
267
268template <> struct FixupInfo<Thumb_MovwPrelNC> : public FixupInfoThumbMov {
269 static constexpr HalfWords Opcode{0xf240, 0x0000};
270};
271
272/// Helper function to read the initial addend for Data-class relocations.
274 Edge::Kind Kind);
275
276/// Helper function to read the initial addend for Arm-class relocations.
278 Edge::Kind Kind);
279
280/// Helper function to read the initial addend for Thumb-class relocations.
282 Edge::Kind Kind, const ArmConfig &ArmCfg);
283
284/// Read the initial addend for a REL-type relocation. It's the value encoded
285/// in the immediate field of the fixup location by the compiler.
288 const ArmConfig &ArmCfg) {
289 if (Kind <= LastDataRelocation)
290 return readAddendData(G, B, Offset, Kind);
291
292 if (Kind <= LastArmRelocation)
293 return readAddendArm(G, B, Offset, Kind);
294
295 if (Kind <= LastThumbRelocation)
296 return readAddendThumb(G, B, Offset, Kind, ArmCfg);
297
298 assert(Kind == None && "Not associated with a relocation class");
299 return 0;
300}
301
302/// Helper function to apply the fixup for Data-class relocations.
304
305/// Helper function to apply the fixup for Arm-class relocations.
307
308/// Helper function to apply the fixup for Thumb-class relocations.
310 const ArmConfig &ArmCfg);
311
312/// Apply fixup expression for edge to block content.
314 const ArmConfig &ArmCfg) {
315 Edge::Kind Kind = E.getKind();
316
317 if (Kind <= LastDataRelocation)
318 return applyFixupData(G, B, E);
319
320 if (Kind <= LastArmRelocation)
321 return applyFixupArm(G, B, E);
322
323 if (Kind <= LastThumbRelocation)
324 return applyFixupThumb(G, B, E, ArmCfg);
325
326 assert(Kind == None && "Not associated with a relocation class");
327 return Error::success();
328}
329
330/// Populate a Global Offset Table from edges that request it.
331class GOTBuilder : public TableManager<GOTBuilder> {
332public:
333 static StringRef getSectionName() { return "$__GOT"; }
334
335 bool visitEdge(LinkGraph &G, Block *B, Edge &E);
337
338private:
339 Section *GOTSection = nullptr;
340};
341
342/// Stubs builder emits non-position-independent Arm stubs for pre-v7 CPUs.
343/// These architectures have no MovT/MovW instructions and don't support Thumb2.
344/// BL is the only Thumb instruction that can generate stubs and they can always
345/// be transformed into BLX.
347public:
349
350 /// Name of the object file section that will contain all our stubs.
352 return "__llvm_jitlink_aarch32_STUBS_prev7";
353 }
354
355 /// Implements link-graph traversal via visitExistingEdges()
356 bool visitEdge(LinkGraph &G, Block *B, Edge &E);
357
358private:
359 // Each stub uses a single block that can have 2 entryponts, one for Arm and
360 // one for Thumb
361 struct StubMapEntry {
362 Block *B = nullptr;
363 Symbol *ArmEntry = nullptr;
364 Symbol *ThumbEntry = nullptr;
365 };
366
367 std::pair<StubMapEntry *, bool> getStubMapSlot(StringRef Name) {
368 auto &&[Stubs, NewStub] = StubMap.try_emplace(Name);
369 return std::make_pair(&Stubs->second, NewStub);
370 }
371
372 Symbol *getOrCreateSlotEntrypoint(LinkGraph &G, StubMapEntry &Slot,
373 bool Thumb);
374
376 Section *StubsSection = nullptr;
377};
378
379/// Stubs builder for v7 emits non-position-independent Arm and Thumb stubs.
381public:
382 StubsManager_v7() = default;
383
384 /// Name of the object file section that will contain all our stubs.
386 return "__llvm_jitlink_aarch32_STUBS_v7";
387 }
388
389 /// Implements link-graph traversal via visitExistingEdges().
390 bool visitEdge(LinkGraph &G, Block *B, Edge &E);
391
392private:
393 // Two slots per external: Arm and Thumb
394 using StubMapEntry = std::tuple<Symbol *, Symbol *>;
395
396 Symbol *&getStubSymbolSlot(StringRef Name, bool Thumb) {
397 StubMapEntry &Stubs = StubMap.try_emplace(Name).first->second;
398 if (Thumb)
399 return std::get<1>(Stubs);
400 return std::get<0>(Stubs);
401 }
402
404 Section *StubsSection = nullptr;
405};
406
407} // namespace aarch32
408} // namespace jitlink
409} // namespace llvm
410
411#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")
std::string Name
Symbol * Sym
Definition: ELF_riscv.cpp:479
#define G(x, y, z)
Definition: MD5.cpp:56
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
support::ulittle32_t & Wd
Definition: aarch32.cpp:227
Lightweight error class with error context and mandatory checking.
Definition: Error.h:160
static ErrorSuccess success()
Create a success value.
Definition: Error.h:334
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.
This is an optimization pass for GlobalISel generic memory operations.
Definition: AddressRanges.h:18
@ Offset
Definition: DWP.cpp:456