[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