[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