[llvm] [RISCV] Support getJumpTableIndex (PR #224197)

Piyou Chen via llvm-commits llvm-commits at lists.llvm.org
Mon Sep 21 00:19:17 PDT 2026


https://github.com/BeMg updated https://github.com/llvm/llvm-project/pull/224197

>From fb8957fe39895cea5aafe1dff5d7e9b4d84d401e Mon Sep 17 00:00:00 2001
From: Piyou Chen <piyou.chen at sifive.com>
Date: Wed, 16 Sep 2026 22:52:12 -0700
Subject: [PATCH 1/3] [NFC] precommit test

---
 .../machine-sink-jumptable-edge-split.ll      | 167 ++++++++++++++++++
 1 file changed, 167 insertions(+)
 create mode 100644 llvm/test/CodeGen/RISCV/machine-sink-jumptable-edge-split.ll

diff --git a/llvm/test/CodeGen/RISCV/machine-sink-jumptable-edge-split.ll b/llvm/test/CodeGen/RISCV/machine-sink-jumptable-edge-split.ll
new file mode 100644
index 0000000000000..86a77c2866956
--- /dev/null
+++ b/llvm/test/CodeGen/RISCV/machine-sink-jumptable-edge-split.ll
@@ -0,0 +1,167 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 4
+; RUN: llc -mtriple=riscv64 -mattr=+zba -O3 < %s | FileCheck %s
+
+declare void @use(i32)
+
+define void @sink_through_jt(ptr %p) {
+; CHECK-LABEL: sink_through_jt:
+; CHECK:       # %bb.0: # %entry
+; CHECK-NEXT:    addi sp, sp, -32
+; CHECK-NEXT:    .cfi_def_cfa_offset 32
+; CHECK-NEXT:    sd ra, 24(sp) # 8-byte Folded Spill
+; CHECK-NEXT:    sd s0, 16(sp) # 8-byte Folded Spill
+; CHECK-NEXT:    sd s1, 8(sp) # 8-byte Folded Spill
+; CHECK-NEXT:    sd s2, 0(sp) # 8-byte Folded Spill
+; CHECK-NEXT:    .cfi_offset ra, -8
+; CHECK-NEXT:    .cfi_offset s0, -16
+; CHECK-NEXT:    .cfi_offset s1, -24
+; CHECK-NEXT:    .cfi_offset s2, -32
+; CHECK-NEXT:    li s0, 12
+; CHECK-NEXT:    addi s1, a0, 1
+; CHECK-NEXT:    lui s2, %hi(.LJTI0_0)
+; CHECK-NEXT:    addi s2, s2, %lo(.LJTI0_0)
+; CHECK-NEXT:    j .LBB0_3
+; CHECK-NEXT:  .LBB0_1: # %c10
+; CHECK-NEXT:    # in Loop: Header=BB0_3 Depth=1
+; CHECK-NEXT:    li a0, 110
+; CHECK-NEXT:  .LBB0_2: # %m
+; CHECK-NEXT:    # in Loop: Header=BB0_3 Depth=1
+; CHECK-NEXT:    call use
+; CHECK-NEXT:    addi s1, s1, 1
+; CHECK-NEXT:  .LBB0_3: # %disp
+; CHECK-NEXT:    # =>This Inner Loop Header: Depth=1
+; CHECK-NEXT:    lbu a0, -1(s1)
+; CHECK-NEXT:    addi a0, a0, -1
+; CHECK-NEXT:    bltu s0, a0, .LBB0_13
+; CHECK-NEXT:  # %bb.4: # %disp
+; CHECK-NEXT:    # in Loop: Header=BB0_3 Depth=1
+; CHECK-NEXT:    sh2add a0, a0, s2
+; CHECK-NEXT:    lw a1, 0(s1)
+; CHECK-NEXT:    lw a2, 0(a0)
+; CHECK-NEXT:    addiw a0, a1, 7
+; CHECK-NEXT:    jr a2
+; CHECK-NEXT:  .LBB0_5: # %other
+; CHECK-NEXT:    # in Loop: Header=BB0_3 Depth=1
+; CHECK-NEXT:    li a0, 55
+; CHECK-NEXT:    call use
+; CHECK-NEXT:    li a0, 0
+; CHECK-NEXT:    j .LBB0_2
+; CHECK-NEXT:  .LBB0_6: # %c3
+; CHECK-NEXT:    # in Loop: Header=BB0_3 Depth=1
+; CHECK-NEXT:    li a0, 103
+; CHECK-NEXT:    j .LBB0_2
+; CHECK-NEXT:  .LBB0_7: # %c11
+; CHECK-NEXT:    # in Loop: Header=BB0_3 Depth=1
+; CHECK-NEXT:    li a0, 111
+; CHECK-NEXT:    j .LBB0_2
+; CHECK-NEXT:  .LBB0_8: # %c8
+; CHECK-NEXT:    # in Loop: Header=BB0_3 Depth=1
+; CHECK-NEXT:    li a0, 108
+; CHECK-NEXT:    j .LBB0_2
+; CHECK-NEXT:  .LBB0_9: # %c1
+; CHECK-NEXT:    # in Loop: Header=BB0_3 Depth=1
+; CHECK-NEXT:    li a0, 101
+; CHECK-NEXT:    j .LBB0_2
+; CHECK-NEXT:  .LBB0_10: # %c2
+; CHECK-NEXT:    # in Loop: Header=BB0_3 Depth=1
+; CHECK-NEXT:    li a0, 102
+; CHECK-NEXT:    j .LBB0_2
+; CHECK-NEXT:  .LBB0_11: # %c6
+; CHECK-NEXT:    # in Loop: Header=BB0_3 Depth=1
+; CHECK-NEXT:    li a0, 106
+; CHECK-NEXT:    j .LBB0_2
+; CHECK-NEXT:  .LBB0_12: # %c4
+; CHECK-NEXT:    # in Loop: Header=BB0_3 Depth=1
+; CHECK-NEXT:    li a0, 104
+; CHECK-NEXT:    j .LBB0_2
+; CHECK-NEXT:  .LBB0_13: # %c0
+; CHECK-NEXT:    # in Loop: Header=BB0_3 Depth=1
+; CHECK-NEXT:    li a0, 100
+; CHECK-NEXT:    j .LBB0_2
+; CHECK-NEXT:  .LBB0_14: # %c5
+; CHECK-NEXT:    # in Loop: Header=BB0_3 Depth=1
+; CHECK-NEXT:    li a0, 105
+; CHECK-NEXT:    j .LBB0_2
+; CHECK-NEXT:  .LBB0_15: # %c9
+; CHECK-NEXT:    # in Loop: Header=BB0_3 Depth=1
+; CHECK-NEXT:    li a0, 109
+; CHECK-NEXT:    j .LBB0_2
+; CHECK-NEXT:  .LBB0_16: # %c7
+; CHECK-NEXT:    # in Loop: Header=BB0_3 Depth=1
+; CHECK-NEXT:    li a0, 107
+; CHECK-NEXT:    j .LBB0_2
+entry:
+  br label %disp
+
+disp:
+  %ip = phi ptr [ %p, %entry ], [ %ipn, %c0 ], [ %ipn, %c1 ], [ %ipn, %c2 ],
+                [ %ipn, %c3 ], [ %ipn, %c4 ], [ %ipn, %c5 ], [ %ipn, %c6 ],
+                [ %ipn, %c7 ], [ %ipn, %c8 ], [ %ipn, %c9 ], [ %ipn, %c10 ],
+                [ %ipn, %c11 ], [ %ipn, %m ]
+  %op = load i8, ptr %ip
+  %ipn = getelementptr i8, ptr %ip, i64 1
+  %x = load i32, ptr %ipn
+  %v = add i32 %x, 7
+  switch i8 %op, label %c0 [
+    i8 1, label %m
+    i8 2, label %other
+    i8 3, label %c1
+    i8 4, label %c2
+    i8 5, label %c3
+    i8 6, label %c4
+    i8 7, label %c5
+    i8 8, label %c6
+    i8 9, label %c7
+    i8 10, label %c8
+    i8 11, label %c9
+    i8 12, label %c10
+    i8 13, label %c11
+  ]
+
+; Second predecessor of %m, so that %disp -> %m is a critical edge.
+other:
+  call void @use(i32 55)
+  br label %m
+
+m:
+  %phi = phi i32 [ %v, %disp ], [ 0, %other ]
+  call void @use(i32 %phi)
+  br label %disp
+
+c0:
+  call void @use(i32 100)
+  br label %disp
+c1:
+  call void @use(i32 101)
+  br label %disp
+c2:
+  call void @use(i32 102)
+  br label %disp
+c3:
+  call void @use(i32 103)
+  br label %disp
+c4:
+  call void @use(i32 104)
+  br label %disp
+c5:
+  call void @use(i32 105)
+  br label %disp
+c6:
+  call void @use(i32 106)
+  br label %disp
+c7:
+  call void @use(i32 107)
+  br label %disp
+c8:
+  call void @use(i32 108)
+  br label %disp
+c9:
+  call void @use(i32 109)
+  br label %disp
+c10:
+  call void @use(i32 110)
+  br label %disp
+c11:
+  call void @use(i32 111)
+  br label %disp
+}

>From 504537d0fb313fa5c8e6c681e1d3118a11a79af4 Mon Sep 17 00:00:00 2001
From: Piyou Chen <piyou.chen at sifive.com>
Date: Wed, 16 Sep 2026 22:55:06 -0700
Subject: [PATCH 2/3] [RISCV] Support getJumpTableIndex

---
 llvm/lib/Target/RISCV/RISCVInstrInfo.cpp      | 76 +++++++++++++++++++
 llvm/lib/Target/RISCV/RISCVInstrInfo.h        |  2 +
 .../machine-sink-jumptable-edge-split.ll      | 32 ++++----
 3 files changed, 95 insertions(+), 15 deletions(-)

diff --git a/llvm/lib/Target/RISCV/RISCVInstrInfo.cpp b/llvm/lib/Target/RISCV/RISCVInstrInfo.cpp
index 6d83480fa6c69..91559ab0e442e 100644
--- a/llvm/lib/Target/RISCV/RISCVInstrInfo.cpp
+++ b/llvm/lib/Target/RISCV/RISCVInstrInfo.cpp
@@ -1817,6 +1817,82 @@ bool RISCVInstrInfo::isBranchOffsetInRange(unsigned BranchOp,
   }
 }
 
+static bool isJumpTableLoad(const MachineInstr &MI) {
+  return any_of(MI.memoperands(), [](const MachineMemOperand *MMO) {
+    const PseudoSourceValue *PSV = MMO->getPseudoValue();
+    return PSV && PSV->isJumpTable();
+  });
+}
+
+/// Walk back from \p Reg through a jump-table address computation and return
+/// the index of the table it reads, or -1 if \p Reg is not part of one.
+static int getJumpTableIndexFromReg(const MachineRegisterInfo &MRI,
+                                    Register Reg, unsigned Depth) {
+  // Set the limit for the recursive search depth.
+  constexpr unsigned MaxDepth = 6;
+  if (Depth > MaxDepth)
+    return -1;
+
+  if (!Reg.isVirtual())
+    return -1;
+
+  const MachineInstr *MI = MRI.getUniqueVRegDef(Reg);
+  if (!MI)
+    return -1;
+
+  // MI has jump table operand, return it.
+  for (const MachineOperand &MO : MI->operands())
+    if (MO.isJTI())
+      return MO.getIndex();
+
+  // Handle intermediate instructions when resolving to the JumpTableIndex.
+  switch (MI->getOpcode()) {
+  case RISCV::ADD:
+  case RISCV::ADDI:
+  case RISCV::SLLI:
+  case RISCV::SH1ADD:
+  case RISCV::SH2ADD:
+  case RISCV::SH3ADD:
+    break;
+  case RISCV::LW:
+  case RISCV::LWU:
+  case RISCV::LD:
+    // Only consider ::(load from jump-table) kind of load.
+    if (!isJumpTableLoad(*MI))
+      return -1;
+    break;
+  default:
+    return -1;
+  }
+
+  for (const MachineOperand &MO : MI->all_uses())
+    if (int JTI = getJumpTableIndexFromReg(MRI, MO.getReg(), Depth + 1);
+        JTI >= 0)
+      return JTI;
+
+  return -1;
+}
+
+// Recursively search for %jump-table.N starting from PseudoBRIND,
+// and return the index of %jump-table.N.
+//
+// One common jump table:
+//
+//   %base   = PseudoMovAddr/PseudoLLA/LUI(+ADDI)/QC_E_LI %jump-table.N
+//   %addr   = SH2ADD %index, %base
+//   %entry  = LW %addr, 0 :: (load from jump-table)
+//   %target = ADD %entry, %base
+//   PseudoBRIND %target, 0
+//
+int RISCVInstrInfo::getJumpTableIndex(const MachineInstr &MI) const {
+  if (MI.getOpcode() != RISCV::PseudoBRIND &&
+      MI.getOpcode() != RISCV::PseudoBRINDX7)
+    return -1;
+
+  const MachineRegisterInfo &MRI = MI.getMF()->getRegInfo();
+  return getJumpTableIndexFromReg(MRI, MI.getOperand(0).getReg(), 0);
+}
+
 // If the operation has a predicated pseudo instruction, return the pseudo
 // instruction opcode. Otherwise, return RISCV::INSTRUCTION_LIST_END.
 // TODO: Support more operations.
diff --git a/llvm/lib/Target/RISCV/RISCVInstrInfo.h b/llvm/lib/Target/RISCV/RISCVInstrInfo.h
index 3f860c93e10b9..ac196ff570080 100644
--- a/llvm/lib/Target/RISCV/RISCVInstrInfo.h
+++ b/llvm/lib/Target/RISCV/RISCVInstrInfo.h
@@ -176,6 +176,8 @@ class RISCVInstrInfo : public RISCVGenInstrInfo {
   bool isBranchOffsetInRange(unsigned BranchOpc,
                              int64_t BrOffset) const override;
 
+  int getJumpTableIndex(const MachineInstr &MI) const override;
+
   MachineInstr *optimizeSelect(MachineInstr &MI,
                                SmallPtrSetImpl<MachineInstr *> &SeenMIs,
                                bool) const override;
diff --git a/llvm/test/CodeGen/RISCV/machine-sink-jumptable-edge-split.ll b/llvm/test/CodeGen/RISCV/machine-sink-jumptable-edge-split.ll
index 86a77c2866956..b98440eb49255 100644
--- a/llvm/test/CodeGen/RISCV/machine-sink-jumptable-edge-split.ll
+++ b/llvm/test/CodeGen/RISCV/machine-sink-jumptable-edge-split.ll
@@ -32,19 +32,15 @@ define void @sink_through_jt(ptr %p) {
 ; CHECK-NEXT:    # =>This Inner Loop Header: Depth=1
 ; CHECK-NEXT:    lbu a0, -1(s1)
 ; CHECK-NEXT:    addi a0, a0, -1
-; CHECK-NEXT:    bltu s0, a0, .LBB0_13
+; CHECK-NEXT:    bltu s0, a0, .LBB0_14
 ; CHECK-NEXT:  # %bb.4: # %disp
 ; CHECK-NEXT:    # in Loop: Header=BB0_3 Depth=1
 ; CHECK-NEXT:    sh2add a0, a0, s2
-; CHECK-NEXT:    lw a1, 0(s1)
-; CHECK-NEXT:    lw a2, 0(a0)
-; CHECK-NEXT:    addiw a0, a1, 7
-; CHECK-NEXT:    jr a2
-; CHECK-NEXT:  .LBB0_5: # %other
-; CHECK-NEXT:    # in Loop: Header=BB0_3 Depth=1
-; CHECK-NEXT:    li a0, 55
-; CHECK-NEXT:    call use
-; CHECK-NEXT:    li a0, 0
+; CHECK-NEXT:    lw a0, 0(a0)
+; CHECK-NEXT:    jr a0
+; CHECK-NEXT:  .LBB0_5: # in Loop: Header=BB0_3 Depth=1
+; CHECK-NEXT:    lw a0, 0(s1)
+; CHECK-NEXT:    addiw a0, a0, 7
 ; CHECK-NEXT:    j .LBB0_2
 ; CHECK-NEXT:  .LBB0_6: # %c3
 ; CHECK-NEXT:    # in Loop: Header=BB0_3 Depth=1
@@ -70,23 +66,29 @@ define void @sink_through_jt(ptr %p) {
 ; CHECK-NEXT:    # in Loop: Header=BB0_3 Depth=1
 ; CHECK-NEXT:    li a0, 106
 ; CHECK-NEXT:    j .LBB0_2
-; CHECK-NEXT:  .LBB0_12: # %c4
+; CHECK-NEXT:  .LBB0_12: # %other
+; CHECK-NEXT:    # in Loop: Header=BB0_3 Depth=1
+; CHECK-NEXT:    li a0, 55
+; CHECK-NEXT:    call use
+; CHECK-NEXT:    li a0, 0
+; CHECK-NEXT:    j .LBB0_2
+; CHECK-NEXT:  .LBB0_13: # %c4
 ; CHECK-NEXT:    # in Loop: Header=BB0_3 Depth=1
 ; CHECK-NEXT:    li a0, 104
 ; CHECK-NEXT:    j .LBB0_2
-; CHECK-NEXT:  .LBB0_13: # %c0
+; CHECK-NEXT:  .LBB0_14: # %c0
 ; CHECK-NEXT:    # in Loop: Header=BB0_3 Depth=1
 ; CHECK-NEXT:    li a0, 100
 ; CHECK-NEXT:    j .LBB0_2
-; CHECK-NEXT:  .LBB0_14: # %c5
+; CHECK-NEXT:  .LBB0_15: # %c5
 ; CHECK-NEXT:    # in Loop: Header=BB0_3 Depth=1
 ; CHECK-NEXT:    li a0, 105
 ; CHECK-NEXT:    j .LBB0_2
-; CHECK-NEXT:  .LBB0_15: # %c9
+; CHECK-NEXT:  .LBB0_16: # %c9
 ; CHECK-NEXT:    # in Loop: Header=BB0_3 Depth=1
 ; CHECK-NEXT:    li a0, 109
 ; CHECK-NEXT:    j .LBB0_2
-; CHECK-NEXT:  .LBB0_16: # %c7
+; CHECK-NEXT:  .LBB0_17: # %c7
 ; CHECK-NEXT:    # in Loop: Header=BB0_3 Depth=1
 ; CHECK-NEXT:    li a0, 107
 ; CHECK-NEXT:    j .LBB0_2

>From 37b4405eecd2de1c1dceb2329a37c6f477aa63bc Mon Sep 17 00:00:00 2001
From: Piyou Chen <piyou.chen at sifive.com>
Date: Sun, 20 Sep 2026 22:38:36 -0700
Subject: [PATCH 3/3] !fixup drop the SLLI due to it will not in the path to
 jump-table index

---
 llvm/lib/Target/RISCV/RISCVInstrInfo.cpp | 1 -
 1 file changed, 1 deletion(-)

diff --git a/llvm/lib/Target/RISCV/RISCVInstrInfo.cpp b/llvm/lib/Target/RISCV/RISCVInstrInfo.cpp
index 91559ab0e442e..2f44fe22c5d3e 100644
--- a/llvm/lib/Target/RISCV/RISCVInstrInfo.cpp
+++ b/llvm/lib/Target/RISCV/RISCVInstrInfo.cpp
@@ -1849,7 +1849,6 @@ static int getJumpTableIndexFromReg(const MachineRegisterInfo &MRI,
   switch (MI->getOpcode()) {
   case RISCV::ADD:
   case RISCV::ADDI:
-  case RISCV::SLLI:
   case RISCV::SH1ADD:
   case RISCV::SH2ADD:
   case RISCV::SH3ADD:



More information about the llvm-commits mailing list