[llvm] 7953762 - [AArch64] Avoid factor-4 deinterleaved loads feeding uitofp (#210894)
via llvm-commits
llvm-commits at lists.llvm.org
Thu Jul 30 21:58:24 PDT 2026
Author: Kamlesh Kumar
Date: 2026-07-31T05:58:19+01:00
New Revision: 79537625e213b6a5f329da1d5a443de265346a5e
URL: https://github.com/llvm/llvm-project/commit/79537625e213b6a5f329da1d5a443de265346a5e
DIFF: https://github.com/llvm/llvm-project/commit/79537625e213b6a5f329da1d5a443de265346a5e.diff
LOG: [AArch64] Avoid factor-4 deinterleaved loads feeding uitofp (#210894)
Avoid generating ld4 when all values produced by the deinterleaved load
are fed into uitofp. Keeping the loads separate allows the backend to
optimize them into shifts and masks.
Added:
llvm/test/CodeGen/AArch64/avoid-ld4.ll
Modified:
llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
Removed:
################################################################################
diff --git a/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp b/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
index f1a91a5537ee0..51be0e66b19b0 100644
--- a/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
+++ b/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
@@ -30772,6 +30772,30 @@ performScalarToVectorCombine(SDNode *N, TargetLowering::DAGCombinerInfo &DCI,
return NVCAST;
}
+static bool isDeinterleave4ForWideningUToFP(SDNode *N) {
+ if (N->getNumOperands() != 4)
+ return false;
+
+ if (N->getValueType(0).isScalableVector())
+ return false;
+ SmallVector<SDNode *, 4> Users(4, nullptr);
+ for (SDUse &Use : N->uses()) {
+ unsigned ResNo = Use.getResNo();
+ SDNode *User = Use.getUser();
+ if (Users[ResNo])
+ return false; // return if more than 1 uses
+ if (User->getOpcode() != ISD::UINT_TO_FP)
+ return false;
+ unsigned InBits = N->getValueType(ResNo).getScalarSizeInBits();
+ unsigned OutBits = User->getValueType(0).getScalarSizeInBits();
+ if (OutBits != InBits * 4)
+ return false;
+ Users[ResNo] = User;
+ }
+
+ return llvm::all_of(Users, [](SDNode *User) { return User != nullptr; });
+}
+
static SDValue performVectorDeinterleaveCombine(
SDNode *N, TargetLowering::DAGCombinerInfo &DCI, SelectionDAG &DAG) {
if (!DCI.isBeforeLegalize())
@@ -30811,6 +30835,12 @@ static SDValue performVectorDeinterleaveCombine(
SDValue WideVec = Op0->getOperand(0);
SDLoc DL(N);
+ // A fixed-length factor-4 deinterleave whose results are only used by
+ // 4x widening unsigned-to-float conversions can be lowered more efficiently
+ // using shifts and masks on the original loaded vectors.
+ if (isDeinterleave4ForWideningUToFP(N))
+ return SDValue();
+
SmallVector<EVT, 5> ResVTs(NumParts, SubVecTy);
ResVTs.push_back(MVT::Other);
SDVTList ResVTList = DAG.getVTList(ResVTs);
diff --git a/llvm/test/CodeGen/AArch64/avoid-ld4.ll b/llvm/test/CodeGen/AArch64/avoid-ld4.ll
new file mode 100644
index 0000000000000..16cc430ca6190
--- /dev/null
+++ b/llvm/test/CodeGen/AArch64/avoid-ld4.ll
@@ -0,0 +1,141 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 6
+; RUN: llc -mtriple=arm64-apple-macosx -o - %s | FileCheck %s --check-prefixes=CHECK,CHECK-IAENABLED
+; RUN: llc -mtriple=arm64-apple-macosx --lower-interleaved-accesses=false -o - %s | FileCheck %s --check-prefixes=CHECK,CHECK-IADISABLED
+
+define <8 x double> @uitofp_load_fadd_intrinsic(ptr %p) {
+; CHECK-IAENABLED-LABEL: uitofp_load_fadd_intrinsic:
+; CHECK-IAENABLED: ; %bb.0:
+; CHECK-IAENABLED-NEXT: ld4.8h { v0, v1, v2, v3 }, [x0]
+; CHECK-IAENABLED-NEXT: ushll2.4s v4, v0, #0
+; CHECK-IAENABLED-NEXT: ushll.4s v5, v0, #0
+; CHECK-IAENABLED-NEXT: ushll2.4s v6, v1, #0
+; CHECK-IAENABLED-NEXT: ushll.4s v7, v1, #0
+; CHECK-IAENABLED-NEXT: ushll2.4s v16, v2, #0
+; CHECK-IAENABLED-NEXT: ushll.4s v17, v2, #0
+; CHECK-IAENABLED-NEXT: ushll2.4s v18, v3, #0
+; CHECK-IAENABLED-NEXT: ushll.4s v0, v3, #0
+; CHECK-IAENABLED-NEXT: ushll2.2d v1, v4, #0
+; CHECK-IAENABLED-NEXT: ushll2.2d v2, v5, #0
+; CHECK-IAENABLED-NEXT: ushll.2d v3, v4, #0
+; CHECK-IAENABLED-NEXT: ushll.2d v4, v5, #0
+; CHECK-IAENABLED-NEXT: ushll2.2d v5, v6, #0
+; CHECK-IAENABLED-NEXT: ushll2.2d v19, v7, #0
+; CHECK-IAENABLED-NEXT: ushll.2d v6, v6, #0
+; CHECK-IAENABLED-NEXT: ushll.2d v7, v7, #0
+; CHECK-IAENABLED-NEXT: ushll2.2d v20, v16, #0
+; CHECK-IAENABLED-NEXT: ushll2.2d v21, v17, #0
+; CHECK-IAENABLED-NEXT: ushll.2d v16, v16, #0
+; CHECK-IAENABLED-NEXT: ushll.2d v17, v17, #0
+; CHECK-IAENABLED-NEXT: ushll.2d v22, v0, #0
+; CHECK-IAENABLED-NEXT: ushll2.2d v23, v18, #0
+; CHECK-IAENABLED-NEXT: ushll2.2d v0, v0, #0
+; CHECK-IAENABLED-NEXT: ushll.2d v18, v18, #0
+; CHECK-IAENABLED-NEXT: ucvtf.2d v1, v1
+; CHECK-IAENABLED-NEXT: ucvtf.2d v2, v2
+; CHECK-IAENABLED-NEXT: ucvtf.2d v3, v3
+; CHECK-IAENABLED-NEXT: ucvtf.2d v4, v4
+; CHECK-IAENABLED-NEXT: ucvtf.2d v5, v5
+; CHECK-IAENABLED-NEXT: ucvtf.2d v19, v19
+; CHECK-IAENABLED-NEXT: ucvtf.2d v6, v6
+; CHECK-IAENABLED-NEXT: ucvtf.2d v7, v7
+; CHECK-IAENABLED-NEXT: ucvtf.2d v20, v20
+; CHECK-IAENABLED-NEXT: ucvtf.2d v21, v21
+; CHECK-IAENABLED-NEXT: ucvtf.2d v16, v16
+; CHECK-IAENABLED-NEXT: ucvtf.2d v17, v17
+; CHECK-IAENABLED-NEXT: ucvtf.2d v22, v22
+; CHECK-IAENABLED-NEXT: ucvtf.2d v23, v23
+; CHECK-IAENABLED-NEXT: ucvtf.2d v0, v0
+; CHECK-IAENABLED-NEXT: ucvtf.2d v18, v18
+; CHECK-IAENABLED-NEXT: fadd.2d v1, v1, v5
+; CHECK-IAENABLED-NEXT: fadd.2d v4, v4, v7
+; CHECK-IAENABLED-NEXT: fadd.2d v6, v3, v6
+; CHECK-IAENABLED-NEXT: fadd.2d v2, v2, v19
+; CHECK-IAENABLED-NEXT: fadd.2d v3, v17, v22
+; CHECK-IAENABLED-NEXT: fadd.2d v5, v16, v18
+; CHECK-IAENABLED-NEXT: fadd.2d v7, v21, v0
+; CHECK-IAENABLED-NEXT: fadd.2d v16, v20, v23
+; CHECK-IAENABLED-NEXT: fadd.2d v0, v4, v3
+; CHECK-IAENABLED-NEXT: fadd.2d v3, v1, v16
+; CHECK-IAENABLED-NEXT: fadd.2d v1, v2, v7
+; CHECK-IAENABLED-NEXT: fadd.2d v2, v6, v5
+; CHECK-IAENABLED-NEXT: ret
+;
+; CHECK-IADISABLED-LABEL: uitofp_load_fadd_intrinsic:
+; CHECK-IADISABLED: ; %bb.0:
+; CHECK-IADISABLED-NEXT: ldp q2, q1, [x0]
+; CHECK-IADISABLED-NEXT: movi.2d v0, #0x00ffff0000ffff
+; CHECK-IADISABLED-NEXT: ldp q4, q3, [x0, #32]
+; CHECK-IADISABLED-NEXT: uzp1.8h v6, v2, v1
+; CHECK-IADISABLED-NEXT: uzp2.8h v1, v2, v1
+; CHECK-IADISABLED-NEXT: uzp1.8h v5, v4, v3
+; CHECK-IADISABLED-NEXT: uzp2.8h v3, v4, v3
+; CHECK-IADISABLED-NEXT: and.16b v2, v6, v0
+; CHECK-IADISABLED-NEXT: and.16b v7, v1, v0
+; CHECK-IADISABLED-NEXT: ushr.4s v6, v6, #16
+; CHECK-IADISABLED-NEXT: and.16b v4, v5, v0
+; CHECK-IADISABLED-NEXT: and.16b v0, v3, v0
+; CHECK-IADISABLED-NEXT: ushr.4s v5, v5, #16
+; CHECK-IADISABLED-NEXT: ushr.4s v1, v1, #16
+; CHECK-IADISABLED-NEXT: ushr.4s v3, v3, #16
+; CHECK-IADISABLED-NEXT: ushll2.2d v16, v2, #0
+; CHECK-IADISABLED-NEXT: ushll.2d v2, v2, #0
+; CHECK-IADISABLED-NEXT: ushll2.2d v18, v7, #0
+; CHECK-IADISABLED-NEXT: ushll2.2d v17, v4, #0
+; CHECK-IADISABLED-NEXT: ushll.2d v4, v4, #0
+; CHECK-IADISABLED-NEXT: ushll2.2d v19, v0, #0
+; CHECK-IADISABLED-NEXT: ushll.2d v7, v7, #0
+; CHECK-IADISABLED-NEXT: ushll.2d v0, v0, #0
+; CHECK-IADISABLED-NEXT: ushll2.2d v20, v6, #0
+; CHECK-IADISABLED-NEXT: ushll2.2d v21, v5, #0
+; CHECK-IADISABLED-NEXT: ushll.2d v6, v6, #0
+; CHECK-IADISABLED-NEXT: ushll.2d v5, v5, #0
+; CHECK-IADISABLED-NEXT: ushll.2d v22, v1, #0
+; CHECK-IADISABLED-NEXT: ushll2.2d v1, v1, #0
+; CHECK-IADISABLED-NEXT: ushll2.2d v23, v3, #0
+; CHECK-IADISABLED-NEXT: ushll.2d v3, v3, #0
+; CHECK-IADISABLED-NEXT: ucvtf.2d v16, v16
+; CHECK-IADISABLED-NEXT: ucvtf.2d v17, v17
+; CHECK-IADISABLED-NEXT: ucvtf.2d v2, v2
+; CHECK-IADISABLED-NEXT: ucvtf.2d v4, v4
+; CHECK-IADISABLED-NEXT: ucvtf.2d v18, v18
+; CHECK-IADISABLED-NEXT: ucvtf.2d v19, v19
+; CHECK-IADISABLED-NEXT: ucvtf.2d v7, v7
+; CHECK-IADISABLED-NEXT: ucvtf.2d v0, v0
+; CHECK-IADISABLED-NEXT: ucvtf.2d v20, v20
+; CHECK-IADISABLED-NEXT: ucvtf.2d v21, v21
+; CHECK-IADISABLED-NEXT: ucvtf.2d v6, v6
+; CHECK-IADISABLED-NEXT: ucvtf.2d v5, v5
+; CHECK-IADISABLED-NEXT: ucvtf.2d v22, v22
+; CHECK-IADISABLED-NEXT: ucvtf.2d v1, v1
+; CHECK-IADISABLED-NEXT: ucvtf.2d v23, v23
+; CHECK-IADISABLED-NEXT: ucvtf.2d v3, v3
+; CHECK-IADISABLED-NEXT: fadd.2d v4, v4, v0
+; CHECK-IADISABLED-NEXT: fadd.2d v0, v2, v7
+; CHECK-IADISABLED-NEXT: fadd.2d v2, v17, v19
+; CHECK-IADISABLED-NEXT: fadd.2d v7, v16, v18
+; CHECK-IADISABLED-NEXT: fadd.2d v6, v6, v22
+; CHECK-IADISABLED-NEXT: fadd.2d v1, v20, v1
+; CHECK-IADISABLED-NEXT: fadd.2d v5, v5, v3
+; CHECK-IADISABLED-NEXT: fadd.2d v3, v21, v23
+; CHECK-IADISABLED-NEXT: fadd.2d v0, v0, v6
+; CHECK-IADISABLED-NEXT: fadd.2d v1, v7, v1
+; CHECK-IADISABLED-NEXT: fadd.2d v3, v2, v3
+; CHECK-IADISABLED-NEXT: fadd.2d v2, v4, v5
+; CHECK-IADISABLED-NEXT: ret
+ %l = load <32 x i16>, ptr %p
+ %deinterleaved = call { <8 x i16>, <8 x i16>, <8 x i16>, <8 x i16> } @llvm.vector.deinterleave4.v32i16(<32 x i16> %l)
+ %s1 = extractvalue { <8 x i16>, <8 x i16>, <8 x i16>, <8 x i16> } %deinterleaved, 0
+ %z1 = uitofp <8 x i16> %s1 to <8 x double>
+ %s2 = extractvalue { <8 x i16>, <8 x i16>, <8 x i16>, <8 x i16> } %deinterleaved, 1
+ %z2 = uitofp <8 x i16> %s2 to <8 x double>
+ %s3 = extractvalue { <8 x i16>, <8 x i16>, <8 x i16>, <8 x i16> } %deinterleaved, 2
+ %z3 = uitofp <8 x i16> %s3 to <8 x double>
+ %s4 = extractvalue { <8 x i16>, <8 x i16>, <8 x i16>, <8 x i16> } %deinterleaved, 3
+ %z4 = uitofp <8 x i16> %s4 to <8 x double>
+ %a = fadd <8 x double> %z1, %z2
+ %b = fadd <8 x double> %z3, %z4
+ %c = fadd <8 x double> %a, %b
+ ret <8 x double> %c
+}
+;; NOTE: These prefixes are unused and the list is autogenerated. Do not add tests below this line:
+; CHECK: {{.*}}
More information about the llvm-commits
mailing list