Skip to content

[ARM][MVE] Match canonical saturating negation patterns - #213085

Merged
stuij merged 2 commits into
llvm:mainfrom
stuij:saturating-negation
Aug 3, 2026
Merged

[ARM][MVE] Match canonical saturating negation patterns#213085
stuij merged 2 commits into
llvm:mainfrom
stuij:saturating-negation

Conversation

@stuij

@stuij stuij commented Jul 30, 2026

Copy link
Copy Markdown
Member

InstCombine pull request #194519 canonicalized the saturating negation idiom to
an llvm.ssub.sat operation. For the ARM backend we only recognized the original
select and subtract pattern, causing vector absolute values to expand to VQSUB
plus a compare and select instead of VQABS.

In this patch we teach the VQABS and VQNEG patterns to recognize this ssub.sat
form.

@llvmorg-github-actions

Copy link
Copy Markdown

@llvm/pr-subscribers-backend-arm

Author: Ties Stuij (stuij)

Changes

InstCombine commit 2c35727 (no pull request) canonicalized the saturating negation idiom to an llvm.ssub.sat operation. For the ARM backend we only recognized the original select and subtract pattern, causing vector absolute values to expand to VQSUB plus a compare and select instead of VQABS.

In this patch we teach the VQABS and VQNEG patterns to recognize the canonical ssub.sat form.


Full diff: https://github.com/llvm/llvm-project/pull/213085.diff

3 Files Affected:

  • (modified) llvm/lib/Target/ARM/ARMInstrMVE.td (+11)
  • (modified) llvm/test/CodeGen/Thumb2/vqabs.ll (+3-12)
  • (modified) llvm/test/CodeGen/Thumb2/vqneg.ll (+3-6)
diff --git a/llvm/lib/Target/ARM/ARMInstrMVE.td b/llvm/lib/Target/ARM/ARMInstrMVE.td
index 38f36cb239535..6b4feb638c9e3 100644
--- a/llvm/lib/Target/ARM/ARMInstrMVE.td
+++ b/llvm/lib/Target/ARM/ARMInstrMVE.td
@@ -2568,6 +2568,14 @@ multiclass vqabsneg_pattern<MVEVectorVTInfo VTI, dag int_min, dag int_max,
                                 int_max,
                                 (sub (VTI.Vec zero_vec), (VTI.Vec MQPR:$reg)))))),
             (VTI.Vec (vqabs_instruction (VTI.Vec MQPR:$reg)))>;
+    // InstCombine canonicalizes the saturating negate in the expression above
+    // to ssub.sat(0, r).
+    def : Pat<(VTI.Vec (vselect
+                      (VTI.Pred (ARMvcmpz (VTI.Vec MQPR:$reg), ARMCCgt)),
+                      (VTI.Vec MQPR:$reg),
+                      (VTI.Vec (ssubsat (VTI.Vec zero_vec),
+                                        (VTI.Vec MQPR:$reg))))),
+              (VTI.Vec (vqabs_instruction (VTI.Vec MQPR:$reg)))>;
     // Similarly, this tree represents vqneg, i.e. the following vectorized expression:
     // r == INT_MIN ? INT_MAX : -r
     def : Pat<(VTI.Vec (vselect
@@ -2575,6 +2583,9 @@ multiclass vqabsneg_pattern<MVEVectorVTInfo VTI, dag int_min, dag int_max,
                         int_max,
                         (sub (VTI.Vec zero_vec), (VTI.Vec MQPR:$reg)))),
                (VTI.Vec (vqneg_instruction (VTI.Vec MQPR:$reg)))>;
+    def : Pat<(VTI.Vec (ssubsat (VTI.Vec zero_vec),
+                              (VTI.Vec MQPR:$reg))),
+              (VTI.Vec (vqneg_instruction (VTI.Vec MQPR:$reg)))>;
   }
 }
 
diff --git a/llvm/test/CodeGen/Thumb2/vqabs.ll b/llvm/test/CodeGen/Thumb2/vqabs.ll
index f8f4b65a1f7dc..832d85b1095c4 100644
--- a/llvm/test/CodeGen/Thumb2/vqabs.ll
+++ b/llvm/test/CodeGen/Thumb2/vqabs.ll
@@ -52,10 +52,7 @@ entry:
 define arm_aapcs_vfpcc <16 x i8> @vqabs_sat_test16(<16 x i8> %A) {
 ; CHECK-LABEL: vqabs_sat_test16:
 ; CHECK:       @ %bb.0: @ %entry
-; CHECK-NEXT:    vmov.i32 q1, #0x0
-; CHECK-NEXT:    vcmp.s8 gt, q0, zr
-; CHECK-NEXT:    vqsub.s8 q1, q1, q0
-; CHECK-NEXT:    vpsel q0, q0, q1
+; CHECK-NEXT:    vqabs.s8 q0, q0
 ; CHECK-NEXT:    bx lr
 entry:
   %0 = icmp sgt <16 x i8> %A, zeroinitializer
@@ -67,10 +64,7 @@ entry:
 define arm_aapcs_vfpcc <8 x i16> @vqabs_sat_test8(<8 x i16> %A) {
 ; CHECK-LABEL: vqabs_sat_test8:
 ; CHECK:       @ %bb.0: @ %entry
-; CHECK-NEXT:    vmov.i32 q1, #0x0
-; CHECK-NEXT:    vcmp.s16 gt, q0, zr
-; CHECK-NEXT:    vqsub.s16 q1, q1, q0
-; CHECK-NEXT:    vpsel q0, q0, q1
+; CHECK-NEXT:    vqabs.s16 q0, q0
 ; CHECK-NEXT:    bx lr
 entry:
   %0 = icmp sgt <8 x i16> %A, zeroinitializer
@@ -82,10 +76,7 @@ entry:
 define arm_aapcs_vfpcc <4 x i32> @vqabs_sat_test4(<4 x i32> %A) {
 ; CHECK-LABEL: vqabs_sat_test4:
 ; CHECK:       @ %bb.0: @ %entry
-; CHECK-NEXT:    vmov.i32 q1, #0x0
-; CHECK-NEXT:    vcmp.s32 gt, q0, zr
-; CHECK-NEXT:    vqsub.s32 q1, q1, q0
-; CHECK-NEXT:    vpsel q0, q0, q1
+; CHECK-NEXT:    vqabs.s32 q0, q0
 ; CHECK-NEXT:    bx lr
 entry:
   %0 = icmp sgt <4 x i32> %A, zeroinitializer
diff --git a/llvm/test/CodeGen/Thumb2/vqneg.ll b/llvm/test/CodeGen/Thumb2/vqneg.ll
index 4f357d81a5fc5..3a7c227bf4d22 100644
--- a/llvm/test/CodeGen/Thumb2/vqneg.ll
+++ b/llvm/test/CodeGen/Thumb2/vqneg.ll
@@ -46,8 +46,7 @@ entry:
 define arm_aapcs_vfpcc <16 x i8> @vqneg_sat_test16(<16 x i8> %A) {
 ; CHECK-LABEL: vqneg_sat_test16:
 ; CHECK:       @ %bb.0: @ %entry
-; CHECK-NEXT:    vmov.i32 q1, #0x0
-; CHECK-NEXT:    vqsub.s8 q0, q1, q0
+; CHECK-NEXT:    vqneg.s8 q0, q0
 ; CHECK-NEXT:    bx lr
 entry:
   %0 = tail call <16 x i8> @llvm.ssub.sat.v16i8(<16 x i8> zeroinitializer, <16 x i8> %A)
@@ -57,8 +56,7 @@ entry:
 define arm_aapcs_vfpcc <8 x i16> @vqneg_sat_test8(<8 x i16> %A) {
 ; CHECK-LABEL: vqneg_sat_test8:
 ; CHECK:       @ %bb.0: @ %entry
-; CHECK-NEXT:    vmov.i32 q1, #0x0
-; CHECK-NEXT:    vqsub.s16 q0, q1, q0
+; CHECK-NEXT:    vqneg.s16 q0, q0
 ; CHECK-NEXT:    bx lr
 entry:
   %0 = tail call <8 x i16> @llvm.ssub.sat.v8i16(<8 x i16> zeroinitializer, <8 x i16> %A)
@@ -68,8 +66,7 @@ entry:
 define arm_aapcs_vfpcc <4 x i32> @vqneg_sat_test4(<4 x i32> %A) {
 ; CHECK-LABEL: vqneg_sat_test4:
 ; CHECK:       @ %bb.0: @ %entry
-; CHECK-NEXT:    vmov.i32 q1, #0x0
-; CHECK-NEXT:    vqsub.s32 q0, q1, q0
+; CHECK-NEXT:    vqneg.s32 q0, q0
 ; CHECK-NEXT:    bx lr
 entry:
   %0 = tail call <4 x i32> @llvm.ssub.sat.v4i32(<4 x i32> zeroinitializer, <4 x i32> %A)

@stuij
stuij force-pushed the saturating-negation branch from e3293aa to a041b1d Compare July 30, 2026 17:47

@davemgreen davemgreen left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh I have a patch to do this somewhere locally (which is why the tests already exist). It was just waiting on the AArch64 side, which works a little differently. They look almost identical to this, almost down to the formatting.

Sorry it wasn't done earlier. LGTM

Comment thread llvm/lib/Target/ARM/ARMInstrMVE.td Outdated
(sub (VTI.Vec zero_vec), (VTI.Vec MQPR:$reg)))),
(VTI.Vec (vqneg_instruction (VTI.Vec MQPR:$reg)))>;
def : Pat<(VTI.Vec (ssubsat (VTI.Vec zero_vec),
(VTI.Vec MQPR:$reg))),

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't need a newline.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done, and np, spoils go to the committer.

stuij added 2 commits July 31, 2026 10:27
InstCombine pull request llvm#194519 canonicalized the saturating negation idiom to
an llvm.ssub.sat operation. For the ARM backend we only recognized the original
select and subtract pattern, causing vector absolute values to expand to VQSUB
plus a compare and select instead of VQABS.

In this patch we teach the VQABS and VQNEG patterns to recognize this ssub.sat
form.
@stuij
stuij force-pushed the saturating-negation branch from a041b1d to a86f2fd Compare July 31, 2026 09:30
@stuij
stuij merged commit c99e675 into llvm:main Aug 3, 2026
12 checks passed
frederik-h pushed a commit to frederik-h/llvm-project that referenced this pull request Aug 3, 2026
InstCombine pull request
llvm#194519 canonicalized the
saturating negation idiom to
an llvm.ssub.sat operation. For the ARM backend we only recognized the
original
select and subtract pattern, causing vector absolute values to expand to
VQSUB
plus a compare and select instead of VQABS.

In this patch we teach the VQABS and VQNEG patterns to recognize this
ssub.sat
form.
@stuij stuij added this to the LLVM 23.x Release milestone Aug 3, 2026
@github-project-automation github-project-automation Bot moved this to Needs Triage in LLVM Release Status Aug 3, 2026
@github-project-automation github-project-automation Bot moved this from Needs Triage to Done in LLVM Release Status Aug 3, 2026
@stuij

stuij commented Aug 3, 2026

Copy link
Copy Markdown
Member Author

/cherry-pick c99e675

@llvmbot

llvmbot commented Aug 3, 2026

Copy link
Copy Markdown
Member

/pull-request #213699

jgreenbaum pushed a commit to jgreenbaum/llvm-project that referenced this pull request Aug 3, 2026
InstCombine pull request
llvm#194519 canonicalized the
saturating negation idiom to
an llvm.ssub.sat operation. For the ARM backend we only recognized the
original
select and subtract pattern, causing vector absolute values to expand to
VQSUB
plus a compare and select instead of VQABS.

In this patch we teach the VQABS and VQNEG patterns to recognize this
ssub.sat
form.
dyung pushed a commit to llvmbot/llvm-project that referenced this pull request Aug 4, 2026
InstCombine pull request
llvm#194519 canonicalized the
saturating negation idiom to
an llvm.ssub.sat operation. For the ARM backend we only recognized the
original
select and subtract pattern, causing vector absolute values to expand to
VQSUB
plus a compare and select instead of VQABS.

In this patch we teach the VQABS and VQNEG patterns to recognize this
ssub.sat
form.

(cherry picked from commit c99e675)
tfzee pushed a commit to tfzee/llvm-project that referenced this pull request Aug 6, 2026
InstCombine pull request
llvm#194519 canonicalized the
saturating negation idiom to
an llvm.ssub.sat operation. For the ARM backend we only recognized the
original
select and subtract pattern, causing vector absolute values to expand to
VQSUB
plus a compare and select instead of VQABS.

In this patch we teach the VQABS and VQNEG patterns to recognize this
ssub.sat
form.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

Development

Successfully merging this pull request may close these issues.

3 participants