[llvm] [Hexagon] Optimize sext + mul pattern to use vmpyh instruction (PR #190316)

Santanu Das via llvm-commits llvm-commits at lists.llvm.org
Mon Apr 13 01:02:53 PDT 2026


https://github.com/quic-santdas updated https://github.com/llvm/llvm-project/pull/190316

>From 39e2259bfd2718bec718540954315f7cbecf3cb5 Mon Sep 17 00:00:00 2001
From: Chandana Mudda <quic_csinderi at quicinc.com>
Date: Fri, 3 Apr 2026 00:17:03 -0700
Subject: [PATCH] Optimize sext + mul pattern to use vmpyh instruction

This patch adds TableGen patterns to recognize and optimize the pattern:
(v2i32 (mul (sext v2i16), (sext v2i16)))

And transforms it to use the M2_vmpy2s_s0 instruction which generates
the efficient vmpyh (vector multiply halfwords) instruction.

The transform is guarded by `nsw` because `M2_vmpy2s_s0` performs a
saturating signed multiply (`vmpyh(...):sat`), so the replacement is
only semantics-preserving when signed overflow is undefined in the IR.

Currently, this pattern expands to:
  r3:2 = vsxthw(r0)    // Sign extend
  r1:0 = vsxthw(r1)    // Sign extend
  r1 = mpyi(r3,r1)     // Scalar multiply
  r0 = mpyi(r2,r0)     // Scalar multiply

With this patch, it generates:
  r1:0 = vmpyh(r0,r1):sat  // Single vector multiply
---
 llvm/lib/Target/Hexagon/HexagonPatterns.td  |  8 ++++++++
 llvm/test/CodeGen/Hexagon/sext-mul-v2i16.ll | 16 ++++++++++++++++
 2 files changed, 24 insertions(+)
 create mode 100644 llvm/test/CodeGen/Hexagon/sext-mul-v2i16.ll

diff --git a/llvm/lib/Target/Hexagon/HexagonPatterns.td b/llvm/lib/Target/Hexagon/HexagonPatterns.td
index 3f836e8c1dbef..91f46a631d409 100644
--- a/llvm/lib/Target/Hexagon/HexagonPatterns.td
+++ b/llvm/lib/Target/Hexagon/HexagonPatterns.td
@@ -1747,10 +1747,18 @@ def n8_0ImmPred: PatLeaf<(i32 imm), [{
   return -255 <= V && V <= 0;
 }]>;
 
+def mulnsw : PatFrag<(ops node:$lhs, node:$rhs),
+                     (mul node:$lhs, node:$rhs), [{
+  return N->getFlags().hasNoSignedWrap();
+}]>;
+
 // Change the sign of the immediate for Rd=-mpyi(Rs,#u8)
 def: Pat<(mul I32:$Rs, n8_0ImmPred:$n8),
          (M2_mpysin I32:$Rs, (NegImm8 imm:$n8))>;
 
+def: Pat<(v2i32 (mulnsw (sext V2I16:$Rs), (sext V2I16:$Rt))),
+         (M2_vmpy2s_s0 V2I16:$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-v2i16.ll b/llvm/test/CodeGen/Hexagon/sext-mul-v2i16.ll
new file mode 100644
index 0000000000000..a34a5faa9cc3b
--- /dev/null
+++ b/llvm/test/CodeGen/Hexagon/sext-mul-v2i16.ll
@@ -0,0 +1,16 @@
+; RUN: llc -O2 -mtriple=hexagon < %s | FileCheck %s
+
+; Test that we optimize sext + mul pattern to use vmpyh instruction
+; instead of expanding to scalar multiplies.
+
+; CHECK-LABEL: test_sext_mul_v2i16:
+; CHECK: vmpyh
+; CHECK-NOT: vsxthw
+; CHECK-NOT: mpyi
+define <2 x i32> @test_sext_mul_v2i16(<2 x i16> %a, <2 x i16> %b) {
+entry:
+  %ext_a = sext <2 x i16> %a to <2 x i32>
+  %ext_b = sext <2 x i16> %b to <2 x i32>
+  %mul = mul nsw <2 x i32> %ext_a, %ext_b
+  ret <2 x i32> %mul
+}



More information about the llvm-commits mailing list