[llvm] [RFC][BPF] Support Jump Table (PR #133856)

via llvm-commits llvm-commits at lists.llvm.org
Thu Jul 10 08:57:11 PDT 2025


https://github.com/yonghong-song updated https://github.com/llvm/llvm-project/pull/133856

>From 0be4d463e41bcfb487f2379611d75a4cddd458ea Mon Sep 17 00:00:00 2001
From: Yonghong Song <yonghong.song at linux.dev>
Date: Mon, 31 Mar 2025 21:25:26 -0700
Subject: [PATCH] [RFC][BPF] Support Jump Table

NOTE: We probably need cpu v5 or other flags to enable this feature.
We can add it later when necessary.

- Generate all jump tables in a single section named .jumptables.
- Represent each jump table as a symbol:
  - value points to an offset within .jumptables;
  - size encodes jump table size in bytes.
- Indirect jump is a gotox instruction:
  - dst register is an index within the table;
  - accompanied by a R_BPF_64_64 relocation pointing to a jump table
    symbol.

clang -S:

  .LJTI0_0:
          .reloc 0, FK_SecRel_8, .BPF.JT.0.0
          gotox r1
          goto LBB0_2
  LBB0_4:
          ...

          .section        .jumptables,"", at progbits
  .L0_0_set_4 = ((LBB0_4-.LBPF.JX.0.0)>>3)-1
  .L0_0_set_2 = ((LBB0_2-.LBPF.JX.0.0)>>3)-1
  ...
  .BPF.JT.0.0:
          .long   .L0_0_set_4
          .long   .L0_0_set_2
          ...

llvm-readelf -r --sections --symbols:

  Section Headers:
    [Nr] Name              Type            Address          Off    Size   ES Flg Lk Inf Al
    ...
    [ 4] .jumptables       PROGBITS        0000000000000000 000118 000100 00      0   0  1
    ...

  Relocation section '.rel.text' at offset 0x2a8 contains 2 entries:
      Offset             Info             Type               Symbol's Value  Symbol's Name
  0000000000000010  0000000300000001 R_BPF_64_64            0000000000000000 .BPF.JT.0.0
  ...

  Symbol table '.symtab' contains 6 entries:
     Num:    Value          Size Type    Bind   Vis       Ndx Name
       ...
       2: 0000000000000000   112 FUNC    GLOBAL DEFAULT     2 foo
       3: 0000000000000000   128 NOTYPE  GLOBAL DEFAULT     4 .BPF.JT.0.0
       ...

llvm-objdump -Sdr:

  0000000000000000 <foo>:
       ...
       2:	gotox r1
		0000000000000010:  R_BPF_64_64	.BPF.JT.0.0

An option -bpf-min-jump-table-entries is implemented to control the minimum
number of entries to use a jump table on BPF. The default value 4, but it
can be changed with the following clang option
  clang ... -mllvm -bpf-min-jump-table-entries=6
where the number of jump table cases needs to be >= 6 in order to
use jump table.
---
 llvm/include/llvm/CodeGen/AsmPrinter.h        |  4 +-
 llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp    |  2 +-
 .../lib/Target/BPF/AsmParser/BPFAsmParser.cpp |  1 +
 llvm/lib/Target/BPF/BPFAsmPrinter.cpp         | 76 +++++++++++++++++++
 llvm/lib/Target/BPF/BPFISelLowering.cpp       | 43 ++++++++++-
 llvm/lib/Target/BPF/BPFISelLowering.h         | 29 ++++++-
 llvm/lib/Target/BPF/BPFInstrInfo.cpp          | 12 +++
 llvm/lib/Target/BPF/BPFInstrInfo.h            |  3 +
 llvm/lib/Target/BPF/BPFInstrInfo.td           | 30 ++++++++
 llvm/lib/Target/BPF/BPFMCInstLower.cpp        | 28 +++++++
 llvm/lib/Target/BPF/BPFMCInstLower.h          |  1 +
 .../BPF/BPFTargetLoweringObjectFile.cpp       | 20 +++++
 .../Target/BPF/BPFTargetLoweringObjectFile.h  | 25 ++++++
 llvm/lib/Target/BPF/BPFTargetMachine.cpp      |  3 +-
 llvm/lib/Target/BPF/CMakeLists.txt            |  1 +
 .../Target/BPF/MCTargetDesc/BPFAsmBackend.cpp | 13 ++++
 16 files changed, 285 insertions(+), 6 deletions(-)
 create mode 100644 llvm/lib/Target/BPF/BPFTargetLoweringObjectFile.cpp
 create mode 100644 llvm/lib/Target/BPF/BPFTargetLoweringObjectFile.h

diff --git a/llvm/include/llvm/CodeGen/AsmPrinter.h b/llvm/include/llvm/CodeGen/AsmPrinter.h
index faab2503ced50..c4c6a7d0a6065 100644
--- a/llvm/include/llvm/CodeGen/AsmPrinter.h
+++ b/llvm/include/llvm/CodeGen/AsmPrinter.h
@@ -26,6 +26,7 @@
 #include "llvm/CodeGen/StackMaps.h"
 #include "llvm/DebugInfo/CodeView/CodeView.h"
 #include "llvm/IR/InlineAsm.h"
+#include "llvm/Support/CommandLine.h"
 #include "llvm/Support/Compiler.h"
 #include "llvm/Support/ErrorHandling.h"
 #include <cstdint>
@@ -34,6 +35,7 @@
 #include <vector>
 
 namespace llvm {
+extern cl::opt<bool> EmitJumpTableSizesSection;
 
 class AddrLabelMap;
 class AsmPrinterHandler;
@@ -663,7 +665,7 @@ class LLVM_ABI AsmPrinter : public MachineFunctionPass {
   MCSymbol *GetExternalSymbolSymbol(const Twine &Sym) const;
 
   /// Return the symbol for the specified jump table entry.
-  MCSymbol *GetJTISymbol(unsigned JTID, bool isLinkerPrivate = false) const;
+  virtual MCSymbol *GetJTISymbol(unsigned JTID, bool isLinkerPrivate = false) const;
 
   /// Return the symbol for the specified jump table .set
   /// FIXME: privatize to AsmPrinter.
diff --git a/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp b/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp
index 76a1d8c931605..7d01ff372bc33 100644
--- a/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp
+++ b/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp
@@ -168,7 +168,7 @@ static cl::opt<bool> BBAddrMapSkipEmitBBEntries(
              "unnecessary for some PGOAnalysisMap features."),
     cl::Hidden, cl::init(false));
 
-static cl::opt<bool> EmitJumpTableSizesSection(
+cl::opt<bool> llvm::EmitJumpTableSizesSection(
     "emit-jump-table-sizes-section",
     cl::desc("Emit a section containing jump table addresses and sizes"),
     cl::Hidden, cl::init(false));
diff --git a/llvm/lib/Target/BPF/AsmParser/BPFAsmParser.cpp b/llvm/lib/Target/BPF/AsmParser/BPFAsmParser.cpp
index a347794a9a30c..d96f403d2f814 100644
--- a/llvm/lib/Target/BPF/AsmParser/BPFAsmParser.cpp
+++ b/llvm/lib/Target/BPF/AsmParser/BPFAsmParser.cpp
@@ -234,6 +234,7 @@ struct BPFOperand : public MCParsedAsmOperand {
         .Case("callx", true)
         .Case("goto", true)
         .Case("gotol", true)
+        .Case("gotox", true)
         .Case("may_goto", true)
         .Case("*", true)
         .Case("exit", true)
diff --git a/llvm/lib/Target/BPF/BPFAsmPrinter.cpp b/llvm/lib/Target/BPF/BPFAsmPrinter.cpp
index e3843e0e112e2..3a6fd608db87a 100644
--- a/llvm/lib/Target/BPF/BPFAsmPrinter.cpp
+++ b/llvm/lib/Target/BPF/BPFAsmPrinter.cpp
@@ -20,7 +20,13 @@
 #include "llvm/CodeGen/AsmPrinter.h"
 #include "llvm/CodeGen/MachineConstantPool.h"
 #include "llvm/CodeGen/MachineInstr.h"
+#include "llvm/CodeGen/MachineJumpTableInfo.h"
 #include "llvm/CodeGen/MachineModuleInfo.h"
+#include "llvm/CodeGen/TargetLowering.h"
+#include "llvm/MC/MCExpr.h"
+#include "llvm/MC/MCSymbolELF.h"
+#include "llvm/BinaryFormat/ELF.h"
+#include "llvm/Target/TargetLoweringObjectFile.h"
 #include "llvm/IR/Module.h"
 #include "llvm/MC/MCAsmInfo.h"
 #include "llvm/MC/MCInst.h"
@@ -49,6 +55,8 @@ class BPFAsmPrinter : public AsmPrinter {
                              const char *ExtraCode, raw_ostream &O) override;
 
   void emitInstruction(const MachineInstr *MI) override;
+  virtual MCSymbol *GetJTISymbol(unsigned JTID, bool isLinkerPrivate = false) const override;
+  virtual void emitJumpTableInfo() override;
 
   static char ID;
 
@@ -150,6 +158,74 @@ void BPFAsmPrinter::emitInstruction(const MachineInstr *MI) {
   EmitToStreamer(*OutStreamer, TmpInst);
 }
 
+MCSymbol *BPFAsmPrinter::GetJTISymbol(unsigned JTID, bool isLinkerPrivate) const {
+  SmallString<60> Name;
+  raw_svector_ostream(Name)
+    << "BPF.JT." << MF->getFunctionNumber() << '.' << JTID;
+  MCSymbol *S = OutContext.getOrCreateSymbol(Name);
+  if (auto *ES = dyn_cast<MCSymbolELF>(S))
+    ES->setBinding(ELF::STB_GLOBAL);
+  return S;
+}
+
+void BPFAsmPrinter::emitJumpTableInfo() {
+  const MachineJumpTableInfo *MJTI = MF->getJumpTableInfo();
+  if (!MJTI) return;
+
+  const std::vector<MachineJumpTableEntry> &JT = MJTI->getJumpTables();
+  if (JT.empty()) return;
+
+  const TargetLoweringObjectFile &TLOF = getObjFileLowering();
+  const Function &F = MF->getFunction();
+  MCSection *JTS = TLOF.getSectionForJumpTable(F, TM);
+  assert(MJTI->getEntryKind() == MachineJumpTableInfo::EK_LabelDifference32);
+  unsigned EntrySize = MJTI->getEntrySize(getDataLayout());
+  OutStreamer->switchSection(JTS);
+  for (unsigned JTI = 0; JTI < JT.size(); JTI++) {
+    ArrayRef<MachineBasicBlock *> JTBBs = JT[JTI].MBBs;
+    if (JTBBs.empty())
+      continue;
+
+    SmallPtrSet<const MachineBasicBlock *, 16> EmittedSets;
+    const TargetLowering *TLI = MF->getSubtarget().getTargetLowering();
+    const MCExpr *Base =
+        TLI->getPICJumpTableRelocBaseExpr(MF, JTI, OutContext);
+    for (const MachineBasicBlock *MBB : JTBBs) {
+      if (!EmittedSets.insert(MBB).second)
+        continue;
+
+      // Offset from gotox to target basic block expressed in number
+      // of instructions, e.g.:
+      //
+      //   .L0_0_set_4 = ((LBB0_4 - .LBPF.JX.0.0) >> 3) - 1
+      const MCExpr *LHS = MCSymbolRefExpr::create(MBB->getSymbol(), OutContext);
+      OutStreamer->emitAssignment(
+        GetJTSetSymbol(JTI, MBB->getNumber()),
+        MCBinaryExpr::createSub(
+          MCBinaryExpr::createAShr(
+            MCBinaryExpr::createSub(LHS, Base, OutContext),
+            MCConstantExpr::create(3, OutContext),
+            OutContext),
+          MCConstantExpr::create(1, OutContext),
+          OutContext));
+    }
+    // BPF.JT.0.0:
+    //    .long   .L0_0_set_4
+    //    .long   .L0_0_set_2
+    //    ...
+    //    .size   BPF.JT.0.0, 128
+    MCSymbol *JTStart = GetJTISymbol(JTI);
+    OutStreamer->emitLabel(JTStart);
+    for (const MachineBasicBlock *MBB : JTBBs) {
+      MCSymbol *SetSymbol = GetJTSetSymbol(JTI, MBB->getNumber());
+      const MCExpr *V = MCSymbolRefExpr::create(SetSymbol, OutContext);
+      OutStreamer->emitValue(V, EntrySize);
+    }
+    const MCExpr *JTSize = MCConstantExpr::create(JTBBs.size() * 4, OutContext);
+    OutStreamer->emitELFSize(JTStart, JTSize);
+  }
+}
+
 char BPFAsmPrinter::ID = 0;
 
 INITIALIZE_PASS(BPFAsmPrinter, "bpf-asm-printer", "BPF Assembly Printer", false,
diff --git a/llvm/lib/Target/BPF/BPFISelLowering.cpp b/llvm/lib/Target/BPF/BPFISelLowering.cpp
index f4f414d192df0..56ed05131688a 100644
--- a/llvm/lib/Target/BPF/BPFISelLowering.cpp
+++ b/llvm/lib/Target/BPF/BPFISelLowering.cpp
@@ -18,6 +18,7 @@
 #include "llvm/CodeGen/MachineFrameInfo.h"
 #include "llvm/CodeGen/MachineFunction.h"
 #include "llvm/CodeGen/MachineInstrBuilder.h"
+#include "llvm/CodeGen/MachineJumpTableInfo.h"
 #include "llvm/CodeGen/MachineRegisterInfo.h"
 #include "llvm/CodeGen/TargetLoweringObjectFileImpl.h"
 #include "llvm/CodeGen/ValueTypes.h"
@@ -25,6 +26,7 @@
 #include "llvm/IR/DiagnosticInfo.h"
 #include "llvm/IR/DiagnosticPrinter.h"
 #include "llvm/IR/Module.h"
+#include "llvm/MC/MCAsmInfo.h"
 #include "llvm/Support/Debug.h"
 #include "llvm/Support/ErrorHandling.h"
 #include "llvm/Support/MathExtras.h"
@@ -38,6 +40,10 @@ static cl::opt<bool> BPFExpandMemcpyInOrder("bpf-expand-memcpy-in-order",
   cl::Hidden, cl::init(false),
   cl::desc("Expand memcpy into load/store pairs in order"));
 
+static cl::opt<unsigned> BPFMinimumJumpTableEntries(
+    "bpf-min-jump-table-entries", cl::init(4), cl::Hidden,
+    cl::desc("Set minimum number of entries to use a jump table on BPF"));
+
 static void fail(const SDLoc &DL, SelectionDAG &DAG, const Twine &Msg,
                  SDValue Val = {}) {
   std::string Str;
@@ -66,8 +72,7 @@ BPFTargetLowering::BPFTargetLowering(const TargetMachine &TM,
   setStackPointerRegisterToSaveRestore(BPF::R11);
 
   setOperationAction(ISD::BR_CC, MVT::i64, Custom);
-  setOperationAction(ISD::BR_JT, MVT::Other, Expand);
-  setOperationAction(ISD::BRIND, MVT::Other, Expand);
+  setOperationAction(ISD::BR_JT, MVT::Other, Custom);
   setOperationAction(ISD::BRCOND, MVT::Other, Expand);
 
   setOperationAction(ISD::TRAP, MVT::Other, Custom);
@@ -159,6 +164,7 @@ BPFTargetLowering::BPFTargetLowering(const TargetMachine &TM,
 
   setBooleanContents(ZeroOrOneBooleanContent);
   setMaxAtomicSizeInBitsSupported(64);
+  setMinimumJumpTableEntries(BPFMinimumJumpTableEntries);
 
   // Function alignments
   setMinFunctionAlignment(Align(8));
@@ -332,6 +338,8 @@ SDValue BPFTargetLowering::LowerOperation(SDValue Op, SelectionDAG &DAG) const {
     return LowerATOMIC_LOAD_STORE(Op, DAG);
   case ISD::TRAP:
     return LowerTRAP(Op, DAG);
+  case ISD::BR_JT:
+    return LowerBR_JT(Op, DAG);
   }
 }
 
@@ -780,6 +788,16 @@ SDValue BPFTargetLowering::LowerTRAP(SDValue Op, SelectionDAG &DAG) const {
   return LowerCall(CLI, InVals);
 }
 
+SDValue BPFTargetLowering::LowerBR_JT(SDValue Op, SelectionDAG &DAG) const {
+  SDValue Chain = Op->getOperand(0);
+  SDValue Table = Op->getOperand(1);
+  SDValue Index = Op->getOperand(2);
+  JumpTableSDNode *JT = cast<JumpTableSDNode>(Table);
+  SDLoc DL(Op);
+  SDValue TargetJT = DAG.getTargetJumpTable(JT->getIndex(), MVT::i32);
+  return DAG.getNode(BPFISD::BPF_BR_JT, DL, MVT::Other, Chain, TargetJT, Index);
+}
+
 const char *BPFTargetLowering::getTargetNodeName(unsigned Opcode) const {
   switch ((BPFISD::NodeType)Opcode) {
   case BPFISD::FIRST_NUMBER:
@@ -796,6 +814,8 @@ const char *BPFTargetLowering::getTargetNodeName(unsigned Opcode) const {
     return "BPFISD::Wrapper";
   case BPFISD::MEMCPY:
     return "BPFISD::MEMCPY";
+  case BPFISD::BPF_BR_JT:
+    return "BPFISD::BPF_BR_JT";
   }
   return nullptr;
 }
@@ -1069,3 +1089,22 @@ bool BPFTargetLowering::isLegalAddressingMode(const DataLayout &DL,
 
   return true;
 }
+
+MCSymbol *BPFTargetLowering::getJXAnchorSymbol(const MachineFunction *MF, unsigned JTI) {
+  const MCAsmInfo *MAI = MF->getContext().getAsmInfo();
+  SmallString<60> Name;
+  raw_svector_ostream(Name)
+    << MAI->getPrivateGlobalPrefix()
+    << "BPF.JX." << MF->getFunctionNumber() << '.' << JTI;
+  return MF->getContext().getOrCreateSymbol(Name);
+}
+
+unsigned BPFTargetLowering::getJumpTableEncoding() const {
+  return MachineJumpTableInfo::EK_LabelDifference32;
+}
+
+const MCExpr *
+BPFTargetLowering::getPICJumpTableRelocBaseExpr(const MachineFunction *MF,
+                                                unsigned JTI, MCContext &Ctx) const {
+  return MCSymbolRefExpr::create(getJXAnchorSymbol(MF, JTI), Ctx);
+}
diff --git a/llvm/lib/Target/BPF/BPFISelLowering.h b/llvm/lib/Target/BPF/BPFISelLowering.h
index 8f60261c10e9e..ce6edea83d4e4 100644
--- a/llvm/lib/Target/BPF/BPFISelLowering.h
+++ b/llvm/lib/Target/BPF/BPFISelLowering.h
@@ -28,7 +28,8 @@ enum NodeType : unsigned {
   SELECT_CC,
   BR_CC,
   Wrapper,
-  MEMCPY
+  MEMCPY,
+  BPF_BR_JT,
 };
 }
 
@@ -66,6 +67,31 @@ class BPFTargetLowering : public TargetLowering {
 
   MVT getScalarShiftAmountTy(const DataLayout &, EVT) const override;
 
+  // Always emit EK_LabelDifference32, computed as difference between
+  // JX instruction location and target basic block label.
+  virtual unsigned getJumpTableEncoding() const override;
+
+  // This is a label for JX instructions, used for jump table offsets
+  // computation, e.g.:
+  //
+  //   .LBPF.JX.0.0:                         <------- this is the anchor
+  //        .reloc 0, FK_SecRel_8, BPF.JT.0.0
+  //        gotox r1
+  //        ...
+  //   .section        .jumptables,"", at progbits
+  //   .L0_0_set_7 = ((LBB0_7-.LBPF.JX.0.0)>>3)-1
+  //   ...
+  //   BPF.JT.0.0:                           <------- JT definition
+  //        .long   .L0_0_set_7
+  //        ...
+  static MCSymbol *getJXAnchorSymbol(const MachineFunction *MF, unsigned JTI);
+
+  // Refers to a symbol returned by getJXAnchorSymbol(), used by
+  // AsmPrinter::emitJumpTableInfo() to define the .L0_0_set_7 etc above.
+  virtual const MCExpr *
+  getPICJumpTableRelocBaseExpr(const MachineFunction *MF,
+                               unsigned JTI, MCContext &Ctx) const override;
+
 private:
   // Control Instruction Selection Features
   bool HasAlu32;
@@ -81,6 +107,7 @@ class BPFTargetLowering : public TargetLowering {
   SDValue LowerConstantPool(SDValue Op, SelectionDAG &DAG) const;
   SDValue LowerGlobalAddress(SDValue Op, SelectionDAG &DAG) const;
   SDValue LowerTRAP(SDValue Op, SelectionDAG &DAG) const;
+  SDValue LowerBR_JT(SDValue Op, SelectionDAG &DAG) const;
 
   template <class NodeTy>
   SDValue getAddr(NodeTy *N, SelectionDAG &DAG, unsigned Flags = 0) const;
diff --git a/llvm/lib/Target/BPF/BPFInstrInfo.cpp b/llvm/lib/Target/BPF/BPFInstrInfo.cpp
index 70bc163615f61..e9f65b0517f95 100644
--- a/llvm/lib/Target/BPF/BPFInstrInfo.cpp
+++ b/llvm/lib/Target/BPF/BPFInstrInfo.cpp
@@ -181,6 +181,10 @@ bool BPFInstrInfo::analyzeBranch(MachineBasicBlock &MBB,
     if (!isUnpredicatedTerminator(*I))
       break;
 
+    // If a JX insn, we're done.
+    if (I->getOpcode() == BPF::JX)
+      break;
+
     // A terminator that isn't a branch can't easily be handled
     // by this analysis.
     if (!I->isBranch())
@@ -259,3 +263,11 @@ unsigned BPFInstrInfo::removeBranch(MachineBasicBlock &MBB,
 
   return Count;
 }
+
+int BPFInstrInfo::getJumpTableIndex(const MachineInstr &MI) const {
+  if (MI.getOpcode() != BPF::JX)
+    return -1;
+  const MachineOperand &MO = MI.getOperand(1);
+  assert(MO.isJTI() && "JX operand #0 should be isJTI");
+  return MO.getIndex();
+}
diff --git a/llvm/lib/Target/BPF/BPFInstrInfo.h b/llvm/lib/Target/BPF/BPFInstrInfo.h
index d8bbad44e314e..d88e37975980a 100644
--- a/llvm/lib/Target/BPF/BPFInstrInfo.h
+++ b/llvm/lib/Target/BPF/BPFInstrInfo.h
@@ -58,6 +58,9 @@ class BPFInstrInfo : public BPFGenInstrInfo {
                         MachineBasicBlock *FBB, ArrayRef<MachineOperand> Cond,
                         const DebugLoc &DL,
                         int *BytesAdded = nullptr) const override;
+
+  int getJumpTableIndex(const MachineInstr &MI) const override;
+
 private:
   void expandMEMCPY(MachineBasicBlock::iterator) const;
 
diff --git a/llvm/lib/Target/BPF/BPFInstrInfo.td b/llvm/lib/Target/BPF/BPFInstrInfo.td
index b21f1a0eee3b0..581e49419c37f 100644
--- a/llvm/lib/Target/BPF/BPFInstrInfo.td
+++ b/llvm/lib/Target/BPF/BPFInstrInfo.td
@@ -31,6 +31,8 @@ def SDT_BPFMEMCPY       : SDTypeProfile<0, 4, [SDTCisVT<0, i64>,
                                                SDTCisVT<1, i64>,
                                                SDTCisVT<2, i64>,
                                                SDTCisVT<3, i64>]>;
+def SDT_BPFBrJt         : SDTypeProfile<0, 2, [SDTCisVT<0, i32>,    // jump table
+                                               SDTCisVT<1, i64>]>;  // index
 
 def BPFcall         : SDNode<"BPFISD::CALL", SDT_BPFCall,
                              [SDNPHasChain, SDNPOptInGlue, SDNPOutGlue,
@@ -49,6 +51,9 @@ def BPFWrapper      : SDNode<"BPFISD::Wrapper", SDT_BPFWrapper>;
 def BPFmemcpy       : SDNode<"BPFISD::MEMCPY", SDT_BPFMEMCPY,
                              [SDNPHasChain, SDNPInGlue, SDNPOutGlue,
                               SDNPMayStore, SDNPMayLoad]>;
+def BPFBrJt         : SDNode<"BPFISD::BPF_BR_JT", SDT_BPFBrJt,
+                             [SDNPHasChain]>;
+
 def BPFIsLittleEndian : Predicate<"Subtarget->isLittleEndian()">;
 def BPFIsBigEndian    : Predicate<"!Subtarget->isLittleEndian()">;
 def BPFHasALU32 : Predicate<"Subtarget->getHasAlu32()">;
@@ -183,6 +188,15 @@ class TYPE_LD_ST<bits<3> mode, bits<2> size,
   let Inst{60-59} = size;
 }
 
+// For indirect jump
+class TYPE_IND_JMP<bits<4> op, bits<1> srctype,
+                   dag outs, dag ins, string asmstr, list<dag> pattern>
+  : InstBPF<outs, ins, asmstr, pattern> {
+
+  let Inst{63-60} = op;
+  let Inst{59} = srctype;
+}
+
 // jump instructions
 class JMP_RR<BPFJumpOp Opc, string OpcodeStr, PatLeaf Cond>
     : TYPE_ALU_JMP<Opc.Value, BPF_X.Value,
@@ -216,6 +230,18 @@ class JMP_RI<BPFJumpOp Opc, string OpcodeStr, PatLeaf Cond>
   let BPFClass = BPF_JMP;
 }
 
+class JMP_IND<BPFJumpOp Opc, string OpcodeStr, list<dag> Pattern>
+    : TYPE_ALU_JMP<Opc.Value, BPF_X.Value,
+                   (outs),
+                   (ins GPR:$dst, i32imm:$jt),
+                   !strconcat(OpcodeStr, " $dst"),
+                   Pattern> {
+  bits<4> dst;
+
+  let Inst{51-48} = dst;
+  let BPFClass = BPF_JMP;
+}
+
 class JMP_JCOND<BPFJumpOp Opc, string OpcodeStr, list<dag> Pattern>
     : TYPE_ALU_JMP<Opc.Value, BPF_K.Value,
                    (outs),
@@ -281,6 +307,10 @@ defm JSLT : J<BPF_JSLT, "s<", BPF_CC_LT, BPF_CC_LT_32>;
 defm JSLE : J<BPF_JSLE, "s<=", BPF_CC_LE, BPF_CC_LE_32>;
 defm JSET : J<BPF_JSET, "&", NoCond, NoCond>;
 def JCOND : JMP_JCOND<BPF_JCOND, "may_goto", []>;
+
+let isIndirectBranch = 1 in {
+  def JX : JMP_IND<BPF_JA, "gotox", [(BPFBrJt tjumptable:$jt, i64:$dst)]>;
+}
 }
 
 // ALU instructions
diff --git a/llvm/lib/Target/BPF/BPFMCInstLower.cpp b/llvm/lib/Target/BPF/BPFMCInstLower.cpp
index 040a1fb750702..5e22f6c226796 100644
--- a/llvm/lib/Target/BPF/BPFMCInstLower.cpp
+++ b/llvm/lib/Target/BPF/BPFMCInstLower.cpp
@@ -12,6 +12,7 @@
 //===----------------------------------------------------------------------===//
 
 #include "BPFMCInstLower.h"
+#include "BPFISelLowering.h"
 #include "llvm/CodeGen/AsmPrinter.h"
 #include "llvm/CodeGen/MachineBasicBlock.h"
 #include "llvm/CodeGen/MachineInstr.h"
@@ -19,6 +20,7 @@
 #include "llvm/MC/MCContext.h"
 #include "llvm/MC/MCExpr.h"
 #include "llvm/MC/MCInst.h"
+#include "llvm/MC/MCStreamer.h"
 #include "llvm/Support/ErrorHandling.h"
 #include "llvm/Support/raw_ostream.h"
 using namespace llvm;
@@ -44,6 +46,29 @@ MCOperand BPFMCInstLower::LowerSymbolOperand(const MachineOperand &MO,
   return MCOperand::createExpr(Expr);
 }
 
+MCOperand BPFMCInstLower::LowerJTIOperand(const MachineInstr &MI, const MachineOperand &MO, int JTI) const {
+  // Emit relocation entry referencing jump table symbol plus a label
+  // for JX anchor, e.g.:
+  //
+  //   .LBPF.JX.0.0:
+  //        .reloc 0, FK_SecRel_8, BPF.JT.0.0
+  //        gotox r1
+  assert((MI.getOpcode() == BPF::JX) &&
+         "Jump Table Index operands are expected only for JX instructions");
+  const MachineFunction *MF = MI.getMF();
+  Printer.OutStreamer->emitLabel(BPFTargetLowering::getJXAnchorSymbol(MF, JTI));
+  MCSymbol *JT = Printer.GetJTISymbol(JTI);
+  const MCExpr *Zero = MCConstantExpr::create(0, Ctx);
+  Printer.OutStreamer->emitRelocDirective(*Zero,
+                                          "FK_SecRel_8",
+                                          MCSymbolRefExpr::create(JT, Ctx),
+                                          {},
+                                          *Ctx.getSubtargetInfo());
+  // JTI parameter is used only to emit relocation and is not a part
+  // of JX instruction encoding, so this operand is not really used.
+  return MCOperand::createImm(JTI);
+}
+
 void BPFMCInstLower::Lower(const MachineInstr *MI, MCInst &OutMI) const {
   OutMI.setOpcode(MI->getOpcode());
 
@@ -77,6 +102,9 @@ void BPFMCInstLower::Lower(const MachineInstr *MI, MCInst &OutMI) const {
     case MachineOperand::MO_ConstantPoolIndex:
       MCOp = LowerSymbolOperand(MO, Printer.GetCPISymbol(MO.getIndex()));
       break;
+    case MachineOperand::MO_JumpTableIndex:
+      MCOp = LowerJTIOperand(*MI, MO, MO.getIndex());
+      break;
     }
 
     OutMI.addOperand(MCOp);
diff --git a/llvm/lib/Target/BPF/BPFMCInstLower.h b/llvm/lib/Target/BPF/BPFMCInstLower.h
index 4bd0f1f0bf1cf..7036f7e7a0e7a 100644
--- a/llvm/lib/Target/BPF/BPFMCInstLower.h
+++ b/llvm/lib/Target/BPF/BPFMCInstLower.h
@@ -32,6 +32,7 @@ class LLVM_LIBRARY_VISIBILITY BPFMCInstLower {
   void Lower(const MachineInstr *MI, MCInst &OutMI) const;
 
   MCOperand LowerSymbolOperand(const MachineOperand &MO, MCSymbol *Sym) const;
+  MCOperand LowerJTIOperand(const MachineInstr &MI, const MachineOperand &MO, int JTI) const;
 
   MCSymbol *GetGlobalAddressSymbol(const MachineOperand &MO) const;
   MCSymbol *GetExternalSymbolSymbol(const MachineOperand &MO) const;
diff --git a/llvm/lib/Target/BPF/BPFTargetLoweringObjectFile.cpp b/llvm/lib/Target/BPF/BPFTargetLoweringObjectFile.cpp
new file mode 100644
index 0000000000000..ccd316d678024
--- /dev/null
+++ b/llvm/lib/Target/BPF/BPFTargetLoweringObjectFile.cpp
@@ -0,0 +1,20 @@
+//===------------------ BPFTargetLoweringObjectFile.cpp -------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/MC/MCContext.h"
+#include "llvm/MC/MCSectionELF.h"
+#include "BPFTargetLoweringObjectFile.h"
+
+using namespace llvm;
+
+MCSection *
+BPFTargetLoweringObjectFileELF::getSectionForJumpTable(const Function &F,
+                                                       const TargetMachine &TM,
+                                                       const MachineJumpTableEntry *JTE) const {
+  return getContext().getELFSection(".jumptables", ELF::SHT_PROGBITS, 0);
+}
diff --git a/llvm/lib/Target/BPF/BPFTargetLoweringObjectFile.h b/llvm/lib/Target/BPF/BPFTargetLoweringObjectFile.h
new file mode 100644
index 0000000000000..3684b15925022
--- /dev/null
+++ b/llvm/lib/Target/BPF/BPFTargetLoweringObjectFile.h
@@ -0,0 +1,25 @@
+//===============-  BPFTargetLoweringObjectFile.h  -*- C++ -*-================//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIB_TARGET_BPF_BPFTARGETLOWERINGOBJECTFILE
+#define LLVM_LIB_TARGET_BPF_BPFTARGETLOWERINGOBJECTFILE
+
+#include "llvm/Target/TargetLoweringObjectFile.h"
+#include "llvm/CodeGen/TargetLoweringObjectFileImpl.h"
+
+namespace llvm {
+class BPFTargetLoweringObjectFileELF : public TargetLoweringObjectFileELF {
+
+public:
+  virtual MCSection *
+  getSectionForJumpTable(const Function &F, const TargetMachine &TM,
+                         const MachineJumpTableEntry *JTE) const override;
+};
+}
+
+#endif // LLVM_LIB_TARGET_BPF_BPFTARGETLOWERINGOBJECTFILE
diff --git a/llvm/lib/Target/BPF/BPFTargetMachine.cpp b/llvm/lib/Target/BPF/BPFTargetMachine.cpp
index 527a480354571..ba800f484d791 100644
--- a/llvm/lib/Target/BPF/BPFTargetMachine.cpp
+++ b/llvm/lib/Target/BPF/BPFTargetMachine.cpp
@@ -13,6 +13,7 @@
 #include "BPFTargetMachine.h"
 #include "BPF.h"
 #include "BPFTargetTransformInfo.h"
+#include "BPFTargetLoweringObjectFile.h"
 #include "MCTargetDesc/BPFMCAsmInfo.h"
 #include "TargetInfo/BPFTargetInfo.h"
 #include "llvm/CodeGen/GlobalISel/IRTranslator.h"
@@ -80,7 +81,7 @@ BPFTargetMachine::BPFTargetMachine(const Target &T, const Triple &TT,
     : CodeGenTargetMachineImpl(T, computeDataLayout(TT), TT, CPU, FS, Options,
                                getEffectiveRelocModel(RM),
                                getEffectiveCodeModel(CM, CodeModel::Small), OL),
-      TLOF(std::make_unique<TargetLoweringObjectFileELF>()),
+      TLOF(std::make_unique<BPFTargetLoweringObjectFileELF>()),
       Subtarget(TT, std::string(CPU), std::string(FS), *this) {
   if (!DisableCheckUnreachable) {
     this->Options.TrapUnreachable = true;
diff --git a/llvm/lib/Target/BPF/CMakeLists.txt b/llvm/lib/Target/BPF/CMakeLists.txt
index eade4cacb7100..3678f1335ca36 100644
--- a/llvm/lib/Target/BPF/CMakeLists.txt
+++ b/llvm/lib/Target/BPF/CMakeLists.txt
@@ -37,6 +37,7 @@ add_llvm_target(BPFCodeGen
   BPFRegisterInfo.cpp
   BPFSelectionDAGInfo.cpp
   BPFSubtarget.cpp
+  BPFTargetLoweringObjectFile.cpp
   BPFTargetMachine.cpp
   BPFMIPeephole.cpp
   BPFMIChecking.cpp
diff --git a/llvm/lib/Target/BPF/MCTargetDesc/BPFAsmBackend.cpp b/llvm/lib/Target/BPF/MCTargetDesc/BPFAsmBackend.cpp
index 958790d49d087..7165a88fb17e7 100644
--- a/llvm/lib/Target/BPF/MCTargetDesc/BPFAsmBackend.cpp
+++ b/llvm/lib/Target/BPF/MCTargetDesc/BPFAsmBackend.cpp
@@ -34,6 +34,7 @@ class BPFAsmBackend : public MCAsmBackend {
   createObjectTargetWriter() const override;
 
   MCFixupKindInfo getFixupKindInfo(MCFixupKind Kind) const override;
+  std::optional<MCFixupKind> getFixupKind(StringRef Name) const override;
 
   bool writeNopData(raw_ostream &OS, uint64_t Count,
                     const MCSubtargetInfo *STI) const override;
@@ -54,6 +55,18 @@ MCFixupKindInfo BPFAsmBackend::getFixupKindInfo(MCFixupKind Kind) const {
   return Infos[Kind - FirstTargetFixupKind];
 }
 
+std::optional<MCFixupKind> BPFAsmBackend::getFixupKind(StringRef Name) const {
+  if (Name == "FK_SecRel_8")
+    return FK_SecRel_8;
+  if (Name == "FK_BPF_PCRel_4")
+    return BPF::FK_BPF_PCRel_4;
+  if (Name == "FK_Data_8")
+    return FK_Data_8;
+  if (Name == "FK_Data_4")
+    return FK_Data_4;
+  return std::nullopt;
+}
+
 bool BPFAsmBackend::writeNopData(raw_ostream &OS, uint64_t Count,
                                  const MCSubtargetInfo *STI) const {
   if ((Count % 8) != 0)



More information about the llvm-commits mailing list