[llvm] [AArch64][GlobalISel] Combine trunc_nsw(smin) to truncsat (PR #218605)
David Green via llvm-commits
llvm-commits at lists.llvm.org
Wed Aug 26 05:17:16 PDT 2026
https://github.com/davemgreen updated https://github.com/llvm/llvm-project/pull/218605
>From 9fa1c5e51b1957f027f0eeaec9568f59fafb7ad8 Mon Sep 17 00:00:00 2001
From: David Green <david.green at arm.com>
Date: Wed, 19 Aug 2026 10:36:57 +0100
Subject: [PATCH 1/3] [AArch64][GlobalISel] Combine trunc_nsw(smin) to truncsat
The midend of LLVM, in CVP, will often transform the canonical pattern for a
saturate trunc(smin(smax)) into trunc nsw (smin), as the range analysis proves
that the smax is outside of range. This adds a fold back, converting the trunc
with nsw + smin into G_TRUNC_SSAT_S.
https://alive2.llvm.org/ce/z/xfPEXE
---
.../lib/CodeGen/GlobalISel/CombinerHelper.cpp | 26 ++--
llvm/test/CodeGen/AArch64/qmovn.ll | 21 +--
.../CodeGen/AArch64/saturating-vec-smull.ll | 125 ++++--------------
3 files changed, 51 insertions(+), 121 deletions(-)
diff --git a/llvm/lib/CodeGen/GlobalISel/CombinerHelper.cpp b/llvm/lib/CodeGen/GlobalISel/CombinerHelper.cpp
index 5804be63fad48..167cd480d398b 100644
--- a/llvm/lib/CodeGen/GlobalISel/CombinerHelper.cpp
+++ b/llvm/lib/CodeGen/GlobalISel/CombinerHelper.cpp
@@ -6290,14 +6290,24 @@ bool CombinerHelper::matchTruncSSatS(MachineInstr &MI,
APInt SignedMax = APInt::getSignedMaxValue(NumDstBits).sext(NumSrcBits);
APInt SignedMin = APInt::getSignedMinValue(NumDstBits).sext(NumSrcBits);
- return mi_match(Src, MRI,
- m_GSMin(m_GSMax(m_Reg(MatchInfo),
- m_SpecificICstOrSplat(SignedMin)),
- m_SpecificICstOrSplat(SignedMax))) ||
- mi_match(Src, MRI,
- m_GSMax(m_GSMin(m_Reg(MatchInfo),
- m_SpecificICstOrSplat(SignedMax)),
- m_SpecificICstOrSplat(SignedMin)));
+ if (mi_match(
+ Src, MRI,
+ m_GSMin(m_GSMax(m_Reg(MatchInfo), m_SpecificICstOrSplat(SignedMin)),
+ m_SpecificICstOrSplat(SignedMax))) ||
+ mi_match(
+ Src, MRI,
+ m_GSMax(m_GSMin(m_Reg(MatchInfo), m_SpecificICstOrSplat(SignedMax)),
+ m_SpecificICstOrSplat(SignedMin))))
+ return true;
+
+ // CVP in the midend will often transform trunc(smin(smax(..)) into
+ // trunc nsw(smin(..)) as the smax against INT_MIN never saturates.
+ if (MI.getFlag(MachineInstr::MIFlag::NoSWrap) &&
+ mi_match(Src, MRI,
+ m_GSMin(m_Reg(MatchInfo), m_SpecificICstOrSplat(SignedMax))))
+ return true;
+
+ return false;
}
void CombinerHelper::applyTruncSSatS(MachineInstr &MI,
diff --git a/llvm/test/CodeGen/AArch64/qmovn.ll b/llvm/test/CodeGen/AArch64/qmovn.ll
index 30bff916f1f02..c1b8c1c221614 100644
--- a/llvm/test/CodeGen/AArch64/qmovn.ll
+++ b/llvm/test/CodeGen/AArch64/qmovn.ll
@@ -640,10 +640,8 @@ define <16 x i8> @signed_minnsw_v16i16_to_v16i8(<16 x i16> %y) {
;
; CHECK-GI-LABEL: signed_minnsw_v16i16_to_v16i8:
; CHECK-GI: // %bb.0: // %entry
-; CHECK-GI-NEXT: movi v2.8h, #127
-; CHECK-GI-NEXT: smin v0.8h, v0.8h, v2.8h
-; CHECK-GI-NEXT: smin v1.8h, v1.8h, v2.8h
-; CHECK-GI-NEXT: uzp1 v0.16b, v0.16b, v1.16b
+; CHECK-GI-NEXT: sqxtn v0.8b, v0.8h
+; CHECK-GI-NEXT: sqxtn2 v0.16b, v1.8h
; CHECK-GI-NEXT: ret
entry:
%min = call <16 x i16> @llvm.smin.v16i16(<16 x i16> %y, <16 x i16> <i16 127, i16 127, i16 127, i16 127, i16 127, i16 127, i16 127, i16 127, i16 127, i16 127, i16 127, i16 127, i16 127, i16 127, i16 127, i16 127>)
@@ -662,10 +660,8 @@ define <8 x i16> @signed_minnsw_v8i32_to_v8i16(<8 x i32> %y) {
;
; CHECK-GI-LABEL: signed_minnsw_v8i32_to_v8i16:
; CHECK-GI: // %bb.0: // %entry
-; CHECK-GI-NEXT: movi v2.4s, #127, msl #8
-; CHECK-GI-NEXT: smin v0.4s, v0.4s, v2.4s
-; CHECK-GI-NEXT: smin v1.4s, v1.4s, v2.4s
-; CHECK-GI-NEXT: uzp1 v0.8h, v0.8h, v1.8h
+; CHECK-GI-NEXT: sqxtn v0.4h, v0.4s
+; CHECK-GI-NEXT: sqxtn2 v0.8h, v1.4s
; CHECK-GI-NEXT: ret
entry:
%min = call <8 x i32> @llvm.smin.v8i32(<8 x i32> %y, <8 x i32> <i32 32767, i32 32767, i32 32767, i32 32767, i32 32767, i32 32767, i32 32767, i32 32767>)
@@ -687,13 +683,8 @@ define <4 x i32> @signed_minnsw_v4i64_to_v4i32(<4 x i64> %y) {
;
; CHECK-GI-LABEL: signed_minnsw_v4i64_to_v4i32:
; CHECK-GI: // %bb.0: // %entry
-; CHECK-GI-NEXT: adrp x8, .LCPI47_0
-; CHECK-GI-NEXT: ldr q2, [x8, :lo12:.LCPI47_0]
-; CHECK-GI-NEXT: cmgt v3.2d, v2.2d, v0.2d
-; CHECK-GI-NEXT: cmgt v4.2d, v2.2d, v1.2d
-; CHECK-GI-NEXT: bif v0.16b, v2.16b, v3.16b
-; CHECK-GI-NEXT: bif v1.16b, v2.16b, v4.16b
-; CHECK-GI-NEXT: uzp1 v0.4s, v0.4s, v1.4s
+; CHECK-GI-NEXT: sqxtn v0.2s, v0.2d
+; CHECK-GI-NEXT: sqxtn2 v0.4s, v1.2d
; CHECK-GI-NEXT: ret
entry:
%min = call <4 x i64> @llvm.smin.v4i64(<4 x i64> %y, <4 x i64> <i64 2147483647, i64 2147483647, i64 2147483647, i64 2147483647>)
diff --git a/llvm/test/CodeGen/AArch64/saturating-vec-smull.ll b/llvm/test/CodeGen/AArch64/saturating-vec-smull.ll
index fe9b060be6ae2..f4585a5cd4dca 100644
--- a/llvm/test/CodeGen/AArch64/saturating-vec-smull.ll
+++ b/llvm/test/CodeGen/AArch64/saturating-vec-smull.ll
@@ -2,7 +2,8 @@
; RUN: llc -mtriple=aarch64-none-elf < %s | FileCheck %s --check-prefixes=CHECK,CHECK-SD
; RUN: llc -mtriple=aarch64-none-elf -global-isel -global-isel-abort=2 2>&1 < %s | FileCheck %s --check-prefixes=CHECK,CHECK-GI
-; CHECK-GI: warning: Instruction selection used fallback path for extend_to_illegal_type
+; CHECK-GI: warning: Instruction selection used fallback path for saturating_6xi16
+; CHECK-GI-NEXT: warning: Instruction selection used fallback path for extend_to_illegal_type
define <2 x i16> @saturating_2xi16(<2 x i16> %a, <2 x i16> %b) {
; CHECK-SD-LABEL: saturating_2xi16:
@@ -43,10 +44,7 @@ define <4 x i16> @saturating_4xi16(<4 x i16> %a, <4 x i16> %b) {
; 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: sqshrn v0.4h, v0.4s, #15
; CHECK-GI-NEXT: ret
%as = sext <4 x i16> %a to <4 x i32>
%bs = sext <4 x i16> %b to <4 x i32>
@@ -65,14 +63,10 @@ define <8 x i16> @saturating_8xi16(<8 x i16> %a, <8 x i16> %b) {
;
; 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: smull v2.4s, v1.4h, v0.4h
+; CHECK-GI-NEXT: smull2 v1.4s, v1.8h, v0.8h
+; CHECK-GI-NEXT: sqshrn v0.4h, v2.4s, #15
+; CHECK-GI-NEXT: sqshrn2 v0.8h, v1.4s, #15
; CHECK-GI-NEXT: ret
%as = sext <8 x i16> %a to <8 x i32>
%bs = sext <8 x i16> %b to <8 x i32>
@@ -92,12 +86,7 @@ define <2 x i32> @saturating_2xi32(<2 x i32> %a, <2 x i32> %b) {
; 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: sqshrn v0.2s, v0.2d, #31
; CHECK-GI-NEXT: ret
%as = sext <2 x i32> %a to <2 x i64>
%bs = sext <2 x i32> %b to <2 x i64>
@@ -117,16 +106,9 @@ define <4 x i32> @saturating_4xi32(<4 x i32> %a, <4 x i32> %b) {
; 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: smull2 v1.2d, v1.4s, v0.4s
+; CHECK-GI-NEXT: sqshrn v0.2s, v2.2d, #31
+; CHECK-GI-NEXT: sqshrn2 v0.4s, v1.2d, #31
; CHECK-GI-NEXT: ret
%as = sext <4 x i32> %a to <4 x i64>
%bs = sext <4 x i32> %b to <4 x i64>
@@ -147,25 +129,13 @@ 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: smull v5.2d, v3.2s, v1.2s
+; CHECK-GI-NEXT: smull2 v2.2d, v2.4s, v0.4s
+; CHECK-GI-NEXT: smull2 v3.2d, v3.4s, v1.4s
+; CHECK-GI-NEXT: sqshrn v0.2s, v4.2d, #31
+; CHECK-GI-NEXT: sqshrn v1.2s, v5.2d, #31
+; CHECK-GI-NEXT: sqshrn2 v0.4s, v2.2d, #31
+; CHECK-GI-NEXT: sqshrn2 v1.4s, v3.2d, #31
; CHECK-GI-NEXT: ret
%as = sext <8 x i32> %a to <8 x i64>
%bs = sext <8 x i32> %b to <8 x i64>
@@ -201,56 +171,15 @@ define <2 x i64> @saturating_2xi32_2xi64(<2 x i32> %a, <2 x i32> %b) {
}
define <6 x i16> @saturating_6xi16(<6 x i16> %a, <6 x i16> %b) {
-; CHECK-SD-LABEL: saturating_6xi16:
-; CHECK-SD: // %bb.0:
-; CHECK-SD-NEXT: smull2 v2.4s, v1.8h, v0.8h
-; CHECK-SD-NEXT: movi v3.4s, #127, msl #8
-; CHECK-SD-NEXT: sqdmulh v0.4h, v1.4h, v0.4h
-; CHECK-SD-NEXT: sshr v2.4s, v2.4s, #15
-; CHECK-SD-NEXT: smin v1.4s, v2.4s, v3.4s
-; CHECK-SD-NEXT: xtn2 v0.8h, v1.4s
-; CHECK-SD-NEXT: ret
-;
-; CHECK-GI-LABEL: saturating_6xi16:
-; CHECK-GI: // %bb.0:
-; CHECK-GI-NEXT: smov w8, v1.h[0]
-; CHECK-GI-NEXT: smov w9, v0.h[0]
-; CHECK-GI-NEXT: smov w10, v1.h[1]
-; CHECK-GI-NEXT: smov w11, v0.h[1]
-; CHECK-GI-NEXT: smov w12, v1.h[2]
-; CHECK-GI-NEXT: movi v2.4s, #127, msl #8
-; CHECK-GI-NEXT: fmov s3, w8
-; CHECK-GI-NEXT: fmov s4, w9
-; CHECK-GI-NEXT: smov w8, v0.h[2]
-; CHECK-GI-NEXT: smov w9, v1.h[3]
-; CHECK-GI-NEXT: sshll2 v1.4s, v1.8h, #0
-; CHECK-GI-NEXT: mov v3.s[1], w10
-; CHECK-GI-NEXT: mov v4.s[1], w11
-; CHECK-GI-NEXT: smov w10, v0.h[3]
-; CHECK-GI-NEXT: sshll2 v0.4s, v0.8h, #0
-; CHECK-GI-NEXT: mov v3.s[2], w12
-; CHECK-GI-NEXT: mov v4.s[2], w8
-; CHECK-GI-NEXT: mul v0.2s, v1.2s, v0.2s
-; CHECK-GI-NEXT: movi v1.2s, #127, msl #8
-; CHECK-GI-NEXT: mov v3.s[3], w9
-; CHECK-GI-NEXT: mov v4.s[3], w10
-; CHECK-GI-NEXT: sshr v0.2s, v0.2s, #15
-; CHECK-GI-NEXT: smin v0.2s, v0.2s, v1.2s
-; CHECK-GI-NEXT: mul v3.4s, v3.4s, v4.4s
-; CHECK-GI-NEXT: sshr v3.4s, v3.4s, #15
-; CHECK-GI-NEXT: smin v2.4s, v3.4s, v2.4s
-; CHECK-GI-NEXT: mov w8, v2.s[1]
-; CHECK-GI-NEXT: mov w9, v2.s[2]
-; CHECK-GI-NEXT: mov w10, v2.s[3]
-; CHECK-GI-NEXT: mov v2.h[1], w8
-; CHECK-GI-NEXT: fmov w8, s0
-; CHECK-GI-NEXT: mov v2.h[2], w9
-; CHECK-GI-NEXT: mov w9, v0.s[1]
-; CHECK-GI-NEXT: mov v2.h[3], w10
-; CHECK-GI-NEXT: mov v2.h[4], w8
-; CHECK-GI-NEXT: mov v2.h[5], w9
-; CHECK-GI-NEXT: mov v0.16b, v2.16b
-; CHECK-GI-NEXT: ret
+; CHECK-LABEL: saturating_6xi16:
+; CHECK: // %bb.0:
+; CHECK-NEXT: smull2 v2.4s, v1.8h, v0.8h
+; CHECK-NEXT: movi v3.4s, #127, msl #8
+; CHECK-NEXT: sqdmulh v0.4h, v1.4h, v0.4h
+; CHECK-NEXT: sshr v2.4s, v2.4s, #15
+; CHECK-NEXT: smin v1.4s, v2.4s, v3.4s
+; CHECK-NEXT: xtn2 v0.8h, v1.4s
+; CHECK-NEXT: ret
%as = sext <6 x i16> %a to <6 x i32>
%bs = sext <6 x i16> %b to <6 x i32>
%m = mul nsw <6 x i32> %bs, %as
>From f4b8956da6c45de9053a594cf3b8997e9a52b1af Mon Sep 17 00:00:00 2001
From: David Green <david.green at arm.com>
Date: Tue, 25 Aug 2026 08:07:26 +0100
Subject: [PATCH 2/3] [AArch64][GlobalISel] G_TRUNC_SSAT_S moreElements
handling
These operations can be widened in the same way as a standard trunc, by using
buildPadVectorWithUndefElements.
---
.../CodeGen/GlobalISel/LegalizerHelper.cpp | 5 +-
.../CodeGen/AArch64/saturating-vec-smull.ll | 55 +++++++++++++++----
2 files changed, 48 insertions(+), 12 deletions(-)
diff --git a/llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp b/llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp
index 9e8895898532e..734dbab45b9a2 100644
--- a/llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp
+++ b/llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp
@@ -7074,7 +7074,10 @@ LegalizerHelper::moreElementsVector(MachineInstr &MI, unsigned TypeIdx,
case TargetOpcode::G_FPTOSI_SAT:
case TargetOpcode::G_FPTOUI_SAT:
case TargetOpcode::G_SITOFP:
- case TargetOpcode::G_UITOFP: {
+ case TargetOpcode::G_UITOFP:
+ case TargetOpcode::G_TRUNC_SSAT_S:
+ case TargetOpcode::G_TRUNC_SSAT_U:
+ case TargetOpcode::G_TRUNC_USAT_U: {
Observer.changingInstr(MI);
LLT SrcExtTy;
LLT DstExtTy;
diff --git a/llvm/test/CodeGen/AArch64/saturating-vec-smull.ll b/llvm/test/CodeGen/AArch64/saturating-vec-smull.ll
index f4585a5cd4dca..a16eb65b32a71 100644
--- a/llvm/test/CodeGen/AArch64/saturating-vec-smull.ll
+++ b/llvm/test/CodeGen/AArch64/saturating-vec-smull.ll
@@ -2,8 +2,7 @@
; RUN: llc -mtriple=aarch64-none-elf < %s | FileCheck %s --check-prefixes=CHECK,CHECK-SD
; RUN: llc -mtriple=aarch64-none-elf -global-isel -global-isel-abort=2 2>&1 < %s | FileCheck %s --check-prefixes=CHECK,CHECK-GI
-; CHECK-GI: warning: Instruction selection used fallback path for saturating_6xi16
-; CHECK-GI-NEXT: warning: Instruction selection used fallback path for extend_to_illegal_type
+; CHECK-GI: warning: Instruction selection used fallback path for extend_to_illegal_type
define <2 x i16> @saturating_2xi16(<2 x i16> %a, <2 x i16> %b) {
; CHECK-SD-LABEL: saturating_2xi16:
@@ -171,15 +170,49 @@ define <2 x i64> @saturating_2xi32_2xi64(<2 x i32> %a, <2 x i32> %b) {
}
define <6 x i16> @saturating_6xi16(<6 x i16> %a, <6 x i16> %b) {
-; CHECK-LABEL: saturating_6xi16:
-; CHECK: // %bb.0:
-; CHECK-NEXT: smull2 v2.4s, v1.8h, v0.8h
-; CHECK-NEXT: movi v3.4s, #127, msl #8
-; CHECK-NEXT: sqdmulh v0.4h, v1.4h, v0.4h
-; CHECK-NEXT: sshr v2.4s, v2.4s, #15
-; CHECK-NEXT: smin v1.4s, v2.4s, v3.4s
-; CHECK-NEXT: xtn2 v0.8h, v1.4s
-; CHECK-NEXT: ret
+; CHECK-SD-LABEL: saturating_6xi16:
+; CHECK-SD: // %bb.0:
+; CHECK-SD-NEXT: smull2 v2.4s, v1.8h, v0.8h
+; CHECK-SD-NEXT: movi v3.4s, #127, msl #8
+; CHECK-SD-NEXT: sqdmulh v0.4h, v1.4h, v0.4h
+; CHECK-SD-NEXT: sshr v2.4s, v2.4s, #15
+; CHECK-SD-NEXT: smin v1.4s, v2.4s, v3.4s
+; CHECK-SD-NEXT: xtn2 v0.8h, v1.4s
+; CHECK-SD-NEXT: ret
+;
+; CHECK-GI-LABEL: saturating_6xi16:
+; CHECK-GI: // %bb.0:
+; CHECK-GI-NEXT: smov w8, v1.h[0]
+; CHECK-GI-NEXT: smov w9, v0.h[0]
+; CHECK-GI-NEXT: smov w10, v1.h[1]
+; CHECK-GI-NEXT: smov w11, v0.h[1]
+; CHECK-GI-NEXT: fmov s2, w8
+; CHECK-GI-NEXT: fmov s3, w9
+; CHECK-GI-NEXT: smov w8, v1.h[2]
+; CHECK-GI-NEXT: smov w9, v0.h[2]
+; CHECK-GI-NEXT: mov v2.s[1], w10
+; CHECK-GI-NEXT: mov v3.s[1], w11
+; CHECK-GI-NEXT: smov w10, v1.h[3]
+; CHECK-GI-NEXT: sshll2 v1.4s, v1.8h, #0
+; CHECK-GI-NEXT: mov v2.s[2], w8
+; CHECK-GI-NEXT: smov w8, v0.h[3]
+; CHECK-GI-NEXT: mov v3.s[2], w9
+; CHECK-GI-NEXT: sshll2 v0.4s, v0.8h, #0
+; CHECK-GI-NEXT: mov v2.s[3], w10
+; CHECK-GI-NEXT: mov v3.s[3], w8
+; CHECK-GI-NEXT: mul v0.2s, v1.2s, v0.2s
+; CHECK-GI-NEXT: mul v2.4s, v2.4s, v3.4s
+; CHECK-GI-NEXT: sshr v0.2s, v0.2s, #15
+; CHECK-GI-NEXT: sqxtn v0.4h, v0.4s
+; CHECK-GI-NEXT: sqshrn v3.4h, v2.4s, #15
+; CHECK-GI-NEXT: mov v2.h[0], v3.h[0]
+; CHECK-GI-NEXT: mov v2.h[1], v3.h[1]
+; CHECK-GI-NEXT: mov v2.h[2], v3.h[2]
+; CHECK-GI-NEXT: mov v2.h[3], v3.h[3]
+; CHECK-GI-NEXT: mov v2.h[4], v0.h[0]
+; CHECK-GI-NEXT: mov v2.h[5], v0.h[1]
+; CHECK-GI-NEXT: mov v0.16b, v2.16b
+; CHECK-GI-NEXT: ret
%as = sext <6 x i16> %a to <6 x i32>
%bs = sext <6 x i16> %b to <6 x i32>
%m = mul nsw <6 x i32> %bs, %as
>From 5c2292970f9c396a82a7964590cc291ff25d8fac Mon Sep 17 00:00:00 2001
From: David Green <david.green at arm.com>
Date: Wed, 26 Aug 2026 13:17:01 +0100
Subject: [PATCH 3/3] Split if
---
llvm/lib/CodeGen/GlobalISel/CombinerHelper.cpp | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/llvm/lib/CodeGen/GlobalISel/CombinerHelper.cpp b/llvm/lib/CodeGen/GlobalISel/CombinerHelper.cpp
index 167cd480d398b..3f5d9ecfa26fb 100644
--- a/llvm/lib/CodeGen/GlobalISel/CombinerHelper.cpp
+++ b/llvm/lib/CodeGen/GlobalISel/CombinerHelper.cpp
@@ -6293,8 +6293,9 @@ bool CombinerHelper::matchTruncSSatS(MachineInstr &MI,
if (mi_match(
Src, MRI,
m_GSMin(m_GSMax(m_Reg(MatchInfo), m_SpecificICstOrSplat(SignedMin)),
- m_SpecificICstOrSplat(SignedMax))) ||
- mi_match(
+ m_SpecificICstOrSplat(SignedMax))))
+ return true;
+ if (mi_match(
Src, MRI,
m_GSMax(m_GSMin(m_Reg(MatchInfo), m_SpecificICstOrSplat(SignedMax)),
m_SpecificICstOrSplat(SignedMin))))
More information about the llvm-commits
mailing list