xref: /freebsd-src/contrib/llvm-project/llvm/lib/ExecutionEngine/JITLink/aarch32.cpp (revision 5f757f3ff9144b609b3c433dfd370cc6bdc191ad)
106c3fb27SDimitry Andric //===--------- aarch32.cpp - Generic JITLink arm/thumb utilities ----------===//
206c3fb27SDimitry Andric //
306c3fb27SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
406c3fb27SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
506c3fb27SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
606c3fb27SDimitry Andric //
706c3fb27SDimitry Andric //===----------------------------------------------------------------------===//
806c3fb27SDimitry Andric //
906c3fb27SDimitry Andric // Generic utilities for graphs representing arm/thumb objects.
1006c3fb27SDimitry Andric //
1106c3fb27SDimitry Andric //===----------------------------------------------------------------------===//
1206c3fb27SDimitry Andric 
1306c3fb27SDimitry Andric #include "llvm/ExecutionEngine/JITLink/aarch32.h"
1406c3fb27SDimitry Andric 
1506c3fb27SDimitry Andric #include "llvm/ADT/StringExtras.h"
1606c3fb27SDimitry Andric #include "llvm/BinaryFormat/ELF.h"
1706c3fb27SDimitry Andric #include "llvm/ExecutionEngine/JITLink/JITLink.h"
1806c3fb27SDimitry Andric #include "llvm/Object/ELFObjectFile.h"
1906c3fb27SDimitry Andric #include "llvm/Support/Endian.h"
20*5f757f3fSDimitry Andric #include "llvm/Support/ManagedStatic.h"
2106c3fb27SDimitry Andric #include "llvm/Support/MathExtras.h"
2206c3fb27SDimitry Andric 
2306c3fb27SDimitry Andric #define DEBUG_TYPE "jitlink"
2406c3fb27SDimitry Andric 
2506c3fb27SDimitry Andric namespace llvm {
2606c3fb27SDimitry Andric namespace jitlink {
2706c3fb27SDimitry Andric namespace aarch32 {
2806c3fb27SDimitry Andric 
29*5f757f3fSDimitry Andric /// Check whether the given target flags are set for this Symbol.
30*5f757f3fSDimitry Andric bool hasTargetFlags(Symbol &Sym, TargetFlagsType Flags) {
31*5f757f3fSDimitry Andric   return static_cast<TargetFlagsType>(Sym.getTargetFlags()) & Flags;
32*5f757f3fSDimitry Andric }
33*5f757f3fSDimitry Andric 
3406c3fb27SDimitry Andric /// Encode 22-bit immediate value for branch instructions without J1J2 range
3506c3fb27SDimitry Andric /// extension (formats B T4, BL T1 and BLX T2).
3606c3fb27SDimitry Andric ///
3706c3fb27SDimitry Andric ///   00000:Imm11H:Imm11L:0 -> [ 00000:Imm11H, 00000:Imm11L ]
3806c3fb27SDimitry Andric ///                                            J1^ ^J2 will always be 1
3906c3fb27SDimitry Andric ///
4006c3fb27SDimitry Andric HalfWords encodeImmBT4BlT1BlxT2(int64_t Value) {
4106c3fb27SDimitry Andric   constexpr uint32_t J1J2 = 0x2800;
4206c3fb27SDimitry Andric   uint32_t Imm11H = (Value >> 12) & 0x07ff;
4306c3fb27SDimitry Andric   uint32_t Imm11L = (Value >> 1) & 0x07ff;
4406c3fb27SDimitry Andric   return HalfWords{Imm11H, Imm11L | J1J2};
4506c3fb27SDimitry Andric }
4606c3fb27SDimitry Andric 
4706c3fb27SDimitry Andric /// Decode 22-bit immediate value for branch instructions without J1J2 range
4806c3fb27SDimitry Andric /// extension (formats B T4, BL T1 and BLX T2).
4906c3fb27SDimitry Andric ///
5006c3fb27SDimitry Andric ///   [ 00000:Imm11H, 00000:Imm11L ] -> 00000:Imm11H:Imm11L:0
5106c3fb27SDimitry Andric ///                   J1^ ^J2 will always be 1
5206c3fb27SDimitry Andric ///
5306c3fb27SDimitry Andric int64_t decodeImmBT4BlT1BlxT2(uint32_t Hi, uint32_t Lo) {
5406c3fb27SDimitry Andric   uint32_t Imm11H = Hi & 0x07ff;
5506c3fb27SDimitry Andric   uint32_t Imm11L = Lo & 0x07ff;
5606c3fb27SDimitry Andric   return SignExtend64<22>(Imm11H << 12 | Imm11L << 1);
5706c3fb27SDimitry Andric }
5806c3fb27SDimitry Andric 
5906c3fb27SDimitry Andric /// Encode 25-bit immediate value for branch instructions with J1J2 range
6006c3fb27SDimitry Andric /// extension (formats B T4, BL T1 and BLX T2).
6106c3fb27SDimitry Andric ///
6206c3fb27SDimitry Andric ///   S:I1:I2:Imm10:Imm11:0 -> [ 00000:S:Imm10, 00:J1:0:J2:Imm11 ]
6306c3fb27SDimitry Andric ///
6406c3fb27SDimitry Andric HalfWords encodeImmBT4BlT1BlxT2_J1J2(int64_t Value) {
6506c3fb27SDimitry Andric   uint32_t S = (Value >> 14) & 0x0400;
6606c3fb27SDimitry Andric   uint32_t J1 = (((~(Value >> 10)) ^ (Value >> 11)) & 0x2000);
6706c3fb27SDimitry Andric   uint32_t J2 = (((~(Value >> 11)) ^ (Value >> 13)) & 0x0800);
6806c3fb27SDimitry Andric   uint32_t Imm10 = (Value >> 12) & 0x03ff;
6906c3fb27SDimitry Andric   uint32_t Imm11 = (Value >> 1) & 0x07ff;
7006c3fb27SDimitry Andric   return HalfWords{S | Imm10, J1 | J2 | Imm11};
7106c3fb27SDimitry Andric }
7206c3fb27SDimitry Andric 
7306c3fb27SDimitry Andric /// Decode 25-bit immediate value for branch instructions with J1J2 range
7406c3fb27SDimitry Andric /// extension (formats B T4, BL T1 and BLX T2).
7506c3fb27SDimitry Andric ///
7606c3fb27SDimitry Andric ///   [ 00000:S:Imm10, 00:J1:0:J2:Imm11] -> S:I1:I2:Imm10:Imm11:0
7706c3fb27SDimitry Andric ///
7806c3fb27SDimitry Andric int64_t decodeImmBT4BlT1BlxT2_J1J2(uint32_t Hi, uint32_t Lo) {
7906c3fb27SDimitry Andric   uint32_t S = Hi & 0x0400;
8006c3fb27SDimitry Andric   uint32_t I1 = ~((Lo ^ (Hi << 3)) << 10) & 0x00800000;
8106c3fb27SDimitry Andric   uint32_t I2 = ~((Lo ^ (Hi << 1)) << 11) & 0x00400000;
8206c3fb27SDimitry Andric   uint32_t Imm10 = Hi & 0x03ff;
8306c3fb27SDimitry Andric   uint32_t Imm11 = Lo & 0x07ff;
8406c3fb27SDimitry Andric   return SignExtend64<25>(S << 14 | I1 | I2 | Imm10 << 12 | Imm11 << 1);
8506c3fb27SDimitry Andric }
8606c3fb27SDimitry Andric 
87*5f757f3fSDimitry Andric /// Encode 26-bit immediate value for branch instructions
88*5f757f3fSDimitry Andric /// (formats B A1, BL A1 and BLX A2).
89*5f757f3fSDimitry Andric ///
90*5f757f3fSDimitry Andric ///   Imm24:00 ->  00000000:Imm24
91*5f757f3fSDimitry Andric ///
92*5f757f3fSDimitry Andric uint32_t encodeImmBA1BlA1BlxA2(int64_t Value) {
93*5f757f3fSDimitry Andric   return (Value >> 2) & 0x00ffffff;
94*5f757f3fSDimitry Andric }
95*5f757f3fSDimitry Andric 
96*5f757f3fSDimitry Andric /// Decode 26-bit immediate value for branch instructions
97*5f757f3fSDimitry Andric /// (formats B A1, BL A1 and BLX A2).
98*5f757f3fSDimitry Andric ///
99*5f757f3fSDimitry Andric ///   00000000:Imm24 ->  Imm24:00
100*5f757f3fSDimitry Andric ///
101*5f757f3fSDimitry Andric int64_t decodeImmBA1BlA1BlxA2(int64_t Value) {
102*5f757f3fSDimitry Andric   return SignExtend64<26>((Value & 0x00ffffff) << 2);
103*5f757f3fSDimitry Andric }
104*5f757f3fSDimitry Andric 
10506c3fb27SDimitry Andric /// Encode 16-bit immediate value for move instruction formats MOVT T1 and
10606c3fb27SDimitry Andric /// MOVW T3.
10706c3fb27SDimitry Andric ///
10806c3fb27SDimitry Andric ///   Imm4:Imm1:Imm3:Imm8 -> [ 00000:i:000000:Imm4, 0:Imm3:0000:Imm8 ]
10906c3fb27SDimitry Andric ///
11006c3fb27SDimitry Andric HalfWords encodeImmMovtT1MovwT3(uint16_t Value) {
11106c3fb27SDimitry Andric   uint32_t Imm4 = (Value >> 12) & 0x0f;
11206c3fb27SDimitry Andric   uint32_t Imm1 = (Value >> 11) & 0x01;
11306c3fb27SDimitry Andric   uint32_t Imm3 = (Value >> 8) & 0x07;
11406c3fb27SDimitry Andric   uint32_t Imm8 = Value & 0xff;
11506c3fb27SDimitry Andric   return HalfWords{Imm1 << 10 | Imm4, Imm3 << 12 | Imm8};
11606c3fb27SDimitry Andric }
11706c3fb27SDimitry Andric 
11806c3fb27SDimitry Andric /// Decode 16-bit immediate value from move instruction formats MOVT T1 and
11906c3fb27SDimitry Andric /// MOVW T3.
12006c3fb27SDimitry Andric ///
12106c3fb27SDimitry Andric ///   [ 00000:i:000000:Imm4, 0:Imm3:0000:Imm8 ] -> Imm4:Imm1:Imm3:Imm8
12206c3fb27SDimitry Andric ///
12306c3fb27SDimitry Andric uint16_t decodeImmMovtT1MovwT3(uint32_t Hi, uint32_t Lo) {
12406c3fb27SDimitry Andric   uint32_t Imm4 = Hi & 0x0f;
12506c3fb27SDimitry Andric   uint32_t Imm1 = (Hi >> 10) & 0x01;
12606c3fb27SDimitry Andric   uint32_t Imm3 = (Lo >> 12) & 0x07;
12706c3fb27SDimitry Andric   uint32_t Imm8 = Lo & 0xff;
12806c3fb27SDimitry Andric   uint32_t Imm16 = Imm4 << 12 | Imm1 << 11 | Imm3 << 8 | Imm8;
12906c3fb27SDimitry Andric   assert(Imm16 <= 0xffff && "Decoded value out-of-range");
13006c3fb27SDimitry Andric   return Imm16;
13106c3fb27SDimitry Andric }
13206c3fb27SDimitry Andric 
13306c3fb27SDimitry Andric /// Encode register ID for instruction formats MOVT T1 and MOVW T3.
13406c3fb27SDimitry Andric ///
13506c3fb27SDimitry Andric ///   Rd4 -> [0000000000000000, 0000:Rd4:00000000]
13606c3fb27SDimitry Andric ///
13706c3fb27SDimitry Andric HalfWords encodeRegMovtT1MovwT3(int64_t Value) {
13806c3fb27SDimitry Andric   uint32_t Rd4 = (Value & 0x0f) << 8;
13906c3fb27SDimitry Andric   return HalfWords{0, Rd4};
14006c3fb27SDimitry Andric }
14106c3fb27SDimitry Andric 
14206c3fb27SDimitry Andric /// Decode register ID from instruction formats MOVT T1 and MOVW T3.
14306c3fb27SDimitry Andric ///
14406c3fb27SDimitry Andric ///   [0000000000000000, 0000:Rd4:00000000] -> Rd4
14506c3fb27SDimitry Andric ///
14606c3fb27SDimitry Andric int64_t decodeRegMovtT1MovwT3(uint32_t Hi, uint32_t Lo) {
14706c3fb27SDimitry Andric   uint32_t Rd4 = (Lo >> 8) & 0x0f;
14806c3fb27SDimitry Andric   return Rd4;
14906c3fb27SDimitry Andric }
15006c3fb27SDimitry Andric 
151*5f757f3fSDimitry Andric /// Encode 16-bit immediate value for move instruction formats MOVT A1 and
152*5f757f3fSDimitry Andric /// MOVW A2.
153*5f757f3fSDimitry Andric ///
154*5f757f3fSDimitry Andric ///   Imm4:Imm12 -> 000000000000:Imm4:0000:Imm12
155*5f757f3fSDimitry Andric ///
156*5f757f3fSDimitry Andric uint32_t encodeImmMovtA1MovwA2(uint16_t Value) {
157*5f757f3fSDimitry Andric   uint32_t Imm4 = (Value >> 12) & 0x0f;
158*5f757f3fSDimitry Andric   uint32_t Imm12 = Value & 0x0fff;
159*5f757f3fSDimitry Andric   return (Imm4 << 16) | Imm12;
160*5f757f3fSDimitry Andric }
161*5f757f3fSDimitry Andric 
162*5f757f3fSDimitry Andric /// Decode 16-bit immediate value for move instruction formats MOVT A1 and
163*5f757f3fSDimitry Andric /// MOVW A2.
164*5f757f3fSDimitry Andric ///
165*5f757f3fSDimitry Andric ///   000000000000:Imm4:0000:Imm12 -> Imm4:Imm12
166*5f757f3fSDimitry Andric ///
167*5f757f3fSDimitry Andric uint16_t decodeImmMovtA1MovwA2(uint64_t Value) {
168*5f757f3fSDimitry Andric   uint32_t Imm4 = (Value >> 16) & 0x0f;
169*5f757f3fSDimitry Andric   uint32_t Imm12 = Value & 0x0fff;
170*5f757f3fSDimitry Andric   return (Imm4 << 12) | Imm12;
171*5f757f3fSDimitry Andric }
172*5f757f3fSDimitry Andric 
173*5f757f3fSDimitry Andric /// Encode register ID for instruction formats MOVT A1 and
174*5f757f3fSDimitry Andric /// MOVW A2.
175*5f757f3fSDimitry Andric ///
176*5f757f3fSDimitry Andric ///   Rd4 -> 0000000000000000:Rd4:000000000000
177*5f757f3fSDimitry Andric ///
178*5f757f3fSDimitry Andric uint32_t encodeRegMovtA1MovwA2(int64_t Value) {
179*5f757f3fSDimitry Andric   uint32_t Rd4 = (Value & 0x00000f) << 12;
180*5f757f3fSDimitry Andric   return Rd4;
181*5f757f3fSDimitry Andric }
182*5f757f3fSDimitry Andric 
183*5f757f3fSDimitry Andric /// Decode register ID for instruction formats MOVT A1 and
184*5f757f3fSDimitry Andric /// MOVW A2.
185*5f757f3fSDimitry Andric ///
186*5f757f3fSDimitry Andric ///   0000000000000000:Rd4:000000000000 -> Rd4
187*5f757f3fSDimitry Andric ///
188*5f757f3fSDimitry Andric int64_t decodeRegMovtA1MovwA2(uint64_t Value) {
189*5f757f3fSDimitry Andric   uint32_t Rd4 = (Value >> 12) & 0x00000f;
190*5f757f3fSDimitry Andric   return Rd4;
191*5f757f3fSDimitry Andric }
192*5f757f3fSDimitry Andric 
193*5f757f3fSDimitry Andric namespace {
194*5f757f3fSDimitry Andric 
19506c3fb27SDimitry Andric /// 32-bit Thumb instructions are stored as two little-endian halfwords.
19606c3fb27SDimitry Andric /// An instruction at address A encodes bytes A+1, A in the first halfword (Hi),
19706c3fb27SDimitry Andric /// followed by bytes A+3, A+2 in the second halfword (Lo).
19806c3fb27SDimitry Andric struct WritableThumbRelocation {
19906c3fb27SDimitry Andric   /// Create a writable reference to a Thumb32 fixup.
20006c3fb27SDimitry Andric   WritableThumbRelocation(char *FixupPtr)
20106c3fb27SDimitry Andric       : Hi{*reinterpret_cast<support::ulittle16_t *>(FixupPtr)},
20206c3fb27SDimitry Andric         Lo{*reinterpret_cast<support::ulittle16_t *>(FixupPtr + 2)} {}
20306c3fb27SDimitry Andric 
20406c3fb27SDimitry Andric   support::ulittle16_t &Hi; // First halfword
20506c3fb27SDimitry Andric   support::ulittle16_t &Lo; // Second halfword
20606c3fb27SDimitry Andric };
20706c3fb27SDimitry Andric 
20806c3fb27SDimitry Andric struct ThumbRelocation {
20906c3fb27SDimitry Andric   /// Create a read-only reference to a Thumb32 fixup.
21006c3fb27SDimitry Andric   ThumbRelocation(const char *FixupPtr)
21106c3fb27SDimitry Andric       : Hi{*reinterpret_cast<const support::ulittle16_t *>(FixupPtr)},
21206c3fb27SDimitry Andric         Lo{*reinterpret_cast<const support::ulittle16_t *>(FixupPtr + 2)} {}
21306c3fb27SDimitry Andric 
21406c3fb27SDimitry Andric   /// Create a read-only Thumb32 fixup from a writeable one.
21506c3fb27SDimitry Andric   ThumbRelocation(WritableThumbRelocation &Writable)
21606c3fb27SDimitry Andric       : Hi{Writable.Hi}, Lo(Writable.Lo) {}
21706c3fb27SDimitry Andric 
21806c3fb27SDimitry Andric   const support::ulittle16_t &Hi; // First halfword
21906c3fb27SDimitry Andric   const support::ulittle16_t &Lo; // Second halfword
22006c3fb27SDimitry Andric };
22106c3fb27SDimitry Andric 
222*5f757f3fSDimitry Andric struct WritableArmRelocation {
223*5f757f3fSDimitry Andric   WritableArmRelocation(char *FixupPtr)
224*5f757f3fSDimitry Andric       : Wd{*reinterpret_cast<support::ulittle32_t *>(FixupPtr)} {}
225*5f757f3fSDimitry Andric 
226*5f757f3fSDimitry Andric   support::ulittle32_t &Wd;
227*5f757f3fSDimitry Andric };
228*5f757f3fSDimitry Andric 
229*5f757f3fSDimitry Andric struct ArmRelocation {
230*5f757f3fSDimitry Andric   ArmRelocation(const char *FixupPtr)
231*5f757f3fSDimitry Andric       : Wd{*reinterpret_cast<const support::ulittle32_t *>(FixupPtr)} {}
232*5f757f3fSDimitry Andric 
233*5f757f3fSDimitry Andric   ArmRelocation(WritableArmRelocation &Writable) : Wd{Writable.Wd} {}
234*5f757f3fSDimitry Andric 
235*5f757f3fSDimitry Andric   const support::ulittle32_t &Wd;
236*5f757f3fSDimitry Andric };
237*5f757f3fSDimitry Andric 
23806c3fb27SDimitry Andric Error makeUnexpectedOpcodeError(const LinkGraph &G, const ThumbRelocation &R,
23906c3fb27SDimitry Andric                                 Edge::Kind Kind) {
24006c3fb27SDimitry Andric   return make_error<JITLinkError>(
241*5f757f3fSDimitry Andric       formatv("Invalid opcode [ {0:x4}, {1:x4} ] for relocation: {2}",
24206c3fb27SDimitry Andric               static_cast<uint16_t>(R.Hi), static_cast<uint16_t>(R.Lo),
24306c3fb27SDimitry Andric               G.getEdgeKindName(Kind)));
24406c3fb27SDimitry Andric }
24506c3fb27SDimitry Andric 
246*5f757f3fSDimitry Andric Error makeUnexpectedOpcodeError(const LinkGraph &G, const ArmRelocation &R,
247*5f757f3fSDimitry Andric                                 Edge::Kind Kind) {
248*5f757f3fSDimitry Andric   return make_error<JITLinkError>(
249*5f757f3fSDimitry Andric       formatv("Invalid opcode {0:x8} for relocation: {1}",
250*5f757f3fSDimitry Andric               static_cast<uint32_t>(R.Wd), G.getEdgeKindName(Kind)));
251*5f757f3fSDimitry Andric }
252*5f757f3fSDimitry Andric 
253*5f757f3fSDimitry Andric template <EdgeKind_aarch32 K> constexpr bool isArm() {
254*5f757f3fSDimitry Andric   return FirstArmRelocation <= K && K <= LastArmRelocation;
255*5f757f3fSDimitry Andric }
256*5f757f3fSDimitry Andric template <EdgeKind_aarch32 K> constexpr bool isThumb() {
257*5f757f3fSDimitry Andric   return FirstThumbRelocation <= K && K <= LastThumbRelocation;
258*5f757f3fSDimitry Andric }
259*5f757f3fSDimitry Andric 
260*5f757f3fSDimitry Andric template <EdgeKind_aarch32 K> static bool checkOpcodeArm(uint32_t Wd) {
261*5f757f3fSDimitry Andric   return (Wd & FixupInfo<K>::OpcodeMask) == FixupInfo<K>::Opcode;
262*5f757f3fSDimitry Andric }
263*5f757f3fSDimitry Andric 
264*5f757f3fSDimitry Andric template <EdgeKind_aarch32 K>
265*5f757f3fSDimitry Andric static bool checkOpcodeThumb(uint16_t Hi, uint16_t Lo) {
266*5f757f3fSDimitry Andric   return (Hi & FixupInfo<K>::OpcodeMask.Hi) == FixupInfo<K>::Opcode.Hi &&
267*5f757f3fSDimitry Andric          (Lo & FixupInfo<K>::OpcodeMask.Lo) == FixupInfo<K>::Opcode.Lo;
268*5f757f3fSDimitry Andric }
269*5f757f3fSDimitry Andric 
270*5f757f3fSDimitry Andric class FixupInfoTable {
271*5f757f3fSDimitry Andric   static constexpr size_t Items = LastRelocation + 1;
272*5f757f3fSDimitry Andric 
273*5f757f3fSDimitry Andric public:
274*5f757f3fSDimitry Andric   FixupInfoTable() {
275*5f757f3fSDimitry Andric     populateEntries<FirstArmRelocation, LastArmRelocation>();
276*5f757f3fSDimitry Andric     populateEntries<FirstThumbRelocation, LastThumbRelocation>();
277*5f757f3fSDimitry Andric   }
278*5f757f3fSDimitry Andric 
279*5f757f3fSDimitry Andric   const FixupInfoBase *getEntry(Edge::Kind K) {
280*5f757f3fSDimitry Andric     assert(K < Data.size() && "Index out of bounds");
281*5f757f3fSDimitry Andric     return Data.at(K).get();
282*5f757f3fSDimitry Andric   }
283*5f757f3fSDimitry Andric 
284*5f757f3fSDimitry Andric private:
285*5f757f3fSDimitry Andric   template <EdgeKind_aarch32 K, EdgeKind_aarch32 LastK> void populateEntries() {
286*5f757f3fSDimitry Andric     assert(K < Data.size() && "Index out of range");
287*5f757f3fSDimitry Andric     assert(Data.at(K) == nullptr && "Initialized entries are immutable");
288*5f757f3fSDimitry Andric     Data[K] = initEntry<K>();
289*5f757f3fSDimitry Andric     if constexpr (K < LastK) {
290*5f757f3fSDimitry Andric       constexpr auto Next = static_cast<EdgeKind_aarch32>(K + 1);
291*5f757f3fSDimitry Andric       populateEntries<Next, LastK>();
292*5f757f3fSDimitry Andric     }
293*5f757f3fSDimitry Andric   }
294*5f757f3fSDimitry Andric 
295*5f757f3fSDimitry Andric   template <EdgeKind_aarch32 K>
296*5f757f3fSDimitry Andric   static std::unique_ptr<FixupInfoBase> initEntry() {
297*5f757f3fSDimitry Andric     auto Entry = std::make_unique<FixupInfo<K>>();
298*5f757f3fSDimitry Andric     static_assert(isArm<K>() != isThumb<K>(), "Classes are mutually exclusive");
299*5f757f3fSDimitry Andric     if constexpr (isArm<K>())
300*5f757f3fSDimitry Andric       Entry->checkOpcode = checkOpcodeArm<K>;
301*5f757f3fSDimitry Andric     if constexpr (isThumb<K>())
302*5f757f3fSDimitry Andric       Entry->checkOpcode = checkOpcodeThumb<K>;
303*5f757f3fSDimitry Andric     return Entry;
304*5f757f3fSDimitry Andric   }
305*5f757f3fSDimitry Andric 
306*5f757f3fSDimitry Andric private:
307*5f757f3fSDimitry Andric   std::array<std::unique_ptr<FixupInfoBase>, Items> Data;
308*5f757f3fSDimitry Andric };
309*5f757f3fSDimitry Andric 
310*5f757f3fSDimitry Andric ManagedStatic<FixupInfoTable> DynFixupInfos;
311*5f757f3fSDimitry Andric 
312*5f757f3fSDimitry Andric } // namespace
313*5f757f3fSDimitry Andric 
314*5f757f3fSDimitry Andric static Error checkOpcode(LinkGraph &G, const ArmRelocation &R,
315*5f757f3fSDimitry Andric                          Edge::Kind Kind) {
316*5f757f3fSDimitry Andric   assert(Kind >= FirstArmRelocation && Kind <= LastArmRelocation &&
317*5f757f3fSDimitry Andric          "Edge kind must be Arm relocation");
318*5f757f3fSDimitry Andric   const FixupInfoBase *Entry = DynFixupInfos->getEntry(Kind);
319*5f757f3fSDimitry Andric   const FixupInfoArm &Info = *static_cast<const FixupInfoArm *>(Entry);
320*5f757f3fSDimitry Andric   assert(Info.checkOpcode && "Opcode check is mandatory for Arm edges");
321*5f757f3fSDimitry Andric   if (!Info.checkOpcode(R.Wd))
322*5f757f3fSDimitry Andric     return makeUnexpectedOpcodeError(G, R, Kind);
323*5f757f3fSDimitry Andric 
324*5f757f3fSDimitry Andric   return Error::success();
325*5f757f3fSDimitry Andric }
326*5f757f3fSDimitry Andric 
327*5f757f3fSDimitry Andric static Error checkOpcode(LinkGraph &G, const ThumbRelocation &R,
328*5f757f3fSDimitry Andric                          Edge::Kind Kind) {
329*5f757f3fSDimitry Andric   assert(Kind >= FirstThumbRelocation && Kind <= LastThumbRelocation &&
330*5f757f3fSDimitry Andric          "Edge kind must be Thumb relocation");
331*5f757f3fSDimitry Andric   const FixupInfoBase *Entry = DynFixupInfos->getEntry(Kind);
332*5f757f3fSDimitry Andric   const FixupInfoThumb &Info = *static_cast<const FixupInfoThumb *>(Entry);
333*5f757f3fSDimitry Andric   assert(Info.checkOpcode && "Opcode check is mandatory for Thumb edges");
334*5f757f3fSDimitry Andric   if (!Info.checkOpcode(R.Hi, R.Lo))
335*5f757f3fSDimitry Andric     return makeUnexpectedOpcodeError(G, R, Kind);
336*5f757f3fSDimitry Andric 
337*5f757f3fSDimitry Andric   return Error::success();
338*5f757f3fSDimitry Andric }
339*5f757f3fSDimitry Andric 
340*5f757f3fSDimitry Andric const FixupInfoBase *FixupInfoBase::getDynFixupInfo(Edge::Kind K) {
341*5f757f3fSDimitry Andric   return DynFixupInfos->getEntry(K);
34206c3fb27SDimitry Andric }
34306c3fb27SDimitry Andric 
34406c3fb27SDimitry Andric template <EdgeKind_aarch32 Kind>
34506c3fb27SDimitry Andric bool checkRegister(const ThumbRelocation &R, HalfWords Reg) {
34606c3fb27SDimitry Andric   uint16_t Hi = R.Hi & FixupInfo<Kind>::RegMask.Hi;
34706c3fb27SDimitry Andric   uint16_t Lo = R.Lo & FixupInfo<Kind>::RegMask.Lo;
34806c3fb27SDimitry Andric   return Hi == Reg.Hi && Lo == Reg.Lo;
34906c3fb27SDimitry Andric }
35006c3fb27SDimitry Andric 
35106c3fb27SDimitry Andric template <EdgeKind_aarch32 Kind>
352*5f757f3fSDimitry Andric bool checkRegister(const ArmRelocation &R, uint32_t Reg) {
353*5f757f3fSDimitry Andric   uint32_t Wd = R.Wd & FixupInfo<Kind>::RegMask;
354*5f757f3fSDimitry Andric   return Wd == Reg;
355*5f757f3fSDimitry Andric }
356*5f757f3fSDimitry Andric 
357*5f757f3fSDimitry Andric template <EdgeKind_aarch32 Kind>
3585c16e71dSDimitry Andric void writeRegister(WritableThumbRelocation &R, HalfWords Reg) {
35906c3fb27SDimitry Andric   static constexpr HalfWords Mask = FixupInfo<Kind>::RegMask;
360*5f757f3fSDimitry Andric   assert((Mask.Hi & Reg.Hi) == Reg.Hi && (Mask.Lo & Reg.Lo) == Reg.Lo &&
36106c3fb27SDimitry Andric          "Value bits exceed bit range of given mask");
36206c3fb27SDimitry Andric   R.Hi = (R.Hi & ~Mask.Hi) | Reg.Hi;
36306c3fb27SDimitry Andric   R.Lo = (R.Lo & ~Mask.Lo) | Reg.Lo;
36406c3fb27SDimitry Andric }
36506c3fb27SDimitry Andric 
36606c3fb27SDimitry Andric template <EdgeKind_aarch32 Kind>
367*5f757f3fSDimitry Andric void writeRegister(WritableArmRelocation &R, uint32_t Reg) {
368*5f757f3fSDimitry Andric   static constexpr uint32_t Mask = FixupInfo<Kind>::RegMask;
369*5f757f3fSDimitry Andric   assert((Mask & Reg) == Reg && "Value bits exceed bit range of given mask");
370*5f757f3fSDimitry Andric   R.Wd = (R.Wd & ~Mask) | Reg;
371*5f757f3fSDimitry Andric }
372*5f757f3fSDimitry Andric 
373*5f757f3fSDimitry Andric template <EdgeKind_aarch32 Kind>
37406c3fb27SDimitry Andric void writeImmediate(WritableThumbRelocation &R, HalfWords Imm) {
37506c3fb27SDimitry Andric   static constexpr HalfWords Mask = FixupInfo<Kind>::ImmMask;
376*5f757f3fSDimitry Andric   assert((Mask.Hi & Imm.Hi) == Imm.Hi && (Mask.Lo & Imm.Lo) == Imm.Lo &&
37706c3fb27SDimitry Andric          "Value bits exceed bit range of given mask");
37806c3fb27SDimitry Andric   R.Hi = (R.Hi & ~Mask.Hi) | Imm.Hi;
37906c3fb27SDimitry Andric   R.Lo = (R.Lo & ~Mask.Lo) | Imm.Lo;
38006c3fb27SDimitry Andric }
38106c3fb27SDimitry Andric 
382*5f757f3fSDimitry Andric template <EdgeKind_aarch32 Kind>
383*5f757f3fSDimitry Andric void writeImmediate(WritableArmRelocation &R, uint32_t Imm) {
384*5f757f3fSDimitry Andric   static constexpr uint32_t Mask = FixupInfo<Kind>::ImmMask;
385*5f757f3fSDimitry Andric   assert((Mask & Imm) == Imm && "Value bits exceed bit range of given mask");
386*5f757f3fSDimitry Andric   R.Wd = (R.Wd & ~Mask) | Imm;
387*5f757f3fSDimitry Andric }
38806c3fb27SDimitry Andric 
389*5f757f3fSDimitry Andric Expected<int64_t> readAddendData(LinkGraph &G, Block &B, Edge::OffsetT Offset,
390*5f757f3fSDimitry Andric                                  Edge::Kind Kind) {
391*5f757f3fSDimitry Andric   endianness Endian = G.getEndianness();
39206c3fb27SDimitry Andric   const char *BlockWorkingMem = B.getContent().data();
393*5f757f3fSDimitry Andric   const char *FixupPtr = BlockWorkingMem + Offset;
39406c3fb27SDimitry Andric 
39506c3fb27SDimitry Andric   switch (Kind) {
39606c3fb27SDimitry Andric   case Data_Delta32:
39706c3fb27SDimitry Andric   case Data_Pointer32:
39806c3fb27SDimitry Andric     return SignExtend64<32>(support::endian::read32(FixupPtr, Endian));
39906c3fb27SDimitry Andric   default:
40006c3fb27SDimitry Andric     return make_error<JITLinkError>(
40106c3fb27SDimitry Andric         "In graph " + G.getName() + ", section " + B.getSection().getName() +
40206c3fb27SDimitry Andric         " can not read implicit addend for aarch32 edge kind " +
403*5f757f3fSDimitry Andric         G.getEdgeKindName(Kind));
40406c3fb27SDimitry Andric   }
40506c3fb27SDimitry Andric }
40606c3fb27SDimitry Andric 
407*5f757f3fSDimitry Andric Expected<int64_t> readAddendArm(LinkGraph &G, Block &B, Edge::OffsetT Offset,
408*5f757f3fSDimitry Andric                                 Edge::Kind Kind) {
409*5f757f3fSDimitry Andric   ArmRelocation R(B.getContent().data() + Offset);
410*5f757f3fSDimitry Andric   if (Error Err = checkOpcode(G, R, Kind))
411*5f757f3fSDimitry Andric     return std::move(Err);
41206c3fb27SDimitry Andric 
41306c3fb27SDimitry Andric   switch (Kind) {
41406c3fb27SDimitry Andric   case Arm_Call:
415*5f757f3fSDimitry Andric   case Arm_Jump24:
416*5f757f3fSDimitry Andric     return decodeImmBA1BlA1BlxA2(R.Wd);
417*5f757f3fSDimitry Andric 
418*5f757f3fSDimitry Andric   case Arm_MovtAbs:
419*5f757f3fSDimitry Andric   case Arm_MovwAbsNC:
420*5f757f3fSDimitry Andric     return decodeImmMovtA1MovwA2(R.Wd);
421*5f757f3fSDimitry Andric 
42206c3fb27SDimitry Andric   default:
42306c3fb27SDimitry Andric     return make_error<JITLinkError>(
42406c3fb27SDimitry Andric         "In graph " + G.getName() + ", section " + B.getSection().getName() +
42506c3fb27SDimitry Andric         " can not read implicit addend for aarch32 edge kind " +
426*5f757f3fSDimitry Andric         G.getEdgeKindName(Kind));
42706c3fb27SDimitry Andric   }
42806c3fb27SDimitry Andric }
42906c3fb27SDimitry Andric 
430*5f757f3fSDimitry Andric Expected<int64_t> readAddendThumb(LinkGraph &G, Block &B, Edge::OffsetT Offset,
431*5f757f3fSDimitry Andric                                   Edge::Kind Kind, const ArmConfig &ArmCfg) {
432*5f757f3fSDimitry Andric   ThumbRelocation R(B.getContent().data() + Offset);
433*5f757f3fSDimitry Andric   if (Error Err = checkOpcode(G, R, Kind))
434*5f757f3fSDimitry Andric     return std::move(Err);
43506c3fb27SDimitry Andric 
43606c3fb27SDimitry Andric   switch (Kind) {
43706c3fb27SDimitry Andric   case Thumb_Call:
43806c3fb27SDimitry Andric   case Thumb_Jump24:
43906c3fb27SDimitry Andric     return LLVM_LIKELY(ArmCfg.J1J2BranchEncoding)
44006c3fb27SDimitry Andric                ? decodeImmBT4BlT1BlxT2_J1J2(R.Hi, R.Lo)
44106c3fb27SDimitry Andric                : decodeImmBT4BlT1BlxT2(R.Hi, R.Lo);
44206c3fb27SDimitry Andric 
44306c3fb27SDimitry Andric   case Thumb_MovwAbsNC:
444*5f757f3fSDimitry Andric   case Thumb_MovwPrelNC:
44506c3fb27SDimitry Andric     // Initial addend is interpreted as a signed value
44606c3fb27SDimitry Andric     return SignExtend64<16>(decodeImmMovtT1MovwT3(R.Hi, R.Lo));
44706c3fb27SDimitry Andric 
44806c3fb27SDimitry Andric   case Thumb_MovtAbs:
449*5f757f3fSDimitry Andric   case Thumb_MovtPrel:
45006c3fb27SDimitry Andric     // Initial addend is interpreted as a signed value
45106c3fb27SDimitry Andric     return SignExtend64<16>(decodeImmMovtT1MovwT3(R.Hi, R.Lo));
45206c3fb27SDimitry Andric 
45306c3fb27SDimitry Andric   default:
45406c3fb27SDimitry Andric     return make_error<JITLinkError>(
45506c3fb27SDimitry Andric         "In graph " + G.getName() + ", section " + B.getSection().getName() +
45606c3fb27SDimitry Andric         " can not read implicit addend for aarch32 edge kind " +
457*5f757f3fSDimitry Andric         G.getEdgeKindName(Kind));
45806c3fb27SDimitry Andric   }
45906c3fb27SDimitry Andric }
46006c3fb27SDimitry Andric 
46106c3fb27SDimitry Andric Error applyFixupData(LinkGraph &G, Block &B, const Edge &E) {
46206c3fb27SDimitry Andric   using namespace support;
46306c3fb27SDimitry Andric 
46406c3fb27SDimitry Andric   char *BlockWorkingMem = B.getAlreadyMutableContent().data();
46506c3fb27SDimitry Andric   char *FixupPtr = BlockWorkingMem + E.getOffset();
46606c3fb27SDimitry Andric 
46706c3fb27SDimitry Andric   auto Write32 = [FixupPtr, Endian = G.getEndianness()](int64_t Value) {
46806c3fb27SDimitry Andric     assert(isInt<32>(Value) && "Must be in signed 32-bit range");
46906c3fb27SDimitry Andric     uint32_t Imm = static_cast<int32_t>(Value);
470*5f757f3fSDimitry Andric     if (LLVM_LIKELY(Endian == endianness::little))
471*5f757f3fSDimitry Andric       endian::write32<endianness::little>(FixupPtr, Imm);
47206c3fb27SDimitry Andric     else
473*5f757f3fSDimitry Andric       endian::write32<endianness::big>(FixupPtr, Imm);
47406c3fb27SDimitry Andric   };
47506c3fb27SDimitry Andric 
47606c3fb27SDimitry Andric   Edge::Kind Kind = E.getKind();
47706c3fb27SDimitry Andric   uint64_t FixupAddress = (B.getAddress() + E.getOffset()).getValue();
47806c3fb27SDimitry Andric   int64_t Addend = E.getAddend();
47906c3fb27SDimitry Andric   Symbol &TargetSymbol = E.getTarget();
48006c3fb27SDimitry Andric   uint64_t TargetAddress = TargetSymbol.getAddress().getValue();
48106c3fb27SDimitry Andric 
48206c3fb27SDimitry Andric   // Regular data relocations have size 4, alignment 1 and write the full 32-bit
48306c3fb27SDimitry Andric   // result to the place; no need for overflow checking. There are three
48406c3fb27SDimitry Andric   // exceptions: R_ARM_ABS8, R_ARM_ABS16, R_ARM_PREL31
48506c3fb27SDimitry Andric   switch (Kind) {
48606c3fb27SDimitry Andric   case Data_Delta32: {
48706c3fb27SDimitry Andric     int64_t Value = TargetAddress - FixupAddress + Addend;
48806c3fb27SDimitry Andric     if (!isInt<32>(Value))
48906c3fb27SDimitry Andric       return makeTargetOutOfRangeError(G, B, E);
49006c3fb27SDimitry Andric     Write32(Value);
49106c3fb27SDimitry Andric     return Error::success();
49206c3fb27SDimitry Andric   }
49306c3fb27SDimitry Andric   case Data_Pointer32: {
49406c3fb27SDimitry Andric     int64_t Value = TargetAddress + Addend;
49506c3fb27SDimitry Andric     if (!isInt<32>(Value))
49606c3fb27SDimitry Andric       return makeTargetOutOfRangeError(G, B, E);
49706c3fb27SDimitry Andric     Write32(Value);
49806c3fb27SDimitry Andric     return Error::success();
49906c3fb27SDimitry Andric   }
50006c3fb27SDimitry Andric   default:
50106c3fb27SDimitry Andric     return make_error<JITLinkError>(
50206c3fb27SDimitry Andric         "In graph " + G.getName() + ", section " + B.getSection().getName() +
50306c3fb27SDimitry Andric         " encountered unfixable aarch32 edge kind " +
50406c3fb27SDimitry Andric         G.getEdgeKindName(E.getKind()));
50506c3fb27SDimitry Andric   }
50606c3fb27SDimitry Andric }
50706c3fb27SDimitry Andric 
50806c3fb27SDimitry Andric Error applyFixupArm(LinkGraph &G, Block &B, const Edge &E) {
509*5f757f3fSDimitry Andric   WritableArmRelocation R(B.getAlreadyMutableContent().data() + E.getOffset());
51006c3fb27SDimitry Andric   Edge::Kind Kind = E.getKind();
511*5f757f3fSDimitry Andric   if (Error Err = checkOpcode(G, R, Kind))
512*5f757f3fSDimitry Andric     return Err;
513*5f757f3fSDimitry Andric 
514*5f757f3fSDimitry Andric   uint64_t FixupAddress = (B.getAddress() + E.getOffset()).getValue();
515*5f757f3fSDimitry Andric   int64_t Addend = E.getAddend();
516*5f757f3fSDimitry Andric   Symbol &TargetSymbol = E.getTarget();
517*5f757f3fSDimitry Andric   uint64_t TargetAddress = TargetSymbol.getAddress().getValue();
51806c3fb27SDimitry Andric 
51906c3fb27SDimitry Andric   switch (Kind) {
520*5f757f3fSDimitry Andric   case Arm_Jump24: {
521*5f757f3fSDimitry Andric     if (hasTargetFlags(TargetSymbol, ThumbSymbol))
522*5f757f3fSDimitry Andric       return make_error<JITLinkError>("Branch relocation needs interworking "
523*5f757f3fSDimitry Andric                                       "stub when bridging to Thumb: " +
52406c3fb27SDimitry Andric                                       StringRef(G.getEdgeKindName(Kind)));
525*5f757f3fSDimitry Andric 
526*5f757f3fSDimitry Andric     int64_t Value = TargetAddress - FixupAddress + Addend;
527*5f757f3fSDimitry Andric 
528*5f757f3fSDimitry Andric     if (!isInt<26>(Value))
529*5f757f3fSDimitry Andric       return makeTargetOutOfRangeError(G, B, E);
530*5f757f3fSDimitry Andric     writeImmediate<Arm_Jump24>(R, encodeImmBA1BlA1BlxA2(Value));
531*5f757f3fSDimitry Andric 
532*5f757f3fSDimitry Andric     return Error::success();
533*5f757f3fSDimitry Andric   }
534*5f757f3fSDimitry Andric   case Arm_Call: {
535*5f757f3fSDimitry Andric     if ((R.Wd & FixupInfo<Arm_Call>::CondMask) !=
536*5f757f3fSDimitry Andric         FixupInfo<Arm_Call>::Unconditional)
537*5f757f3fSDimitry Andric       return make_error<JITLinkError>("Relocation expects an unconditional "
538*5f757f3fSDimitry Andric                                       "BL/BLX branch instruction: " +
539*5f757f3fSDimitry Andric                                       StringRef(G.getEdgeKindName(Kind)));
540*5f757f3fSDimitry Andric 
541*5f757f3fSDimitry Andric     int64_t Value = TargetAddress - FixupAddress + Addend;
542*5f757f3fSDimitry Andric 
543*5f757f3fSDimitry Andric     // The call instruction itself is Arm. The call destination can either be
544*5f757f3fSDimitry Andric     // Thumb or Arm. We use BL to stay in Arm and BLX to change to Thumb.
545*5f757f3fSDimitry Andric     bool TargetIsThumb = hasTargetFlags(TargetSymbol, ThumbSymbol);
546*5f757f3fSDimitry Andric     bool InstrIsBlx = (~R.Wd & FixupInfo<Arm_Call>::BitBlx) == 0;
547*5f757f3fSDimitry Andric     if (TargetIsThumb != InstrIsBlx) {
548*5f757f3fSDimitry Andric       if (LLVM_LIKELY(TargetIsThumb)) {
549*5f757f3fSDimitry Andric         // Change opcode BL -> BLX
550*5f757f3fSDimitry Andric         R.Wd = R.Wd | FixupInfo<Arm_Call>::BitBlx;
551*5f757f3fSDimitry Andric         R.Wd = R.Wd & ~FixupInfo<Arm_Call>::BitH;
552*5f757f3fSDimitry Andric       } else {
553*5f757f3fSDimitry Andric         // Change opcode BLX -> BL
554*5f757f3fSDimitry Andric         R.Wd = R.Wd & ~FixupInfo<Arm_Call>::BitBlx;
555*5f757f3fSDimitry Andric       }
556*5f757f3fSDimitry Andric     }
557*5f757f3fSDimitry Andric 
558*5f757f3fSDimitry Andric     if (!isInt<26>(Value))
559*5f757f3fSDimitry Andric       return makeTargetOutOfRangeError(G, B, E);
560*5f757f3fSDimitry Andric     writeImmediate<Arm_Call>(R, encodeImmBA1BlA1BlxA2(Value));
561*5f757f3fSDimitry Andric 
562*5f757f3fSDimitry Andric     return Error::success();
563*5f757f3fSDimitry Andric   }
564*5f757f3fSDimitry Andric   case Arm_MovwAbsNC: {
565*5f757f3fSDimitry Andric     uint16_t Value = (TargetAddress + Addend) & 0xffff;
566*5f757f3fSDimitry Andric     writeImmediate<Arm_MovwAbsNC>(R, encodeImmMovtA1MovwA2(Value));
567*5f757f3fSDimitry Andric     return Error::success();
568*5f757f3fSDimitry Andric   }
569*5f757f3fSDimitry Andric   case Arm_MovtAbs: {
570*5f757f3fSDimitry Andric     uint16_t Value = ((TargetAddress + Addend) >> 16) & 0xffff;
571*5f757f3fSDimitry Andric     writeImmediate<Arm_MovtAbs>(R, encodeImmMovtA1MovwA2(Value));
572*5f757f3fSDimitry Andric     return Error::success();
573*5f757f3fSDimitry Andric   }
57406c3fb27SDimitry Andric   default:
57506c3fb27SDimitry Andric     return make_error<JITLinkError>(
57606c3fb27SDimitry Andric         "In graph " + G.getName() + ", section " + B.getSection().getName() +
57706c3fb27SDimitry Andric         " encountered unfixable aarch32 edge kind " +
57806c3fb27SDimitry Andric         G.getEdgeKindName(E.getKind()));
57906c3fb27SDimitry Andric   }
58006c3fb27SDimitry Andric }
58106c3fb27SDimitry Andric 
58206c3fb27SDimitry Andric Error applyFixupThumb(LinkGraph &G, Block &B, const Edge &E,
58306c3fb27SDimitry Andric                       const ArmConfig &ArmCfg) {
58406c3fb27SDimitry Andric   WritableThumbRelocation R(B.getAlreadyMutableContent().data() +
58506c3fb27SDimitry Andric                             E.getOffset());
58606c3fb27SDimitry Andric   Edge::Kind Kind = E.getKind();
587*5f757f3fSDimitry Andric   if (Error Err = checkOpcode(G, R, Kind))
588*5f757f3fSDimitry Andric     return Err;
589*5f757f3fSDimitry Andric 
59006c3fb27SDimitry Andric   uint64_t FixupAddress = (B.getAddress() + E.getOffset()).getValue();
59106c3fb27SDimitry Andric   int64_t Addend = E.getAddend();
59206c3fb27SDimitry Andric   Symbol &TargetSymbol = E.getTarget();
59306c3fb27SDimitry Andric   uint64_t TargetAddress = TargetSymbol.getAddress().getValue();
59406c3fb27SDimitry Andric 
59506c3fb27SDimitry Andric   switch (Kind) {
59606c3fb27SDimitry Andric   case Thumb_Jump24: {
597*5f757f3fSDimitry Andric     if (!hasTargetFlags(TargetSymbol, ThumbSymbol))
59806c3fb27SDimitry Andric       return make_error<JITLinkError>("Branch relocation needs interworking "
59906c3fb27SDimitry Andric                                       "stub when bridging to ARM: " +
60006c3fb27SDimitry Andric                                       StringRef(G.getEdgeKindName(Kind)));
60106c3fb27SDimitry Andric 
60206c3fb27SDimitry Andric     int64_t Value = TargetAddress - FixupAddress + Addend;
60306c3fb27SDimitry Andric     if (LLVM_LIKELY(ArmCfg.J1J2BranchEncoding)) {
60406c3fb27SDimitry Andric       if (!isInt<25>(Value))
60506c3fb27SDimitry Andric         return makeTargetOutOfRangeError(G, B, E);
60606c3fb27SDimitry Andric       writeImmediate<Thumb_Jump24>(R, encodeImmBT4BlT1BlxT2_J1J2(Value));
60706c3fb27SDimitry Andric     } else {
60806c3fb27SDimitry Andric       if (!isInt<22>(Value))
60906c3fb27SDimitry Andric         return makeTargetOutOfRangeError(G, B, E);
61006c3fb27SDimitry Andric       writeImmediate<Thumb_Jump24>(R, encodeImmBT4BlT1BlxT2(Value));
61106c3fb27SDimitry Andric     }
61206c3fb27SDimitry Andric 
61306c3fb27SDimitry Andric     return Error::success();
61406c3fb27SDimitry Andric   }
61506c3fb27SDimitry Andric 
61606c3fb27SDimitry Andric   case Thumb_Call: {
61706c3fb27SDimitry Andric     int64_t Value = TargetAddress - FixupAddress + Addend;
61806c3fb27SDimitry Andric 
61906c3fb27SDimitry Andric     // The call instruction itself is Thumb. The call destination can either be
62006c3fb27SDimitry Andric     // Thumb or Arm. We use BL to stay in Thumb and BLX to change to Arm.
621*5f757f3fSDimitry Andric     bool TargetIsArm = !hasTargetFlags(TargetSymbol, ThumbSymbol);
62206c3fb27SDimitry Andric     bool InstrIsBlx = (R.Lo & FixupInfo<Thumb_Call>::LoBitNoBlx) == 0;
62306c3fb27SDimitry Andric     if (TargetIsArm != InstrIsBlx) {
62406c3fb27SDimitry Andric       if (LLVM_LIKELY(TargetIsArm)) {
625*5f757f3fSDimitry Andric         // Change opcode BL -> BLX and fix range value: account for 4-byte
62606c3fb27SDimitry Andric         // aligned destination while instruction may only be 2-byte aligned
62706c3fb27SDimitry Andric         R.Lo = R.Lo & ~FixupInfo<Thumb_Call>::LoBitNoBlx;
62806c3fb27SDimitry Andric         R.Lo = R.Lo & ~FixupInfo<Thumb_Call>::LoBitH;
62906c3fb27SDimitry Andric         Value = alignTo(Value, 4);
63006c3fb27SDimitry Andric       } else {
631*5f757f3fSDimitry Andric         // Change opcode BLX -> BL
63206c3fb27SDimitry Andric         R.Lo = R.Lo & ~FixupInfo<Thumb_Call>::LoBitNoBlx;
63306c3fb27SDimitry Andric       }
63406c3fb27SDimitry Andric     }
63506c3fb27SDimitry Andric 
63606c3fb27SDimitry Andric     if (LLVM_LIKELY(ArmCfg.J1J2BranchEncoding)) {
63706c3fb27SDimitry Andric       if (!isInt<25>(Value))
63806c3fb27SDimitry Andric         return makeTargetOutOfRangeError(G, B, E);
63906c3fb27SDimitry Andric       writeImmediate<Thumb_Call>(R, encodeImmBT4BlT1BlxT2_J1J2(Value));
64006c3fb27SDimitry Andric     } else {
64106c3fb27SDimitry Andric       if (!isInt<22>(Value))
64206c3fb27SDimitry Andric         return makeTargetOutOfRangeError(G, B, E);
64306c3fb27SDimitry Andric       writeImmediate<Thumb_Call>(R, encodeImmBT4BlT1BlxT2(Value));
64406c3fb27SDimitry Andric     }
64506c3fb27SDimitry Andric 
64606c3fb27SDimitry Andric     assert(((R.Lo & FixupInfo<Thumb_Call>::LoBitNoBlx) ||
64706c3fb27SDimitry Andric             (R.Lo & FixupInfo<Thumb_Call>::LoBitH) == 0) &&
64806c3fb27SDimitry Andric            "Opcode BLX implies H bit is clear (avoid UB in BLX T2)");
64906c3fb27SDimitry Andric     return Error::success();
65006c3fb27SDimitry Andric   }
65106c3fb27SDimitry Andric 
65206c3fb27SDimitry Andric   case Thumb_MovwAbsNC: {
65306c3fb27SDimitry Andric     uint16_t Value = (TargetAddress + Addend) & 0xffff;
65406c3fb27SDimitry Andric     writeImmediate<Thumb_MovwAbsNC>(R, encodeImmMovtT1MovwT3(Value));
65506c3fb27SDimitry Andric     return Error::success();
65606c3fb27SDimitry Andric   }
65706c3fb27SDimitry Andric   case Thumb_MovtAbs: {
65806c3fb27SDimitry Andric     uint16_t Value = ((TargetAddress + Addend) >> 16) & 0xffff;
65906c3fb27SDimitry Andric     writeImmediate<Thumb_MovtAbs>(R, encodeImmMovtT1MovwT3(Value));
66006c3fb27SDimitry Andric     return Error::success();
66106c3fb27SDimitry Andric   }
662*5f757f3fSDimitry Andric   case Thumb_MovwPrelNC: {
663*5f757f3fSDimitry Andric     uint16_t Value = ((TargetAddress + Addend - FixupAddress) & 0xffff);
664*5f757f3fSDimitry Andric     writeImmediate<Thumb_MovwPrelNC>(R, encodeImmMovtT1MovwT3(Value));
665*5f757f3fSDimitry Andric     return Error::success();
666*5f757f3fSDimitry Andric   }
667*5f757f3fSDimitry Andric   case Thumb_MovtPrel: {
668*5f757f3fSDimitry Andric     uint16_t Value = (((TargetAddress + Addend - FixupAddress) >> 16) & 0xffff);
669*5f757f3fSDimitry Andric     writeImmediate<Thumb_MovtPrel>(R, encodeImmMovtT1MovwT3(Value));
670*5f757f3fSDimitry Andric     return Error::success();
671*5f757f3fSDimitry Andric   }
67206c3fb27SDimitry Andric 
67306c3fb27SDimitry Andric   default:
67406c3fb27SDimitry Andric     return make_error<JITLinkError>(
67506c3fb27SDimitry Andric         "In graph " + G.getName() + ", section " + B.getSection().getName() +
67606c3fb27SDimitry Andric         " encountered unfixable aarch32 edge kind " +
67706c3fb27SDimitry Andric         G.getEdgeKindName(E.getKind()));
67806c3fb27SDimitry Andric   }
67906c3fb27SDimitry Andric }
68006c3fb27SDimitry Andric 
68106c3fb27SDimitry Andric const uint8_t Thumbv7ABS[] = {
68206c3fb27SDimitry Andric     0x40, 0xf2, 0x00, 0x0c, // movw r12, #0x0000    ; lower 16-bit
68306c3fb27SDimitry Andric     0xc0, 0xf2, 0x00, 0x0c, // movt r12, #0x0000    ; upper 16-bit
68406c3fb27SDimitry Andric     0x60, 0x47              // bx   r12
68506c3fb27SDimitry Andric };
68606c3fb27SDimitry Andric 
68706c3fb27SDimitry Andric template <>
68806c3fb27SDimitry Andric Symbol &StubsManager<Thumbv7>::createEntry(LinkGraph &G, Symbol &Target) {
68906c3fb27SDimitry Andric   constexpr uint64_t Alignment = 4;
69006c3fb27SDimitry Andric   Block &B = addStub(G, Thumbv7ABS, Alignment);
69106c3fb27SDimitry Andric   LLVM_DEBUG({
69206c3fb27SDimitry Andric     const char *StubPtr = B.getContent().data();
69306c3fb27SDimitry Andric     HalfWords Reg12 = encodeRegMovtT1MovwT3(12);
69406c3fb27SDimitry Andric     assert(checkRegister<Thumb_MovwAbsNC>(StubPtr, Reg12) &&
69506c3fb27SDimitry Andric            checkRegister<Thumb_MovtAbs>(StubPtr + 4, Reg12) &&
69606c3fb27SDimitry Andric            "Linker generated stubs may only corrupt register r12 (IP)");
69706c3fb27SDimitry Andric   });
69806c3fb27SDimitry Andric   B.addEdge(Thumb_MovwAbsNC, 0, Target, 0);
69906c3fb27SDimitry Andric   B.addEdge(Thumb_MovtAbs, 4, Target, 0);
70006c3fb27SDimitry Andric   Symbol &Stub = G.addAnonymousSymbol(B, 0, B.getSize(), true, false);
70106c3fb27SDimitry Andric   Stub.setTargetFlags(ThumbSymbol);
70206c3fb27SDimitry Andric   return Stub;
70306c3fb27SDimitry Andric }
70406c3fb27SDimitry Andric 
70506c3fb27SDimitry Andric const char *getEdgeKindName(Edge::Kind K) {
70606c3fb27SDimitry Andric #define KIND_NAME_CASE(K)                                                      \
70706c3fb27SDimitry Andric   case K:                                                                      \
70806c3fb27SDimitry Andric     return #K;
70906c3fb27SDimitry Andric 
71006c3fb27SDimitry Andric   switch (K) {
71106c3fb27SDimitry Andric     KIND_NAME_CASE(Data_Delta32)
712*5f757f3fSDimitry Andric     KIND_NAME_CASE(Data_Pointer32)
71306c3fb27SDimitry Andric     KIND_NAME_CASE(Arm_Call)
714*5f757f3fSDimitry Andric     KIND_NAME_CASE(Arm_Jump24)
715*5f757f3fSDimitry Andric     KIND_NAME_CASE(Arm_MovwAbsNC)
716*5f757f3fSDimitry Andric     KIND_NAME_CASE(Arm_MovtAbs)
71706c3fb27SDimitry Andric     KIND_NAME_CASE(Thumb_Call)
71806c3fb27SDimitry Andric     KIND_NAME_CASE(Thumb_Jump24)
71906c3fb27SDimitry Andric     KIND_NAME_CASE(Thumb_MovwAbsNC)
72006c3fb27SDimitry Andric     KIND_NAME_CASE(Thumb_MovtAbs)
721*5f757f3fSDimitry Andric     KIND_NAME_CASE(Thumb_MovwPrelNC)
722*5f757f3fSDimitry Andric     KIND_NAME_CASE(Thumb_MovtPrel)
72306c3fb27SDimitry Andric   default:
72406c3fb27SDimitry Andric     return getGenericEdgeKindName(K);
72506c3fb27SDimitry Andric   }
72606c3fb27SDimitry Andric #undef KIND_NAME_CASE
72706c3fb27SDimitry Andric }
72806c3fb27SDimitry Andric 
72906c3fb27SDimitry Andric const char *getCPUArchName(ARMBuildAttrs::CPUArch K) {
73006c3fb27SDimitry Andric #define CPUARCH_NAME_CASE(K)                                                   \
73106c3fb27SDimitry Andric   case K:                                                                      \
73206c3fb27SDimitry Andric     return #K;
73306c3fb27SDimitry Andric 
73406c3fb27SDimitry Andric   using namespace ARMBuildAttrs;
73506c3fb27SDimitry Andric   switch (K) {
73606c3fb27SDimitry Andric     CPUARCH_NAME_CASE(Pre_v4)
73706c3fb27SDimitry Andric     CPUARCH_NAME_CASE(v4)
73806c3fb27SDimitry Andric     CPUARCH_NAME_CASE(v4T)
73906c3fb27SDimitry Andric     CPUARCH_NAME_CASE(v5T)
74006c3fb27SDimitry Andric     CPUARCH_NAME_CASE(v5TE)
74106c3fb27SDimitry Andric     CPUARCH_NAME_CASE(v5TEJ)
74206c3fb27SDimitry Andric     CPUARCH_NAME_CASE(v6)
74306c3fb27SDimitry Andric     CPUARCH_NAME_CASE(v6KZ)
74406c3fb27SDimitry Andric     CPUARCH_NAME_CASE(v6T2)
74506c3fb27SDimitry Andric     CPUARCH_NAME_CASE(v6K)
74606c3fb27SDimitry Andric     CPUARCH_NAME_CASE(v7)
74706c3fb27SDimitry Andric     CPUARCH_NAME_CASE(v6_M)
74806c3fb27SDimitry Andric     CPUARCH_NAME_CASE(v6S_M)
74906c3fb27SDimitry Andric     CPUARCH_NAME_CASE(v7E_M)
75006c3fb27SDimitry Andric     CPUARCH_NAME_CASE(v8_A)
75106c3fb27SDimitry Andric     CPUARCH_NAME_CASE(v8_R)
75206c3fb27SDimitry Andric     CPUARCH_NAME_CASE(v8_M_Base)
75306c3fb27SDimitry Andric     CPUARCH_NAME_CASE(v8_M_Main)
75406c3fb27SDimitry Andric     CPUARCH_NAME_CASE(v8_1_M_Main)
75506c3fb27SDimitry Andric     CPUARCH_NAME_CASE(v9_A)
75606c3fb27SDimitry Andric   }
75706c3fb27SDimitry Andric   llvm_unreachable("Missing CPUArch in switch?");
75806c3fb27SDimitry Andric #undef CPUARCH_NAME_CASE
75906c3fb27SDimitry Andric }
76006c3fb27SDimitry Andric 
76106c3fb27SDimitry Andric } // namespace aarch32
76206c3fb27SDimitry Andric } // namespace jitlink
76306c3fb27SDimitry Andric } // namespace llvm
764