[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