[llvm] [JITLink][AArch32] Add TableGen Backend for Instr Encodings (PR #76996)

Eymen Ünay via llvm-commits llvm-commits at lists.llvm.org
Thu Jan 4 12:12:55 PST 2024


https://github.com/eymay created https://github.com/llvm/llvm-project/pull/76996

This TableGen backend uses the Target info in lib/Target/ARM to
produce instruction encodings necessary for JITLink AArch32 backend.
Currently opcode, opcode mask, register mask and immediate mask are
generated. These were used to replace the `mov` related instruction
information in `aarch32.h`.


>From becbe3a324aa8b484a539cb5e07ea1caf6db5e11 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Eymen=20=C3=9Cnay?= <eymenunay at outlook.com>
Date: Fri, 22 Dec 2023 17:56:07 +0300
Subject: [PATCH] [JITLink][AArch32] Add TableGen Backend for Instr Encodings

This TableGen backend uses the Target info in lib/Target/ARM to
produce instruction encodings necessary for JITLink AArch32 backend.
Currently opcode, opcode mask, register mask and immediate mask are
generated. These were used to replace the `mov` related instruction
information in aarch32.h.
---
 .../llvm/ExecutionEngine/JITLink/aarch32.h    |  35 ----
 .../ExecutionEngine/JITLink/CMakeLists.txt    |   5 +
 llvm/lib/ExecutionEngine/JITLink/aarch32.cpp  |   2 +
 .../ExecutionEngine/JITLink/AArch32Tests.cpp  |   2 +
 .../JITLink/JITLinkAArch32.inc                |  58 ++++++
 llvm/utils/TableGen/CMakeLists.txt            |   5 +
 .../TableGen/JITLinkAArch32InstrInfo.cpp      | 196 ++++++++++++++++++
 7 files changed, 268 insertions(+), 35 deletions(-)
 create mode 100644 llvm/unittests/ExecutionEngine/JITLink/JITLinkAArch32.inc
 create mode 100644 llvm/utils/TableGen/JITLinkAArch32InstrInfo.cpp

diff --git a/llvm/include/llvm/ExecutionEngine/JITLink/aarch32.h b/llvm/include/llvm/ExecutionEngine/JITLink/aarch32.h
index f346cfb2a93112..a0c25b56770f5a 100644
--- a/llvm/include/llvm/ExecutionEngine/JITLink/aarch32.h
+++ b/llvm/include/llvm/ExecutionEngine/JITLink/aarch32.h
@@ -212,20 +212,6 @@ template <> struct FixupInfo<Arm_Call> : public FixupInfoArmBranch {
   static constexpr uint32_t BitBlx = 0x10000000;
 };
 
-struct FixupInfoArmMov : public FixupInfoArm {
-  static constexpr uint32_t OpcodeMask = 0x0ff00000;
-  static constexpr uint32_t ImmMask = 0x000f0fff;
-  static constexpr uint32_t RegMask = 0x0000f000;
-};
-
-template <> struct FixupInfo<Arm_MovtAbs> : public FixupInfoArmMov {
-  static constexpr uint32_t Opcode = 0x03400000;
-};
-
-template <> struct FixupInfo<Arm_MovwAbsNC> : public FixupInfoArmMov {
-  static constexpr uint32_t Opcode = 0x03000000;
-};
-
 template <> struct FixupInfo<Thumb_Jump24> : public FixupInfoThumb {
   static constexpr HalfWords Opcode{0xf000, 0x9000};
   static constexpr HalfWords OpcodeMask{0xf800, 0x9000};
@@ -240,27 +226,6 @@ template <> struct FixupInfo<Thumb_Call> : public FixupInfoThumb {
   static constexpr uint16_t LoBitNoBlx = 0x1000;
 };
 
-struct FixupInfoThumbMov : public FixupInfoThumb {
-  static constexpr HalfWords OpcodeMask{0xfbf0, 0x8000};
-  static constexpr HalfWords ImmMask{0x040f, 0x70ff};
-  static constexpr HalfWords RegMask{0x0000, 0x0f00};
-};
-
-template <> struct FixupInfo<Thumb_MovtAbs> : public FixupInfoThumbMov {
-  static constexpr HalfWords Opcode{0xf2c0, 0x0000};
-};
-
-template <> struct FixupInfo<Thumb_MovtPrel> : public FixupInfoThumbMov {
-  static constexpr HalfWords Opcode{0xf2c0, 0x0000};
-};
-
-template <> struct FixupInfo<Thumb_MovwAbsNC> : public FixupInfoThumbMov {
-  static constexpr HalfWords Opcode{0xf240, 0x0000};
-};
-
-template <> struct FixupInfo<Thumb_MovwPrelNC> : public FixupInfoThumbMov {
-  static constexpr HalfWords Opcode{0xf240, 0x0000};
-};
 
 /// Helper function to read the initial addend for Data-class relocations.
 Expected<int64_t> readAddendData(LinkGraph &G, Block &B, Edge::OffsetT Offset,
diff --git a/llvm/lib/ExecutionEngine/JITLink/CMakeLists.txt b/llvm/lib/ExecutionEngine/JITLink/CMakeLists.txt
index e5f5a99c39bc00..524bd9fad8e53e 100644
--- a/llvm/lib/ExecutionEngine/JITLink/CMakeLists.txt
+++ b/llvm/lib/ExecutionEngine/JITLink/CMakeLists.txt
@@ -1,5 +1,10 @@
 set(LLVM_TARGET_DEFINITIONS COFFOptions.td)
 tablegen(LLVM COFFOptions.inc -gen-opt-parser-defs)
+
+include_directories(${PROJECT_SOURCE_DIR}/lib/Target/ARM/)
+set(LLVM_TARGET_DEFINITIONS ${PROJECT_SOURCE_DIR}/lib/Target/ARM/ARM.td)
+tablegen(LLVM JITLinkAArch32.inc -gen-jitlink-aarch32-instr-info)
+
 add_public_tablegen_target(JITLinkTableGen)
 
 add_llvm_component_library(LLVMJITLink
diff --git a/llvm/lib/ExecutionEngine/JITLink/aarch32.cpp b/llvm/lib/ExecutionEngine/JITLink/aarch32.cpp
index 671ee1a8125252..e603b0bb19fd73 100644
--- a/llvm/lib/ExecutionEngine/JITLink/aarch32.cpp
+++ b/llvm/lib/ExecutionEngine/JITLink/aarch32.cpp
@@ -20,6 +20,8 @@
 #include "llvm/Support/ManagedStatic.h"
 #include "llvm/Support/MathExtras.h"
 
+#include "JITLinkAArch32.inc"
+
 #define DEBUG_TYPE "jitlink"
 
 namespace llvm {
diff --git a/llvm/unittests/ExecutionEngine/JITLink/AArch32Tests.cpp b/llvm/unittests/ExecutionEngine/JITLink/AArch32Tests.cpp
index 26c773b8dc3a71..4536cad755e13d 100644
--- a/llvm/unittests/ExecutionEngine/JITLink/AArch32Tests.cpp
+++ b/llvm/unittests/ExecutionEngine/JITLink/AArch32Tests.cpp
@@ -11,6 +11,8 @@
 
 #include "gtest/gtest.h"
 
+#include "JITLinkAArch32.inc"
+
 using namespace llvm;
 using namespace llvm::jitlink;
 using namespace llvm::jitlink::aarch32;
diff --git a/llvm/unittests/ExecutionEngine/JITLink/JITLinkAArch32.inc b/llvm/unittests/ExecutionEngine/JITLink/JITLinkAArch32.inc
new file mode 100644
index 00000000000000..42ef9795921e34
--- /dev/null
+++ b/llvm/unittests/ExecutionEngine/JITLink/JITLinkAArch32.inc
@@ -0,0 +1,58 @@
+/*===- TableGen'erated file -------------------------------------*- C++ -*-===*\
+|*                                                                            *|
+|* Skeleton data structures                                                   *|
+|*                                                                            *|
+|* Automatically generated file, do not edit!                                 *|
+|*                                                                            *|
+\*===----------------------------------------------------------------------===*/
+
+using namespace llvm::jitlink::aarch32;
+
+namespace llvm {
+namespace jitlink {
+namespace aarch32 {
+template <> struct FixupInfo<Arm_MovwAbsNC> : public FixupInfoArm {
+    static constexpr uint32_t Opcode = 0x3000000;
+    static constexpr uint32_t OpcodeMask = 0xff00000;
+    static constexpr uint32_t ImmMask = 0xf0fff;
+    static constexpr uint32_t RegMask = 0xf000;
+};
+
+template <> struct FixupInfo<Arm_MovtAbs> : public FixupInfoArm {
+    static constexpr uint32_t Opcode = 0x3400000;
+    static constexpr uint32_t OpcodeMask = 0xff00000;
+    static constexpr uint32_t ImmMask = 0xf0fff;
+    static constexpr uint32_t RegMask = 0xf000;
+};
+
+template <> struct FixupInfo<Thumb_MovwAbsNC> : public FixupInfoThumb {
+    static constexpr HalfWords Opcode {0xf240, 0x0};
+    static constexpr HalfWords OpcodeMask {0xfbf0, 0x8000};
+    static constexpr HalfWords ImmMask {0x40f, 0x70ff};
+    static constexpr HalfWords RegMask {0x0, 0xf00};
+};
+
+template <> struct FixupInfo<Thumb_MovtAbs> : public FixupInfoThumb {
+    static constexpr HalfWords Opcode {0xf2c0, 0x0};
+    static constexpr HalfWords OpcodeMask {0xfbf0, 0x8000};
+    static constexpr HalfWords ImmMask {0x40f, 0x70ff};
+    static constexpr HalfWords RegMask {0x0, 0xf00};
+};
+
+template <> struct FixupInfo<Thumb_MovwPrelNC> : public FixupInfoThumb {
+    static constexpr HalfWords Opcode {0xf240, 0x0};
+    static constexpr HalfWords OpcodeMask {0xfbf0, 0x8000};
+    static constexpr HalfWords ImmMask {0x40f, 0x70ff};
+    static constexpr HalfWords RegMask {0x0, 0xf00};
+};
+
+template <> struct FixupInfo<Thumb_MovtPrel> : public FixupInfoThumb {
+    static constexpr HalfWords Opcode {0xf2c0, 0x0};
+    static constexpr HalfWords OpcodeMask {0xfbf0, 0x8000};
+    static constexpr HalfWords ImmMask {0x40f, 0x70ff};
+    static constexpr HalfWords RegMask {0x0, 0xf00};
+};
+
+} //aarch32
+} //jitlink
+} //llvm
diff --git a/llvm/utils/TableGen/CMakeLists.txt b/llvm/utils/TableGen/CMakeLists.txt
index 071ea3bc07054b..1e629deca93a83 100644
--- a/llvm/utils/TableGen/CMakeLists.txt
+++ b/llvm/utils/TableGen/CMakeLists.txt
@@ -66,6 +66,7 @@ add_tablegen(llvm-tblgen LLVM
   InfoByHwMode.cpp
   InstrInfoEmitter.cpp
   InstrDocsEmitter.cpp
+  JITLinkAArch32InstrInfo.cpp
   OptEmitter.cpp
   OptParserEmitter.cpp
   OptRSTEmitter.cpp
@@ -89,6 +90,10 @@ add_tablegen(llvm-tblgen LLVM
   WebAssemblyDisassemblerEmitter.cpp
   $<TARGET_OBJECTS:obj.LLVMTableGenCommon>
 
+  ADDITIONAL_HEADER_DIRS
+  ${LLVM_MAIN_INCLUDE_DIR}/llvm/ExecutionEngine/JITLink
+
+
   DEPENDS
   intrinsics_gen # via llvm-min-tablegen
   )
diff --git a/llvm/utils/TableGen/JITLinkAArch32InstrInfo.cpp b/llvm/utils/TableGen/JITLinkAArch32InstrInfo.cpp
new file mode 100644
index 00000000000000..6144764d482295
--- /dev/null
+++ b/llvm/utils/TableGen/JITLinkAArch32InstrInfo.cpp
@@ -0,0 +1,196 @@
+//===- JITLinkAArch32InstrInfo.cpp - JITLink AArch32 TableGen backend -----===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This Tablegen backend emits instruction encodings of AArch32 for JITLink.
+//
+//===----------------------------------------------------------------------===//
+#include "CodeGenDAGPatterns.h"
+#include "CodeGenInstruction.h"
+#include "CodeGenSchedule.h"
+#include "CodeGenTarget.h"
+#include "PredicateExpander.h"
+#include "SequenceToOffsetTable.h"
+#include "SubtargetFeatureInfo.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ExecutionEngine/JITLink/aarch32.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/TableGen/Error.h"
+#include "llvm/TableGen/TableGenBackend.h"
+
+#define DEBUG_TYPE "jitlink-aarch32-tblgen"
+
+namespace llvm {
+class RecordKeeper;
+class raw_ostream;
+} // namespace llvm
+
+using namespace llvm;
+using namespace llvm::jitlink;
+using namespace llvm::jitlink::aarch32;
+
+namespace {
+
+// Any helper data structures can be defined here. Some backends use
+// structs to collect information from the records.
+
+Twine getEdgeKindName(Edge::Kind K) {
+#define KIND_NAME_CASE(K)                                                      \
+  case K:                                                                      \
+    return #K;
+
+  switch (K) {
+    KIND_NAME_CASE(Data_Delta32)
+    KIND_NAME_CASE(Data_Pointer32)
+    KIND_NAME_CASE(Arm_Call)
+    KIND_NAME_CASE(Arm_Jump24)
+    KIND_NAME_CASE(Arm_MovwAbsNC)
+    KIND_NAME_CASE(Arm_MovtAbs)
+    KIND_NAME_CASE(Thumb_Call)
+    KIND_NAME_CASE(Thumb_Jump24)
+    KIND_NAME_CASE(Thumb_MovwAbsNC)
+    KIND_NAME_CASE(Thumb_MovtAbs)
+    KIND_NAME_CASE(Thumb_MovwPrelNC)
+    KIND_NAME_CASE(Thumb_MovtPrel)
+  default:
+    return "";
+  }
+#undef KIND_NAME_CASE
+}
+
+static StringRef getInstrFromJITLinkEdgeKind(Edge::Kind Kind) {
+  /// Translate from JITLink-internal edge kind to TableGen instruction names.
+  switch (Kind) {
+  case Arm_Call:
+    return "";
+  case aarch32::Arm_Jump24:
+    return "";
+  case aarch32::Arm_MovwAbsNC:
+    return "MOVi16";
+  case aarch32::Arm_MovtAbs:
+    return "MOVTi16";
+  case aarch32::Thumb_Call:
+    return "";
+  case aarch32::Thumb_Jump24:
+    return "";
+  case aarch32::Thumb_MovwAbsNC:
+  case aarch32::Thumb_MovwPrelNC:
+    return "t2MOVi16";
+  case aarch32::Thumb_MovtAbs:
+  case aarch32::Thumb_MovtPrel:
+    return "t2MOVTi16";
+  default:
+    return "";
+  }
+}
+
+struct InstrInfo {
+  uint32_t Opcode = 0;
+  uint32_t OpcodeMask = 0;
+  uint32_t ImmMask = 0;
+  uint32_t RegMask = 0;
+};
+
+static void extractBits(BitsInit &InstBits, InstrInfo &II) {
+  for (unsigned i = 0; i < InstBits.getNumBits(); ++i) {
+    Init *Bit = InstBits.getBit(i);
+
+    if (auto *VarBit = dyn_cast<VarBitInit>(Bit)) {
+      // Check if the VarBit is for 'imm' or 'Rd'
+      std::string VarName = VarBit->getBitVar()->getAsUnquotedString();
+      if (VarName == "imm") {
+        II.ImmMask |= 1 << i;
+      } else if (VarName == "Rd") {
+        II.RegMask |= 1 << i;
+      }
+    } else if (auto *TheBit = dyn_cast<BitInit>(Bit)) {
+      II.OpcodeMask |= 1 << i;
+      if (TheBit->getValue()) {
+        II.Opcode |= 1 << i;
+      }
+    }
+  }
+
+  assert((II.OpcodeMask & II.ImmMask & II.RegMask) == 0 &&
+         "Masks have intersecting bits");
+}
+
+static void writeArmElement(raw_ostream &OS, Twine InfoName, uint32_t Value,
+                            int Indentation = 4) {
+  OS.indent(Indentation) << "static constexpr uint32_t " + InfoName + " = 0x";
+  OS.write_hex(Value) << ";\n";
+}
+
+static void writeArmInfo(raw_ostream &OS, InstrInfo &II, Edge::Kind Kind) {
+  OS << "template <> struct FixupInfo<" + getEdgeKindName(Kind) +
+            "> : public FixupInfoArm {\n";
+  writeArmElement(OS, "Opcode", II.Opcode);
+  writeArmElement(OS, "OpcodeMask", II.OpcodeMask);
+  writeArmElement(OS, "ImmMask", II.ImmMask);
+  writeArmElement(OS, "RegMask", II.RegMask);
+  OS << "};\n\n";
+}
+
+static void writeThumbElement(raw_ostream &OS, Twine InfoName, uint32_t Value,
+                              int Indentation = 4) {
+  OS.indent(Indentation) << "static constexpr HalfWords " + InfoName + " {0x";
+  OS.write_hex(Value >> 16) << ", 0x";
+  OS.write_hex(Value & 0x0000FFFF) << "};\n";
+}
+
+static void writeThumbInfo(raw_ostream &OS, InstrInfo &II, Edge::Kind Kind) {
+  OS << "template <> struct FixupInfo<" + getEdgeKindName(Kind) +
+            "> : public FixupInfoThumb {\n";
+  writeThumbElement(OS, "Opcode", II.Opcode);
+  writeThumbElement(OS, "OpcodeMask", II.OpcodeMask);
+  writeThumbElement(OS, "ImmMask", II.ImmMask);
+  writeThumbElement(OS, "RegMask", II.RegMask);
+  OS << "};\n\n";
+}
+
+class JITLinkAArch32Emitter {
+private:
+  RecordKeeper &Records;
+
+public:
+  JITLinkAArch32Emitter(RecordKeeper &RK) : Records(RK) {}
+
+  void run(raw_ostream &OS);
+}; // emitter class
+
+} // anonymous namespace
+
+void JITLinkAArch32Emitter::run(raw_ostream &OS) {
+  emitSourceFileHeader("Skeleton data structures", OS);
+  OS << "using namespace llvm::jitlink::aarch32;\n\n";
+  OS << "namespace llvm {\n";
+  OS << "namespace jitlink {\n";
+  OS << "namespace aarch32 {\n";
+  // const auto &Instructions = Records.getAllDerivedDefinitions("Instruction");
+  for (Edge::Kind JITLinkEdgeKind = aarch32::FirstArmRelocation;
+       JITLinkEdgeKind <= aarch32::LastThumbRelocation; JITLinkEdgeKind += 1) {
+    auto InstName = getInstrFromJITLinkEdgeKind(JITLinkEdgeKind);
+    if (InstName.empty())
+      continue;
+    auto *InstRecord = Records.getDef(InstName);
+    auto *InstBits = InstRecord->getValueAsBitsInit("Inst");
+    InstrInfo II;
+    extractBits(*InstBits, II);
+    if (JITLinkEdgeKind > LastArmRelocation)
+      writeThumbInfo(OS, II, JITLinkEdgeKind);
+    else
+      writeArmInfo(OS, II, JITLinkEdgeKind);
+  }
+
+  OS << "} //aarch32\n";
+  OS << "} //jitlink\n";
+  OS << "} //llvm\n";
+}
+
+static TableGen::Emitter::OptClass<JITLinkAArch32Emitter>
+    X("gen-jitlink-aarch32-instr-info",
+      "Generate JITLink AArch32 Instruction Information");



More information about the llvm-commits mailing list