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