[llvm] [ARM] optimize to `vsri`/`vsli` (PR #182051)

Folkert de Vries via llvm-commits llvm-commits at lists.llvm.org
Wed Feb 18 08:08:55 PST 2026


https://github.com/folkertdev created https://github.com/llvm/llvm-project/pull/182051

fixes https://github.com/llvm/llvm-project/issues/181495

>From 38536ee5335502ad511a99aab5cefa218a58536b Mon Sep 17 00:00:00 2001
From: Folkert de Vries <folkert at folkertdev.nl>
Date: Wed, 18 Feb 2026 15:01:51 +0100
Subject: [PATCH 1/2] add tests

---
 llvm/lib/Target/ARM/ARMISelLowering.cpp |   1 +
 llvm/test/CodeGen/ARM/shift-combine.ll  | 313 ++++++++++++++++++++++++
 2 files changed, 314 insertions(+)

diff --git a/llvm/lib/Target/ARM/ARMISelLowering.cpp b/llvm/lib/Target/ARM/ARMISelLowering.cpp
index 7b240462c66fb..16b63f5c96521 100644
--- a/llvm/lib/Target/ARM/ARMISelLowering.cpp
+++ b/llvm/lib/Target/ARM/ARMISelLowering.cpp
@@ -14516,6 +14516,7 @@ static SDValue PerformORCombine(SDNode *N,
                                         VT == MVT::v8i1 || VT == MVT::v16i1))
     return PerformORCombine_i1(N, DAG, Subtarget);
 
+
   APInt SplatBits, SplatUndef;
   unsigned SplatBitSize;
   bool HasAnyUndefs;
diff --git a/llvm/test/CodeGen/ARM/shift-combine.ll b/llvm/test/CodeGen/ARM/shift-combine.ll
index 66417cddd4d56..e22ebfd4193b9 100644
--- a/llvm/test/CodeGen/ARM/shift-combine.ll
+++ b/llvm/test/CodeGen/ARM/shift-combine.ll
@@ -1240,6 +1240,67 @@ define <4 x i32> @or_tree_with_shifts_vec_i32(<4 x i32> %a, <4 x i32> %b, <4 x i
 ; CHECK-BE-NEXT:    vorr q8, q8, q10
 ; CHECK-BE-NEXT:    vrev64.32 q0, q8
 ; CHECK-BE-NEXT:    bx lr
+;
+; CHECK-ALIGN-LABEL: or_tree_with_shifts_vec_i32:
+; CHECK-ALIGN:       @ %bb.0:
+; CHECK-ALIGN-NEXT:    ldr.w r12, [sp, #16]
+; CHECK-ALIGN-NEXT:    orr.w r12, r12, r0
+; CHECK-ALIGN-NEXT:    ldr r0, [sp]
+; CHECK-ALIGN-NEXT:    orr.w r12, r0, r12, lsl #16
+; CHECK-ALIGN-NEXT:    ldr r0, [sp, #32]
+; CHECK-ALIGN-NEXT:    orr.w r0, r0, r12
+; CHECK-ALIGN-NEXT:    ldr.w r12, [sp, #20]
+; CHECK-ALIGN-NEXT:    orr.w r12, r12, r1
+; CHECK-ALIGN-NEXT:    ldr r1, [sp, #4]
+; CHECK-ALIGN-NEXT:    orr.w r12, r1, r12, lsl #16
+; CHECK-ALIGN-NEXT:    ldr r1, [sp, #36]
+; CHECK-ALIGN-NEXT:    orr.w r1, r1, r12
+; CHECK-ALIGN-NEXT:    ldr.w r12, [sp, #24]
+; CHECK-ALIGN-NEXT:    orr.w r12, r12, r2
+; CHECK-ALIGN-NEXT:    ldr r2, [sp, #8]
+; CHECK-ALIGN-NEXT:    orr.w r12, r2, r12, lsl #16
+; CHECK-ALIGN-NEXT:    ldr r2, [sp, #40]
+; CHECK-ALIGN-NEXT:    orr.w r2, r2, r12
+; CHECK-ALIGN-NEXT:    ldr.w r12, [sp, #28]
+; CHECK-ALIGN-NEXT:    orr.w r12, r12, r3
+; CHECK-ALIGN-NEXT:    ldr r3, [sp, #12]
+; CHECK-ALIGN-NEXT:    orr.w r12, r3, r12, lsl #16
+; CHECK-ALIGN-NEXT:    ldr r3, [sp, #44]
+; CHECK-ALIGN-NEXT:    orr.w r3, r3, r12
+; CHECK-ALIGN-NEXT:    bx lr
+;
+; CHECK-V6M-LABEL: or_tree_with_shifts_vec_i32:
+; CHECK-V6M:       @ %bb.0:
+; CHECK-V6M-NEXT:    push {r4, lr}
+; CHECK-V6M-NEXT:    ldr r4, [sp, #24]
+; CHECK-V6M-NEXT:    orrs r4, r0
+; CHECK-V6M-NEXT:    lsls r0, r4, #16
+; CHECK-V6M-NEXT:    ldr r4, [sp, #8]
+; CHECK-V6M-NEXT:    orrs r4, r0
+; CHECK-V6M-NEXT:    ldr r0, [sp, #40]
+; CHECK-V6M-NEXT:    orrs r0, r4
+; CHECK-V6M-NEXT:    ldr r4, [sp, #28]
+; CHECK-V6M-NEXT:    orrs r4, r1
+; CHECK-V6M-NEXT:    lsls r1, r4, #16
+; CHECK-V6M-NEXT:    ldr r4, [sp, #12]
+; CHECK-V6M-NEXT:    orrs r4, r1
+; CHECK-V6M-NEXT:    ldr r1, [sp, #44]
+; CHECK-V6M-NEXT:    orrs r1, r4
+; CHECK-V6M-NEXT:    ldr r4, [sp, #32]
+; CHECK-V6M-NEXT:    orrs r4, r2
+; CHECK-V6M-NEXT:    lsls r2, r4, #16
+; CHECK-V6M-NEXT:    ldr r4, [sp, #16]
+; CHECK-V6M-NEXT:    orrs r4, r2
+; CHECK-V6M-NEXT:    ldr r2, [sp, #48]
+; CHECK-V6M-NEXT:    orrs r2, r4
+; CHECK-V6M-NEXT:    ldr r4, [sp, #36]
+; CHECK-V6M-NEXT:    orrs r4, r3
+; CHECK-V6M-NEXT:    lsls r3, r4, #16
+; CHECK-V6M-NEXT:    ldr r4, [sp, #20]
+; CHECK-V6M-NEXT:    orrs r4, r3
+; CHECK-V6M-NEXT:    ldr r3, [sp, #52]
+; CHECK-V6M-NEXT:    orrs r3, r4
+; CHECK-V6M-NEXT:    pop {r4, pc}
   %a.shifted = shl <4 x i32> %a, <i32 16, i32 16, i32 16, i32 16>
   %c.shifted = shl <4 x i32> %c, <i32 16, i32 16, i32 16, i32 16>
   %or.ab = or <4 x i32> %a.shifted, %b
@@ -1271,6 +1332,72 @@ define <4 x i32> @or_tree_with_mismatching_shifts_vec_i32(<4 x i32> %a, <4 x i32
 ; CHECK-BE-NEXT:    vorr q8, q9, q8
 ; CHECK-BE-NEXT:    vrev64.32 q0, q8
 ; CHECK-BE-NEXT:    bx lr
+;
+; CHECK-ALIGN-LABEL: or_tree_with_mismatching_shifts_vec_i32:
+; CHECK-ALIGN:       @ %bb.0:
+; CHECK-ALIGN-NEXT:    push {r7, lr}
+; CHECK-ALIGN-NEXT:    ldr.w r12, [sp, #24]
+; CHECK-ALIGN-NEXT:    ldr.w lr, [sp, #40]
+; CHECK-ALIGN-NEXT:    orr.w r12, lr, r12, lsl #17
+; CHECK-ALIGN-NEXT:    ldr.w lr, [sp, #8]
+; CHECK-ALIGN-NEXT:    orr.w r0, lr, r0, lsl #16
+; CHECK-ALIGN-NEXT:    ldr.w lr, [sp, #44]
+; CHECK-ALIGN-NEXT:    orr.w r0, r0, r12
+; CHECK-ALIGN-NEXT:    ldr.w r12, [sp, #28]
+; CHECK-ALIGN-NEXT:    orr.w r12, lr, r12, lsl #17
+; CHECK-ALIGN-NEXT:    ldr.w lr, [sp, #12]
+; CHECK-ALIGN-NEXT:    orr.w r1, lr, r1, lsl #16
+; CHECK-ALIGN-NEXT:    ldr.w lr, [sp, #48]
+; CHECK-ALIGN-NEXT:    orr.w r1, r1, r12
+; CHECK-ALIGN-NEXT:    ldr.w r12, [sp, #32]
+; CHECK-ALIGN-NEXT:    orr.w r12, lr, r12, lsl #17
+; CHECK-ALIGN-NEXT:    ldr.w lr, [sp, #16]
+; CHECK-ALIGN-NEXT:    orr.w r2, lr, r2, lsl #16
+; CHECK-ALIGN-NEXT:    ldr.w lr, [sp, #52]
+; CHECK-ALIGN-NEXT:    orr.w r2, r2, r12
+; CHECK-ALIGN-NEXT:    ldr.w r12, [sp, #36]
+; CHECK-ALIGN-NEXT:    orr.w r12, lr, r12, lsl #17
+; CHECK-ALIGN-NEXT:    ldr.w lr, [sp, #20]
+; CHECK-ALIGN-NEXT:    orr.w r3, lr, r3, lsl #16
+; CHECK-ALIGN-NEXT:    orr.w r3, r3, r12
+; CHECK-ALIGN-NEXT:    pop {r7, pc}
+;
+; CHECK-V6M-LABEL: or_tree_with_mismatching_shifts_vec_i32:
+; CHECK-V6M:       @ %bb.0:
+; CHECK-V6M-NEXT:    push {r4, r5, r7, lr}
+; CHECK-V6M-NEXT:    ldr r4, [sp, #32]
+; CHECK-V6M-NEXT:    lsls r4, r4, #17
+; CHECK-V6M-NEXT:    ldr r5, [sp, #48]
+; CHECK-V6M-NEXT:    orrs r5, r4
+; CHECK-V6M-NEXT:    lsls r4, r0, #16
+; CHECK-V6M-NEXT:    ldr r0, [sp, #16]
+; CHECK-V6M-NEXT:    orrs r0, r4
+; CHECK-V6M-NEXT:    orrs r0, r5
+; CHECK-V6M-NEXT:    ldr r4, [sp, #36]
+; CHECK-V6M-NEXT:    lsls r4, r4, #17
+; CHECK-V6M-NEXT:    ldr r5, [sp, #52]
+; CHECK-V6M-NEXT:    orrs r5, r4
+; CHECK-V6M-NEXT:    lsls r4, r1, #16
+; CHECK-V6M-NEXT:    ldr r1, [sp, #20]
+; CHECK-V6M-NEXT:    orrs r1, r4
+; CHECK-V6M-NEXT:    orrs r1, r5
+; CHECK-V6M-NEXT:    ldr r4, [sp, #40]
+; CHECK-V6M-NEXT:    lsls r4, r4, #17
+; CHECK-V6M-NEXT:    ldr r5, [sp, #56]
+; CHECK-V6M-NEXT:    orrs r5, r4
+; CHECK-V6M-NEXT:    lsls r4, r2, #16
+; CHECK-V6M-NEXT:    ldr r2, [sp, #24]
+; CHECK-V6M-NEXT:    orrs r2, r4
+; CHECK-V6M-NEXT:    orrs r2, r5
+; CHECK-V6M-NEXT:    ldr r4, [sp, #44]
+; CHECK-V6M-NEXT:    lsls r4, r4, #17
+; CHECK-V6M-NEXT:    ldr r5, [sp, #60]
+; CHECK-V6M-NEXT:    orrs r5, r4
+; CHECK-V6M-NEXT:    lsls r4, r3, #16
+; CHECK-V6M-NEXT:    ldr r3, [sp, #28]
+; CHECK-V6M-NEXT:    orrs r3, r4
+; CHECK-V6M-NEXT:    orrs r3, r5
+; CHECK-V6M-NEXT:    pop {r4, r5, r7, pc}
   %a.shifted = shl <4 x i32> %a, <i32 16, i32 16, i32 16, i32 16>
   %c.shifted = shl <4 x i32> %c, <i32 17, i32 17, i32 17, i32 17>
   %or.ab = or <4 x i32> %a.shifted, %b
@@ -1390,3 +1517,189 @@ entry:
   %and = and i32 %lshr, 2040
   ret i32 %and
 }
+
+define <2 x i32> @lshr_into_vsri(<2 x i32> %a, <2 x i32> %b) {
+; CHECK-ARM-LABEL: lshr_into_vsri:
+; CHECK-ARM:       @ %bb.0: @ %bb1
+; CHECK-ARM-NEXT:    vmov.i32 d16, #0xe0000000
+; CHECK-ARM-NEXT:    vshr.u32 d17, d1, #3
+; CHECK-ARM-NEXT:    vand d16, d0, d16
+; CHECK-ARM-NEXT:    vorr d0, d17, d16
+; CHECK-ARM-NEXT:    bx lr
+;
+; CHECK-BE-LABEL: lshr_into_vsri:
+; CHECK-BE:       @ %bb.0: @ %bb1
+; CHECK-BE-NEXT:    vrev64.32 d17, d1
+; CHECK-BE-NEXT:    vmov.i32 d16, #0xe0000000
+; CHECK-BE-NEXT:    vrev64.32 d18, d0
+; CHECK-BE-NEXT:    vand d16, d18, d16
+; CHECK-BE-NEXT:    vshr.u32 d17, d17, #3
+; CHECK-BE-NEXT:    vorr d16, d17, d16
+; CHECK-BE-NEXT:    vrev64.32 d0, d16
+; CHECK-BE-NEXT:    bx lr
+;
+; CHECK-ALIGN-LABEL: lshr_into_vsri:
+; CHECK-ALIGN:       @ %bb.0: @ %bb1
+; CHECK-ALIGN-NEXT:    and r0, r0, #-536870912
+; CHECK-ALIGN-NEXT:    and r1, r1, #-536870912
+; CHECK-ALIGN-NEXT:    orr.w r0, r0, r2, lsr #3
+; CHECK-ALIGN-NEXT:    orr.w r1, r1, r3, lsr #3
+; CHECK-ALIGN-NEXT:    bx lr
+;
+; CHECK-V6M-LABEL: lshr_into_vsri:
+; CHECK-V6M:       @ %bb.0: @ %bb1
+; CHECK-V6M-NEXT:    push {r4, lr}
+; CHECK-V6M-NEXT:    movs r4, #7
+; CHECK-V6M-NEXT:    lsls r4, r4, #29
+; CHECK-V6M-NEXT:    ands r0, r4
+; CHECK-V6M-NEXT:    lsrs r2, r2, #3
+; CHECK-V6M-NEXT:    adds r0, r2, r0
+; CHECK-V6M-NEXT:    ands r1, r4
+; CHECK-V6M-NEXT:    lsrs r2, r3, #3
+; CHECK-V6M-NEXT:    adds r1, r2, r1
+; CHECK-V6M-NEXT:    pop {r4, pc}
+bb1:
+  %0 = and <2 x i32> %a, splat (i32 -536870912)
+  %1 = lshr <2 x i32> %b, splat (i32 3)
+  %2 = or disjoint <2 x i32> %1, %0
+  ret <2 x i32> %2
+}
+
+define <2 x i32> @shl_into_vsli(<2 x i32> %a, <2 x i32> %b) {
+; CHECK-ARM-LABEL: shl_into_vsli:
+; CHECK-ARM:       @ %bb.0: @ %bb1
+; CHECK-ARM-NEXT:    vmov.i32 d16, #0x7
+; CHECK-ARM-NEXT:    vshl.i32 d17, d1, #3
+; CHECK-ARM-NEXT:    vand d16, d0, d16
+; CHECK-ARM-NEXT:    vorr d0, d17, d16
+; CHECK-ARM-NEXT:    bx lr
+;
+; CHECK-BE-LABEL: shl_into_vsli:
+; CHECK-BE:       @ %bb.0: @ %bb1
+; CHECK-BE-NEXT:    vrev64.32 d17, d1
+; CHECK-BE-NEXT:    vmov.i32 d16, #0x7
+; CHECK-BE-NEXT:    vrev64.32 d18, d0
+; CHECK-BE-NEXT:    vand d16, d18, d16
+; CHECK-BE-NEXT:    vshl.i32 d17, d17, #3
+; CHECK-BE-NEXT:    vorr d16, d17, d16
+; CHECK-BE-NEXT:    vrev64.32 d0, d16
+; CHECK-BE-NEXT:    bx lr
+;
+; CHECK-ALIGN-LABEL: shl_into_vsli:
+; CHECK-ALIGN:       @ %bb.0: @ %bb1
+; CHECK-ALIGN-NEXT:    and r0, r0, #7
+; CHECK-ALIGN-NEXT:    and r1, r1, #7
+; CHECK-ALIGN-NEXT:    orr.w r0, r0, r2, lsl #3
+; CHECK-ALIGN-NEXT:    orr.w r1, r1, r3, lsl #3
+; CHECK-ALIGN-NEXT:    bx lr
+;
+; CHECK-V6M-LABEL: shl_into_vsli:
+; CHECK-V6M:       @ %bb.0: @ %bb1
+; CHECK-V6M-NEXT:    push {r4, lr}
+; CHECK-V6M-NEXT:    movs r4, #7
+; CHECK-V6M-NEXT:    ands r0, r4
+; CHECK-V6M-NEXT:    lsls r2, r2, #3
+; CHECK-V6M-NEXT:    adds r0, r2, r0
+; CHECK-V6M-NEXT:    ands r1, r4
+; CHECK-V6M-NEXT:    lsls r2, r3, #3
+; CHECK-V6M-NEXT:    adds r1, r2, r1
+; CHECK-V6M-NEXT:    pop {r4, pc}
+bb1:
+  %0 = and <2 x i32> %a, splat (i32 7)
+  %1 = shl <2 x i32> %b, splat (i32 3)
+  %2 = or disjoint <2 x i32> %1, %0
+  ret <2 x i32> %2
+}
+
+define <2 x i32> @lshr_into_vsri_shift1(<2 x i32> %a, <2 x i32> %b) {
+; CHECK-ARM-LABEL: lshr_into_vsri_shift1:
+; CHECK-ARM:       @ %bb.0: @ %bb1
+; CHECK-ARM-NEXT:    vmov.i32 d16, #0x80000000
+; CHECK-ARM-NEXT:    vshr.u32 d17, d1, #1
+; CHECK-ARM-NEXT:    vand d16, d0, d16
+; CHECK-ARM-NEXT:    vorr d0, d17, d16
+; CHECK-ARM-NEXT:    bx lr
+;
+; CHECK-BE-LABEL: lshr_into_vsri_shift1:
+; CHECK-BE:       @ %bb.0: @ %bb1
+; CHECK-BE-NEXT:    vrev64.32 d17, d1
+; CHECK-BE-NEXT:    vmov.i32 d16, #0x80000000
+; CHECK-BE-NEXT:    vrev64.32 d18, d0
+; CHECK-BE-NEXT:    vand d16, d18, d16
+; CHECK-BE-NEXT:    vshr.u32 d17, d17, #1
+; CHECK-BE-NEXT:    vorr d16, d17, d16
+; CHECK-BE-NEXT:    vrev64.32 d0, d16
+; CHECK-BE-NEXT:    bx lr
+;
+; CHECK-ALIGN-LABEL: lshr_into_vsri_shift1:
+; CHECK-ALIGN:       @ %bb.0: @ %bb1
+; CHECK-ALIGN-NEXT:    and r0, r0, #-2147483648
+; CHECK-ALIGN-NEXT:    and r1, r1, #-2147483648
+; CHECK-ALIGN-NEXT:    orr.w r0, r0, r2, lsr #1
+; CHECK-ALIGN-NEXT:    orr.w r1, r1, r3, lsr #1
+; CHECK-ALIGN-NEXT:    bx lr
+;
+; CHECK-V6M-LABEL: lshr_into_vsri_shift1:
+; CHECK-V6M:       @ %bb.0: @ %bb1
+; CHECK-V6M-NEXT:    push {r4, lr}
+; CHECK-V6M-NEXT:    movs r4, #1
+; CHECK-V6M-NEXT:    lsls r4, r4, #31
+; CHECK-V6M-NEXT:    ands r0, r4
+; CHECK-V6M-NEXT:    lsrs r2, r2, #1
+; CHECK-V6M-NEXT:    adds r0, r2, r0
+; CHECK-V6M-NEXT:    ands r1, r4
+; CHECK-V6M-NEXT:    lsrs r2, r3, #1
+; CHECK-V6M-NEXT:    adds r1, r2, r1
+; CHECK-V6M-NEXT:    pop {r4, pc}
+bb1:
+  %0 = and <2 x i32> %a, splat (i32 -2147483648)
+  %1 = lshr <2 x i32> %b, splat (i32 1)
+  %2 = or disjoint <2 x i32> %1, %0
+  ret <2 x i32> %2
+}
+
+define <2 x i32> @shl_into_vsli_shift1(<2 x i32> %a, <2 x i32> %b) {
+; CHECK-ARM-LABEL: shl_into_vsli_shift1:
+; CHECK-ARM:       @ %bb.0: @ %bb1
+; CHECK-ARM-NEXT:    vmov.i32 d16, #0x1
+; CHECK-ARM-NEXT:    vshl.i32 d17, d1, #1
+; CHECK-ARM-NEXT:    vand d16, d0, d16
+; CHECK-ARM-NEXT:    vorr d0, d17, d16
+; CHECK-ARM-NEXT:    bx lr
+;
+; CHECK-BE-LABEL: shl_into_vsli_shift1:
+; CHECK-BE:       @ %bb.0: @ %bb1
+; CHECK-BE-NEXT:    vrev64.32 d17, d1
+; CHECK-BE-NEXT:    vmov.i32 d16, #0x1
+; CHECK-BE-NEXT:    vrev64.32 d18, d0
+; CHECK-BE-NEXT:    vand d16, d18, d16
+; CHECK-BE-NEXT:    vshl.i32 d17, d17, #1
+; CHECK-BE-NEXT:    vorr d16, d17, d16
+; CHECK-BE-NEXT:    vrev64.32 d0, d16
+; CHECK-BE-NEXT:    bx lr
+;
+; CHECK-ALIGN-LABEL: shl_into_vsli_shift1:
+; CHECK-ALIGN:       @ %bb.0: @ %bb1
+; CHECK-ALIGN-NEXT:    and r0, r0, #1
+; CHECK-ALIGN-NEXT:    and r1, r1, #1
+; CHECK-ALIGN-NEXT:    orr.w r0, r0, r2, lsl #1
+; CHECK-ALIGN-NEXT:    orr.w r1, r1, r3, lsl #1
+; CHECK-ALIGN-NEXT:    bx lr
+;
+; CHECK-V6M-LABEL: shl_into_vsli_shift1:
+; CHECK-V6M:       @ %bb.0: @ %bb1
+; CHECK-V6M-NEXT:    push {r4, lr}
+; CHECK-V6M-NEXT:    movs r4, #1
+; CHECK-V6M-NEXT:    ands r0, r4
+; CHECK-V6M-NEXT:    lsls r2, r2, #1
+; CHECK-V6M-NEXT:    adds r0, r2, r0
+; CHECK-V6M-NEXT:    ands r1, r4
+; CHECK-V6M-NEXT:    lsls r2, r3, #1
+; CHECK-V6M-NEXT:    adds r1, r2, r1
+; CHECK-V6M-NEXT:    pop {r4, pc}
+bb1:
+  %0 = and <2 x i32> %a, splat (i32 1)
+  %1 = shl <2 x i32> %b, splat (i32 1)
+  %2 = or disjoint <2 x i32> %1, %0
+  ret <2 x i32> %2
+}

>From 3c371c4dcb2ff50d584e4c4ce83de4c1634b2b1e Mon Sep 17 00:00:00 2001
From: Folkert de Vries <folkert at folkertdev.nl>
Date: Wed, 18 Feb 2026 16:06:04 +0100
Subject: [PATCH 2/2] [ARM] optimize to shift {left, right} insert

---
 llvm/lib/Target/ARM/ARMISelLowering.cpp | 72 +++++++++++++++++++++++--
 llvm/test/CodeGen/ARM/shift-combine.ll  | 64 +++++++---------------
 2 files changed, 88 insertions(+), 48 deletions(-)

diff --git a/llvm/lib/Target/ARM/ARMISelLowering.cpp b/llvm/lib/Target/ARM/ARMISelLowering.cpp
index 16b63f5c96521..dbcb5d3147055 100644
--- a/llvm/lib/Target/ARM/ARMISelLowering.cpp
+++ b/llvm/lib/Target/ARM/ARMISelLowering.cpp
@@ -14499,9 +14499,61 @@ static SDValue PerformORCombine_i1(SDNode *N, SelectionDAG &DAG,
   return DAG.getLogicalNOT(DL, And, VT);
 }
 
+// Try to form a NEON shift-{right, left}-and-insert (VSRI/VSLI) from:
+//   (or (and X, splat (i32 C1)), (srl Y, splat (i32 C2))) -> VSRI X, Y, #C2
+//   (or (and X, splat (i32 C1)), (shl Y, splat (i32 C2))) -> VSLI X, Y, #C2
+// where C1 is a mask that preserves the bits not written by the shift/insert,
+// i.e. `C1 == (1 << C2) - 1`.
+static SDValue PerformORCombineToShiftInsert(SelectionDAG &DAG, SDValue AndOp,
+                                             SDValue ShiftOp, EVT VT,
+                                             SDLoc dl) {
+  // Match (and X, Mask)
+  if (AndOp.getOpcode() != ISD::AND)
+    return SDValue();
+
+  SDValue X = AndOp.getOperand(0);
+  SDValue Mask = AndOp.getOperand(1);
+
+  ConstantSDNode *MaskC = isConstOrConstSplat(Mask);
+  if (!MaskC)
+    return SDValue();
+  APInt MaskBits = MaskC->getAPIntValue();
+
+  // Match shift (srl/shl Y, CntVec)
+  int64_t Cnt = 0;
+  bool IsShiftRight = false;
+  SDValue Y;
+  SDValue CntOp;
+
+  if (ShiftOp.getOpcode() == ISD::SRL) {
+    IsShiftRight = true;
+    Y = ShiftOp.getOperand(0);
+    CntOp = ShiftOp.getOperand(1);
+    if (!isVShiftRImm(CntOp, VT, /*isNarrow=*/false,
+                      /*isIntrinsic=*/false, Cnt))
+      return SDValue();
+  } else if (ShiftOp.getOpcode() == ISD::SHL) {
+    Y = ShiftOp.getOperand(0);
+    CntOp = ShiftOp.getOperand(1);
+    if (!isVShiftLImm(CntOp, VT, /*isLong=*/false, Cnt))
+      return SDValue();
+  } else {
+    return SDValue();
+  }
+
+  unsigned ElemBits = VT.getScalarSizeInBits();
+  APInt RequiredMask = IsShiftRight
+                           ? APInt::getHighBitsSet(ElemBits, (unsigned)Cnt)
+                           : APInt::getLowBitsSet(ElemBits, (unsigned)Cnt);
+  if (MaskBits != RequiredMask)
+    return SDValue();
+
+  unsigned Opc = IsShiftRight ? ARMISD::VSRIIMM : ARMISD::VSLIIMM;
+  return DAG.getNode(Opc, dl, VT, X, Y, DAG.getConstant(Cnt, dl, MVT::i32));
+}
+
 /// PerformORCombine - Target-specific dag combine xforms for ISD::OR
-static SDValue PerformORCombine(SDNode *N,
-                                TargetLowering::DAGCombinerInfo &DCI,
+static SDValue PerformORCombine(SDNode *N, TargetLowering::DAGCombinerInfo &DCI,
                                 const ARMSubtarget *Subtarget) {
   // Attempt to use immediate-form VORR
   BuildVectorSDNode *BVN = dyn_cast<BuildVectorSDNode>(N->getOperand(1));
@@ -14509,14 +14561,13 @@ static SDValue PerformORCombine(SDNode *N,
   EVT VT = N->getValueType(0);
   SelectionDAG &DAG = DCI.DAG;
 
-  if(!DAG.getTargetLoweringInfo().isTypeLegal(VT))
+  if (!DAG.getTargetLoweringInfo().isTypeLegal(VT))
     return SDValue();
 
   if (Subtarget->hasMVEIntegerOps() && (VT == MVT::v2i1 || VT == MVT::v4i1 ||
                                         VT == MVT::v8i1 || VT == MVT::v16i1))
     return PerformORCombine_i1(N, DAG, Subtarget);
 
-
   APInt SplatBits, SplatUndef;
   unsigned SplatBitSize;
   bool HasAnyUndefs;
@@ -14548,6 +14599,19 @@ static SDValue PerformORCombine(SDNode *N,
   SDValue N0 = N->getOperand(0);
   SDValue N1 = N->getOperand(1);
 
+  // (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 (SDValue ShiftInsert =
+            PerformORCombineToShiftInsert(DAG, N0, N1, VT, dl))
+      return ShiftInsert;
+
+    if (SDValue ShiftInsert =
+            PerformORCombineToShiftInsert(DAG, N1, N0, VT, dl))
+      return ShiftInsert;
+  }
+
   // (or (and B, A), (and C, ~A)) => (VBSL A, B, C) when A is a constant.
   if (Subtarget->hasNEON() && N1.getOpcode() == ISD::AND && VT.isVector() &&
       DAG.getTargetLoweringInfo().isTypeLegal(VT)) {
diff --git a/llvm/test/CodeGen/ARM/shift-combine.ll b/llvm/test/CodeGen/ARM/shift-combine.ll
index e22ebfd4193b9..0bbe555a1341c 100644
--- a/llvm/test/CodeGen/ARM/shift-combine.ll
+++ b/llvm/test/CodeGen/ARM/shift-combine.ll
@@ -1521,21 +1521,15 @@ entry:
 define <2 x i32> @lshr_into_vsri(<2 x i32> %a, <2 x i32> %b) {
 ; CHECK-ARM-LABEL: lshr_into_vsri:
 ; CHECK-ARM:       @ %bb.0: @ %bb1
-; CHECK-ARM-NEXT:    vmov.i32 d16, #0xe0000000
-; CHECK-ARM-NEXT:    vshr.u32 d17, d1, #3
-; CHECK-ARM-NEXT:    vand d16, d0, d16
-; CHECK-ARM-NEXT:    vorr d0, d17, d16
+; CHECK-ARM-NEXT:    vsri.32 d0, d1, #3
 ; CHECK-ARM-NEXT:    bx lr
 ;
 ; CHECK-BE-LABEL: lshr_into_vsri:
 ; CHECK-BE:       @ %bb.0: @ %bb1
-; CHECK-BE-NEXT:    vrev64.32 d17, d1
-; CHECK-BE-NEXT:    vmov.i32 d16, #0xe0000000
-; CHECK-BE-NEXT:    vrev64.32 d18, d0
-; CHECK-BE-NEXT:    vand d16, d18, d16
-; CHECK-BE-NEXT:    vshr.u32 d17, d17, #3
-; CHECK-BE-NEXT:    vorr d16, d17, d16
-; CHECK-BE-NEXT:    vrev64.32 d0, d16
+; CHECK-BE-NEXT:    vrev64.32 d16, d1
+; CHECK-BE-NEXT:    vrev64.32 d17, d0
+; CHECK-BE-NEXT:    vsri.32 d17, d16, #3
+; CHECK-BE-NEXT:    vrev64.32 d0, d17
 ; CHECK-BE-NEXT:    bx lr
 ;
 ; CHECK-ALIGN-LABEL: lshr_into_vsri:
@@ -1568,21 +1562,15 @@ bb1:
 define <2 x i32> @shl_into_vsli(<2 x i32> %a, <2 x i32> %b) {
 ; CHECK-ARM-LABEL: shl_into_vsli:
 ; CHECK-ARM:       @ %bb.0: @ %bb1
-; CHECK-ARM-NEXT:    vmov.i32 d16, #0x7
-; CHECK-ARM-NEXT:    vshl.i32 d17, d1, #3
-; CHECK-ARM-NEXT:    vand d16, d0, d16
-; CHECK-ARM-NEXT:    vorr d0, d17, d16
+; CHECK-ARM-NEXT:    vsli.32 d0, d1, #3
 ; CHECK-ARM-NEXT:    bx lr
 ;
 ; CHECK-BE-LABEL: shl_into_vsli:
 ; CHECK-BE:       @ %bb.0: @ %bb1
-; CHECK-BE-NEXT:    vrev64.32 d17, d1
-; CHECK-BE-NEXT:    vmov.i32 d16, #0x7
-; CHECK-BE-NEXT:    vrev64.32 d18, d0
-; CHECK-BE-NEXT:    vand d16, d18, d16
-; CHECK-BE-NEXT:    vshl.i32 d17, d17, #3
-; CHECK-BE-NEXT:    vorr d16, d17, d16
-; CHECK-BE-NEXT:    vrev64.32 d0, d16
+; CHECK-BE-NEXT:    vrev64.32 d16, d1
+; CHECK-BE-NEXT:    vrev64.32 d17, d0
+; CHECK-BE-NEXT:    vsli.32 d17, d16, #3
+; CHECK-BE-NEXT:    vrev64.32 d0, d17
 ; CHECK-BE-NEXT:    bx lr
 ;
 ; CHECK-ALIGN-LABEL: shl_into_vsli:
@@ -1614,21 +1602,15 @@ bb1:
 define <2 x i32> @lshr_into_vsri_shift1(<2 x i32> %a, <2 x i32> %b) {
 ; CHECK-ARM-LABEL: lshr_into_vsri_shift1:
 ; CHECK-ARM:       @ %bb.0: @ %bb1
-; CHECK-ARM-NEXT:    vmov.i32 d16, #0x80000000
-; CHECK-ARM-NEXT:    vshr.u32 d17, d1, #1
-; CHECK-ARM-NEXT:    vand d16, d0, d16
-; CHECK-ARM-NEXT:    vorr d0, d17, d16
+; CHECK-ARM-NEXT:    vsri.32 d0, d1, #1
 ; CHECK-ARM-NEXT:    bx lr
 ;
 ; CHECK-BE-LABEL: lshr_into_vsri_shift1:
 ; CHECK-BE:       @ %bb.0: @ %bb1
-; CHECK-BE-NEXT:    vrev64.32 d17, d1
-; CHECK-BE-NEXT:    vmov.i32 d16, #0x80000000
-; CHECK-BE-NEXT:    vrev64.32 d18, d0
-; CHECK-BE-NEXT:    vand d16, d18, d16
-; CHECK-BE-NEXT:    vshr.u32 d17, d17, #1
-; CHECK-BE-NEXT:    vorr d16, d17, d16
-; CHECK-BE-NEXT:    vrev64.32 d0, d16
+; CHECK-BE-NEXT:    vrev64.32 d16, d1
+; CHECK-BE-NEXT:    vrev64.32 d17, d0
+; CHECK-BE-NEXT:    vsri.32 d17, d16, #1
+; CHECK-BE-NEXT:    vrev64.32 d0, d17
 ; CHECK-BE-NEXT:    bx lr
 ;
 ; CHECK-ALIGN-LABEL: lshr_into_vsri_shift1:
@@ -1661,21 +1643,15 @@ bb1:
 define <2 x i32> @shl_into_vsli_shift1(<2 x i32> %a, <2 x i32> %b) {
 ; CHECK-ARM-LABEL: shl_into_vsli_shift1:
 ; CHECK-ARM:       @ %bb.0: @ %bb1
-; CHECK-ARM-NEXT:    vmov.i32 d16, #0x1
-; CHECK-ARM-NEXT:    vshl.i32 d17, d1, #1
-; CHECK-ARM-NEXT:    vand d16, d0, d16
-; CHECK-ARM-NEXT:    vorr d0, d17, d16
+; CHECK-ARM-NEXT:    vsli.32 d0, d1, #1
 ; CHECK-ARM-NEXT:    bx lr
 ;
 ; CHECK-BE-LABEL: shl_into_vsli_shift1:
 ; CHECK-BE:       @ %bb.0: @ %bb1
-; CHECK-BE-NEXT:    vrev64.32 d17, d1
-; CHECK-BE-NEXT:    vmov.i32 d16, #0x1
-; CHECK-BE-NEXT:    vrev64.32 d18, d0
-; CHECK-BE-NEXT:    vand d16, d18, d16
-; CHECK-BE-NEXT:    vshl.i32 d17, d17, #1
-; CHECK-BE-NEXT:    vorr d16, d17, d16
-; CHECK-BE-NEXT:    vrev64.32 d0, d16
+; CHECK-BE-NEXT:    vrev64.32 d16, d1
+; CHECK-BE-NEXT:    vrev64.32 d17, d0
+; CHECK-BE-NEXT:    vsli.32 d17, d16, #1
+; CHECK-BE-NEXT:    vrev64.32 d0, d17
 ; CHECK-BE-NEXT:    bx lr
 ;
 ; CHECK-ALIGN-LABEL: shl_into_vsli_shift1:



More information about the llvm-commits mailing list