[llvm] [Hexagon] Optimize sext + mul pattern for splatted scalar sext i16 (PR #206893)

Chandana Mudda via llvm-commits llvm-commits at lists.llvm.org
Wed Jul 1 20:45:39 PDT 2026


https://github.com/chandmudda updated https://github.com/llvm/llvm-project/pull/206893

>From e9583eb158781abc5e462138175332b00df1d0cf Mon Sep 17 00:00:00 2001
From: Chandana Mudda <quic_csinderi at quicinc.com>
Date: Tue, 30 Jun 2026 22:40:04 -0700
Subject: [PATCH 1/2] [Hexagon] Optimize sext + mul pattern for splatted scalar
 sext i16

Extend the existing vmpyh pattern to handle the case where one operand
of a v2i32 nsw mul is a splatted scalar sext i16 value. When the splat
is hoisted out of a loop, it arrives as assertsext v2i32, i16 in the
DAG rather than sext v2i16. The existing pattern did not match this
form, causing the multiply to expand to two scalar mpyi instructions.

Add a PatFrag assertsext_v2i32_i16 to match assertsext nodes of type
v2i32 extended from i16, and two new patterns (both operand orderings)
that recover the v2i16 using A2_combine_ll before feeding into
M2_vmpy2s_s0.
---
 llvm/lib/Target/Hexagon/HexagonPatterns.td    | 22 +++++++++++++
 .../CodeGen/Hexagon/sext-mul-splat-v2i16.ll   | 31 +++++++++++++++++++
 2 files changed, 53 insertions(+)
 create mode 100644 llvm/test/CodeGen/Hexagon/sext-mul-splat-v2i16.ll

diff --git a/llvm/lib/Target/Hexagon/HexagonPatterns.td b/llvm/lib/Target/Hexagon/HexagonPatterns.td
index 63e94b302c117..dbaa6c1fef572 100644
--- a/llvm/lib/Target/Hexagon/HexagonPatterns.td
+++ b/llvm/lib/Target/Hexagon/HexagonPatterns.td
@@ -1764,6 +1764,28 @@ def: Pat<(mul I32:$Rs, n8_0ImmPred:$n8),
 def: Pat<(v2i32 (mulnsw (sext V2I16:$Rs), (sext V2I16:$Rt))),
          (M2_vmpy2s_s0 V2I16:$Rs, V2I16:$Rt)>;
 
+// PatFrag matching assertsext of a v2i32 from i16, produced when a scalar
+// sext i16 is splatted into a v2i32 vector and the splat is hoisted out of
+// the loop into an earlier block, arriving as a live-in v2i32 register.
+def assertsext_v2i32_i16 : PatFrag<(ops node:$Rs),
+                                    (assertsext node:$Rs), [{
+  auto *T = cast<VTSDNode>(N->getOperand(1));
+  return N->getValueType(0) == MVT::v2i32 && T->getVT() == MVT::i16;
+}]>;
+
+// Handle sext v2i16 multiplied by a splatted scalar sext i16, where the
+// splat was hoisted and arrives as assertsext v2i32. Recover the v2i16
+// by combining the low halfwords of both elements.
+def: Pat<(v2i32 (mulnsw (sext V2I16:$Rs),
+                         (assertsext_v2i32_i16 V2I32:$Rt))),
+         (M2_vmpy2s_s0 V2I16:$Rs,
+                       (A2_combine_ll (HiReg $Rt), (LoReg $Rt)))>;
+
+def: Pat<(v2i32 (mulnsw (assertsext_v2i32_i16 V2I32:$Rs),
+                         (sext V2I16:$Rt))),
+         (M2_vmpy2s_s0 (A2_combine_ll (HiReg $Rs), (LoReg $Rs)),
+                       V2I16:$Rt)>;
+
 def: Pat<(add Sext64:$Rs, I64:$Rt),
          (A2_addsp (LoReg Sext64:$Rs), I64:$Rt)>;
 
diff --git a/llvm/test/CodeGen/Hexagon/sext-mul-splat-v2i16.ll b/llvm/test/CodeGen/Hexagon/sext-mul-splat-v2i16.ll
new file mode 100644
index 0000000000000..91b93f43e298b
--- /dev/null
+++ b/llvm/test/CodeGen/Hexagon/sext-mul-splat-v2i16.ll
@@ -0,0 +1,31 @@
+; RUN: llc -O2 -mtriple=hexagon < %s | FileCheck %s
+
+; Test that sext v2i16 multiplied by a splatted scalar sext i16 (where the
+; splat is hoisted and arrives as assertsext v2i32) is optimized to vmpyh.
+
+; CHECK-LABEL: test_sext_mul_splat:
+; CHECK-NOT: vsxthw
+; CHECK-NOT: mpyi
+; CHECK: vmpyh
+define void @test_sext_mul_splat(ptr %src, ptr %dst, i16 signext %scale, i32 %n) {
+entry:
+  %scale32 = sext i16 %scale to i32
+  %ins0 = insertelement <2 x i32> undef, i32 %scale32, i32 0
+  %splat = insertelement <2 x i32> %ins0, i32 %scale32, i32 1
+  br label %loop
+
+loop:
+  %i = phi i32 [ 0, %entry ], [ %i.next, %loop ]
+  %ptr = getelementptr <2 x i16>, ptr %src, i32 %i
+  %v = load <2 x i16>, ptr %ptr, align 4
+  %ext = sext <2 x i16> %v to <2 x i32>
+  %mul = mul nsw <2 x i32> %ext, %splat
+  %dptr = getelementptr <2 x i32>, ptr %dst, i32 %i
+  store <2 x i32> %mul, ptr %dptr, align 8
+  %i.next = add i32 %i, 1
+  %done = icmp eq i32 %i.next, %n
+  br i1 %done, label %exit, label %loop
+
+exit:
+  ret void
+}

>From cb42c49ad1f44e3de7fb78b7231518a4d0163033 Mon Sep 17 00:00:00 2001
From: Chandana Mudda <quic_csinderi at quicinc.com>
Date: Wed, 1 Jul 2026 20:44:42 -0700
Subject: [PATCH 2/2] [Hexagon] Replace undef with poison in
 sext-mul-splat-v2i16.ll test

---
 llvm/test/CodeGen/Hexagon/sext-mul-splat-v2i16.ll | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/llvm/test/CodeGen/Hexagon/sext-mul-splat-v2i16.ll b/llvm/test/CodeGen/Hexagon/sext-mul-splat-v2i16.ll
index 91b93f43e298b..5c8f3356e305e 100644
--- a/llvm/test/CodeGen/Hexagon/sext-mul-splat-v2i16.ll
+++ b/llvm/test/CodeGen/Hexagon/sext-mul-splat-v2i16.ll
@@ -10,7 +10,7 @@
 define void @test_sext_mul_splat(ptr %src, ptr %dst, i16 signext %scale, i32 %n) {
 entry:
   %scale32 = sext i16 %scale to i32
-  %ins0 = insertelement <2 x i32> undef, i32 %scale32, i32 0
+  %ins0 = insertelement <2 x i32> poison, i32 %scale32, i32 0
   %splat = insertelement <2 x i32> %ins0, i32 %scale32, i32 1
   br label %loop
 



More information about the llvm-commits mailing list