Skip to content

[ARM][MVE] Add SLI and SRI recognition. - #183471

Merged
davemgreen merged 1 commit into
llvm:mainfrom
davemgreen:gh-mve-slisri
Feb 28, 2026
Merged

davemgreen merged 1 commit into
llvm:mainfrom
davemgreen:gh-mve-slisri

Conversation

@davemgreen

Copy link
Copy Markdown
Contributor

This uses the newly added code from #182051 to optimize to MVE sli and sri. The only major difference is the legal types supported, but we also lower intrinsics via VSLIIMM/VSLIIMM, so that only one tablegen pattern is needed.

This uses the newly added code from llvm#182051 to optimize to MVE sli and sri. The
only major difference is the legal types supported.
@llvmbot

llvmbot commented Feb 26, 2026

Copy link
Copy Markdown
Member

@llvm/pr-subscribers-backend-arm

Author: David Green (davemgreen)

Changes

This uses the newly added code from #182051 to optimize to MVE sli and sri. The only major difference is the legal types supported, but we also lower intrinsics via VSLIIMM/VSLIIMM, so that only one tablegen pattern is needed.


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

3 Files Affected:

  • (modified) llvm/lib/Target/ARM/ARMISelLowering.cpp (+10-2)
  • (modified) llvm/lib/Target/ARM/ARMInstrMVE.td (+12-12)
  • (modified) llvm/test/CodeGen/Thumb2/mve-sli-sri.ll (+6-24)
diff --git a/llvm/lib/Target/ARM/ARMISelLowering.cpp b/llvm/lib/Target/ARM/ARMISelLowering.cpp
index bd851ccf13501..ef34cb1119168 100644
--- a/llvm/lib/Target/ARM/ARMISelLowering.cpp
+++ b/llvm/lib/Target/ARM/ARMISelLowering.cpp
@@ -3958,6 +3958,12 @@ ARMTargetLowering::LowerINTRINSIC_WO_CHAIN(SDValue Op, SelectionDAG &DAG,
   case Intrinsic::arm_mve_asrl:
     return DAG.getNode(ARMISD::ASRL, SDLoc(Op), Op->getVTList(),
                        Op.getOperand(1), Op.getOperand(2), Op.getOperand(3));
+  case Intrinsic::arm_mve_vsli:
+    return DAG.getNode(ARMISD::VSLIIMM, SDLoc(Op), Op->getVTList(),
+                       Op.getOperand(1), Op.getOperand(2), Op.getOperand(3));
+  case Intrinsic::arm_mve_vsri:
+    return DAG.getNode(ARMISD::VSRIIMM, SDLoc(Op), Op->getVTList(),
+                       Op.getOperand(1), Op.getOperand(2), Op.getOperand(3));
   }
 }
 
@@ -14692,8 +14698,10 @@ static SDValue PerformORCombine(SDNode *N, TargetLowering::DAGCombinerInfo &DCI,
 
   // (or (and X, C1), (srl Y, C2)) -> VSRI X, Y, #C2
   // (or (and X, C1), (shl Y, C2)) -> VSLI X, Y, #C2
-  if (Subtarget->hasNEON() && VT.isVector() &&
-      DAG.getTargetLoweringInfo().isTypeLegal(VT)) {
+  if (VT.isVector() &&
+      ((Subtarget->hasNEON() && DAG.getTargetLoweringInfo().isTypeLegal(VT)) ||
+       (Subtarget->hasMVEIntegerOps() &&
+        (VT == MVT::v16i8 || VT == MVT::v8i16 || VT == MVT::v4i32)))) {
     if (SDValue ShiftInsert =
             PerformORCombineToShiftInsert(DAG, N0, N1, VT, dl))
       return ShiftInsert;
diff --git a/llvm/lib/Target/ARM/ARMInstrMVE.td b/llvm/lib/Target/ARM/ARMInstrMVE.td
index d4b39676b7b4f..38f36cb239535 100644
--- a/llvm/lib/Target/ARM/ARMInstrMVE.td
+++ b/llvm/lib/Target/ARM/ARMInstrMVE.td
@@ -3280,27 +3280,27 @@ def MVE_VSLIimm32 : MVE_VSxI_imm<"vsli", "32", 0b1,imm0_31, 0b10> {
   let Inst{21} = 0b1;
 }
 
-multiclass MVE_VSxI_patterns<MVE_VSxI_imm inst, string name,
-                              MVEVectorVTInfo VTI> {
+multiclass MVE_VSxI_patterns<MVE_VSxI_imm inst, SDPatternOperator Node,
+                             SDPatternOperator PredIntr, MVEVectorVTInfo VTI> {
   defvar inparams = (? (VTI.Vec MQPR:$QdSrc), (VTI.Vec MQPR:$Qm),
                        (inst.immediateType:$imm));
   defvar outparams = (inst (VTI.Vec MQPR:$QdSrc), (VTI.Vec MQPR:$Qm),
                            (inst.immediateType:$imm));
-  defvar unpred_int = !cast<Intrinsic>("int_arm_mve_" # name);
-  defvar pred_int = !cast<Intrinsic>("int_arm_mve_" # name # "_predicated");
 
-  def : Pat<(VTI.Vec !setdagop(inparams, unpred_int)),
+  def : Pat<(VTI.Vec !setdagop(inparams, Node)),
             (VTI.Vec outparams)>;
-  def : Pat<(VTI.Vec !con(inparams, (pred_int (VTI.Pred VCCR:$pred)))),
+  def : Pat<(VTI.Vec !con(inparams, (PredIntr (VTI.Pred VCCR:$pred)))),
             (VTI.Vec !con(outparams, (? ARMVCCThen, VCCR:$pred, zero_reg)))>;
 }
 
-defm : MVE_VSxI_patterns<MVE_VSLIimm8,  "vsli", MVE_v16i8>;
-defm : MVE_VSxI_patterns<MVE_VSLIimm16, "vsli", MVE_v8i16>;
-defm : MVE_VSxI_patterns<MVE_VSLIimm32, "vsli", MVE_v4i32>;
-defm : MVE_VSxI_patterns<MVE_VSRIimm8,  "vsri", MVE_v16i8>;
-defm : MVE_VSxI_patterns<MVE_VSRIimm16, "vsri", MVE_v8i16>;
-defm : MVE_VSxI_patterns<MVE_VSRIimm32, "vsri", MVE_v4i32>;
+let Predicates = [HasMVEInt] in {
+defm : MVE_VSxI_patterns<MVE_VSLIimm8,  NEONvsliImm, int_arm_mve_vsli_predicated, MVE_v16i8>;
+defm : MVE_VSxI_patterns<MVE_VSLIimm16, NEONvsliImm, int_arm_mve_vsli_predicated, MVE_v8i16>;
+defm : MVE_VSxI_patterns<MVE_VSLIimm32, NEONvsliImm, int_arm_mve_vsli_predicated, MVE_v4i32>;
+defm : MVE_VSxI_patterns<MVE_VSRIimm8,  NEONvsriImm, int_arm_mve_vsri_predicated, MVE_v16i8>;
+defm : MVE_VSxI_patterns<MVE_VSRIimm16, NEONvsriImm, int_arm_mve_vsri_predicated, MVE_v8i16>;
+defm : MVE_VSxI_patterns<MVE_VSRIimm32, NEONvsriImm, int_arm_mve_vsri_predicated, MVE_v4i32>;
+}
 
 class MVE_VQSHL_imm<MVEVectorVTInfo VTI_, Operand immType>
   : MVE_shift_with_imm<"vqshl", VTI_.Suffix, (outs MQPR:$Qd),
diff --git a/llvm/test/CodeGen/Thumb2/mve-sli-sri.ll b/llvm/test/CodeGen/Thumb2/mve-sli-sri.ll
index 2fc8761762b94..f768580044f93 100644
--- a/llvm/test/CodeGen/Thumb2/mve-sli-sri.ll
+++ b/llvm/test/CodeGen/Thumb2/mve-sli-sri.ll
@@ -4,10 +4,7 @@
 define <8 x i8> @testLeftGood8x8(<8 x i8> %src1, <8 x i8> %src2) {
 ; CHECK-LABEL: testLeftGood8x8:
 ; CHECK:       @ %bb.0:
-; CHECK-NEXT:    vmov.i16 q2, #0x7
-; CHECK-NEXT:    vshl.i16 q1, q1, #3
-; CHECK-NEXT:    vand q0, q0, q2
-; CHECK-NEXT:    vorr q0, q0, q1
+; CHECK-NEXT:    vsli.16 q0, q1, #3
 ; CHECK-NEXT:    bx lr
   %and.i = and <8 x i8> %src1, <i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7>
   %vshl_n = shl <8 x i8> %src2, <i8 3, i8 3, i8 3, i8 3, i8 3, i8 3, i8 3, i8 3>
@@ -62,10 +59,7 @@ define <8 x i8> @testRightBad8x8(<8 x i8> %src1, <8 x i8> %src2) {
 define <16 x i8> @testLeftGood16x8(<16 x i8> %src1, <16 x i8> %src2) {
 ; CHECK-LABEL: testLeftGood16x8:
 ; CHECK:       @ %bb.0:
-; CHECK-NEXT:    vmov.i8 q2, #0x7
-; CHECK-NEXT:    vshl.i8 q1, q1, #3
-; CHECK-NEXT:    vand q0, q0, q2
-; CHECK-NEXT:    vorr q0, q0, q1
+; CHECK-NEXT:    vsli.8 q0, q1, #3
 ; CHECK-NEXT:    bx lr
   %and.i = and <16 x i8> %src1, <i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7>
   %vshl_n = shl <16 x i8> %src2, <i8 3, i8 3, i8 3, i8 3, i8 3, i8 3, i8 3, i8 3, i8 3, i8 3, i8 3, i8 3, i8 3, i8 3, i8 3, i8 3>
@@ -90,10 +84,7 @@ define <16 x i8> @testLeftBad16x8(<16 x i8> %src1, <16 x i8> %src2) {
 define <16 x i8> @testRightGood16x8(<16 x i8> %src1, <16 x i8> %src2) {
 ; CHECK-LABEL: testRightGood16x8:
 ; CHECK:       @ %bb.0:
-; CHECK-NEXT:    vmov.i8 q2, #0xe0
-; CHECK-NEXT:    vshr.u8 q1, q1, #3
-; CHECK-NEXT:    vand q0, q0, q2
-; CHECK-NEXT:    vorr q0, q0, q1
+; CHECK-NEXT:    vsri.8 q0, q1, #3
 ; CHECK-NEXT:    bx lr
   %and.i = and <16 x i8> %src1, <i8 224, i8 224, i8 224, i8 224, i8 224, i8 224, i8 224, i8 224, i8 224, i8 224, i8 224, i8 224, i8 224, i8 224, i8 224, i8 224>
   %vshl_n = lshr <16 x i8> %src2, <i8 3, i8 3, i8 3, i8 3, i8 3, i8 3, i8 3, i8 3, i8 3, i8 3, i8 3, i8 3, i8 3, i8 3, i8 3, i8 3>
@@ -118,10 +109,7 @@ define <16 x i8> @testRightBad16x8(<16 x i8> %src1, <16 x i8> %src2) {
 define <4 x i16> @testLeftGood4x16(<4 x i16> %src1, <4 x i16> %src2) {
 ; CHECK-LABEL: testLeftGood4x16:
 ; CHECK:       @ %bb.0:
-; CHECK-NEXT:    vmov.i32 q2, #0x3fff
-; CHECK-NEXT:    vshl.i32 q1, q1, #14
-; CHECK-NEXT:    vand q0, q0, q2
-; CHECK-NEXT:    vorr q0, q0, q1
+; CHECK-NEXT:    vsli.32 q0, q1, #14
 ; CHECK-NEXT:    bx lr
   %and.i = and <4 x i16> %src1, <i16 16383, i16 16383, i16 16383, i16 16383>
   %vshl_n = shl <4 x i16> %src2, <i16 14, i16 14, i16 14, i16 14>
@@ -347,10 +335,7 @@ define <2 x i32> @testRightBad2x32(<2 x i32> %src1, <2 x i32> %src2) {
 define <4 x i32> @testLeftGood4x32(<4 x i32> %src1, <4 x i32> %src2) {
 ; CHECK-LABEL: testLeftGood4x32:
 ; CHECK:       @ %bb.0:
-; CHECK-NEXT:    vmov.i32 q2, #0x3fffff
-; CHECK-NEXT:    vshl.i32 q1, q1, #22
-; CHECK-NEXT:    vand q0, q0, q2
-; CHECK-NEXT:    vorr q0, q0, q1
+; CHECK-NEXT:    vsli.32 q0, q1, #22
 ; CHECK-NEXT:    bx lr
   %and.i = and <4 x i32> %src1, <i32 4194303, i32 4194303, i32 4194303, i32 4194303>
   %vshl_n = shl <4 x i32> %src2, <i32 22, i32 22, i32 22, i32 22>
@@ -377,10 +362,7 @@ define <4 x i32> @testLeftBad4x32(<4 x i32> %src1, <4 x i32> %src2) {
 define <4 x i32> @testRightGood4x32(<4 x i32> %src1, <4 x i32> %src2) {
 ; CHECK-LABEL: testRightGood4x32:
 ; CHECK:       @ %bb.0:
-; CHECK-NEXT:    vmvn.i32 q2, #0x3ff
-; CHECK-NEXT:    vshr.u32 q1, q1, #22
-; CHECK-NEXT:    vand q0, q0, q2
-; CHECK-NEXT:    vorr q0, q0, q1
+; CHECK-NEXT:    vsri.32 q0, q1, #22
 ; CHECK-NEXT:    bx lr
   %and.i = and <4 x i32> %src1, <i32 4294966272, i32 4294966272, i32 4294966272, i32 4294966272>
   %vshl_n = lshr <4 x i32> %src2, <i32 22, i32 22, i32 22, i32 22>

@nasherm nasherm 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.

LGTM

@folkertdev folkertdev 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.

LGTM

@davemgreen
davemgreen merged commit 9b1f784 into llvm:main Feb 28, 2026
12 checks passed
@davemgreen
davemgreen deleted the gh-mve-slisri branch February 28, 2026 10:43
sahas3 pushed a commit to sahas3/llvm-project that referenced this pull request Mar 4, 2026
This uses the newly added code from llvm#182051 to optimize to MVE sli and
sri. The only major difference is the legal types supported, but we also
lower intrinsics via VSLIIMM/VSLIIMM, so that only one tablegen pattern
is needed.
sujianIBM pushed a commit to sujianIBM/llvm-project that referenced this pull request Mar 5, 2026
This uses the newly added code from llvm#182051 to optimize to MVE sli and
sri. The only major difference is the legal types supported, but we also
lower intrinsics via VSLIIMM/VSLIIMM, so that only one tablegen pattern
is needed.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants