[llvm] [AArch64][GlobalISel] Add tablegen patterns for smull+sqshrn -> sqdmulh. (PR #217318)
David Green via llvm-commits
llvm-commits at lists.llvm.org
Tue Aug 25 01:26:56 PDT 2026
https://github.com/davemgreen updated https://github.com/llvm/llvm-project/pull/217318
>From 2d9a47436f858ed67589dc1e389c3922a20def4f Mon Sep 17 00:00:00 2001
From: David Green <david.green at arm.com>
Date: Tue, 25 Aug 2026 09:26:31 +0100
Subject: [PATCH] [AArch64][GlobalISel] Add tablegen patterns for smull+sqshrn
-> sqdmulh.
We do this in parts in globalisel, recognizing the smull and trunc_sat, which
when combined with the correct shift can fold into a single sqdmulh.
---
llvm/lib/Target/AArch64/AArch64InstrInfo.td | 21 ++++
.../CodeGen/AArch64/saturating-vec-smull.ll | 101 ++++--------------
llvm/test/CodeGen/AArch64/smul_fix_sat.ll | 62 +++--------
3 files changed, 55 insertions(+), 129 deletions(-)
diff --git a/llvm/lib/Target/AArch64/AArch64InstrInfo.td b/llvm/lib/Target/AArch64/AArch64InstrInfo.td
index 93937f57b7d39..c418d60af5eaf 100644
--- a/llvm/lib/Target/AArch64/AArch64InstrInfo.td
+++ b/llvm/lib/Target/AArch64/AArch64InstrInfo.td
@@ -10767,6 +10767,27 @@ def : Pat<(v8i16 (AArch64sqdmulh (v8i16 V128:$Rn), (v8i16 V128:$Rm))),
def : Pat<(v4i32 (AArch64sqdmulh (v4i32 V128:$Rn), (v4i32 V128:$Rm))),
(SQDMULHv4i32 V128:$Rn, V128:$Rm)>;
+def AArch64sqdmulhPat : PatFrag<(ops node:$Rn, node:$Rm, node:$offset),
+ (truncssat_s (AArch64vashr (AArch64smull node:$Rn, node:$Rm), node:$offset))>;
+def : Pat<(v4i16 (AArch64sqdmulhPat (v4i16 V64:$Rn), (v4i16 V64:$Rm), (i32 15))),
+ (SQDMULHv4i16 V64:$Rn, V64:$Rm)>;
+def : Pat<(v2i32 (AArch64sqdmulhPat (v2i32 V64:$Rn), (v2i32 V64:$Rm), (i32 31))),
+ (SQDMULHv2i32 V64:$Rn, V64:$Rm)>;
+def : Pat<(v8i16 (concat_vectors (v4i16 (AArch64sqdmulhPat (v4i16 (extract_subvector V128:$Rn, (i64 0))),
+ (v4i16 (extract_subvector V128:$Rm, (i64 0))),
+ (i32 15))),
+ (v4i16 (AArch64sqdmulhPat (v4i16 (extract_subvector V128:$Rn, (i64 4))),
+ (v4i16 (extract_subvector V128:$Rm, (i64 4))),
+ (i32 15))))),
+ (SQDMULHv8i16 V128:$Rn, V128:$Rm)>;
+def : Pat<(v4i32 (concat_vectors (v2i32 (AArch64sqdmulhPat (v2i32 (extract_subvector V128:$Rn, (i64 0))),
+ (v2i32 (extract_subvector V128:$Rm, (i64 0))),
+ (i32 31))),
+ (v2i32 (AArch64sqdmulhPat (v2i32 (extract_subvector V128:$Rn, (i64 2))),
+ (v2i32 (extract_subvector V128:$Rm, (i64 2))),
+ (i32 31))))),
+ (SQDMULHv4i32 V128:$Rn, V128:$Rm)>;
+
// Conversions within AdvSIMD types in the same register size are free.
// But because we need a consistent lane ordering, in big endian many
// conversions require one or more REV instructions.
diff --git a/llvm/test/CodeGen/AArch64/saturating-vec-smull.ll b/llvm/test/CodeGen/AArch64/saturating-vec-smull.ll
index fe9b060be6ae2..421797c16148f 100644
--- a/llvm/test/CodeGen/AArch64/saturating-vec-smull.ll
+++ b/llvm/test/CodeGen/AArch64/saturating-vec-smull.ll
@@ -35,19 +35,10 @@ define <2 x i16> @saturating_2xi16(<2 x i16> %a, <2 x i16> %b) {
}
define <4 x i16> @saturating_4xi16(<4 x i16> %a, <4 x i16> %b) {
-; CHECK-SD-LABEL: saturating_4xi16:
-; CHECK-SD: // %bb.0:
-; CHECK-SD-NEXT: sqdmulh v0.4h, v1.4h, v0.4h
-; CHECK-SD-NEXT: ret
-;
-; CHECK-GI-LABEL: saturating_4xi16:
-; CHECK-GI: // %bb.0:
-; CHECK-GI-NEXT: smull v0.4s, v1.4h, v0.4h
-; CHECK-GI-NEXT: movi v1.4s, #127, msl #8
-; CHECK-GI-NEXT: sshr v0.4s, v0.4s, #15
-; CHECK-GI-NEXT: smin v0.4s, v0.4s, v1.4s
-; CHECK-GI-NEXT: xtn v0.4h, v0.4s
-; CHECK-GI-NEXT: ret
+; CHECK-LABEL: saturating_4xi16:
+; CHECK: // %bb.0:
+; CHECK-NEXT: sqdmulh v0.4h, v1.4h, v0.4h
+; CHECK-NEXT: ret
%as = sext <4 x i16> %a to <4 x i32>
%bs = sext <4 x i16> %b to <4 x i32>
%m = mul nsw <4 x i32> %bs, %as
@@ -58,22 +49,10 @@ define <4 x i16> @saturating_4xi16(<4 x i16> %a, <4 x i16> %b) {
}
define <8 x i16> @saturating_8xi16(<8 x i16> %a, <8 x i16> %b) {
-; CHECK-SD-LABEL: saturating_8xi16:
-; CHECK-SD: // %bb.0:
-; CHECK-SD-NEXT: sqdmulh v0.8h, v1.8h, v0.8h
-; CHECK-SD-NEXT: ret
-;
-; CHECK-GI-LABEL: saturating_8xi16:
-; CHECK-GI: // %bb.0:
-; CHECK-GI-NEXT: smull v3.4s, v1.4h, v0.4h
-; CHECK-GI-NEXT: smull2 v0.4s, v1.8h, v0.8h
-; CHECK-GI-NEXT: movi v2.4s, #127, msl #8
-; CHECK-GI-NEXT: sshr v1.4s, v3.4s, #15
-; CHECK-GI-NEXT: sshr v0.4s, v0.4s, #15
-; CHECK-GI-NEXT: smin v1.4s, v1.4s, v2.4s
-; CHECK-GI-NEXT: smin v0.4s, v0.4s, v2.4s
-; CHECK-GI-NEXT: uzp1 v0.8h, v1.8h, v0.8h
-; CHECK-GI-NEXT: ret
+; CHECK-LABEL: saturating_8xi16:
+; CHECK: // %bb.0:
+; CHECK-NEXT: sqdmulh v0.8h, v1.8h, v0.8h
+; CHECK-NEXT: ret
%as = sext <8 x i16> %a to <8 x i32>
%bs = sext <8 x i16> %b to <8 x i32>
%m = mul nsw <8 x i32> %bs, %as
@@ -84,21 +63,10 @@ define <8 x i16> @saturating_8xi16(<8 x i16> %a, <8 x i16> %b) {
}
define <2 x i32> @saturating_2xi32(<2 x i32> %a, <2 x i32> %b) {
-; CHECK-SD-LABEL: saturating_2xi32:
-; CHECK-SD: // %bb.0:
-; CHECK-SD-NEXT: sqdmulh v0.2s, v1.2s, v0.2s
-; CHECK-SD-NEXT: ret
-;
-; CHECK-GI-LABEL: saturating_2xi32:
-; CHECK-GI: // %bb.0:
-; CHECK-GI-NEXT: smull v0.2d, v1.2s, v0.2s
-; CHECK-GI-NEXT: adrp x8, .LCPI3_0
-; CHECK-GI-NEXT: ldr q1, [x8, :lo12:.LCPI3_0]
-; CHECK-GI-NEXT: sshr v0.2d, v0.2d, #31
-; CHECK-GI-NEXT: cmgt v2.2d, v1.2d, v0.2d
-; CHECK-GI-NEXT: bif v0.16b, v1.16b, v2.16b
-; CHECK-GI-NEXT: xtn v0.2s, v0.2d
-; CHECK-GI-NEXT: ret
+; CHECK-LABEL: saturating_2xi32:
+; CHECK: // %bb.0:
+; CHECK-NEXT: sqdmulh v0.2s, v1.2s, v0.2s
+; CHECK-NEXT: ret
%as = sext <2 x i32> %a to <2 x i64>
%bs = sext <2 x i32> %b to <2 x i64>
%m = mul nsw <2 x i64> %bs, %as
@@ -109,25 +77,10 @@ define <2 x i32> @saturating_2xi32(<2 x i32> %a, <2 x i32> %b) {
}
define <4 x i32> @saturating_4xi32(<4 x i32> %a, <4 x i32> %b) {
-; CHECK-SD-LABEL: saturating_4xi32:
-; CHECK-SD: // %bb.0:
-; CHECK-SD-NEXT: sqdmulh v0.4s, v1.4s, v0.4s
-; CHECK-SD-NEXT: ret
-;
-; CHECK-GI-LABEL: saturating_4xi32:
-; CHECK-GI: // %bb.0:
-; CHECK-GI-NEXT: smull v2.2d, v1.2s, v0.2s
-; CHECK-GI-NEXT: smull2 v0.2d, v1.4s, v0.4s
-; CHECK-GI-NEXT: adrp x8, .LCPI4_0
-; CHECK-GI-NEXT: sshr v1.2d, v2.2d, #31
-; CHECK-GI-NEXT: sshr v0.2d, v0.2d, #31
-; CHECK-GI-NEXT: ldr q2, [x8, :lo12:.LCPI4_0]
-; CHECK-GI-NEXT: cmgt v3.2d, v2.2d, v1.2d
-; CHECK-GI-NEXT: cmgt v4.2d, v2.2d, v0.2d
-; CHECK-GI-NEXT: bif v1.16b, v2.16b, v3.16b
-; CHECK-GI-NEXT: bif v0.16b, v2.16b, v4.16b
-; CHECK-GI-NEXT: uzp1 v0.4s, v1.4s, v0.4s
-; CHECK-GI-NEXT: ret
+; CHECK-LABEL: saturating_4xi32:
+; CHECK: // %bb.0:
+; CHECK-NEXT: sqdmulh v0.4s, v1.4s, v0.4s
+; CHECK-NEXT: ret
%as = sext <4 x i32> %a to <4 x i64>
%bs = sext <4 x i32> %b to <4 x i64>
%m = mul nsw <4 x i64> %bs, %as
@@ -146,26 +99,8 @@ define <8 x i32> @saturating_8xi32(<8 x i32> %a, <8 x i32> %b) {
;
; CHECK-GI-LABEL: saturating_8xi32:
; CHECK-GI: // %bb.0:
-; CHECK-GI-NEXT: smull v4.2d, v2.2s, v0.2s
-; CHECK-GI-NEXT: smull2 v0.2d, v2.4s, v0.4s
-; CHECK-GI-NEXT: adrp x8, .LCPI5_0
-; CHECK-GI-NEXT: smull v2.2d, v3.2s, v1.2s
-; CHECK-GI-NEXT: smull2 v1.2d, v3.4s, v1.4s
-; CHECK-GI-NEXT: ldr q3, [x8, :lo12:.LCPI5_0]
-; CHECK-GI-NEXT: sshr v4.2d, v4.2d, #31
-; CHECK-GI-NEXT: sshr v0.2d, v0.2d, #31
-; CHECK-GI-NEXT: sshr v2.2d, v2.2d, #31
-; CHECK-GI-NEXT: sshr v1.2d, v1.2d, #31
-; CHECK-GI-NEXT: cmgt v5.2d, v3.2d, v4.2d
-; CHECK-GI-NEXT: cmgt v6.2d, v3.2d, v0.2d
-; CHECK-GI-NEXT: cmgt v7.2d, v3.2d, v2.2d
-; CHECK-GI-NEXT: cmgt v16.2d, v3.2d, v1.2d
-; CHECK-GI-NEXT: bif v4.16b, v3.16b, v5.16b
-; CHECK-GI-NEXT: bif v0.16b, v3.16b, v6.16b
-; CHECK-GI-NEXT: bif v2.16b, v3.16b, v7.16b
-; CHECK-GI-NEXT: bif v1.16b, v3.16b, v16.16b
-; CHECK-GI-NEXT: uzp1 v0.4s, v4.4s, v0.4s
-; CHECK-GI-NEXT: uzp1 v1.4s, v2.4s, v1.4s
+; CHECK-GI-NEXT: sqdmulh v0.4s, v2.4s, v0.4s
+; CHECK-GI-NEXT: sqdmulh v1.4s, v3.4s, v1.4s
; CHECK-GI-NEXT: ret
%as = sext <8 x i32> %a to <8 x i64>
%bs = sext <8 x i32> %b to <8 x i64>
diff --git a/llvm/test/CodeGen/AArch64/smul_fix_sat.ll b/llvm/test/CodeGen/AArch64/smul_fix_sat.ll
index 865b11100c4f5..744d1be126ff1 100644
--- a/llvm/test/CodeGen/AArch64/smul_fix_sat.ll
+++ b/llvm/test/CodeGen/AArch64/smul_fix_sat.ll
@@ -790,68 +790,38 @@ define <4 x i64> @vec_v4i64(<4 x i64> %x, <4 x i64> %y) {
}
define <8 x i16> @vec_sqdmulh_v8i16(<8 x i16> %x, <8 x i16> %y) {
-; CHECK-SD-LABEL: vec_sqdmulh_v8i16:
-; CHECK-SD: // %bb.0:
-; CHECK-SD-NEXT: sqdmulh v0.8h, v0.8h, v1.8h
-; CHECK-SD-NEXT: ret
-;
-; CHECK-GI-LABEL: vec_sqdmulh_v8i16:
-; CHECK-GI: // %bb.0:
-; CHECK-GI-NEXT: smull v2.4s, v0.4h, v1.4h
-; CHECK-GI-NEXT: smull2 v1.4s, v0.8h, v1.8h
-; CHECK-GI-NEXT: sqshrn v0.4h, v2.4s, #15
-; CHECK-GI-NEXT: sqshrn2 v0.8h, v1.4s, #15
-; CHECK-GI-NEXT: ret
+; CHECK-LABEL: vec_sqdmulh_v8i16:
+; CHECK: // %bb.0:
+; CHECK-NEXT: sqdmulh v0.8h, v0.8h, v1.8h
+; CHECK-NEXT: ret
%tmp = call <8 x i16> @llvm.smul.fix.sat.v8i16(<8 x i16> %x, <8 x i16> %y, i32 15)
ret <8 x i16> %tmp
}
define <4 x i16> @vec_sqdmulh_v4i16(<4 x i16> %x, <4 x i16> %y) {
-; CHECK-SD-LABEL: vec_sqdmulh_v4i16:
-; CHECK-SD: // %bb.0:
-; CHECK-SD-NEXT: sqdmulh v0.4h, v0.4h, v1.4h
-; CHECK-SD-NEXT: ret
-;
-; CHECK-GI-LABEL: vec_sqdmulh_v4i16:
-; CHECK-GI: // %bb.0:
-; CHECK-GI-NEXT: smull v0.4s, v0.4h, v1.4h
-; CHECK-GI-NEXT: sqshrn v0.4h, v0.4s, #15
-; CHECK-GI-NEXT: ret
+; CHECK-LABEL: vec_sqdmulh_v4i16:
+; CHECK: // %bb.0:
+; CHECK-NEXT: sqdmulh v0.4h, v0.4h, v1.4h
+; CHECK-NEXT: ret
%tmp = call <4 x i16> @llvm.smul.fix.sat.v4i16(<4 x i16> %x, <4 x i16> %y, i32 15)
ret <4 x i16> %tmp
}
define <4 x i32> @vec_sqdmulh_v4i32(<4 x i32> %x, <4 x i32> %y) {
-; CHECK-SD-LABEL: vec_sqdmulh_v4i32:
-; CHECK-SD: // %bb.0:
-; CHECK-SD-NEXT: sqdmulh v0.4s, v0.4s, v1.4s
-; CHECK-SD-NEXT: ret
-;
-; CHECK-GI-LABEL: vec_sqdmulh_v4i32:
-; CHECK-GI: // %bb.0:
-; CHECK-GI-NEXT: smull v2.2d, v0.2s, v1.2s
-; CHECK-GI-NEXT: smull2 v1.2d, v0.4s, v1.4s
-; CHECK-GI-NEXT: sqshrn v0.2s, v2.2d, #31
-; CHECK-GI-NEXT: sqshrn2 v0.4s, v1.2d, #31
-; CHECK-GI-NEXT: ret
+; CHECK-LABEL: vec_sqdmulh_v4i32:
+; CHECK: // %bb.0:
+; CHECK-NEXT: sqdmulh v0.4s, v0.4s, v1.4s
+; CHECK-NEXT: ret
%tmp = call <4 x i32> @llvm.smul.fix.sat.v4i32(<4 x i32> %x, <4 x i32> %y, i32 31)
ret <4 x i32> %tmp
}
define <2 x i32> @vec_sqdmulh_v2i32(<2 x i32> %x, <2 x i32> %y) {
-; CHECK-SD-LABEL: vec_sqdmulh_v2i32:
-; CHECK-SD: // %bb.0:
-; CHECK-SD-NEXT: sqdmulh v0.2s, v0.2s, v1.2s
-; CHECK-SD-NEXT: ret
-;
-; CHECK-GI-LABEL: vec_sqdmulh_v2i32:
-; CHECK-GI: // %bb.0:
-; CHECK-GI-NEXT: smull v0.2d, v0.2s, v1.2s
-; CHECK-GI-NEXT: sqshrn v0.2s, v0.2d, #31
-; CHECK-GI-NEXT: ret
+; CHECK-LABEL: vec_sqdmulh_v2i32:
+; CHECK: // %bb.0:
+; CHECK-NEXT: sqdmulh v0.2s, v0.2s, v1.2s
+; CHECK-NEXT: ret
%tmp = call <2 x i32> @llvm.smul.fix.sat.v2i32(<2 x i32> %x, <2 x i32> %y, i32 31)
ret <2 x i32> %tmp
}
-;; NOTE: These prefixes are unused and the list is autogenerated. Do not add tests below this line:
-; CHECK: {{.*}}
More information about the llvm-commits
mailing list