23#define DEBUG_TYPE "jitlink"
56 return SignExtend64<22>(Imm11H << 12 | Imm11L << 1);
70 return HalfWords{S | Imm10, J1 | J2 | Imm11};
84 return SignExtend64<25>(S << 14 | I1 | I2 | Imm10 << 12 | Imm11 << 1);
93 return (
Value >> 2) & 0x00ffffff;
102 return SignExtend64<26>((
Value & 0x00ffffff) << 2);
115 return HalfWords{Imm1 << 10 | Imm4, Imm3 << 12 | Imm8};
128 uint32_t Imm16 = Imm4 << 12 | Imm1 << 11 | Imm3 << 8 | Imm8;
129 assert(Imm16 <= 0xffff &&
"Decoded value out-of-range");
159 return (Imm4 << 16) | Imm12;
170 return (Imm4 << 12) | Imm12;
198struct WritableThumbRelocation {
200 WritableThumbRelocation(
char *FixupPtr)
201 :
Hi{*reinterpret_cast<support::ulittle16_t *>(FixupPtr)},
202 Lo{*reinterpret_cast<support::ulittle16_t *>(FixupPtr + 2)} {}
208struct ThumbRelocation {
210 ThumbRelocation(
const char *FixupPtr)
215 ThumbRelocation(WritableThumbRelocation &Writable)
216 :
Hi{Writable.
Hi},
Lo(Writable.
Lo) {}
222struct WritableArmRelocation {
223 WritableArmRelocation(
char *FixupPtr)
229struct ArmRelocation {
230 ArmRelocation(
const char *FixupPtr)
233 ArmRelocation(WritableArmRelocation &Writable) :
Wd{Writable.
Wd} {}
238Error makeUnexpectedOpcodeError(
const LinkGraph &
G,
const ThumbRelocation &R,
240 return make_error<JITLinkError>(
241 formatv(
"Invalid opcode [ {0:x4}, {1:x4} ] for relocation: {2}",
243 G.getEdgeKindName(Kind)));
246Error makeUnexpectedOpcodeError(
const LinkGraph &
G,
const ArmRelocation &R,
248 return make_error<JITLinkError>(
249 formatv(
"Invalid opcode {0:x8} for relocation: {1}",
250 static_cast<uint32_t>(
R.Wd),
G.getEdgeKindName(Kind)));
253template <EdgeKind_aarch32 K>
constexpr bool isArm() {
256template <EdgeKind_aarch32 K>
constexpr bool isThumb() {
260template <EdgeKind_aarch32 K>
static bool checkOpcodeArm(
uint32_t Wd) {
261 return (
Wd & FixupInfo<K>::OpcodeMask) == FixupInfo<K>::Opcode;
264template <EdgeKind_aarch32 K>
266 return (
Hi & FixupInfo<K>::OpcodeMask.
Hi) == FixupInfo<K>::Opcode.Hi &&
267 (
Lo & FixupInfo<K>::OpcodeMask.Lo) == FixupInfo<K>::Opcode.
Lo;
270class FixupInfoTable {
275 populateEntries<FirstArmRelocation, LastArmRelocation>();
276 populateEntries<FirstThumbRelocation, LastThumbRelocation>();
280 assert(K < Data.size() &&
"Index out of bounds");
281 return Data.at(K).get();
285 template <EdgeKind_aarch32 K, EdgeKind_aarch32 LastK>
void populateEntries() {
286 assert(K < Data.size() &&
"Index out of range");
287 assert(Data.at(K) ==
nullptr &&
"Initialized entries are immutable");
288 Data[
K] = initEntry<K>();
289 if constexpr (
K < LastK) {
291 populateEntries<Next, LastK>();
295 template <EdgeKind_aarch32 K>
296 static std::unique_ptr<FixupInfoBase> initEntry() {
297 auto Entry = std::make_unique<FixupInfo<K>>();
298 static_assert(isArm<K>() != isThumb<K>(),
"Classes are mutually exclusive");
299 if constexpr (isArm<K>())
300 Entry->checkOpcode = checkOpcodeArm<K>;
301 if constexpr (isThumb<K>())
302 Entry->checkOpcode = checkOpcodeThumb<K>;
307 std::array<std::unique_ptr<FixupInfoBase>, Items> Data;
310ManagedStatic<FixupInfoTable> DynFixupInfos;
317 "Edge kind must be Arm relocation");
320 assert(
Info.checkOpcode &&
"Opcode check is mandatory for Arm edges");
321 if (!
Info.checkOpcode(R.Wd))
322 return makeUnexpectedOpcodeError(
G, R, Kind);
330 "Edge kind must be Thumb relocation");
333 assert(
Info.checkOpcode &&
"Opcode check is mandatory for Thumb edges");
334 if (!
Info.checkOpcode(R.Hi, R.Lo))
335 return makeUnexpectedOpcodeError(
G, R, Kind);
341 return DynFixupInfos->getEntry(K);
344template <EdgeKind_aarch32 Kind>
351template <EdgeKind_aarch32 Kind>
357template <EdgeKind_aarch32 Kind>
361 "Value bits exceed bit range of given mask");
362 R.Hi = (R.Hi & ~Mask.Hi) |
Reg.Hi;
363 R.Lo = (R.Lo & ~Mask.Lo) |
Reg.Lo;
366template <EdgeKind_aarch32 Kind>
369 assert((Mask &
Reg) ==
Reg &&
"Value bits exceed bit range of given mask");
370 R.Wd = (R.Wd & ~Mask) |
Reg;
373template <EdgeKind_aarch32 Kind>
376 assert((Mask.Hi & Imm.Hi) == Imm.Hi && (Mask.Lo & Imm.Lo) == Imm.Lo &&
377 "Value bits exceed bit range of given mask");
378 R.Hi = (R.Hi & ~Mask.Hi) | Imm.Hi;
379 R.Lo = (R.Lo & ~Mask.Lo) | Imm.Lo;
382template <EdgeKind_aarch32 Kind>
385 assert((Mask & Imm) == Imm &&
"Value bits exceed bit range of given mask");
386 R.Wd = (R.Wd & ~Mask) | Imm;
392 const char *BlockWorkingMem =
B.getContent().data();
393 const char *FixupPtr = BlockWorkingMem +
Offset;
400 return make_error<JITLinkError>(
401 "In graph " +
G.getName() +
", section " +
B.getSection().getName() +
402 " can not read implicit addend for aarch32 edge kind " +
403 G.getEdgeKindName(Kind));
409 ArmRelocation R(
B.getContent().data() +
Offset);
411 return std::move(Err);
423 return make_error<JITLinkError>(
424 "In graph " +
G.getName() +
", section " +
B.getSection().getName() +
425 " can not read implicit addend for aarch32 edge kind " +
426 G.getEdgeKindName(Kind));
432 ThumbRelocation R(
B.getContent().data() +
Offset);
434 return std::move(Err);
454 return make_error<JITLinkError>(
455 "In graph " +
G.getName() +
", section " +
B.getSection().getName() +
456 " can not read implicit addend for aarch32 edge kind " +
457 G.getEdgeKindName(Kind));
462 using namespace support;
464 char *BlockWorkingMem =
B.getAlreadyMutableContent().data();
465 char *FixupPtr = BlockWorkingMem +
E.getOffset();
467 auto Write32 = [FixupPtr,
Endian =
G.getEndianness()](int64_t
Value) {
468 assert(isInt<32>(
Value) &&
"Must be in signed 32-bit range");
471 endian::write32<endianness::little>(FixupPtr, Imm);
473 endian::write32<endianness::big>(FixupPtr, Imm);
477 uint64_t FixupAddress = (
B.getAddress() +
E.getOffset()).getValue();
478 int64_t Addend =
E.getAddend();
479 Symbol &TargetSymbol =
E.getTarget();
487 int64_t
Value = TargetAddress - FixupAddress + Addend;
488 if (!isInt<32>(
Value))
494 int64_t
Value = TargetAddress + Addend;
495 if (!isInt<32>(
Value))
501 return make_error<JITLinkError>(
502 "In graph " +
G.getName() +
", section " +
B.getSection().getName() +
503 " encountered unfixable aarch32 edge kind " +
504 G.getEdgeKindName(
E.getKind()));
509 WritableArmRelocation R(
B.getAlreadyMutableContent().data() +
E.getOffset());
514 uint64_t FixupAddress = (
B.getAddress() +
E.getOffset()).getValue();
515 int64_t Addend =
E.getAddend();
516 Symbol &TargetSymbol =
E.getTarget();
522 return make_error<JITLinkError>(
"Branch relocation needs interworking "
523 "stub when bridging to Thumb: " +
526 int64_t
Value = TargetAddress - FixupAddress + Addend;
528 if (!isInt<26>(
Value))
537 return make_error<JITLinkError>(
"Relocation expects an unconditional "
538 "BL/BLX branch instruction: " +
541 int64_t
Value = TargetAddress - FixupAddress + Addend;
547 if (TargetIsThumb != InstrIsBlx) {
558 if (!isInt<26>(
Value))
575 return make_error<JITLinkError>(
576 "In graph " +
G.getName() +
", section " +
B.getSection().getName() +
577 " encountered unfixable aarch32 edge kind " +
578 G.getEdgeKindName(
E.getKind()));
584 WritableThumbRelocation R(
B.getAlreadyMutableContent().data() +
590 uint64_t FixupAddress = (
B.getAddress() +
E.getOffset()).getValue();
591 int64_t Addend =
E.getAddend();
592 Symbol &TargetSymbol =
E.getTarget();
598 return make_error<JITLinkError>(
"Branch relocation needs interworking "
599 "stub when bridging to ARM: " +
602 int64_t
Value = TargetAddress - FixupAddress + Addend;
604 if (!isInt<25>(
Value))
608 if (!isInt<22>(
Value))
617 int64_t
Value = TargetAddress - FixupAddress + Addend;
623 if (TargetIsArm != InstrIsBlx) {
637 if (!isInt<25>(
Value))
641 if (!isInt<22>(
Value))
648 "Opcode BLX implies H bit is clear (avoid UB in BLX T2)");
663 uint16_t Value = ((TargetAddress + Addend - FixupAddress) & 0xffff);
668 uint16_t Value = (((TargetAddress + Addend - FixupAddress) >> 16) & 0xffff);
674 return make_error<JITLinkError>(
675 "In graph " +
G.getName() +
", section " +
B.getSection().getName() +
676 " encountered unfixable aarch32 edge kind " +
677 G.getEdgeKindName(
E.getKind()));
682 0x40, 0xf2, 0x00, 0x0c,
683 0xc0, 0xf2, 0x00, 0x0c,
692 const char *StubPtr =
B.getContent().data();
694 assert(checkRegister<Thumb_MovwAbsNC>(StubPtr, Reg12) &&
695 checkRegister<Thumb_MovtAbs>(StubPtr + 4, Reg12) &&
696 "Linker generated stubs may only corrupt register r12 (IP)");
700 Symbol &Stub =
G.addAnonymousSymbol(
B, 0,
B.getSize(),
true,
false);
706#define KIND_NAME_CASE(K) \
730#define CPUARCH_NAME_CASE(K) \
734 using namespace ARMBuildAttrs;
758#undef CPUARCH_NAME_CASE
static bool isThumb(const MCSubtargetInfo &STI)
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
Analysis containing CSE Info
#define LLVM_LIKELY(EXPR)
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
#define CPUARCH_NAME_CASE(K)
support::ulittle16_t & Lo
support::ulittle32_t & Wd
#define KIND_NAME_CASE(K)
support::ulittle16_t & Hi
Lightweight error class with error context and mandatory checking.
static ErrorSuccess success()
Create a success value.
Tagged union holding either a T or a Error.
StringRef - Represent a constant reference to a string, i.e.
Target - Wrapper for Target specific information.
LLVM Value Representation.
An Addressable with content and edges.
Represents fixups and constraints in the LinkGraph.
void setTargetFlags(TargetFlagsType Flags)
Set the target flags for this Symbol.
orc::ExecutorAddr getAddress() const
Returns the address of this symbol.
Symbol & createEntry(LinkGraph &G, Symbol &Target)
Create a branch range extension stub for the class's flavor.
uint64_t getValue() const
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
EdgeKind_aarch32
JITLink-internal AArch32 fixup kinds.
@ Arm_MovtAbs
Write immediate value to the top halfword of the destination register.
@ Data_Pointer32
Absolute 32-bit value relocation.
@ FirstThumbRelocation
Relocations of class Thumb16 and Thumb32 (covers Thumb instruction subset)
@ Arm_MovwAbsNC
Write immediate value to the lower halfword of the destination register.
@ Arm_Call
Write immediate value for unconditional PC-relative branch with link.
@ Thumb_MovtPrel
Write PC-relative immediate value to the top halfword of the destination register.
@ Thumb_Jump24
Write immediate value for PC-relative branch without link.
@ Arm_Jump24
Write immediate value for conditional PC-relative branch without link.
@ Thumb_MovwAbsNC
Write immediate value to the lower halfword of the destination register.
@ FirstArmRelocation
Relocations of class Arm (covers fixed-width 4-byte instruction subset)
@ Data_Delta32
Relative 32-bit value relocation.
@ Thumb_Call
Write immediate value for unconditional PC-relative branch with link.
@ Thumb_MovtAbs
Write immediate value to the top halfword of the destination register.
@ Thumb_MovwPrelNC
Write PC-relative immediate value to the lower halfword of the destination register.
Error applyFixupThumb(LinkGraph &G, Block &B, const Edge &E, const ArmConfig &ArmCfg)
Helper function to apply the fixup for Thumb-class relocations.
int64_t decodeImmBT4BlT1BlxT2(uint32_t Hi, uint32_t Lo)
Decode 22-bit immediate value for branch instructions without J1J2 range extension (formats B T4,...
HalfWords encodeRegMovtT1MovwT3(int64_t Value)
Encode register ID for instruction formats MOVT T1 and MOVW T3.
Error applyFixupData(LinkGraph &G, Block &B, const Edge &E)
Helper function to apply the fixup for Data-class relocations.
uint32_t encodeRegMovtA1MovwA2(int64_t Value)
Encode register ID for instruction formats MOVT A1 and MOVW A2.
Expected< int64_t > readAddendData(LinkGraph &G, Block &B, Edge::OffsetT Offset, Edge::Kind Kind)
Helper function to read the initial addend for Data-class relocations.
HalfWords encodeImmBT4BlT1BlxT2(int64_t Value)
Encode 22-bit immediate value for branch instructions without J1J2 range extension (formats B T4,...
int64_t decodeRegMovtT1MovwT3(uint32_t Hi, uint32_t Lo)
Decode register ID from instruction formats MOVT T1 and MOVW T3.
const char * getCPUArchName(ARMBuildAttrs::CPUArch K)
Human-readable name for a given CPU architecture kind.
uint16_t decodeImmMovtT1MovwT3(uint32_t Hi, uint32_t Lo)
Decode 16-bit immediate value from move instruction formats MOVT T1 and MOVW T3.
uint32_t encodeImmBA1BlA1BlxA2(int64_t Value)
Encode 26-bit immediate value for branch instructions (formats B A1, BL A1 and BLX A2).
uint32_t encodeImmMovtA1MovwA2(uint16_t Value)
Encode 16-bit immediate value for move instruction formats MOVT A1 and MOVW A2.
Error applyFixupArm(LinkGraph &G, Block &B, const Edge &E)
Helper function to apply the fixup for Arm-class relocations.
HalfWords encodeImmMovtT1MovwT3(uint16_t Value)
Encode 16-bit immediate value for move instruction formats MOVT T1 and MOVW T3.
const char * getEdgeKindName(Edge::Kind K)
Get a human-readable name for the given AArch32 edge kind.
int64_t decodeRegMovtA1MovwA2(uint64_t Value)
Decode register ID for instruction formats MOVT A1 and MOVW A2.
bool hasTargetFlags(Symbol &Sym, TargetFlagsType Flags)
Check whether the given target flags are set for this Symbol.
uint16_t decodeImmMovtA1MovwA2(uint64_t Value)
Decode 16-bit immediate value for move instruction formats MOVT A1 and MOVW A2.
const uint8_t Thumbv7ABS[]
HalfWords encodeImmBT4BlT1BlxT2_J1J2(int64_t Value)
Encode 25-bit immediate value for branch instructions with J1J2 range extension (formats B T4,...
static Error checkOpcode(LinkGraph &G, const ArmRelocation &R, Edge::Kind Kind)
int64_t decodeImmBA1BlA1BlxA2(int64_t Value)
Decode 26-bit immediate value for branch instructions (formats B A1, BL A1 and BLX A2).
Expected< int64_t > readAddendThumb(LinkGraph &G, Block &B, Edge::OffsetT Offset, Edge::Kind Kind, const ArmConfig &ArmCfg)
Helper function to read the initial addend for Thumb-class relocations.
void writeRegister(WritableThumbRelocation &R, HalfWords Reg)
bool checkRegister(const ThumbRelocation &R, HalfWords Reg)
int64_t decodeImmBT4BlT1BlxT2_J1J2(uint32_t Hi, uint32_t Lo)
Decode 25-bit immediate value for branch instructions with J1J2 range extension (formats B T4,...
void writeImmediate(WritableThumbRelocation &R, HalfWords Imm)
Expected< int64_t > readAddendArm(LinkGraph &G, Block &B, Edge::OffsetT Offset, Edge::Kind Kind)
Helper function to read the initial addend for Arm-class relocations.
Error makeTargetOutOfRangeError(const LinkGraph &G, const Block &B, const Edge &E)
Create an out of range error for the given edge in the given block.
const char * getGenericEdgeKindName(Edge::Kind K)
Returns the string name of the given generic edge kind, or "unknown" otherwise.
uint8_t TargetFlagsType
Holds target-specific properties for a symbol.
uint32_t read32(const void *P, endianness E)
detail::packed_endian_specific_integral< uint16_t, llvm::endianness::little, unaligned > ulittle16_t
detail::packed_endian_specific_integral< uint32_t, llvm::endianness::little, unaligned > ulittle32_t
This is an optimization pass for GlobalISel generic memory operations.
auto formatv(const char *Fmt, Ts &&... Vals) -> formatv_object< decltype(std::make_tuple(detail::build_format_adapter(std::forward< Ts >(Vals))...))>
uint64_t alignTo(uint64_t Size, Align A)
Returns a multiple of A needed to store Size bytes.
JITLink sub-arch configuration for Arm CPU models.
FixupInfo checks for Arm edge kinds work on 32-bit words.
FixupInfo base class is required for dynamic lookups.
static const FixupInfoBase * getDynFixupInfo(Edge::Kind K)
FixupInfo check for Thumb32 edge kinds work on a pair of 16-bit halfwords.
Collection of named constants per fixup kind.
Immutable pair of halfwords, Hi and Lo, with overflow check.