[llvm] [DAGCombiner] Look through freeze for ext(freeze(extload(x))) (PR #178669)

David Sherwood via llvm-commits llvm-commits at lists.llvm.org
Thu Jan 29 07:01:00 PST 2026


https://github.com/david-arm created https://github.com/llvm/llvm-project/pull/178669

This patch fixes a regression introduced by PR #175022, where
a freeze was introduced with the following transformation:

  ext(freeze(load(x))) -> freeze(extload(x))

If a new extend is introduced afterwards we then have

  ext(freeze(extload(x)))

which doesn't get picked up by existing DAG combines due to
the freeze getting in the way.

>From 9938fe8fed7bf937093c7bb62567d2492b443f6e Mon Sep 17 00:00:00 2001
From: David Sherwood <david.sherwood at arm.com>
Date: Thu, 29 Jan 2026 14:57:57 +0000
Subject: [PATCH 1/2] [NFC] Refactor tryToFoldExtOfExtload

---
 llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp | 33 ++++++++++---------
 1 file changed, 18 insertions(+), 15 deletions(-)

diff --git a/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp b/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
index 93cc67ae00f4b..8281578a1b095 100644
--- a/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
@@ -14592,27 +14592,30 @@ static SDValue tryToFoldExtOfExtload(SelectionDAG &DAG, DAGCombiner &Combiner,
                                      const TargetLowering &TLI, EVT VT,
                                      bool LegalOperations, SDNode *N,
                                      SDValue N0, ISD::LoadExtType ExtLoadType) {
-  SDNode *N0Node = N0.getNode();
-  bool isAExtLoad = (ExtLoadType == ISD::SEXTLOAD) ? ISD::isSEXTLoad(N0Node)
-                                                   : ISD::isZEXTLoad(N0Node);
-  if ((!isAExtLoad && !ISD::isEXTLoad(N0Node)) ||
-      !ISD::isUNINDEXEDLoad(N0Node) || !N0.hasOneUse())
+  auto OldExtLoad = dyn_cast<LoadSDNode>(N0.getNode());
+  if (!OldExtLoad)
     return SDValue();
 
-  LoadSDNode *LN0 = cast<LoadSDNode>(N0);
-  EVT MemVT = LN0->getMemoryVT();
-  if ((LegalOperations || !LN0->isSimple() ||
-       VT.isVector()) &&
+  bool isAExtLoad = (ExtLoadType == ISD::SEXTLOAD)
+                        ? ISD::isSEXTLoad(OldExtLoad)
+                        : ISD::isZEXTLoad(OldExtLoad);
+  if ((!isAExtLoad && !ISD::isEXTLoad(OldExtLoad)) ||
+      !ISD::isUNINDEXEDLoad(OldExtLoad) || !N0.hasOneUse())
+    return SDValue();
+
+  EVT MemVT = OldExtLoad->getMemoryVT();
+  if ((LegalOperations || !OldExtLoad->isSimple() || VT.isVector()) &&
       !TLI.isLoadExtLegal(ExtLoadType, VT, MemVT))
     return SDValue();
 
-  SDValue ExtLoad =
-      DAG.getExtLoad(ExtLoadType, SDLoc(LN0), VT, LN0->getChain(),
-                     LN0->getBasePtr(), MemVT, LN0->getMemOperand());
+  SDLoc DL(OldExtLoad);
+  SDValue ExtLoad = DAG.getExtLoad(ExtLoadType, DL, VT, OldExtLoad->getChain(),
+                                   OldExtLoad->getBasePtr(), MemVT,
+                                   OldExtLoad->getMemOperand());
   Combiner.CombineTo(N, ExtLoad);
-  DAG.ReplaceAllUsesOfValueWith(SDValue(LN0, 1), ExtLoad.getValue(1));
-  if (LN0->use_empty())
-    Combiner.recursivelyDeleteUnusedNodes(LN0);
+  DAG.ReplaceAllUsesOfValueWith(SDValue(OldExtLoad, 1), ExtLoad.getValue(1));
+  if (OldExtLoad->use_empty())
+    Combiner.recursivelyDeleteUnusedNodes(OldExtLoad);
   return SDValue(N, 0); // Return N so it doesn't get rechecked!
 }
 

>From b333f80490aaa8e4e7f02440f0b9e74a14bd82ad Mon Sep 17 00:00:00 2001
From: David Sherwood <david.sherwood at arm.com>
Date: Thu, 29 Jan 2026 14:58:18 +0000
Subject: [PATCH 2/2] [DAGCombiner] Look through freeze for
 ext(freeze(extload(x)))

This patch fixes a regression introduced by PR #175022, where
a freeze was introduced with the following transformation:

  ext(freeze(load(x))) -> freeze(extload(x))

If a new extend is introduced afterwards we then have

  ext(freeze(extload(x)))

which doesn't get picked up by existing DAG combines due to
the freeze getting in the way.
---
 llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp | 20 ++++++++++++++-----
 llvm/test/CodeGen/X86/known-bits.ll           |  4 +---
 2 files changed, 16 insertions(+), 8 deletions(-)

diff --git a/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp b/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
index 8281578a1b095..cb00a1acc4bca 100644
--- a/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
@@ -14592,7 +14592,9 @@ static SDValue tryToFoldExtOfExtload(SelectionDAG &DAG, DAGCombiner &Combiner,
                                      const TargetLowering &TLI, EVT VT,
                                      bool LegalOperations, SDNode *N,
                                      SDValue N0, ISD::LoadExtType ExtLoadType) {
-  auto OldExtLoad = dyn_cast<LoadSDNode>(N0.getNode());
+  bool Frozen = N0.getOpcode() == ISD::FREEZE;
+  auto OldExtLoad =
+      dyn_cast<LoadSDNode>(Frozen ? N0.getOperand(0).getNode() : N0.getNode());
   if (!OldExtLoad)
     return SDValue();
 
@@ -14600,7 +14602,7 @@ static SDValue tryToFoldExtOfExtload(SelectionDAG &DAG, DAGCombiner &Combiner,
                         ? ISD::isSEXTLoad(OldExtLoad)
                         : ISD::isZEXTLoad(OldExtLoad);
   if ((!isAExtLoad && !ISD::isEXTLoad(OldExtLoad)) ||
-      !ISD::isUNINDEXEDLoad(OldExtLoad) || !N0.hasOneUse())
+      !ISD::isUNINDEXEDLoad(OldExtLoad) || !OldExtLoad->hasNUsesOfValue(1, 0))
     return SDValue();
 
   EVT MemVT = OldExtLoad->getMemoryVT();
@@ -14612,10 +14614,18 @@ static SDValue tryToFoldExtOfExtload(SelectionDAG &DAG, DAGCombiner &Combiner,
   SDValue ExtLoad = DAG.getExtLoad(ExtLoadType, DL, VT, OldExtLoad->getChain(),
                                    OldExtLoad->getBasePtr(), MemVT,
                                    OldExtLoad->getMemOperand());
-  Combiner.CombineTo(N, ExtLoad);
+  SDValue Res = ExtLoad;
+  if (Frozen) {
+    Res = DAG.getFreeze(ExtLoad);
+    Res = DAG.getNode(
+        ExtLoadType == ISD::SEXTLOAD ? ISD::AssertSext : ISD::AssertZext, DL,
+        Res.getValueType(), Res,
+        DAG.getValueType(OldExtLoad->getValueType(0).getScalarType()));
+  }
+  Combiner.CombineTo(N, Res);
   DAG.ReplaceAllUsesOfValueWith(SDValue(OldExtLoad, 1), ExtLoad.getValue(1));
-  if (OldExtLoad->use_empty())
-    Combiner.recursivelyDeleteUnusedNodes(OldExtLoad);
+  if (N0->use_empty())
+    Combiner.recursivelyDeleteUnusedNodes(N0.getNode());
   return SDValue(N, 0); // Return N so it doesn't get rechecked!
 }
 
diff --git a/llvm/test/CodeGen/X86/known-bits.ll b/llvm/test/CodeGen/X86/known-bits.ll
index dbcc8eceeb037..58a0595e4322a 100644
--- a/llvm/test/CodeGen/X86/known-bits.ll
+++ b/llvm/test/CodeGen/X86/known-bits.ll
@@ -7,8 +7,7 @@ define void @knownbits_zext_in_reg(ptr) nounwind {
 ; X86:       # %bb.0: # %BB
 ; X86-NEXT:    pushl %ebx
 ; X86-NEXT:    movl {{[0-9]+}}(%esp), %eax
-; X86-NEXT:    movzbl (%eax), %eax
-; X86-NEXT:    movzwl %ax, %ecx
+; X86-NEXT:    movzbl (%eax), %ecx
 ; X86-NEXT:    imull $101, %ecx, %eax
 ; X86-NEXT:    shrl $14, %eax
 ; X86-NEXT:    imull $177, %ecx, %edx
@@ -32,7 +31,6 @@ define void @knownbits_zext_in_reg(ptr) nounwind {
 ; X64-LABEL: knownbits_zext_in_reg:
 ; X64:       # %bb.0: # %BB
 ; X64-NEXT:    movzbl (%rdi), %eax
-; X64-NEXT:    movzwl %ax, %eax
 ; X64-NEXT:    imull $101, %eax, %ecx
 ; X64-NEXT:    shrl $14, %ecx
 ; X64-NEXT:    imull $177, %eax, %edx



More information about the llvm-commits mailing list