[llvm] [AArch64][CodeGen] Fold tbx(splat(0), table, idxs) to tbl(table, idxs) (PR #214146)

Durgesh Nandan Mohanty via llvm-commits llvm-commits at lists.llvm.org
Wed Aug 5 01:52:10 PDT 2026


https://github.com/dnmohanty updated https://github.com/llvm/llvm-project/pull/214146

>From ed834f4ba06bade06a50c9c0cb00fbf881d6ca56 Mon Sep 17 00:00:00 2001
From: Durgesh Nandan Mohanty <durgeshnandanmohanty at gmail.com>
Date: Wed, 5 Aug 2026 06:16:47 +0000
Subject: [PATCH 1/5] [AArch64] Optimize tbx with zero-splat to tbl (Fixes
 #214077)

---
 .../Target/AArch64/AArch64ISelLowering.cpp    | 20 +++++++++++++++++++
 llvm/test/CodeGen/AArch64/test_tbx.ll         | 11 ++++++++++
 2 files changed, 31 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 51be0e66b19b0..f41c0cae79043 100644
--- a/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
+++ b/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
@@ -25035,6 +25035,26 @@ 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..d7752e0d07494
--- /dev/null
+++ b/llvm/test/CodeGen/AArch64/test_tbx.ll
@@ -0,0 +1,11 @@
+; RUN: llc -mtriple=aarch64 -mattr=+neon < %s | FileCheck %s
+
+define <16 x i8> @test_zero_splat(<16 x i8> %tbl, <16 x i8> %idx) {
+; CHECK-LABEL: test_zero_splat:
+; CHECK: tbl
+; CHECK: 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
+}
+
+declare <16 x i8> @llvm.aarch64.neon.tbx1.v16i8(<16 x i8>, <16 x i8>, <16 x i8>)
\ No newline at end of file

>From 3f56a5ffaedba22f25ddc73263bc057b62396dc0 Mon Sep 17 00:00:00 2001
From: Durgesh Nandan Mohanty <durgeshnandanmohanty at gmail.com>
Date: Wed, 5 Aug 2026 06:39:06 +0000
Subject: [PATCH 2/5] Fix tbx optimization

---
 test_tbx.ll | 11 +++++++++++
 1 file changed, 11 insertions(+)
 create mode 100644 test_tbx.ll

diff --git a/test_tbx.ll b/test_tbx.ll
new file mode 100644
index 0000000000000..d7752e0d07494
--- /dev/null
+++ b/test_tbx.ll
@@ -0,0 +1,11 @@
+; RUN: llc -mtriple=aarch64 -mattr=+neon < %s | FileCheck %s
+
+define <16 x i8> @test_zero_splat(<16 x i8> %tbl, <16 x i8> %idx) {
+; CHECK-LABEL: test_zero_splat:
+; CHECK: tbl
+; CHECK: 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
+}
+
+declare <16 x i8> @llvm.aarch64.neon.tbx1.v16i8(<16 x i8>, <16 x i8>, <16 x i8>)
\ No newline at end of file

>From d61f4b77f211178ed4a45f2e3ed8a4e147a90c61 Mon Sep 17 00:00:00 2001
From: Durgesh Nandan Mohanty <durgeshnandanmohanty at gmail.com>
Date: Wed, 5 Aug 2026 08:23:21 +0000
Subject: [PATCH 3/5] Fix clang-format issues

---
 .../Target/AArch64/AArch64ISelLowering.cpp    | 27 ++++++++++++-------
 1 file changed, 17 insertions(+), 10 deletions(-)

diff --git a/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp b/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
index f41c0cae79043..851e2aba026ed 100644
--- a/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
+++ b/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
@@ -25040,16 +25040,23 @@ static SDValue performIntrinsicCombine(SDNode *N,
   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));
+     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);
 
       return DAG.getNode(ISD::INTRINSIC_WO_CHAIN, SDLoc(N), N->getValueType(0), Ops);
     }

>From ec41a78fab285e7b4f0bd3938a29086e4d56d78d Mon Sep 17 00:00:00 2001
From: Durgesh Nandan Mohanty <durgeshnandanmohanty at gmail.com>
Date: Wed, 5 Aug 2026 08:46:03 +0000
Subject: [PATCH 4/5] Add tests for all tbx variants and auto-generate checks

---
 llvm/test/CodeGen/AArch64/test_tbx.ll | 59 ++++++++++++++++++++++++---
 test_tbx.ll                           | 11 -----
 2 files changed, 54 insertions(+), 16 deletions(-)
 delete mode 100644 test_tbx.ll

diff --git a/llvm/test/CodeGen/AArch64/test_tbx.ll b/llvm/test/CodeGen/AArch64/test_tbx.ll
index d7752e0d07494..5194b14035243 100644
--- a/llvm/test/CodeGen/AArch64/test_tbx.ll
+++ b/llvm/test/CodeGen/AArch64/test_tbx.ll
@@ -1,11 +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_zero_splat(<16 x i8> %tbl, <16 x i8> %idx) {
-; CHECK-LABEL: test_zero_splat:
-; CHECK: tbl
-; CHECK: ret
+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
 }
 
-declare <16 x i8> @llvm.aarch64.neon.tbx1.v16i8(<16 x i8>, <16 x i8>, <16 x i8>)
\ No newline at end of file
+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>)
diff --git a/test_tbx.ll b/test_tbx.ll
deleted file mode 100644
index d7752e0d07494..0000000000000
--- a/test_tbx.ll
+++ /dev/null
@@ -1,11 +0,0 @@
-; RUN: llc -mtriple=aarch64 -mattr=+neon < %s | FileCheck %s
-
-define <16 x i8> @test_zero_splat(<16 x i8> %tbl, <16 x i8> %idx) {
-; CHECK-LABEL: test_zero_splat:
-; CHECK: tbl
-; CHECK: 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
-}
-
-declare <16 x i8> @llvm.aarch64.neon.tbx1.v16i8(<16 x i8>, <16 x i8>, <16 x i8>)
\ No newline at end of file

>From 839722430cf3a21024189d9ed9268bf8e736366d Mon Sep 17 00:00:00 2001
From: Durgesh Nandan Mohanty <durgeshnandanmohanty at gmail.com>
Date: Wed, 5 Aug 2026 14:21:59 +0530
Subject: [PATCH 5/5] Update llvm/test/CodeGen/AArch64/test_tbx.ll

Co-authored-by: Benjamin Maxwell <macdue at dueutil.tech>
---
 llvm/test/CodeGen/AArch64/test_tbx.ll | 4 ----
 1 file changed, 4 deletions(-)

diff --git a/llvm/test/CodeGen/AArch64/test_tbx.ll b/llvm/test/CodeGen/AArch64/test_tbx.ll
index 5194b14035243..876e00f3ace9a 100644
--- a/llvm/test/CodeGen/AArch64/test_tbx.ll
+++ b/llvm/test/CodeGen/AArch64/test_tbx.ll
@@ -54,7 +54,3 @@ define <16 x i8> @test_tbx4_zero_splat(<16 x i8> %tbl1, <16 x i8> %tbl2, <16 x i
   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>)



More information about the llvm-commits mailing list