[llvm] [JITLink][AArch32] Add dynamic lookup for relocation fixup infos (PR #71649)

Stefan Gränitz via llvm-commits llvm-commits at lists.llvm.org
Thu Nov 9 06:23:30 PST 2023


https://github.com/weliveindetail updated https://github.com/llvm/llvm-project/pull/71649

>From c3852d550e5675245269df12a37ca4b45c6bfe50 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Stefan=20Gr=C3=A4nitz?= <stefan.graenitz at gmail.com>
Date: Tue, 7 Nov 2023 18:50:35 +0100
Subject: [PATCH 1/6] [JITLink][AArch32] Add dynamic lookup for relocation
 fixup infos

---
 .../llvm/ExecutionEngine/JITLink/aarch32.h    |  94 ++++++++++++---
 .../ExecutionEngine/JITLink/ELF_aarch32.cpp   |   2 +
 llvm/lib/ExecutionEngine/JITLink/aarch32.cpp  | 114 +++++++++---------
 3 files changed, 136 insertions(+), 74 deletions(-)

diff --git a/llvm/include/llvm/ExecutionEngine/JITLink/aarch32.h b/llvm/include/llvm/ExecutionEngine/JITLink/aarch32.h
index 70a97ff83820cec..6714dc3afb09529 100644
--- a/llvm/include/llvm/ExecutionEngine/JITLink/aarch32.h
+++ b/llvm/include/llvm/ExecutionEngine/JITLink/aarch32.h
@@ -163,49 +163,83 @@ struct HalfWords {
   const uint16_t Lo; // Second halfword
 };
 
-/// Collection of named constants per fixup kind. It may contain but is not
-/// limited to the following entries:
+struct FixupInfoBaseArm {
+  virtual ~FixupInfoBaseArm() {}
+  virtual bool checkOpcode(uint32_t Wd) const = 0;
+};
+
+struct FixupInfoBaseThumb {
+  virtual ~FixupInfoBaseThumb() {}
+  virtual bool checkOpcode(uint16_t Hi, uint16_t Lo) const = 0;
+};
+
+template <EdgeKind_aarch32 Kind> struct FixupInfoArm : public FixupInfoBaseArm {
+  bool checkOpcode(uint32_t Wd) const override;
+};
+
+template <EdgeKind_aarch32 Kind> struct FixupInfoThumb : public FixupInfoBaseThumb {
+  bool checkOpcode(uint16_t Hi, uint16_t Lo) const override;
+};
+
+/// Collection of named constants per fixup kind
 ///
+/// Mandatory entries:
 ///   Opcode      - Values of the op-code bits in the instruction, with
 ///                 unaffected bits nulled
 ///   OpcodeMask  - Mask with all bits set that encode the op-code
+///
+/// Other common entries:
 ///   ImmMask     - Mask with all bits set that encode the immediate value
 ///   RegMask     - Mask with all bits set that encode the register
 ///
+/// Specializations can add further custom fields without restrictions.
+///
 template <EdgeKind_aarch32 Kind> struct FixupInfo {};
 
-template <> struct FixupInfo<Arm_Jump24> {
+namespace {
+template <EdgeKind_aarch32 Kind>
+struct FixupInfoArmBranch : public FixupInfoArm<Kind> {
   static constexpr uint32_t Opcode = 0x0a000000;
-  static constexpr uint32_t OpcodeMask = 0x0f000000;
   static constexpr uint32_t ImmMask = 0x00ffffff;
-  static constexpr uint32_t Unconditional = 0xe0000000;
-  static constexpr uint32_t CondMask = 0xe0000000; // excluding BLX bit
+};
+} // namespace
+
+template <> struct FixupInfo<Arm_Jump24> : public FixupInfoArmBranch<Arm_Jump24> {
+  static constexpr uint32_t OpcodeMask = 0x0f000000;
 };
 
-template <> struct FixupInfo<Arm_Call> : public FixupInfo<Arm_Jump24> {
+template <> struct FixupInfo<Arm_Call> : public FixupInfoArmBranch<Arm_Call> {
   static constexpr uint32_t OpcodeMask = 0x0e000000;
+  static constexpr uint32_t CondMask = 0xe0000000; // excluding BLX bit
+  static constexpr uint32_t Unconditional = 0xe0000000;
   static constexpr uint32_t BitH = 0x01000000;
   static constexpr uint32_t BitBlx = 0x10000000;
 };
 
-template <> struct FixupInfo<Arm_MovtAbs> {
-  static constexpr uint32_t Opcode = 0x03400000;
+namespace {
+template <EdgeKind_aarch32 Kind>
+struct FixupInfoArmMov : public FixupInfoArm<Kind> {
   static constexpr uint32_t OpcodeMask = 0x0ff00000;
   static constexpr uint32_t ImmMask = 0x000f0fff;
   static constexpr uint32_t RegMask = 0x0000f000;
 };
+} // namespace
+
+template <> struct FixupInfo<Arm_MovtAbs> : public FixupInfoArmMov<Arm_MovtAbs> {
+  static constexpr uint32_t Opcode = 0x03400000;
+};
 
-template <> struct FixupInfo<Arm_MovwAbsNC> : public FixupInfo<Arm_MovtAbs> {
+template <> struct FixupInfo<Arm_MovwAbsNC> : public FixupInfoArmMov<Arm_MovwAbsNC> {
   static constexpr uint32_t Opcode = 0x03000000;
 };
 
-template <> struct FixupInfo<Thumb_Jump24> {
+template <> struct FixupInfo<Thumb_Jump24> : public FixupInfoThumb<Thumb_Jump24> {
   static constexpr HalfWords Opcode{0xf000, 0x9000};
   static constexpr HalfWords OpcodeMask{0xf800, 0x9000};
   static constexpr HalfWords ImmMask{0x07ff, 0x2fff};
 };
 
-template <> struct FixupInfo<Thumb_Call> {
+template <> struct FixupInfo<Thumb_Call> : public FixupInfoThumb<Thumb_Call> {
   static constexpr HalfWords Opcode{0xf000, 0xc000};
   static constexpr HalfWords OpcodeMask{0xf800, 0xc000};
   static constexpr HalfWords ImmMask{0x07ff, 0x2fff};
@@ -213,18 +247,48 @@ template <> struct FixupInfo<Thumb_Call> {
   static constexpr uint16_t LoBitNoBlx = 0x1000;
 };
 
-template <> struct FixupInfo<Thumb_MovtAbs> {
-  static constexpr HalfWords Opcode{0xf2c0, 0x0000};
+namespace {
+template <EdgeKind_aarch32 Kind>
+struct FixupInfoThumbMov : public FixupInfoThumb<Kind> {
   static constexpr HalfWords OpcodeMask{0xfbf0, 0x8000};
   static constexpr HalfWords ImmMask{0x040f, 0x70ff};
   static constexpr HalfWords RegMask{0x0000, 0x0f00};
 };
+} // namespace
+
+template <>
+struct FixupInfo<Thumb_MovtAbs> : public FixupInfoThumbMov<Thumb_MovtAbs> {
+  static constexpr HalfWords Opcode{0xf2c0, 0x0000};
+};
+
+template <>
+struct FixupInfo<Thumb_MovtPrel> : public FixupInfoThumbMov<Thumb_MovtPrel> {
+  static constexpr HalfWords Opcode{0xf2c0, 0x0000};
+};
+
+template <>
+struct FixupInfo<Thumb_MovwAbsNC> : public FixupInfoThumbMov<Thumb_MovwAbsNC> {
+  static constexpr HalfWords Opcode{0xf240, 0x0000};
+};
 
 template <>
-struct FixupInfo<Thumb_MovwAbsNC> : public FixupInfo<Thumb_MovtAbs> {
+struct FixupInfo<Thumb_MovwPrelNC> : public FixupInfoThumbMov<Thumb_MovwPrelNC> {
   static constexpr HalfWords Opcode{0xf240, 0x0000};
 };
 
+template <EdgeKind_aarch32 Kind>
+bool FixupInfoArm<Kind>::checkOpcode(uint32_t Wd) const {
+  return (Wd & FixupInfo<Kind>::OpcodeMask) == FixupInfo<Kind>::Opcode;
+}
+
+template <EdgeKind_aarch32 Kind>
+bool FixupInfoThumb<Kind>::checkOpcode(uint16_t Hi, uint16_t Lo) const {
+  return (Hi & FixupInfo<Kind>::OpcodeMask.Hi) == FixupInfo<Kind>::Opcode.Hi &&
+         (Lo & FixupInfo<Kind>::OpcodeMask.Lo) == FixupInfo<Kind>::Opcode.Lo;
+}
+
+void populateFixupInfos();
+
 /// Helper function to read the initial addend for Data-class relocations.
 Expected<int64_t> readAddendData(LinkGraph &G, Block &B, const Edge &E);
 
diff --git a/llvm/lib/ExecutionEngine/JITLink/ELF_aarch32.cpp b/llvm/lib/ExecutionEngine/JITLink/ELF_aarch32.cpp
index b6b63691d8408ea..f5d24817595dd7d 100644
--- a/llvm/lib/ExecutionEngine/JITLink/ELF_aarch32.cpp
+++ b/llvm/lib/ExecutionEngine/JITLink/ELF_aarch32.cpp
@@ -233,6 +233,8 @@ createLinkGraphFromELFObject_aarch32(MemoryBufferRef ObjectBuffer) {
            << ObjectBuffer.getBufferIdentifier() << "...\n";
   });
 
+  aarch32::populateFixupInfos();
+
   auto ELFObj = ObjectFile::createELFObjectFile(ObjectBuffer);
   if (!ELFObj)
     return ELFObj.takeError();
diff --git a/llvm/lib/ExecutionEngine/JITLink/aarch32.cpp b/llvm/lib/ExecutionEngine/JITLink/aarch32.cpp
index c3823f985ce182d..303dac19da2b99f 100644
--- a/llvm/lib/ExecutionEngine/JITLink/aarch32.cpp
+++ b/llvm/lib/ExecutionEngine/JITLink/aarch32.cpp
@@ -224,7 +224,6 @@ struct WritableArmRelocation {
 };
 
 struct ArmRelocation {
-
   ArmRelocation(const char *FixupPtr)
       : Wd{*reinterpret_cast<const support::ulittle32_t *>(FixupPtr)} {}
 
@@ -248,15 +247,49 @@ Error makeUnexpectedOpcodeError(const LinkGraph &G, const ArmRelocation &R,
               static_cast<uint32_t>(R.Wd), G.getEdgeKindName(Kind)));
 }
 
-template <EdgeKind_aarch32 Kind> bool checkOpcode(const ThumbRelocation &R) {
-  uint16_t Hi = R.Hi & FixupInfo<Kind>::OpcodeMask.Hi;
-  uint16_t Lo = R.Lo & FixupInfo<Kind>::OpcodeMask.Lo;
-  return Hi == FixupInfo<Kind>::Opcode.Hi && Lo == FixupInfo<Kind>::Opcode.Lo;
+static auto &getFixupInfoTableArm() {
+  static constexpr size_t Items = LastArmRelocation - FirstArmRelocation + 1;
+  static std::array<std::unique_ptr<FixupInfoBaseArm>, Items> FixupInfoTableArm;
+  return FixupInfoTableArm;
+}
+
+static auto &getFixupInfoTableThumb() {
+  static constexpr size_t Items = LastThumbRelocation - FirstThumbRelocation + 1;
+  static std::array<std::unique_ptr<FixupInfoBaseThumb>, Items> FixupInfoTableThumb;
+  return FixupInfoTableThumb;
 }
 
-template <EdgeKind_aarch32 Kind> bool checkOpcode(const ArmRelocation &R) {
-  uint32_t Wd = R.Wd & FixupInfo<Kind>::OpcodeMask;
-  return Wd == FixupInfo<Kind>::Opcode;
+template <EdgeKind_aarch32 It, EdgeKind_aarch32 Last, typename TableT>
+void populateFixupInfos(TableT &Table, size_t Idx = 0) {
+  Table[Idx] = std::make_unique<FixupInfo<It>>();
+  if constexpr (It < Last) {
+    constexpr auto Next = EdgeKind_aarch32((Edge::Kind)It + 1);
+    populateFixupInfos<Next, Last>(Table, Idx + 1);
+  }
+}
+
+void populateFixupInfos() {
+  static std::once_flag Flag;
+  std::call_once(Flag, []() {
+    populateFixupInfos<FirstArmRelocation, LastArmRelocation>(getFixupInfoTableArm());
+    populateFixupInfos<FirstThumbRelocation, LastThumbRelocation>(getFixupInfoTableThumb());
+  });
+}
+
+static bool checkOpcode(const ArmRelocation &R, Edge::Kind Kind) {
+  assert(Kind >= FirstArmRelocation && Kind <= LastArmRelocation &&
+         "Edge kind is no Arm relocation");
+  assert(getFixupInfoTableArm().at(Kind - FirstArmRelocation) != nullptr &&
+         "Call populateFixupInfos() before dynamic access");
+  return getFixupInfoTableArm()[Kind - FirstArmRelocation]->checkOpcode(R.Wd);
+}
+
+static bool checkOpcode(const ThumbRelocation &R, Edge::Kind Kind) {
+  assert(Kind >= FirstThumbRelocation && Kind <= LastThumbRelocation &&
+         "Edge kind is no Thumb relocation");
+  assert(getFixupInfoTableThumb().at(Kind - FirstThumbRelocation) != nullptr &&
+         "Call populateFixupInfos() before dynamic access");
+  return getFixupInfoTableThumb()[Kind - FirstThumbRelocation]->checkOpcode(R.Hi, R.Lo);
 }
 
 template <EdgeKind_aarch32 Kind>
@@ -326,26 +359,16 @@ Expected<int64_t> readAddendData(LinkGraph &G, Block &B, const Edge &E) {
 Expected<int64_t> readAddendArm(LinkGraph &G, Block &B, const Edge &E) {
   ArmRelocation R(B.getContent().data() + E.getOffset());
   Edge::Kind Kind = E.getKind();
+  if (!checkOpcode(R, Kind))
+      return makeUnexpectedOpcodeError(G, R, Kind);
 
   switch (Kind) {
   case Arm_Call:
-    if (!checkOpcode<Arm_Call>(R))
-      return makeUnexpectedOpcodeError(G, R, Kind);
-    return decodeImmBA1BlA1BlxA2(R.Wd);
-
   case Arm_Jump24:
-    if (!checkOpcode<Arm_Jump24>(R))
-      return makeUnexpectedOpcodeError(G, R, Kind);
     return decodeImmBA1BlA1BlxA2(R.Wd);
 
-  case Arm_MovwAbsNC:
-    if (!checkOpcode<Arm_MovwAbsNC>(R))
-      return makeUnexpectedOpcodeError(G, R, Kind);
-    return decodeImmMovtA1MovwA2(R.Wd);
-
   case Arm_MovtAbs:
-    if (!checkOpcode<Arm_MovtAbs>(R))
-      return makeUnexpectedOpcodeError(G, R, Kind);
+  case Arm_MovwAbsNC:
     return decodeImmMovtA1MovwA2(R.Wd);
 
   default:
@@ -360,33 +383,23 @@ Expected<int64_t> readAddendThumb(LinkGraph &G, Block &B, const Edge &E,
                                   const ArmConfig &ArmCfg) {
   ThumbRelocation R(B.getContent().data() + E.getOffset());
   Edge::Kind Kind = E.getKind();
+  if (!checkOpcode(R, Kind))
+      return makeUnexpectedOpcodeError(G, R, Kind);
 
   switch (Kind) {
   case Thumb_Call:
-    if (!checkOpcode<Thumb_Call>(R))
-      return makeUnexpectedOpcodeError(G, R, Kind);
+  case Thumb_Jump24:
     return LLVM_LIKELY(ArmCfg.J1J2BranchEncoding)
                ? decodeImmBT4BlT1BlxT2_J1J2(R.Hi, R.Lo)
                : decodeImmBT4BlT1BlxT2(R.Hi, R.Lo);
 
-  case Thumb_Jump24:
-    if (!checkOpcode<Thumb_Jump24>(R))
-      return makeUnexpectedOpcodeError(G, R, Kind);
-    return LLVM_LIKELY(ArmCfg.J1J2BranchEncoding)
-                  ? decodeImmBT4BlT1BlxT2_J1J2(R.Hi, R.Lo)
-                  : decodeImmBT4BlT1BlxT2(R.Hi, R.Lo);
-
   case Thumb_MovwAbsNC:
   case Thumb_MovwPrelNC:
-    if (!checkOpcode<Thumb_MovwAbsNC>(R))
-      return makeUnexpectedOpcodeError(G, R, Kind);
     // Initial addend is interpreted as a signed value
     return SignExtend64<16>(decodeImmMovtT1MovwT3(R.Hi, R.Lo));
 
   case Thumb_MovtAbs:
   case Thumb_MovtPrel:
-    if (!checkOpcode<Thumb_MovtAbs>(R))
-      return makeUnexpectedOpcodeError(G, R, Kind);
     // Initial addend is interpreted as a signed value
     return SignExtend64<16>(decodeImmMovtT1MovwT3(R.Hi, R.Lo));
 
@@ -448,6 +461,9 @@ Error applyFixupData(LinkGraph &G, Block &B, const Edge &E) {
 Error applyFixupArm(LinkGraph &G, Block &B, const Edge &E) {
   WritableArmRelocation R(B.getAlreadyMutableContent().data() + E.getOffset());
   Edge::Kind Kind = E.getKind();
+  if (!checkOpcode(R, Kind))
+      return makeUnexpectedOpcodeError(G, R, Kind);
+
   uint64_t FixupAddress = (B.getAddress() + E.getOffset()).getValue();
   int64_t Addend = E.getAddend();
   Symbol &TargetSymbol = E.getTarget();
@@ -455,8 +471,6 @@ Error applyFixupArm(LinkGraph &G, Block &B, const Edge &E) {
 
   switch (Kind) {
   case Arm_Jump24: {
-    if (!checkOpcode<Arm_Jump24>(R))
-      return makeUnexpectedOpcodeError(G, R, Kind);
     if (hasTargetFlags(TargetSymbol, ThumbSymbol))
       return make_error<JITLinkError>("Branch relocation needs interworking "
                                       "stub when bridging to Thumb: " +
@@ -471,8 +485,6 @@ Error applyFixupArm(LinkGraph &G, Block &B, const Edge &E) {
     return Error::success();
   }
   case Arm_Call: {
-    if (!checkOpcode<Arm_Call>(R))
-      return makeUnexpectedOpcodeError(G, R, Kind);
     if ((R.Wd & FixupInfo<Arm_Call>::CondMask) !=
         FixupInfo<Arm_Call>::Unconditional)
       return make_error<JITLinkError>("Relocation expects an unconditional "
@@ -503,15 +515,11 @@ Error applyFixupArm(LinkGraph &G, Block &B, const Edge &E) {
     return Error::success();
   }
   case Arm_MovwAbsNC: {
-    if (!checkOpcode<Arm_MovwAbsNC>(R))
-      return makeUnexpectedOpcodeError(G, R, Kind);
     uint16_t Value = (TargetAddress + Addend) & 0xffff;
     writeImmediate<Arm_MovwAbsNC>(R, encodeImmMovtA1MovwA2(Value));
     return Error::success();
   }
   case Arm_MovtAbs: {
-    if (!checkOpcode<Arm_MovtAbs>(R))
-      return makeUnexpectedOpcodeError(G, R, Kind);
     uint16_t Value = ((TargetAddress + Addend) >> 16) & 0xffff;
     writeImmediate<Arm_MovtAbs>(R, encodeImmMovtA1MovwA2(Value));
     return Error::success();
@@ -528,8 +536,10 @@ Error applyFixupThumb(LinkGraph &G, Block &B, const Edge &E,
                       const ArmConfig &ArmCfg) {
   WritableThumbRelocation R(B.getAlreadyMutableContent().data() +
                             E.getOffset());
-
   Edge::Kind Kind = E.getKind();
+  if (!checkOpcode(R, Kind))
+      return makeUnexpectedOpcodeError(G, R, Kind);
+
   uint64_t FixupAddress = (B.getAddress() + E.getOffset()).getValue();
   int64_t Addend = E.getAddend();
   Symbol &TargetSymbol = E.getTarget();
@@ -537,8 +547,6 @@ Error applyFixupThumb(LinkGraph &G, Block &B, const Edge &E,
 
   switch (Kind) {
   case Thumb_Jump24: {
-    if (!checkOpcode<Thumb_Jump24>(R))
-      return makeUnexpectedOpcodeError(G, R, Kind);
     if (!hasTargetFlags(TargetSymbol, ThumbSymbol))
       return make_error<JITLinkError>("Branch relocation needs interworking "
                                       "stub when bridging to ARM: " +
@@ -559,9 +567,6 @@ Error applyFixupThumb(LinkGraph &G, Block &B, const Edge &E,
   }
 
   case Thumb_Call: {
-    if (!checkOpcode<Thumb_Call>(R))
-      return makeUnexpectedOpcodeError(G, R, Kind);
-
     int64_t Value = TargetAddress - FixupAddress + Addend;
 
     // The call instruction itself is Thumb. The call destination can either be
@@ -598,32 +603,23 @@ Error applyFixupThumb(LinkGraph &G, Block &B, const Edge &E,
   }
 
   case Thumb_MovwAbsNC: {
-    if (!checkOpcode<Thumb_MovwAbsNC>(R))
-      return makeUnexpectedOpcodeError(G, R, Kind);
     uint16_t Value = (TargetAddress + Addend) & 0xffff;
     writeImmediate<Thumb_MovwAbsNC>(R, encodeImmMovtT1MovwT3(Value));
     return Error::success();
   }
-
   case Thumb_MovtAbs: {
-    if (!checkOpcode<Thumb_MovtAbs>(R))
-      return makeUnexpectedOpcodeError(G, R, Kind);
     uint16_t Value = ((TargetAddress + Addend) >> 16) & 0xffff;
     writeImmediate<Thumb_MovtAbs>(R, encodeImmMovtT1MovwT3(Value));
     return Error::success();
   }
   case Thumb_MovwPrelNC: {
-    if (!checkOpcode<Thumb_MovwAbsNC>(R))
-      return makeUnexpectedOpcodeError(G, R, Kind);
     uint16_t Value = ((TargetAddress + Addend - FixupAddress) & 0xffff);
-    writeImmediate<Thumb_MovwAbsNC>(R, encodeImmMovtT1MovwT3(Value));
+    writeImmediate<Thumb_MovwPrelNC>(R, encodeImmMovtT1MovwT3(Value));
     return Error::success();
   }
   case Thumb_MovtPrel: {
-    if (!checkOpcode<Thumb_MovtAbs>(R))
-      return makeUnexpectedOpcodeError(G, R, Kind);
     uint16_t Value = (((TargetAddress + Addend - FixupAddress) >> 16) & 0xffff);
-    writeImmediate<Thumb_MovtAbs>(R, encodeImmMovtT1MovwT3(Value));
+    writeImmediate<Thumb_MovtPrel>(R, encodeImmMovtT1MovwT3(Value));
     return Error::success();
   }
 

>From 5cfc5dd551a1368c9d17e6bb9ae7cbea628cf0bf Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Stefan=20Gr=C3=A4nitz?= <stefan.graenitz at gmail.com>
Date: Wed, 8 Nov 2023 13:56:05 +0100
Subject: [PATCH 2/6] Add root class FixupInfoBase for both, Arm and Thumb, and
 store all fixup infos in one table

---
 .../llvm/ExecutionEngine/JITLink/aarch32.h    | 33 +++++++-------
 llvm/lib/ExecutionEngine/JITLink/aarch32.cpp  | 43 +++++++++----------
 2 files changed, 37 insertions(+), 39 deletions(-)

diff --git a/llvm/include/llvm/ExecutionEngine/JITLink/aarch32.h b/llvm/include/llvm/ExecutionEngine/JITLink/aarch32.h
index 6714dc3afb09529..4218f4181a6d507 100644
--- a/llvm/include/llvm/ExecutionEngine/JITLink/aarch32.h
+++ b/llvm/include/llvm/ExecutionEngine/JITLink/aarch32.h
@@ -98,6 +98,7 @@ enum EdgeKind_aarch32 : Edge::Kind {
   Thumb_MovtPrel,
 
   LastThumbRelocation = Thumb_MovtPrel,
+  LastRelocation = LastThumbRelocation,
 };
 
 /// Flags enum for AArch32-specific symbol properties
@@ -163,22 +164,31 @@ struct HalfWords {
   const uint16_t Lo; // Second halfword
 };
 
-struct FixupInfoBaseArm {
-  virtual ~FixupInfoBaseArm() {}
+struct FixupInfoBase {
+  virtual ~FixupInfoBase() {}
+};
+
+struct FixupInfoBaseArm : public FixupInfoBase {
   virtual bool checkOpcode(uint32_t Wd) const = 0;
 };
 
-struct FixupInfoBaseThumb {
-  virtual ~FixupInfoBaseThumb() {}
+struct FixupInfoBaseThumb : public FixupInfoBase {
   virtual bool checkOpcode(uint16_t Hi, uint16_t Lo) const = 0;
 };
 
+template <EdgeKind_aarch32 Kind> struct FixupInfo;
+
 template <EdgeKind_aarch32 Kind> struct FixupInfoArm : public FixupInfoBaseArm {
-  bool checkOpcode(uint32_t Wd) const override;
+  bool checkOpcode(uint32_t Wd) const override {
+    return (Wd & FixupInfo<Kind>::OpcodeMask) == FixupInfo<Kind>::Opcode;
+  }
 };
 
 template <EdgeKind_aarch32 Kind> struct FixupInfoThumb : public FixupInfoBaseThumb {
-  bool checkOpcode(uint16_t Hi, uint16_t Lo) const override;
+  bool checkOpcode(uint16_t Hi, uint16_t Lo) const override {
+    return (Hi & FixupInfo<Kind>::OpcodeMask.Hi) == FixupInfo<Kind>::Opcode.Hi &&
+           (Lo & FixupInfo<Kind>::OpcodeMask.Lo) == FixupInfo<Kind>::Opcode.Lo;
+  }
 };
 
 /// Collection of named constants per fixup kind
@@ -276,17 +286,6 @@ struct FixupInfo<Thumb_MovwPrelNC> : public FixupInfoThumbMov<Thumb_MovwPrelNC>
   static constexpr HalfWords Opcode{0xf240, 0x0000};
 };
 
-template <EdgeKind_aarch32 Kind>
-bool FixupInfoArm<Kind>::checkOpcode(uint32_t Wd) const {
-  return (Wd & FixupInfo<Kind>::OpcodeMask) == FixupInfo<Kind>::Opcode;
-}
-
-template <EdgeKind_aarch32 Kind>
-bool FixupInfoThumb<Kind>::checkOpcode(uint16_t Hi, uint16_t Lo) const {
-  return (Hi & FixupInfo<Kind>::OpcodeMask.Hi) == FixupInfo<Kind>::Opcode.Hi &&
-         (Lo & FixupInfo<Kind>::OpcodeMask.Lo) == FixupInfo<Kind>::Opcode.Lo;
-}
-
 void populateFixupInfos();
 
 /// Helper function to read the initial addend for Data-class relocations.
diff --git a/llvm/lib/ExecutionEngine/JITLink/aarch32.cpp b/llvm/lib/ExecutionEngine/JITLink/aarch32.cpp
index 303dac19da2b99f..332eda0c69b09c5 100644
--- a/llvm/lib/ExecutionEngine/JITLink/aarch32.cpp
+++ b/llvm/lib/ExecutionEngine/JITLink/aarch32.cpp
@@ -247,49 +247,48 @@ Error makeUnexpectedOpcodeError(const LinkGraph &G, const ArmRelocation &R,
               static_cast<uint32_t>(R.Wd), G.getEdgeKindName(Kind)));
 }
 
-static auto &getFixupInfoTableArm() {
-  static constexpr size_t Items = LastArmRelocation - FirstArmRelocation + 1;
-  static std::array<std::unique_ptr<FixupInfoBaseArm>, Items> FixupInfoTableArm;
-  return FixupInfoTableArm;
-}
-
-static auto &getFixupInfoTableThumb() {
-  static constexpr size_t Items = LastThumbRelocation - FirstThumbRelocation + 1;
-  static std::array<std::unique_ptr<FixupInfoBaseThumb>, Items> FixupInfoTableThumb;
-  return FixupInfoTableThumb;
+static auto &getFixupInfoTable() {
+  static constexpr size_t Items = LastRelocation + 1;
+  static std::array<std::unique_ptr<FixupInfoBase>, Items> FixupInfoTable;
+  return FixupInfoTable;
 }
 
 template <EdgeKind_aarch32 It, EdgeKind_aarch32 Last, typename TableT>
-void populateFixupInfos(TableT &Table, size_t Idx = 0) {
-  Table[Idx] = std::make_unique<FixupInfo<It>>();
+void populateFixupInfos(TableT &Table) {
+  assert(It < Table.size() && Table.at(It) == nullptr && "Once set, entries are immutable");
+  Table[It] = std::make_unique<FixupInfo<It>>();
   if constexpr (It < Last) {
-    constexpr auto Next = EdgeKind_aarch32((Edge::Kind)It + 1);
-    populateFixupInfos<Next, Last>(Table, Idx + 1);
+    constexpr auto Next = static_cast<EdgeKind_aarch32>(It + 1);
+    populateFixupInfos<Next, Last>(Table);
   }
 }
 
 void populateFixupInfos() {
   static std::once_flag Flag;
   std::call_once(Flag, []() {
-    populateFixupInfos<FirstArmRelocation, LastArmRelocation>(getFixupInfoTableArm());
-    populateFixupInfos<FirstThumbRelocation, LastThumbRelocation>(getFixupInfoTableThumb());
+    populateFixupInfos<FirstArmRelocation, LastArmRelocation>(getFixupInfoTable());
+    populateFixupInfos<FirstThumbRelocation, LastThumbRelocation>(getFixupInfoTable());
   });
 }
 
+template <typename TargetModeSubclass>
+const TargetModeSubclass &getDynFixupInfo(Edge::Kind K) {
+  assert(K >= Edge::FirstRelocation && "Invalid value for edge kind");
+  assert(K <= LastRelocation && "Invalid value for edge kind");
+  assert(getFixupInfoTable().at(K) && "Call populateFixupInfos() first");
+  return *static_cast<TargetModeSubclass *>(getFixupInfoTable().at(K).get());
+}
+
 static bool checkOpcode(const ArmRelocation &R, Edge::Kind Kind) {
   assert(Kind >= FirstArmRelocation && Kind <= LastArmRelocation &&
          "Edge kind is no Arm relocation");
-  assert(getFixupInfoTableArm().at(Kind - FirstArmRelocation) != nullptr &&
-         "Call populateFixupInfos() before dynamic access");
-  return getFixupInfoTableArm()[Kind - FirstArmRelocation]->checkOpcode(R.Wd);
+  return getDynFixupInfo<FixupInfoBaseArm>(Kind).checkOpcode(R.Wd);
 }
 
 static bool checkOpcode(const ThumbRelocation &R, Edge::Kind Kind) {
   assert(Kind >= FirstThumbRelocation && Kind <= LastThumbRelocation &&
          "Edge kind is no Thumb relocation");
-  assert(getFixupInfoTableThumb().at(Kind - FirstThumbRelocation) != nullptr &&
-         "Call populateFixupInfos() before dynamic access");
-  return getFixupInfoTableThumb()[Kind - FirstThumbRelocation]->checkOpcode(R.Hi, R.Lo);
+  return getDynFixupInfo<FixupInfoBaseThumb>(Kind).checkOpcode(R.Hi, R.Lo);
 }
 
 template <EdgeKind_aarch32 Kind>

>From 8cb9279be7a3fe6e81b6d483dc3888f460e75e6a Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Stefan=20Gr=C3=A4nitz?= <stefan.graenitz at gmail.com>
Date: Wed, 8 Nov 2023 19:01:59 +0100
Subject: [PATCH 3/6] [JITLink][AArch32] For better performance, assign
 checkOpcode() implementations as function pointers during initialization

---
 llvm/include/llvm/ExecutionEngine/JITLink/aarch32.h | 8 ++++----
 llvm/lib/ExecutionEngine/JITLink/aarch32.cpp        | 4 +++-
 2 files changed, 7 insertions(+), 5 deletions(-)

diff --git a/llvm/include/llvm/ExecutionEngine/JITLink/aarch32.h b/llvm/include/llvm/ExecutionEngine/JITLink/aarch32.h
index 4218f4181a6d507..1fbd2cde7738d0f 100644
--- a/llvm/include/llvm/ExecutionEngine/JITLink/aarch32.h
+++ b/llvm/include/llvm/ExecutionEngine/JITLink/aarch32.h
@@ -169,23 +169,23 @@ struct FixupInfoBase {
 };
 
 struct FixupInfoBaseArm : public FixupInfoBase {
-  virtual bool checkOpcode(uint32_t Wd) const = 0;
+  bool (*checkOpcode)(uint32_t Wd) = nullptr;
 };
 
 struct FixupInfoBaseThumb : public FixupInfoBase {
-  virtual bool checkOpcode(uint16_t Hi, uint16_t Lo) const = 0;
+  bool (*checkOpcode)(uint16_t Hi, uint16_t Lo) = nullptr;
 };
 
 template <EdgeKind_aarch32 Kind> struct FixupInfo;
 
 template <EdgeKind_aarch32 Kind> struct FixupInfoArm : public FixupInfoBaseArm {
-  bool checkOpcode(uint32_t Wd) const override {
+  static bool checkOpcodeImpl(uint32_t Wd) {
     return (Wd & FixupInfo<Kind>::OpcodeMask) == FixupInfo<Kind>::Opcode;
   }
 };
 
 template <EdgeKind_aarch32 Kind> struct FixupInfoThumb : public FixupInfoBaseThumb {
-  bool checkOpcode(uint16_t Hi, uint16_t Lo) const override {
+  static bool checkOpcodeImpl(uint16_t Hi, uint16_t Lo) {
     return (Hi & FixupInfo<Kind>::OpcodeMask.Hi) == FixupInfo<Kind>::Opcode.Hi &&
            (Lo & FixupInfo<Kind>::OpcodeMask.Lo) == FixupInfo<Kind>::Opcode.Lo;
   }
diff --git a/llvm/lib/ExecutionEngine/JITLink/aarch32.cpp b/llvm/lib/ExecutionEngine/JITLink/aarch32.cpp
index 332eda0c69b09c5..356cf6d8ae11de8 100644
--- a/llvm/lib/ExecutionEngine/JITLink/aarch32.cpp
+++ b/llvm/lib/ExecutionEngine/JITLink/aarch32.cpp
@@ -256,7 +256,9 @@ static auto &getFixupInfoTable() {
 template <EdgeKind_aarch32 It, EdgeKind_aarch32 Last, typename TableT>
 void populateFixupInfos(TableT &Table) {
   assert(It < Table.size() && Table.at(It) == nullptr && "Once set, entries are immutable");
-  Table[It] = std::make_unique<FixupInfo<It>>();
+  auto Entry = std::make_unique<FixupInfo<It>>();
+  Entry->checkOpcode = FixupInfo<It>::checkOpcodeImpl;
+  Table[It] = std::move(Entry);
   if constexpr (It < Last) {
     constexpr auto Next = static_cast<EdgeKind_aarch32>(It + 1);
     populateFixupInfos<Next, Last>(Table);

>From ac1f3782ba5642a183be675878e618ddf1849632 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Stefan=20Gr=C3=A4nitz?= <stefan.graenitz at gmail.com>
Date: Wed, 8 Nov 2023 19:18:30 +0100
Subject: [PATCH 4/6] Fix formatting and polish

---
 .../llvm/ExecutionEngine/JITLink/aarch32.h    | 28 +++++++++++--------
 llvm/lib/ExecutionEngine/JITLink/aarch32.cpp  | 16 ++++++-----
 2 files changed, 26 insertions(+), 18 deletions(-)

diff --git a/llvm/include/llvm/ExecutionEngine/JITLink/aarch32.h b/llvm/include/llvm/ExecutionEngine/JITLink/aarch32.h
index 1fbd2cde7738d0f..94c422de82cbc50 100644
--- a/llvm/include/llvm/ExecutionEngine/JITLink/aarch32.h
+++ b/llvm/include/llvm/ExecutionEngine/JITLink/aarch32.h
@@ -176,18 +176,19 @@ struct FixupInfoBaseThumb : public FixupInfoBase {
   bool (*checkOpcode)(uint16_t Hi, uint16_t Lo) = nullptr;
 };
 
-template <EdgeKind_aarch32 Kind> struct FixupInfo;
+template <EdgeKind_aarch32 K> struct FixupInfo;
 
-template <EdgeKind_aarch32 Kind> struct FixupInfoArm : public FixupInfoBaseArm {
+template <EdgeKind_aarch32 K> struct FixupInfoArm : public FixupInfoBaseArm {
   static bool checkOpcodeImpl(uint32_t Wd) {
-    return (Wd & FixupInfo<Kind>::OpcodeMask) == FixupInfo<Kind>::Opcode;
+    return (Wd & FixupInfo<K>::OpcodeMask) == FixupInfo<K>::Opcode;
   }
 };
 
-template <EdgeKind_aarch32 Kind> struct FixupInfoThumb : public FixupInfoBaseThumb {
+template <EdgeKind_aarch32 K>
+struct FixupInfoThumb : public FixupInfoBaseThumb {
   static bool checkOpcodeImpl(uint16_t Hi, uint16_t Lo) {
-    return (Hi & FixupInfo<Kind>::OpcodeMask.Hi) == FixupInfo<Kind>::Opcode.Hi &&
-           (Lo & FixupInfo<Kind>::OpcodeMask.Lo) == FixupInfo<Kind>::Opcode.Lo;
+    return (Hi & FixupInfo<K>::OpcodeMask.Hi) == FixupInfo<K>::Opcode.Hi &&
+           (Lo & FixupInfo<K>::OpcodeMask.Lo) == FixupInfo<K>::Opcode.Lo;
   }
 };
 
@@ -214,7 +215,8 @@ struct FixupInfoArmBranch : public FixupInfoArm<Kind> {
 };
 } // namespace
 
-template <> struct FixupInfo<Arm_Jump24> : public FixupInfoArmBranch<Arm_Jump24> {
+template <>
+struct FixupInfo<Arm_Jump24> : public FixupInfoArmBranch<Arm_Jump24> {
   static constexpr uint32_t OpcodeMask = 0x0f000000;
 };
 
@@ -235,15 +237,18 @@ struct FixupInfoArmMov : public FixupInfoArm<Kind> {
 };
 } // namespace
 
-template <> struct FixupInfo<Arm_MovtAbs> : public FixupInfoArmMov<Arm_MovtAbs> {
+template <>
+struct FixupInfo<Arm_MovtAbs> : public FixupInfoArmMov<Arm_MovtAbs> {
   static constexpr uint32_t Opcode = 0x03400000;
 };
 
-template <> struct FixupInfo<Arm_MovwAbsNC> : public FixupInfoArmMov<Arm_MovwAbsNC> {
+template <>
+struct FixupInfo<Arm_MovwAbsNC> : public FixupInfoArmMov<Arm_MovwAbsNC> {
   static constexpr uint32_t Opcode = 0x03000000;
 };
 
-template <> struct FixupInfo<Thumb_Jump24> : public FixupInfoThumb<Thumb_Jump24> {
+template <>
+struct FixupInfo<Thumb_Jump24> : public FixupInfoThumb<Thumb_Jump24> {
   static constexpr HalfWords Opcode{0xf000, 0x9000};
   static constexpr HalfWords OpcodeMask{0xf800, 0x9000};
   static constexpr HalfWords ImmMask{0x07ff, 0x2fff};
@@ -282,7 +287,8 @@ struct FixupInfo<Thumb_MovwAbsNC> : public FixupInfoThumbMov<Thumb_MovwAbsNC> {
 };
 
 template <>
-struct FixupInfo<Thumb_MovwPrelNC> : public FixupInfoThumbMov<Thumb_MovwPrelNC> {
+struct FixupInfo<Thumb_MovwPrelNC>
+    : public FixupInfoThumbMov<Thumb_MovwPrelNC> {
   static constexpr HalfWords Opcode{0xf240, 0x0000};
 };
 
diff --git a/llvm/lib/ExecutionEngine/JITLink/aarch32.cpp b/llvm/lib/ExecutionEngine/JITLink/aarch32.cpp
index 356cf6d8ae11de8..fe2c6ac82009449 100644
--- a/llvm/lib/ExecutionEngine/JITLink/aarch32.cpp
+++ b/llvm/lib/ExecutionEngine/JITLink/aarch32.cpp
@@ -255,7 +255,8 @@ static auto &getFixupInfoTable() {
 
 template <EdgeKind_aarch32 It, EdgeKind_aarch32 Last, typename TableT>
 void populateFixupInfos(TableT &Table) {
-  assert(It < Table.size() && Table.at(It) == nullptr && "Once set, entries are immutable");
+  assert(It < Table.size() && "Index out of range");
+  assert(Table.at(It) == nullptr && "Initialized entries are immutable");
   auto Entry = std::make_unique<FixupInfo<It>>();
   Entry->checkOpcode = FixupInfo<It>::checkOpcodeImpl;
   Table[It] = std::move(Entry);
@@ -268,8 +269,9 @@ void populateFixupInfos(TableT &Table) {
 void populateFixupInfos() {
   static std::once_flag Flag;
   std::call_once(Flag, []() {
-    populateFixupInfos<FirstArmRelocation, LastArmRelocation>(getFixupInfoTable());
-    populateFixupInfos<FirstThumbRelocation, LastThumbRelocation>(getFixupInfoTable());
+    auto &Table = getFixupInfoTable();
+    populateFixupInfos<FirstArmRelocation, LastArmRelocation>(Table);
+    populateFixupInfos<FirstThumbRelocation, LastThumbRelocation>(Table);
   });
 }
 
@@ -361,7 +363,7 @@ Expected<int64_t> readAddendArm(LinkGraph &G, Block &B, const Edge &E) {
   ArmRelocation R(B.getContent().data() + E.getOffset());
   Edge::Kind Kind = E.getKind();
   if (!checkOpcode(R, Kind))
-      return makeUnexpectedOpcodeError(G, R, Kind);
+    return makeUnexpectedOpcodeError(G, R, Kind);
 
   switch (Kind) {
   case Arm_Call:
@@ -385,7 +387,7 @@ Expected<int64_t> readAddendThumb(LinkGraph &G, Block &B, const Edge &E,
   ThumbRelocation R(B.getContent().data() + E.getOffset());
   Edge::Kind Kind = E.getKind();
   if (!checkOpcode(R, Kind))
-      return makeUnexpectedOpcodeError(G, R, Kind);
+    return makeUnexpectedOpcodeError(G, R, Kind);
 
   switch (Kind) {
   case Thumb_Call:
@@ -463,7 +465,7 @@ Error applyFixupArm(LinkGraph &G, Block &B, const Edge &E) {
   WritableArmRelocation R(B.getAlreadyMutableContent().data() + E.getOffset());
   Edge::Kind Kind = E.getKind();
   if (!checkOpcode(R, Kind))
-      return makeUnexpectedOpcodeError(G, R, Kind);
+    return makeUnexpectedOpcodeError(G, R, Kind);
 
   uint64_t FixupAddress = (B.getAddress() + E.getOffset()).getValue();
   int64_t Addend = E.getAddend();
@@ -539,7 +541,7 @@ Error applyFixupThumb(LinkGraph &G, Block &B, const Edge &E,
                             E.getOffset());
   Edge::Kind Kind = E.getKind();
   if (!checkOpcode(R, Kind))
-      return makeUnexpectedOpcodeError(G, R, Kind);
+    return makeUnexpectedOpcodeError(G, R, Kind);
 
   uint64_t FixupAddress = (B.getAddress() + E.getOffset()).getValue();
   int64_t Addend = E.getAddend();

>From 5f919ac4c393f87b452b1d597539c0ee616211dc Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Stefan=20Gr=C3=A4nitz?= <stefan.graenitz at gmail.com>
Date: Thu, 9 Nov 2023 14:32:08 +0100
Subject: [PATCH 5/6] Rebase and reduce template boilerplate in header file

---
 .../llvm/ExecutionEngine/JITLink/aarch32.h    | 57 ++++++--------
 llvm/lib/ExecutionEngine/JITLink/aarch32.cpp  | 75 +++++++++++++++----
 2 files changed, 82 insertions(+), 50 deletions(-)

diff --git a/llvm/include/llvm/ExecutionEngine/JITLink/aarch32.h b/llvm/include/llvm/ExecutionEngine/JITLink/aarch32.h
index 94c422de82cbc50..14ab5e4b093369c 100644
--- a/llvm/include/llvm/ExecutionEngine/JITLink/aarch32.h
+++ b/llvm/include/llvm/ExecutionEngine/JITLink/aarch32.h
@@ -164,34 +164,24 @@ struct HalfWords {
   const uint16_t Lo; // Second halfword
 };
 
+/// Initialize the lookup table for dynamic FixupInfo checks, e.g. checkOpcode()
+void populateFixupInfos();
+
+/// FixupInfo base class is required for dynamic lookups.
 struct FixupInfoBase {
   virtual ~FixupInfoBase() {}
 };
 
-struct FixupInfoBaseArm : public FixupInfoBase {
+/// FixupInfo checks for Arm edge kinds work on 32-bit words
+struct FixupInfoArm : public FixupInfoBase {
   bool (*checkOpcode)(uint32_t Wd) = nullptr;
 };
 
-struct FixupInfoBaseThumb : public FixupInfoBase {
+/// FixupInfo check for Thumb32 edge kinds work on a pair of 16-bit halfwords
+struct FixupInfoThumb : public FixupInfoBase {
   bool (*checkOpcode)(uint16_t Hi, uint16_t Lo) = nullptr;
 };
 
-template <EdgeKind_aarch32 K> struct FixupInfo;
-
-template <EdgeKind_aarch32 K> struct FixupInfoArm : public FixupInfoBaseArm {
-  static bool checkOpcodeImpl(uint32_t Wd) {
-    return (Wd & FixupInfo<K>::OpcodeMask) == FixupInfo<K>::Opcode;
-  }
-};
-
-template <EdgeKind_aarch32 K>
-struct FixupInfoThumb : public FixupInfoBaseThumb {
-  static bool checkOpcodeImpl(uint16_t Hi, uint16_t Lo) {
-    return (Hi & FixupInfo<K>::OpcodeMask.Hi) == FixupInfo<K>::Opcode.Hi &&
-           (Lo & FixupInfo<K>::OpcodeMask.Lo) == FixupInfo<K>::Opcode.Lo;
-  }
-};
-
 /// Collection of named constants per fixup kind
 ///
 /// Mandatory entries:
@@ -208,19 +198,18 @@ struct FixupInfoThumb : public FixupInfoBaseThumb {
 template <EdgeKind_aarch32 Kind> struct FixupInfo {};
 
 namespace {
-template <EdgeKind_aarch32 Kind>
-struct FixupInfoArmBranch : public FixupInfoArm<Kind> {
+struct FixupInfoArmBranch : public FixupInfoArm {
   static constexpr uint32_t Opcode = 0x0a000000;
   static constexpr uint32_t ImmMask = 0x00ffffff;
 };
 } // namespace
 
 template <>
-struct FixupInfo<Arm_Jump24> : public FixupInfoArmBranch<Arm_Jump24> {
+struct FixupInfo<Arm_Jump24> : public FixupInfoArmBranch {
   static constexpr uint32_t OpcodeMask = 0x0f000000;
 };
 
-template <> struct FixupInfo<Arm_Call> : public FixupInfoArmBranch<Arm_Call> {
+template <> struct FixupInfo<Arm_Call> : public FixupInfoArmBranch {
   static constexpr uint32_t OpcodeMask = 0x0e000000;
   static constexpr uint32_t CondMask = 0xe0000000; // excluding BLX bit
   static constexpr uint32_t Unconditional = 0xe0000000;
@@ -229,8 +218,7 @@ template <> struct FixupInfo<Arm_Call> : public FixupInfoArmBranch<Arm_Call> {
 };
 
 namespace {
-template <EdgeKind_aarch32 Kind>
-struct FixupInfoArmMov : public FixupInfoArm<Kind> {
+struct FixupInfoArmMov : public FixupInfoArm {
   static constexpr uint32_t OpcodeMask = 0x0ff00000;
   static constexpr uint32_t ImmMask = 0x000f0fff;
   static constexpr uint32_t RegMask = 0x0000f000;
@@ -238,23 +226,23 @@ struct FixupInfoArmMov : public FixupInfoArm<Kind> {
 } // namespace
 
 template <>
-struct FixupInfo<Arm_MovtAbs> : public FixupInfoArmMov<Arm_MovtAbs> {
+struct FixupInfo<Arm_MovtAbs> : public FixupInfoArmMov {
   static constexpr uint32_t Opcode = 0x03400000;
 };
 
 template <>
-struct FixupInfo<Arm_MovwAbsNC> : public FixupInfoArmMov<Arm_MovwAbsNC> {
+struct FixupInfo<Arm_MovwAbsNC> : public FixupInfoArmMov {
   static constexpr uint32_t Opcode = 0x03000000;
 };
 
 template <>
-struct FixupInfo<Thumb_Jump24> : public FixupInfoThumb<Thumb_Jump24> {
+struct FixupInfo<Thumb_Jump24> : public FixupInfoThumb {
   static constexpr HalfWords Opcode{0xf000, 0x9000};
   static constexpr HalfWords OpcodeMask{0xf800, 0x9000};
   static constexpr HalfWords ImmMask{0x07ff, 0x2fff};
 };
 
-template <> struct FixupInfo<Thumb_Call> : public FixupInfoThumb<Thumb_Call> {
+template <> struct FixupInfo<Thumb_Call> : public FixupInfoThumb {
   static constexpr HalfWords Opcode{0xf000, 0xc000};
   static constexpr HalfWords OpcodeMask{0xf800, 0xc000};
   static constexpr HalfWords ImmMask{0x07ff, 0x2fff};
@@ -263,8 +251,7 @@ template <> struct FixupInfo<Thumb_Call> : public FixupInfoThumb<Thumb_Call> {
 };
 
 namespace {
-template <EdgeKind_aarch32 Kind>
-struct FixupInfoThumbMov : public FixupInfoThumb<Kind> {
+struct FixupInfoThumbMov : public FixupInfoThumb {
   static constexpr HalfWords OpcodeMask{0xfbf0, 0x8000};
   static constexpr HalfWords ImmMask{0x040f, 0x70ff};
   static constexpr HalfWords RegMask{0x0000, 0x0f00};
@@ -272,28 +259,26 @@ struct FixupInfoThumbMov : public FixupInfoThumb<Kind> {
 } // namespace
 
 template <>
-struct FixupInfo<Thumb_MovtAbs> : public FixupInfoThumbMov<Thumb_MovtAbs> {
+struct FixupInfo<Thumb_MovtAbs> : public FixupInfoThumbMov {
   static constexpr HalfWords Opcode{0xf2c0, 0x0000};
 };
 
 template <>
-struct FixupInfo<Thumb_MovtPrel> : public FixupInfoThumbMov<Thumb_MovtPrel> {
+struct FixupInfo<Thumb_MovtPrel> : public FixupInfoThumbMov {
   static constexpr HalfWords Opcode{0xf2c0, 0x0000};
 };
 
 template <>
-struct FixupInfo<Thumb_MovwAbsNC> : public FixupInfoThumbMov<Thumb_MovwAbsNC> {
+struct FixupInfo<Thumb_MovwAbsNC> : public FixupInfoThumbMov {
   static constexpr HalfWords Opcode{0xf240, 0x0000};
 };
 
 template <>
 struct FixupInfo<Thumb_MovwPrelNC>
-    : public FixupInfoThumbMov<Thumb_MovwPrelNC> {
+    : public FixupInfoThumbMov {
   static constexpr HalfWords Opcode{0xf240, 0x0000};
 };
 
-void populateFixupInfos();
-
 /// Helper function to read the initial addend for Data-class relocations.
 Expected<int64_t> readAddendData(LinkGraph &G, Block &B, const Edge &E);
 
diff --git a/llvm/lib/ExecutionEngine/JITLink/aarch32.cpp b/llvm/lib/ExecutionEngine/JITLink/aarch32.cpp
index fe2c6ac82009449..e5cf6ecb4eb415e 100644
--- a/llvm/lib/ExecutionEngine/JITLink/aarch32.cpp
+++ b/llvm/lib/ExecutionEngine/JITLink/aarch32.cpp
@@ -189,6 +189,8 @@ int64_t decodeRegMovtA1MovwA2(uint64_t Value) {
   return Rd4;
 }
 
+namespace {
+
 /// 32-bit Thumb instructions are stored as two little-endian halfwords.
 /// An instruction at address A encodes bytes A+1, A in the first halfword (Hi),
 /// followed by bytes A+3, A+2 in the second halfword (Lo).
@@ -253,18 +255,53 @@ static auto &getFixupInfoTable() {
   return FixupInfoTable;
 }
 
-template <EdgeKind_aarch32 It, EdgeKind_aarch32 Last, typename TableT>
+template <EdgeKind_aarch32 K> constexpr bool isArm() {
+  return FirstArmRelocation <= K && K <= LastArmRelocation;
+}
+template <EdgeKind_aarch32 K> constexpr bool isThumb() {
+  return FirstThumbRelocation <= K && K <= LastThumbRelocation;
+}
+
+template <EdgeKind_aarch32 K> constexpr bool hasOpcode(...) { return false; }
+template <EdgeKind_aarch32 K, auto _ = FixupInfo<K>::Opcode>
+constexpr bool hasOpcode(int) { return true; }
+
+template <EdgeKind_aarch32 K>
+static bool checkOpcodeArm(uint32_t Wd) {
+  return (Wd & FixupInfo<K>::OpcodeMask) == FixupInfo<K>::Opcode;
+}
+
+template <EdgeKind_aarch32 K>
+static bool checkOpcodeThumb(uint16_t Hi, uint16_t Lo) {
+    return (Hi & FixupInfo<K>::OpcodeMask.Hi) == FixupInfo<K>::Opcode.Hi &&
+           (Lo & FixupInfo<K>::OpcodeMask.Lo) == FixupInfo<K>::Opcode.Lo;
+}
+
+template <EdgeKind_aarch32 K>
+static std::unique_ptr<FixupInfoBase> initFixupInfo() {
+  auto Entry = std::make_unique<FixupInfo<K>>();
+  if constexpr (hasOpcode<K>(0)) {
+    if constexpr (isArm<K>())
+      Entry->checkOpcode = checkOpcodeArm<K>;
+    else if constexpr (isThumb<K>())
+      Entry->checkOpcode = checkOpcodeThumb<K>;
+    else
+      llvm_unreachable("Visited edge kinds must either be Arm or Thumb");
+  }
+  return Entry;
+}
+
+template <EdgeKind_aarch32 K, EdgeKind_aarch32 LastK, typename TableT>
 void populateFixupInfos(TableT &Table) {
-  assert(It < Table.size() && "Index out of range");
-  assert(Table.at(It) == nullptr && "Initialized entries are immutable");
-  auto Entry = std::make_unique<FixupInfo<It>>();
-  Entry->checkOpcode = FixupInfo<It>::checkOpcodeImpl;
-  Table[It] = std::move(Entry);
-  if constexpr (It < Last) {
-    constexpr auto Next = static_cast<EdgeKind_aarch32>(It + 1);
-    populateFixupInfos<Next, Last>(Table);
+  assert(K < Table.size() && "Index out of range");
+  assert(Table.at(K) == nullptr && "Initialized entries are immutable");
+  Table[K] = initFixupInfo<K>();
+  if constexpr (K < LastK) {
+    constexpr auto Next = static_cast<EdgeKind_aarch32>(K + 1);
+    populateFixupInfos<Next, LastK>(Table);
   }
 }
+} // namespace
 
 void populateFixupInfos() {
   static std::once_flag Flag;
@@ -276,23 +313,33 @@ void populateFixupInfos() {
 }
 
 template <typename TargetModeSubclass>
-const TargetModeSubclass &getDynFixupInfo(Edge::Kind K) {
+static const TargetModeSubclass * const getDynFixupInfo(Edge::Kind K) {
   assert(K >= Edge::FirstRelocation && "Invalid value for edge kind");
   assert(K <= LastRelocation && "Invalid value for edge kind");
-  assert(getFixupInfoTable().at(K) && "Call populateFixupInfos() first");
-  return *static_cast<TargetModeSubclass *>(getFixupInfoTable().at(K).get());
+  assert(getFixupInfoTable().at(K) && "Please call populateFixupInfos() first");
+  return static_cast<TargetModeSubclass *>(getFixupInfoTable().at(K).get());
 }
 
 static bool checkOpcode(const ArmRelocation &R, Edge::Kind Kind) {
   assert(Kind >= FirstArmRelocation && Kind <= LastArmRelocation &&
          "Edge kind is no Arm relocation");
-  return getDynFixupInfo<FixupInfoBaseArm>(Kind).checkOpcode(R.Wd);
+  const FixupInfoArm *const Info = getDynFixupInfo<FixupInfoArm>(Kind);
+  if (LLVM_LIKELY(Info) && LLVM_LIKELY(Info->checkOpcode))
+    return Info->checkOpcode(R.Wd);
+  LLVM_DEBUG(dbgs() << "Can not perform Opcode check for aarch32 edge kind "
+                    << getEdgeKindName(Kind));
+  return true;
 }
 
 static bool checkOpcode(const ThumbRelocation &R, Edge::Kind Kind) {
   assert(Kind >= FirstThumbRelocation && Kind <= LastThumbRelocation &&
          "Edge kind is no Thumb relocation");
-  return getDynFixupInfo<FixupInfoBaseThumb>(Kind).checkOpcode(R.Hi, R.Lo);
+  const FixupInfoThumb *const Info = getDynFixupInfo<FixupInfoThumb>(Kind);
+  if (LLVM_LIKELY(Info) && LLVM_LIKELY(Info->checkOpcode))
+    return Info->checkOpcode(R.Hi, R.Lo);
+  LLVM_DEBUG(dbgs() << "Can not perform Opcode check for aarch32 edge kind "
+                    << getEdgeKindName(Kind));
+  return true;
 }
 
 template <EdgeKind_aarch32 Kind>

>From 339f27ab9a88c4829a450d2f5e31bb57f59f838a Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Stefan=20Gr=C3=A4nitz?= <stefan.graenitz at gmail.com>
Date: Thu, 9 Nov 2023 15:23:07 +0100
Subject: [PATCH 6/6] Apply clang-format

---
 .../llvm/ExecutionEngine/JITLink/aarch32.h    | 25 ++++++-------------
 llvm/lib/ExecutionEngine/JITLink/aarch32.cpp  | 13 +++++-----
 2 files changed, 15 insertions(+), 23 deletions(-)

diff --git a/llvm/include/llvm/ExecutionEngine/JITLink/aarch32.h b/llvm/include/llvm/ExecutionEngine/JITLink/aarch32.h
index 14ab5e4b093369c..870b8cdb9c34c01 100644
--- a/llvm/include/llvm/ExecutionEngine/JITLink/aarch32.h
+++ b/llvm/include/llvm/ExecutionEngine/JITLink/aarch32.h
@@ -204,8 +204,7 @@ struct FixupInfoArmBranch : public FixupInfoArm {
 };
 } // namespace
 
-template <>
-struct FixupInfo<Arm_Jump24> : public FixupInfoArmBranch {
+template <> struct FixupInfo<Arm_Jump24> : public FixupInfoArmBranch {
   static constexpr uint32_t OpcodeMask = 0x0f000000;
 };
 
@@ -225,18 +224,15 @@ struct FixupInfoArmMov : public FixupInfoArm {
 };
 } // namespace
 
-template <>
-struct FixupInfo<Arm_MovtAbs> : public FixupInfoArmMov {
+template <> struct FixupInfo<Arm_MovtAbs> : public FixupInfoArmMov {
   static constexpr uint32_t Opcode = 0x03400000;
 };
 
-template <>
-struct FixupInfo<Arm_MovwAbsNC> : public FixupInfoArmMov {
+template <> struct FixupInfo<Arm_MovwAbsNC> : public FixupInfoArmMov {
   static constexpr uint32_t Opcode = 0x03000000;
 };
 
-template <>
-struct FixupInfo<Thumb_Jump24> : public FixupInfoThumb {
+template <> struct FixupInfo<Thumb_Jump24> : public FixupInfoThumb {
   static constexpr HalfWords Opcode{0xf000, 0x9000};
   static constexpr HalfWords OpcodeMask{0xf800, 0x9000};
   static constexpr HalfWords ImmMask{0x07ff, 0x2fff};
@@ -258,24 +254,19 @@ struct FixupInfoThumbMov : public FixupInfoThumb {
 };
 } // namespace
 
-template <>
-struct FixupInfo<Thumb_MovtAbs> : public FixupInfoThumbMov {
+template <> struct FixupInfo<Thumb_MovtAbs> : public FixupInfoThumbMov {
   static constexpr HalfWords Opcode{0xf2c0, 0x0000};
 };
 
-template <>
-struct FixupInfo<Thumb_MovtPrel> : public FixupInfoThumbMov {
+template <> struct FixupInfo<Thumb_MovtPrel> : public FixupInfoThumbMov {
   static constexpr HalfWords Opcode{0xf2c0, 0x0000};
 };
 
-template <>
-struct FixupInfo<Thumb_MovwAbsNC> : public FixupInfoThumbMov {
+template <> struct FixupInfo<Thumb_MovwAbsNC> : public FixupInfoThumbMov {
   static constexpr HalfWords Opcode{0xf240, 0x0000};
 };
 
-template <>
-struct FixupInfo<Thumb_MovwPrelNC>
-    : public FixupInfoThumbMov {
+template <> struct FixupInfo<Thumb_MovwPrelNC> : public FixupInfoThumbMov {
   static constexpr HalfWords Opcode{0xf240, 0x0000};
 };
 
diff --git a/llvm/lib/ExecutionEngine/JITLink/aarch32.cpp b/llvm/lib/ExecutionEngine/JITLink/aarch32.cpp
index e5cf6ecb4eb415e..616a7781c1f341e 100644
--- a/llvm/lib/ExecutionEngine/JITLink/aarch32.cpp
+++ b/llvm/lib/ExecutionEngine/JITLink/aarch32.cpp
@@ -264,17 +264,18 @@ template <EdgeKind_aarch32 K> constexpr bool isThumb() {
 
 template <EdgeKind_aarch32 K> constexpr bool hasOpcode(...) { return false; }
 template <EdgeKind_aarch32 K, auto _ = FixupInfo<K>::Opcode>
-constexpr bool hasOpcode(int) { return true; }
+constexpr bool hasOpcode(int) {
+  return true;
+}
 
-template <EdgeKind_aarch32 K>
-static bool checkOpcodeArm(uint32_t Wd) {
+template <EdgeKind_aarch32 K> static bool checkOpcodeArm(uint32_t Wd) {
   return (Wd & FixupInfo<K>::OpcodeMask) == FixupInfo<K>::Opcode;
 }
 
 template <EdgeKind_aarch32 K>
 static bool checkOpcodeThumb(uint16_t Hi, uint16_t Lo) {
-    return (Hi & FixupInfo<K>::OpcodeMask.Hi) == FixupInfo<K>::Opcode.Hi &&
-           (Lo & FixupInfo<K>::OpcodeMask.Lo) == FixupInfo<K>::Opcode.Lo;
+  return (Hi & FixupInfo<K>::OpcodeMask.Hi) == FixupInfo<K>::Opcode.Hi &&
+         (Lo & FixupInfo<K>::OpcodeMask.Lo) == FixupInfo<K>::Opcode.Lo;
 }
 
 template <EdgeKind_aarch32 K>
@@ -313,7 +314,7 @@ void populateFixupInfos() {
 }
 
 template <typename TargetModeSubclass>
-static const TargetModeSubclass * const getDynFixupInfo(Edge::Kind K) {
+static const TargetModeSubclass *const getDynFixupInfo(Edge::Kind K) {
   assert(K >= Edge::FirstRelocation && "Invalid value for edge kind");
   assert(K <= LastRelocation && "Invalid value for edge kind");
   assert(getFixupInfoTable().at(K) && "Please call populateFixupInfos() first");



More information about the llvm-commits mailing list