[llvm] [AArch64][CodeGen] Fold tbx(splat(0), table, idxs) to tbl(table, idxs) (PR #214268)
Durgesh Nandan Mohanty via llvm-commits
llvm-commits at lists.llvm.org
Thu Aug 6 04:34:22 PDT 2026
https://github.com/dnmohanty updated https://github.com/llvm/llvm-project/pull/214268
>From 4eb5d4773b255f1ef82fb7998f6d15ac48d1c13d Mon Sep 17 00:00:00 2001
From: Durgesh Nandan Mohanty <durgeshnandanmohanty at gmail.com>
Date: Wed, 5 Aug 2026 15:56:57 +0000
Subject: [PATCH 1/3] [AArch64][CodeGen] Fold tbx(splat(0), table, idxs) to
tbl(table, idxs)
---
.../Target/AArch64/AArch64ISelLowering.cpp | 25 ++++++++
llvm/test/CodeGen/AArch64/test_tbx.ll | 60 +++++++++++++++++++
2 files changed, 85 insertions(+)
create mode 100644 llvm/test/CodeGen/AArch64/test_tbx.ll
diff --git a/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp b/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
index 52095b4618aaf..a9091f2baa398 100644
--- a/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
+++ b/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
@@ -25069,6 +25069,31 @@ static SDValue performIntrinsicCombine(SDNode *N,
switch (IID) {
default:
break;
+ case Intrinsic::aarch64_neon_tbx1:
+ case Intrinsic::aarch64_neon_tbx2:
+ case Intrinsic::aarch64_neon_tbx3:
+ case Intrinsic::aarch64_neon_tbx4: {
+ if (ISD::isBuildVectorAllZeros(N->getOperand(1).getNode())) {
+ unsigned TblIID = 0;
+ if (IID == Intrinsic::aarch64_neon_tbx1)
+ TblIID = Intrinsic::aarch64_neon_tbl1;
+ else if (IID == Intrinsic::aarch64_neon_tbx2)
+ TblIID = Intrinsic::aarch64_neon_tbl2;
+ else if (IID == Intrinsic::aarch64_neon_tbx3)
+ TblIID = Intrinsic::aarch64_neon_tbl3;
+ else if (IID == Intrinsic::aarch64_neon_tbx4)
+ TblIID = Intrinsic::aarch64_neon_tbl4;
+
+ SmallVector<SDValue, 4> Ops;
+ Ops.push_back(DAG.getTargetConstant(TblIID, SDLoc(N), MVT::i32));
+ for (unsigned i = 2; i < N->getNumOperands(); ++i)
+ Ops.push_back(N->getOperand(i));
+
+ return DAG.getNode(ISD::INTRINSIC_WO_CHAIN, SDLoc(N), N->getValueType(0),
+ Ops);
+ }
+ break;
+ }
case Intrinsic::aarch64_neon_vcvtfxs2fp:
case Intrinsic::aarch64_neon_vcvtfxu2fp:
return tryCombineFixedPointConvert(N, DCI, DAG);
diff --git a/llvm/test/CodeGen/AArch64/test_tbx.ll b/llvm/test/CodeGen/AArch64/test_tbx.ll
new file mode 100644
index 0000000000000..5194b14035243
--- /dev/null
+++ b/llvm/test/CodeGen/AArch64/test_tbx.ll
@@ -0,0 +1,60 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 6
+; RUN: llc -mtriple=aarch64 -mattr=+neon < %s | FileCheck %s
+
+define <16 x i8> @test_tbx1_zero_splat(<16 x i8> %tbl, <16 x i8> %idx) {
+; CHECK-LABEL: test_tbx1_zero_splat:
+; CHECK: // %bb.0:
+; CHECK-NEXT: movi v2.2d, #0000000000000000
+; CHECK-NEXT: tbx v2.16b, { v0.16b }, v1.16b
+; CHECK-NEXT: mov v0.16b, v2.16b
+; CHECK-NEXT: ret
+ %res = call <16 x i8> @llvm.aarch64.neon.tbx1.v16i8(<16 x i8> zeroinitializer, <16 x i8> %tbl, <16 x i8> %idx)
+ ret <16 x i8> %res
+}
+
+define <16 x i8> @test_tbx2_zero_splat(<16 x i8> %tbl1, <16 x i8> %tbl2, <16 x i8> %idx) {
+; CHECK-LABEL: test_tbx2_zero_splat:
+; CHECK: // %bb.0:
+; CHECK-NEXT: movi v3.2d, #0000000000000000
+; CHECK-NEXT: // kill: def $q1 killed $q1 killed $q0_q1 def $q0_q1
+; CHECK-NEXT: // kill: def $q0 killed $q0 killed $q0_q1 def $q0_q1
+; CHECK-NEXT: tbx v3.16b, { v0.16b, v1.16b }, v2.16b
+; CHECK-NEXT: mov v0.16b, v3.16b
+; CHECK-NEXT: ret
+ %res = call <16 x i8> @llvm.aarch64.neon.tbx2.v16i8(<16 x i8> zeroinitializer, <16 x i8> %tbl1, <16 x i8> %tbl2, <16 x i8> %idx)
+ ret <16 x i8> %res
+}
+
+define <16 x i8> @test_tbx3_zero_splat(<16 x i8> %tbl1, <16 x i8> %tbl2, <16 x i8> %tbl3, <16 x i8> %idx) {
+; CHECK-LABEL: test_tbx3_zero_splat:
+; CHECK: // %bb.0:
+; CHECK-NEXT: movi v4.2d, #0000000000000000
+; CHECK-NEXT: // kill: def $q2 killed $q2 killed $q0_q1_q2 def $q0_q1_q2
+; CHECK-NEXT: // kill: def $q1 killed $q1 killed $q0_q1_q2 def $q0_q1_q2
+; CHECK-NEXT: // kill: def $q0 killed $q0 killed $q0_q1_q2 def $q0_q1_q2
+; CHECK-NEXT: tbx v4.16b, { v0.16b, v1.16b, v2.16b }, v3.16b
+; CHECK-NEXT: mov v0.16b, v4.16b
+; CHECK-NEXT: ret
+ %res = call <16 x i8> @llvm.aarch64.neon.tbx3.v16i8(<16 x i8> zeroinitializer, <16 x i8> %tbl1, <16 x i8> %tbl2, <16 x i8> %tbl3, <16 x i8> %idx)
+ ret <16 x i8> %res
+}
+
+define <16 x i8> @test_tbx4_zero_splat(<16 x i8> %tbl1, <16 x i8> %tbl2, <16 x i8> %tbl3, <16 x i8> %tbl4, <16 x i8> %idx) {
+; CHECK-LABEL: test_tbx4_zero_splat:
+; CHECK: // %bb.0:
+; CHECK-NEXT: movi v5.2d, #0000000000000000
+; CHECK-NEXT: // kill: def $q3 killed $q3 killed $q0_q1_q2_q3 def $q0_q1_q2_q3
+; CHECK-NEXT: // kill: def $q2 killed $q2 killed $q0_q1_q2_q3 def $q0_q1_q2_q3
+; CHECK-NEXT: // kill: def $q1 killed $q1 killed $q0_q1_q2_q3 def $q0_q1_q2_q3
+; CHECK-NEXT: // kill: def $q0 killed $q0 killed $q0_q1_q2_q3 def $q0_q1_q2_q3
+; CHECK-NEXT: tbx v5.16b, { v0.16b, v1.16b, v2.16b, v3.16b }, v4.16b
+; CHECK-NEXT: mov v0.16b, v5.16b
+; CHECK-NEXT: ret
+ %res = call <16 x i8> @llvm.aarch64.neon.tbx4.v16i8(<16 x i8> zeroinitializer, <16 x i8> %tbl1, <16 x i8> %tbl2, <16 x i8> %tbl3, <16 x i8> %tbl4, <16 x i8> %idx)
+ ret <16 x i8> %res
+}
+
+declare <16 x i8> @llvm.aarch64.neon.tbx1.v16i8(<16 x i8>, <16 x i8>, <16 x i8>)
+declare <16 x i8> @llvm.aarch64.neon.tbx2.v16i8(<16 x i8>, <16 x i8>, <16 x i8>, <16 x i8>)
+declare <16 x i8> @llvm.aarch64.neon.tbx3.v16i8(<16 x i8>, <16 x i8>, <16 x i8>, <16 x i8>, <16 x i8>)
+declare <16 x i8> @llvm.aarch64.neon.tbx4.v16i8(<16 x i8>, <16 x i8>, <16 x i8>, <16 x i8>, <16 x i8>, <16 x i8>)
>From 42cc131cf8c8a7a412d00216a9da996cb62306bf Mon Sep 17 00:00:00 2001
From: Durgesh Nandan Mohanty <durgeshnandanmohanty at gmail.com>
Date: Wed, 5 Aug 2026 18:24:43 +0000
Subject: [PATCH 2/3] fixup! [AArch64][CodeGen] Fold tbx(splat(0), table, idxs)
to tbl(table, idxs)
---
llvm/test/CodeGen/AArch64/test_tbx.ll | 20 ++++----------------
1 file changed, 4 insertions(+), 16 deletions(-)
diff --git a/llvm/test/CodeGen/AArch64/test_tbx.ll b/llvm/test/CodeGen/AArch64/test_tbx.ll
index 5194b14035243..b8fc48d094b1f 100644
--- a/llvm/test/CodeGen/AArch64/test_tbx.ll
+++ b/llvm/test/CodeGen/AArch64/test_tbx.ll
@@ -4,9 +4,7 @@
define <16 x i8> @test_tbx1_zero_splat(<16 x i8> %tbl, <16 x i8> %idx) {
; CHECK-LABEL: test_tbx1_zero_splat:
; CHECK: // %bb.0:
-; CHECK-NEXT: movi v2.2d, #0000000000000000
-; CHECK-NEXT: tbx v2.16b, { v0.16b }, v1.16b
-; CHECK-NEXT: mov v0.16b, v2.16b
+; CHECK-NEXT: tbl v0.16b, { v0.16b }, v1.16b
; CHECK-NEXT: ret
%res = call <16 x i8> @llvm.aarch64.neon.tbx1.v16i8(<16 x i8> zeroinitializer, <16 x i8> %tbl, <16 x i8> %idx)
ret <16 x i8> %res
@@ -15,11 +13,9 @@ define <16 x i8> @test_tbx1_zero_splat(<16 x i8> %tbl, <16 x i8> %idx) {
define <16 x i8> @test_tbx2_zero_splat(<16 x i8> %tbl1, <16 x i8> %tbl2, <16 x i8> %idx) {
; CHECK-LABEL: test_tbx2_zero_splat:
; CHECK: // %bb.0:
-; CHECK-NEXT: movi v3.2d, #0000000000000000
; CHECK-NEXT: // kill: def $q1 killed $q1 killed $q0_q1 def $q0_q1
; CHECK-NEXT: // kill: def $q0 killed $q0 killed $q0_q1 def $q0_q1
-; CHECK-NEXT: tbx v3.16b, { v0.16b, v1.16b }, v2.16b
-; CHECK-NEXT: mov v0.16b, v3.16b
+; CHECK-NEXT: tbl v0.16b, { v0.16b, v1.16b }, v2.16b
; CHECK-NEXT: ret
%res = call <16 x i8> @llvm.aarch64.neon.tbx2.v16i8(<16 x i8> zeroinitializer, <16 x i8> %tbl1, <16 x i8> %tbl2, <16 x i8> %idx)
ret <16 x i8> %res
@@ -28,12 +24,10 @@ define <16 x i8> @test_tbx2_zero_splat(<16 x i8> %tbl1, <16 x i8> %tbl2, <16 x i
define <16 x i8> @test_tbx3_zero_splat(<16 x i8> %tbl1, <16 x i8> %tbl2, <16 x i8> %tbl3, <16 x i8> %idx) {
; CHECK-LABEL: test_tbx3_zero_splat:
; CHECK: // %bb.0:
-; CHECK-NEXT: movi v4.2d, #0000000000000000
; CHECK-NEXT: // kill: def $q2 killed $q2 killed $q0_q1_q2 def $q0_q1_q2
; CHECK-NEXT: // kill: def $q1 killed $q1 killed $q0_q1_q2 def $q0_q1_q2
; CHECK-NEXT: // kill: def $q0 killed $q0 killed $q0_q1_q2 def $q0_q1_q2
-; CHECK-NEXT: tbx v4.16b, { v0.16b, v1.16b, v2.16b }, v3.16b
-; CHECK-NEXT: mov v0.16b, v4.16b
+; CHECK-NEXT: tbl v0.16b, { v0.16b, v1.16b, v2.16b }, v3.16b
; CHECK-NEXT: ret
%res = call <16 x i8> @llvm.aarch64.neon.tbx3.v16i8(<16 x i8> zeroinitializer, <16 x i8> %tbl1, <16 x i8> %tbl2, <16 x i8> %tbl3, <16 x i8> %idx)
ret <16 x i8> %res
@@ -42,19 +36,13 @@ define <16 x i8> @test_tbx3_zero_splat(<16 x i8> %tbl1, <16 x i8> %tbl2, <16 x i
define <16 x i8> @test_tbx4_zero_splat(<16 x i8> %tbl1, <16 x i8> %tbl2, <16 x i8> %tbl3, <16 x i8> %tbl4, <16 x i8> %idx) {
; CHECK-LABEL: test_tbx4_zero_splat:
; CHECK: // %bb.0:
-; CHECK-NEXT: movi v5.2d, #0000000000000000
; CHECK-NEXT: // kill: def $q3 killed $q3 killed $q0_q1_q2_q3 def $q0_q1_q2_q3
; CHECK-NEXT: // kill: def $q2 killed $q2 killed $q0_q1_q2_q3 def $q0_q1_q2_q3
; CHECK-NEXT: // kill: def $q1 killed $q1 killed $q0_q1_q2_q3 def $q0_q1_q2_q3
; CHECK-NEXT: // kill: def $q0 killed $q0 killed $q0_q1_q2_q3 def $q0_q1_q2_q3
-; CHECK-NEXT: tbx v5.16b, { v0.16b, v1.16b, v2.16b, v3.16b }, v4.16b
-; CHECK-NEXT: mov v0.16b, v5.16b
+; CHECK-NEXT: tbl v0.16b, { v0.16b, v1.16b, v2.16b, v3.16b }, v4.16b
; CHECK-NEXT: ret
%res = call <16 x i8> @llvm.aarch64.neon.tbx4.v16i8(<16 x i8> zeroinitializer, <16 x i8> %tbl1, <16 x i8> %tbl2, <16 x i8> %tbl3, <16 x i8> %tbl4, <16 x i8> %idx)
ret <16 x i8> %res
}
-declare <16 x i8> @llvm.aarch64.neon.tbx1.v16i8(<16 x i8>, <16 x i8>, <16 x i8>)
-declare <16 x i8> @llvm.aarch64.neon.tbx2.v16i8(<16 x i8>, <16 x i8>, <16 x i8>, <16 x i8>)
-declare <16 x i8> @llvm.aarch64.neon.tbx3.v16i8(<16 x i8>, <16 x i8>, <16 x i8>, <16 x i8>, <16 x i8>)
-declare <16 x i8> @llvm.aarch64.neon.tbx4.v16i8(<16 x i8>, <16 x i8>, <16 x i8>, <16 x i8>, <16 x i8>, <16 x i8>)
>From 337deb0ec92488048781c5ca1a9a819d76c47e10 Mon Sep 17 00:00:00 2001
From: Durgesh Nandan Mohanty <durgeshnandanmohanty at gmail.com>
Date: Thu, 6 Aug 2026 11:33:29 +0000
Subject: [PATCH 3/3] fixup! fixup! [AArch64][CodeGen] Fold tbx(splat(0),
table, idxs) to tbl(table, idxs)
---
.../Target/AArch64/AArch64ISelLowering.cpp | 33 +++++++-------
llvm/test/CodeGen/AArch64/test_tbx.ll | 44 +++++++++++++++++++
2 files changed, 60 insertions(+), 17 deletions(-)
diff --git a/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp b/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
index a9091f2baa398..035cc8ffe0d28 100644
--- a/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
+++ b/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
@@ -25073,24 +25073,23 @@ static SDValue performIntrinsicCombine(SDNode *N,
case Intrinsic::aarch64_neon_tbx2:
case Intrinsic::aarch64_neon_tbx3:
case Intrinsic::aarch64_neon_tbx4: {
- if (ISD::isBuildVectorAllZeros(N->getOperand(1).getNode())) {
+ if (ISD::isBuildVectorAllZeros(N->getOperand(1).getNode())) {
+ SDLoc DL(N);
unsigned TblIID = 0;
- if (IID == Intrinsic::aarch64_neon_tbx1)
- TblIID = Intrinsic::aarch64_neon_tbl1;
- else if (IID == Intrinsic::aarch64_neon_tbx2)
- TblIID = Intrinsic::aarch64_neon_tbl2;
- else if (IID == Intrinsic::aarch64_neon_tbx3)
- TblIID = Intrinsic::aarch64_neon_tbl3;
- else if (IID == Intrinsic::aarch64_neon_tbx4)
- TblIID = Intrinsic::aarch64_neon_tbl4;
-
- SmallVector<SDValue, 4> Ops;
- Ops.push_back(DAG.getTargetConstant(TblIID, SDLoc(N), MVT::i32));
- for (unsigned i = 2; i < N->getNumOperands(); ++i)
- Ops.push_back(N->getOperand(i));
-
- return DAG.getNode(ISD::INTRINSIC_WO_CHAIN, SDLoc(N), N->getValueType(0),
- Ops);
+ switch (IID) {
+ case Intrinsic::aarch64_neon_tbx1: TblIID = Intrinsic::aarch64_neon_tbl1; break;
+ case Intrinsic::aarch64_neon_tbx2: TblIID = Intrinsic::aarch64_neon_tbl2; break;
+ case Intrinsic::aarch64_neon_tbx3: TblIID = Intrinsic::aarch64_neon_tbl3; break;
+ case Intrinsic::aarch64_neon_tbx4: TblIID = Intrinsic::aarch64_neon_tbl4; break;
+ default: llvm_unreachable("Unexpected TBX intrinsic");
+ }
+
+ SmallVector<SDValue, 6> Ops;
+ Ops.push_back(DAG.getConstant(TblIID, DL, MVT::i32));
+ for (unsigned I = 2; I < N->getNumOperands(); ++I)
+ Ops.push_back(N->getOperand(I));
+
+ return DAG.getNode(ISD::INTRINSIC_WO_CHAIN, DL, N->getValueType(0), Ops);
}
break;
}
diff --git a/llvm/test/CodeGen/AArch64/test_tbx.ll b/llvm/test/CodeGen/AArch64/test_tbx.ll
index b8fc48d094b1f..030206d119420 100644
--- a/llvm/test/CodeGen/AArch64/test_tbx.ll
+++ b/llvm/test/CodeGen/AArch64/test_tbx.ll
@@ -45,4 +45,48 @@ define <16 x i8> @test_tbx4_zero_splat(<16 x i8> %tbl1, <16 x i8> %tbl2, <16 x i
%res = call <16 x i8> @llvm.aarch64.neon.tbx4.v16i8(<16 x i8> zeroinitializer, <16 x i8> %tbl1, <16 x i8> %tbl2, <16 x i8> %tbl3, <16 x i8> %tbl4, <16 x i8> %idx)
ret <16 x i8> %res
}
+define <8 x i8> @test_tbx1_zero_splat_8x8(<16 x i8> %tbl, <8 x i8> %idx) {
+; CHECK-LABEL: test_tbx1_zero_splat_8x8:
+; CHECK: // %bb.0:
+; CHECK-NEXT: tbl v0.8b, { v0.16b }, v1.8b
+; CHECK-NEXT: ret
+ %res = call <8 x i8> @llvm.aarch64.neon.tbx1.v8i8(<8 x i8> zeroinitializer, <16 x i8> %tbl, <8 x i8> %idx)
+ ret <8 x i8> %res
+}
+
+define <8 x i8> @test_tbx2_zero_splat_8x8(<16 x i8> %tbl1, <16 x i8> %tbl2, <8 x i8> %idx) {
+; CHECK-LABEL: test_tbx2_zero_splat_8x8:
+; CHECK: // %bb.0:
+; CHECK-NEXT: // kill: def $q1 killed $q1 killed $q0_q1 def $q0_q1
+; CHECK-NEXT: // kill: def $q0 killed $q0 killed $q0_q1 def $q0_q1
+; CHECK-NEXT: tbl v0.8b, { v0.16b, v1.16b }, v2.8b
+; CHECK-NEXT: ret
+ %res = call <8 x i8> @llvm.aarch64.neon.tbx2.v8i8(<8 x i8> zeroinitializer, <16 x i8> %tbl1, <16 x i8> %tbl2, <8 x i8> %idx)
+ ret <8 x i8> %res
+}
+
+define <8 x i8> @test_tbx3_zero_splat_8x8(<16 x i8> %tbl1, <16 x i8> %tbl2, <16 x i8> %tbl3, <8 x i8> %idx) {
+; CHECK-LABEL: test_tbx3_zero_splat_8x8:
+; CHECK: // %bb.0:
+; CHECK-NEXT: // kill: def $q2 killed $q2 killed $q0_q1_q2 def $q0_q1_q2
+; CHECK-NEXT: // kill: def $q1 killed $q1 killed $q0_q1_q2 def $q0_q1_q2
+; CHECK-NEXT: // kill: def $q0 killed $q0 killed $q0_q1_q2 def $q0_q1_q2
+; CHECK-NEXT: tbl v0.8b, { v0.16b, v1.16b, v2.16b }, v3.8b
+; CHECK-NEXT: ret
+ %res = call <8 x i8> @llvm.aarch64.neon.tbx3.v8i8(<8 x i8> zeroinitializer, <16 x i8> %tbl1, <16 x i8> %tbl2, <16 x i8> %tbl3, <8 x i8> %idx)
+ ret <8 x i8> %res
+}
+
+define <8 x i8> @test_tbx4_zero_splat_8x8(<16 x i8> %tbl1, <16 x i8> %tbl2, <16 x i8> %tbl3, <16 x i8> %tbl4, <8 x i8> %idx) {
+; CHECK-LABEL: test_tbx4_zero_splat_8x8:
+; CHECK: // %bb.0:
+; CHECK-NEXT: // kill: def $q3 killed $q3 killed $q0_q1_q2_q3 def $q0_q1_q2_q3
+; CHECK-NEXT: // kill: def $q2 killed $q2 killed $q0_q1_q2_q3 def $q0_q1_q2_q3
+; CHECK-NEXT: // kill: def $q1 killed $q1 killed $q0_q1_q2_q3 def $q0_q1_q2_q3
+; CHECK-NEXT: // kill: def $q0 killed $q0 killed $q0_q1_q2_q3 def $q0_q1_q2_q3
+; CHECK-NEXT: tbl v0.8b, { v0.16b, v1.16b, v2.16b, v3.16b }, v4.8b
+; CHECK-NEXT: ret
+ %res = call <8 x i8> @llvm.aarch64.neon.tbx4.v8i8(<8 x i8> zeroinitializer, <16 x i8> %tbl1, <16 x i8> %tbl2, <16 x i8> %tbl3, <16 x i8> %tbl4, <8 x i8> %idx)
+ ret <8 x i8> %res
+}
More information about the llvm-commits
mailing list