[llvm] 8d5cc01 - [AArch64] Optimize two large shifts and a combine into a single combine and shift (#99480)
via llvm-commits
llvm-commits at lists.llvm.org
Fri Aug 2 08:50:51 PDT 2024
Author: Sopy
Date: 2024-08-02T18:50:47+03:00
New Revision: 8d5cc015e006616ec818522c966b685bcb4951c2
URL: https://github.com/llvm/llvm-project/commit/8d5cc015e006616ec818522c966b685bcb4951c2
DIFF: https://github.com/llvm/llvm-project/commit/8d5cc015e006616ec818522c966b685bcb4951c2.diff
LOG: [AArch64] Optimize two large shifts and a combine into a single combine and shift (#99480)
Addresses a missing optimization in the AArch64 back-end where two large
shifts followed by a combine operation can be optimized into a single
combine operation followed by a shift.
Closes #59502
Added:
llvm/test/CodeGen/AArch64/optimize_combine_large_shifts.ll
Modified:
llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
llvm/test/CodeGen/AArch64/neon-rshrn.ll
Removed:
################################################################################
diff --git a/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp b/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
index 2e869f11b8431..7704321a0fc3a 100644
--- a/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
+++ b/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
@@ -19456,23 +19456,24 @@ static SDValue performConcatVectorsCombine(SDNode *N,
if (VT.isScalableVector())
return SDValue();
- // Optimize concat_vectors of truncated vectors, where the intermediate
- // type is illegal, to avoid said illegality, e.g.,
- // (v4i16 (concat_vectors (v2i16 (truncate (v2i64))),
- // (v2i16 (truncate (v2i64)))))
- // ->
- // (v4i16 (truncate (vector_shuffle (v4i32 (bitcast (v2i64))),
- // (v4i32 (bitcast (v2i64))),
- // <0, 2, 4, 6>)))
- // This isn't really target-specific, but ISD::TRUNCATE legality isn't keyed
- // on both input and result type, so we might generate worse code.
- // On AArch64 we know it's fine for v2i64->v4i16 and v4i32->v8i8.
if (N->getNumOperands() == 2 && N0Opc == ISD::TRUNCATE &&
N1Opc == ISD::TRUNCATE) {
SDValue N00 = N0->getOperand(0);
SDValue N10 = N1->getOperand(0);
EVT N00VT = N00.getValueType();
+ unsigned N00Opc = N00.getOpcode(), N10Opc = N10.getOpcode();
+ // Optimize concat_vectors of truncated vectors, where the intermediate
+ // type is illegal, to avoid said illegality, e.g.,
+ // (v4i16 (concat_vectors (v2i16 (truncate (v2i64))),
+ // (v2i16 (truncate (v2i64)))))
+ // ->
+ // (v4i16 (truncate (vector_shuffle (v4i32 (bitcast (v2i64))),
+ // (v4i32 (bitcast (v2i64))),
+ // <0, 2, 4, 6>)))
+ // This isn't really target-specific, but ISD::TRUNCATE legality isn't keyed
+ // on both input and result type, so we might generate worse code.
+ // On AArch64 we know it's fine for v2i64->v4i16 and v4i32->v8i8.
if (N00VT == N10.getValueType() &&
(N00VT == MVT::v2i64 || N00VT == MVT::v4i32) &&
N00VT.getScalarSizeInBits() == 4 * VT.getScalarSizeInBits()) {
@@ -19486,6 +19487,38 @@ static SDValue performConcatVectorsCombine(SDNode *N,
DAG.getNode(ISD::BITCAST, dl, MidVT, N00),
DAG.getNode(ISD::BITCAST, dl, MidVT, N10), Mask));
}
+
+ // Optimize two large shifts and a combine into a single combine and shift
+ // For AArch64 architectures, sequences like the following:
+ //
+ // ushr v0.4s, v0.4s, #20
+ // ushr v1.4s, v1.4s, #20
+ // uzp1 v0.8h, v0.8h, v1.8h
+ //
+ // Can be optimized to:
+ //
+ // uzp2 v0.8h, v0.8h, v1.8h
+ // ushr v0.8h, v0.8h, #4
+ //
+ // This optimization reduces instruction count.
+ if (N00Opc == AArch64ISD::VLSHR && N10Opc == AArch64ISD::VLSHR &&
+ N00->getOperand(1) == N10->getOperand(1)) {
+
+ SDValue N000 = N00->getOperand(0);
+ SDValue N100 = N10->getOperand(0);
+ uint64_t N001ConstVal = N00->getConstantOperandVal(1),
+ N101ConstVal = N10->getConstantOperandVal(1),
+ NScalarSize = N->getValueType(0).getScalarSizeInBits();
+
+ if (N001ConstVal == N101ConstVal && N001ConstVal > NScalarSize) {
+
+ SDValue Uzp = DAG.getNode(AArch64ISD::UZP2, dl, VT, N000, N100);
+ SDValue NewShiftConstant =
+ DAG.getConstant(N001ConstVal - NScalarSize, dl, MVT::i32);
+
+ return DAG.getNode(AArch64ISD::VLSHR, dl, VT, Uzp, NewShiftConstant);
+ }
+ }
}
if (N->getOperand(0).getValueType() == MVT::v4i8 ||
diff --git a/llvm/test/CodeGen/AArch64/neon-rshrn.ll b/llvm/test/CodeGen/AArch64/neon-rshrn.ll
index 8d47f4afb355f..e648b10ea357b 100644
--- a/llvm/test/CodeGen/AArch64/neon-rshrn.ll
+++ b/llvm/test/CodeGen/AArch64/neon-rshrn.ll
@@ -110,11 +110,10 @@ define <16 x i8> @rshrn_v16i16_9(<16 x i16> %a) {
; CHECK-LABEL: rshrn_v16i16_9:
; CHECK: // %bb.0: // %entry
; CHECK-NEXT: movi v2.8h, #1, lsl #8
-; CHECK-NEXT: add v0.8h, v0.8h, v2.8h
; CHECK-NEXT: add v1.8h, v1.8h, v2.8h
-; CHECK-NEXT: ushr v1.8h, v1.8h, #9
-; CHECK-NEXT: ushr v0.8h, v0.8h, #9
-; CHECK-NEXT: uzp1 v0.16b, v0.16b, v1.16b
+; CHECK-NEXT: add v0.8h, v0.8h, v2.8h
+; CHECK-NEXT: uzp2 v0.16b, v0.16b, v1.16b
+; CHECK-NEXT: ushr v0.16b, v0.16b, #1
; CHECK-NEXT: ret
entry:
%b = add <16 x i16> %a, <i16 256, i16 256, i16 256, i16 256, i16 256, i16 256, i16 256, i16 256, i16 256, i16 256, i16 256, i16 256, i16 256, i16 256, i16 256, i16 256>
@@ -336,11 +335,10 @@ define <8 x i16> @rshrn_v8i32_17(<8 x i32> %a) {
; CHECK-LABEL: rshrn_v8i32_17:
; CHECK: // %bb.0: // %entry
; CHECK-NEXT: movi v2.4s, #1, lsl #16
-; CHECK-NEXT: add v0.4s, v0.4s, v2.4s
; CHECK-NEXT: add v1.4s, v1.4s, v2.4s
-; CHECK-NEXT: ushr v1.4s, v1.4s, #17
-; CHECK-NEXT: ushr v0.4s, v0.4s, #17
-; CHECK-NEXT: uzp1 v0.8h, v0.8h, v1.8h
+; CHECK-NEXT: add v0.4s, v0.4s, v2.4s
+; CHECK-NEXT: uzp2 v0.8h, v0.8h, v1.8h
+; CHECK-NEXT: ushr v0.8h, v0.8h, #1
; CHECK-NEXT: ret
entry:
%b = add <8 x i32> %a, <i32 65536, i32 65536, i32 65536, i32 65536, i32 65536, i32 65536, i32 65536, i32 65536>
@@ -771,11 +769,10 @@ define <4 x i32> @rshrn_v4i64_33(<4 x i64> %a) {
; CHECK: // %bb.0: // %entry
; CHECK-NEXT: mov x8, #4294967296 // =0x100000000
; CHECK-NEXT: dup v2.2d, x8
-; CHECK-NEXT: add v0.2d, v0.2d, v2.2d
; CHECK-NEXT: add v1.2d, v1.2d, v2.2d
-; CHECK-NEXT: ushr v1.2d, v1.2d, #33
-; CHECK-NEXT: ushr v0.2d, v0.2d, #33
-; CHECK-NEXT: uzp1 v0.4s, v0.4s, v1.4s
+; CHECK-NEXT: add v0.2d, v0.2d, v2.2d
+; CHECK-NEXT: uzp2 v0.4s, v0.4s, v1.4s
+; CHECK-NEXT: ushr v0.4s, v0.4s, #1
; CHECK-NEXT: ret
entry:
%b = add <4 x i64> %a, <i64 4294967296, i64 4294967296, i64 4294967296, i64 4294967296>
diff --git a/llvm/test/CodeGen/AArch64/optimize_combine_large_shifts.ll b/llvm/test/CodeGen/AArch64/optimize_combine_large_shifts.ll
new file mode 100644
index 0000000000000..f75b6ac0deb6c
--- /dev/null
+++ b/llvm/test/CodeGen/AArch64/optimize_combine_large_shifts.ll
@@ -0,0 +1,41 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 5
+; RUN: llc < %s -verify-machineinstrs -mtriple=aarch64-none-linux-gnu -mattr=neon | FileCheck %s
+
+define <16 x i8> @combine16ix8(<8 x i16> %0, <8 x i16> %1) {
+; CHECK-LABEL: combine16ix8:
+; CHECK: // %bb.0:
+; CHECK-NEXT: uzp2 v0.16b, v0.16b, v1.16b
+; CHECK-NEXT: ushr v0.16b, v0.16b, #2
+; CHECK-NEXT: ret
+ %3 = lshr <8 x i16> %0, <i16 10, i16 10, i16 10, i16 10, i16 10, i16 10, i16 10, i16 10>
+ %4 = lshr <8 x i16> %1, <i16 10, i16 10, i16 10, i16 10, i16 10, i16 10, i16 10, i16 10>
+ %5 = shufflevector <8 x i16> %3, <8 x i16> %4, <16 x i32> <i32 0, i32 1, i32 2, i32 3, i32 4, i32 5, i32 6, i32 7, i32 8, i32 9, i32 10, i32 11, i32 12, i32 13, i32 14, i32 15>
+ %6 = trunc nuw nsw <16 x i16> %5 to <16 x i8>
+ ret <16 x i8> %6
+}
+
+define <8 x i16> @combine32ix4(<4 x i32> %0, <4 x i32> %1) {
+; CHECK-LABEL: combine32ix4:
+; CHECK: // %bb.0:
+; CHECK-NEXT: uzp2 v0.8h, v0.8h, v1.8h
+; CHECK-NEXT: ushr v0.8h, v0.8h, #4
+; CHECK-NEXT: ret
+ %3 = lshr <4 x i32> %0, <i32 20, i32 20, i32 20, i32 20>
+ %4 = lshr <4 x i32> %1, <i32 20, i32 20, i32 20, i32 20>
+ %5 = shufflevector <4 x i32> %3, <4 x i32> %4, <8 x i32> <i32 0, i32 1, i32 2, i32 3, i32 4, i32 5, i32 6, i32 7>
+ %6 = trunc nuw nsw <8 x i32> %5 to <8 x i16>
+ ret <8 x i16> %6
+}
+
+define <4 x i32> @combine64ix2(<2 x i64> %0, <2 x i64> %1) {
+; CHECK-LABEL: combine64ix2:
+; CHECK: // %bb.0:
+; CHECK-NEXT: uzp2 v0.4s, v0.4s, v1.4s
+; CHECK-NEXT: ushr v0.4s, v0.4s, #8
+; CHECK-NEXT: ret
+ %3 = lshr <2 x i64> %0, <i64 40, i64 40>
+ %4 = lshr <2 x i64> %1, <i64 40, i64 40>
+ %5 = shufflevector <2 x i64> %3, <2 x i64> %4, <4 x i32> <i32 0, i32 1, i32 2, i32 3>
+ %6 = trunc nuw nsw <4 x i64> %5 to <4 x i32>
+ ret <4 x i32> %6
+}
More information about the llvm-commits
mailing list