[llvm] Calculate KnownBits from Metadata correctly for vector loads (PR #128908)

via llvm-commits llvm-commits at lists.llvm.org
Thu Mar 13 07:26:23 PDT 2025


https://github.com/LU-JOHN updated https://github.com/llvm/llvm-project/pull/128908

>From d8d5f022d9c9e128205f418d815f9f9d40a83a76 Mon Sep 17 00:00:00 2001
From: John Lu <John.Lu at amd.com>
Date: Wed, 26 Feb 2025 10:35:34 -0600
Subject: [PATCH 1/7] Calculate KnownBits from Metadata correctly for vector
 loads

Signed-off-by: John Lu <John.Lu at amd.com>
---
 llvm/lib/Analysis/ValueTracking.cpp      | 7 ++++++-
 llvm/test/CodeGen/AMDGPU/shl64_reduce.ll | 3 ++-
 2 files changed, 8 insertions(+), 2 deletions(-)

diff --git a/llvm/lib/Analysis/ValueTracking.cpp b/llvm/lib/Analysis/ValueTracking.cpp
index 2920738445d5b..0413045aeb6d3 100644
--- a/llvm/lib/Analysis/ValueTracking.cpp
+++ b/llvm/lib/Analysis/ValueTracking.cpp
@@ -429,11 +429,16 @@ void llvm::computeKnownBitsFromRangeMetadata(const MDNode &Ranges,
     ConstantInt *Upper =
         mdconst::extract<ConstantInt>(Ranges.getOperand(2 * i + 1));
     ConstantRange Range(Lower->getValue(), Upper->getValue());
+    unsigned RangeBitWidth = Lower->getBitWidth();
+    // BitWidth > RangeBitWidth can happen if Known is set to the width of a
+    // vector load but Ranges describes a vector element.
+    assert(BitWidth >= RangeBitWidth);
 
     // The first CommonPrefixBits of all values in Range are equal.
     unsigned CommonPrefixBits =
         (Range.getUnsignedMax() ^ Range.getUnsignedMin()).countl_zero();
-    APInt Mask = APInt::getHighBitsSet(BitWidth, CommonPrefixBits);
+    APInt Mask = APInt::getBitsSet(BitWidth, RangeBitWidth - CommonPrefixBits,
+                                   RangeBitWidth);
     APInt UnsignedMax = Range.getUnsignedMax().zextOrTrunc(BitWidth);
     Known.One &= UnsignedMax & Mask;
     Known.Zero &= ~UnsignedMax & Mask;
diff --git a/llvm/test/CodeGen/AMDGPU/shl64_reduce.ll b/llvm/test/CodeGen/AMDGPU/shl64_reduce.ll
index 05430213c17d2..25f32ac3c44ff 100644
--- a/llvm/test/CodeGen/AMDGPU/shl64_reduce.ll
+++ b/llvm/test/CodeGen/AMDGPU/shl64_reduce.ll
@@ -36,8 +36,9 @@ define <2 x i64> @shl_v2_metadata(<2 x i64> %arg0, ptr %arg1.ptr) {
 ; CHECK-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
 ; CHECK-NEXT:    flat_load_dwordx4 v[4:7], v[4:5]
 ; CHECK-NEXT:    s_waitcnt vmcnt(0) lgkmcnt(0)
-; CHECK-NEXT:    v_lshlrev_b64 v[0:1], v4, v[0:1]
 ; CHECK-NEXT:    v_lshlrev_b64 v[2:3], v6, v[2:3]
+; CHECK-NEXT:    v_lshlrev_b32_e32 v1, v4, v0
+; CHECK-NEXT:    v_mov_b32_e32 v0, 0
 ; CHECK-NEXT:    s_setpc_b64 s[30:31]
   %shift.amt = load <2 x i64>, ptr %arg1.ptr, !range !0
   %shl = shl <2 x i64> %arg0, %shift.amt

>From 8cc932e310df2255faf617e77cb279b58acf7b65 Mon Sep 17 00:00:00 2001
From: John Lu <John.Lu at amd.com>
Date: Fri, 7 Mar 2025 09:50:54 -0600
Subject: [PATCH 2/7] Set KnownBits to correct width.  Reduce 64-bit shl for
 all vector elts

Signed-off-by: John Lu <John.Lu at amd.com>
---
 llvm/lib/Analysis/ValueTracking.cpp           |  9 ++--
 .../lib/CodeGen/SelectionDAG/SelectionDAG.cpp | 12 +++--
 llvm/lib/Target/AMDGPU/AMDGPUISelLowering.cpp | 46 ++++++++++++++-----
 llvm/test/CodeGen/AMDGPU/shl64_reduce.ll      | 30 +++++++-----
 4 files changed, 66 insertions(+), 31 deletions(-)

diff --git a/llvm/lib/Analysis/ValueTracking.cpp b/llvm/lib/Analysis/ValueTracking.cpp
index 0413045aeb6d3..a0500e221188e 100644
--- a/llvm/lib/Analysis/ValueTracking.cpp
+++ b/llvm/lib/Analysis/ValueTracking.cpp
@@ -430,15 +430,14 @@ void llvm::computeKnownBitsFromRangeMetadata(const MDNode &Ranges,
         mdconst::extract<ConstantInt>(Ranges.getOperand(2 * i + 1));
     ConstantRange Range(Lower->getValue(), Upper->getValue());
     unsigned RangeBitWidth = Lower->getBitWidth();
-    // BitWidth > RangeBitWidth can happen if Known is set to the width of a
-    // vector load but Ranges describes a vector element.
-    assert(BitWidth >= RangeBitWidth);
 
     // The first CommonPrefixBits of all values in Range are equal.
     unsigned CommonPrefixBits =
         (Range.getUnsignedMax() ^ Range.getUnsignedMin()).countl_zero();
-    APInt Mask = APInt::getBitsSet(BitWidth, RangeBitWidth - CommonPrefixBits,
-                                   RangeBitWidth);
+    // BitWidth must equal RangeBitWidth.  Otherwise Mask will be set
+    // incorrectly.
+    assert(BitWidth == RangeBitWidth && "BitWidth must equal RangeBitWidth");
+    APInt Mask = APInt::getHighBitsSet(BitWidth, CommonPrefixBits);
     APInt UnsignedMax = Range.getUnsignedMax().zextOrTrunc(BitWidth);
     Known.One &= UnsignedMax & Mask;
     Known.Zero &= ~UnsignedMax & Mask;
diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
index df30148b78b65..f588c6307c437 100644
--- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
@@ -4011,15 +4011,19 @@ KnownBits SelectionDAG::computeKnownBits(SDValue Op, const APInt &DemandedElts,
       // Fill in any known bits from range information. There are 3 types being
       // used. The results VT (same vector elt size as BitWidth), the loaded
       // MemoryVT (which may or may not be vector) and the range VTs original
-      // type. The range matadata needs the full range (i.e
+      // type. The range metadata needs the full range (i.e
       // MemoryVT().getSizeInBits()), which is truncated to the correct elt size
       // if it is know. These are then extended to the original VT sizes below.
       if (const MDNode *MD = LD->getRanges()) {
+        ConstantInt *Lower = mdconst::extract<ConstantInt>(MD->getOperand(0));
+
+        // FIXME: If loads are modified (e.g. type legalization)
+        // so that the load type no longer matches the range metadata type, the
+        // range metadata should be updated to match the new load width.
+        Known0 = Known0.trunc(Lower->getBitWidth());
         computeKnownBitsFromRangeMetadata(*MD, Known0);
         if (VT.isVector()) {
-          // Handle truncation to the first demanded element.
-          // TODO: Figure out which demanded elements are covered
-          if (DemandedElts != 1 || !getDataLayout().isLittleEndian())
+          if (!getDataLayout().isLittleEndian())
             break;
           Known0 = Known0.trunc(BitWidth);
         }
diff --git a/llvm/lib/Target/AMDGPU/AMDGPUISelLowering.cpp b/llvm/lib/Target/AMDGPU/AMDGPUISelLowering.cpp
index ade81f17ecca5..ecc5ca3436ccf 100644
--- a/llvm/lib/Target/AMDGPU/AMDGPUISelLowering.cpp
+++ b/llvm/lib/Target/AMDGPU/AMDGPUISelLowering.cpp
@@ -4084,7 +4084,7 @@ SDValue AMDGPUTargetLowering::performShlCombine(SDNode *N,
     }
   }
 
-  if (VT != MVT::i64)
+  if (VT.getScalarType() != MVT::i64)
     return SDValue();
 
   // i64 (shl x, C) -> (build_pair 0, (shl x, C -32))
@@ -4092,21 +4092,24 @@ SDValue AMDGPUTargetLowering::performShlCombine(SDNode *N,
   // On some subtargets, 64-bit shift is a quarter rate instruction. In the
   // common case, splitting this into a move and a 32-bit shift is faster and
   // the same code size.
-  EVT TargetType = VT.getHalfSizedIntegerVT(*DAG.getContext());
-  EVT TargetVecPairType = EVT::getVectorVT(*DAG.getContext(), TargetType, 2);
   KnownBits Known = DAG.computeKnownBits(RHS);
 
-  if (Known.getMinValue().getZExtValue() < TargetType.getSizeInBits())
+  EVT ElementType = VT.getScalarType();
+  EVT TargetScalarType = ElementType.getHalfSizedIntegerVT(*DAG.getContext());
+  EVT TargetType = (VT.isVector() ? VT.changeVectorElementType(TargetScalarType)
+                                  : TargetScalarType);
+
+  if (Known.getMinValue().getZExtValue() < TargetScalarType.getSizeInBits())
     return SDValue();
   SDValue ShiftAmt;
 
   if (CRHS) {
-    ShiftAmt =
-        DAG.getConstant(RHSVal - TargetType.getSizeInBits(), SL, TargetType);
+    ShiftAmt = DAG.getConstant(RHSVal - TargetScalarType.getSizeInBits(), SL,
+                               TargetType);
   } else {
     SDValue truncShiftAmt = DAG.getNode(ISD::TRUNCATE, SL, TargetType, RHS);
     const SDValue ShiftMask =
-        DAG.getConstant(TargetType.getSizeInBits() - 1, SL, TargetType);
+        DAG.getConstant(TargetScalarType.getSizeInBits() - 1, SL, TargetType);
     // This AND instruction will clamp out of bounds shift values.
     // It will also be removed during later instruction selection.
     ShiftAmt = DAG.getNode(ISD::AND, SL, TargetType, truncShiftAmt, ShiftMask);
@@ -4116,9 +4119,24 @@ SDValue AMDGPUTargetLowering::performShlCombine(SDNode *N,
   SDValue NewShift =
       DAG.getNode(ISD::SHL, SL, TargetType, Lo, ShiftAmt, N->getFlags());
 
-  const SDValue Zero = DAG.getConstant(0, SL, TargetType);
-
-  SDValue Vec = DAG.getBuildVector(TargetVecPairType, SL, {Zero, NewShift});
+  const SDValue Zero = DAG.getConstant(0, SL, TargetScalarType);
+  SDValue Vec;
+
+  if (VT.isVector()) {
+    EVT ConcatType = TargetType.getDoubleNumVectorElementsVT(*DAG.getContext());
+    SmallVector<SDValue, 8> Ops;
+    for (unsigned I = 0, E = TargetType.getVectorNumElements(); I != E; ++I) {
+      SDValue Index = DAG.getConstant(I, SL, MVT::i32);
+      Ops.push_back(Zero);
+      SDValue Elt = DAG.getNode(ISD::EXTRACT_VECTOR_ELT, SL, TargetScalarType,
+                                NewShift, Index);
+      Ops.push_back(Elt);
+    }
+    Vec = DAG.getNode(ISD::BUILD_VECTOR, SL, ConcatType, Ops);
+  } else {
+    EVT ConcatType = EVT::getVectorVT(*DAG.getContext(), TargetType, 2);
+    Vec = DAG.getBuildVector(ConcatType, SL, {Zero, NewShift});
+  }
   return DAG.getNode(ISD::BITCAST, SL, VT, Vec);
 }
 
@@ -5182,7 +5200,13 @@ SDValue AMDGPUTargetLowering::PerformDAGCombine(SDNode *N,
     break;
   }
   case ISD::SHL: {
-    if (DCI.getDAGCombineLevel() < AfterLegalizeDAG)
+    // Range metadata can be invalidated when loads are converted to legal types
+    // (e.g. v2i64 -> v4i32).
+    // Try to convert vector shl before type legalization so that range metadata
+    // can be utilized.
+    if (!(N->getValueType(0).isVector() &&
+          DCI.getDAGCombineLevel() == BeforeLegalizeTypes) &&
+        DCI.getDAGCombineLevel() < AfterLegalizeDAG)
       break;
 
     return performShlCombine(N, DCI);
diff --git a/llvm/test/CodeGen/AMDGPU/shl64_reduce.ll b/llvm/test/CodeGen/AMDGPU/shl64_reduce.ll
index 25f32ac3c44ff..378c5d2316704 100644
--- a/llvm/test/CodeGen/AMDGPU/shl64_reduce.ll
+++ b/llvm/test/CodeGen/AMDGPU/shl64_reduce.ll
@@ -34,11 +34,12 @@ define <2 x i64> @shl_v2_metadata(<2 x i64> %arg0, ptr %arg1.ptr) {
 ; CHECK-LABEL: shl_v2_metadata:
 ; CHECK:       ; %bb.0:
 ; CHECK-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
-; CHECK-NEXT:    flat_load_dwordx4 v[4:7], v[4:5]
+; CHECK-NEXT:    flat_load_dwordx4 v[3:6], v[4:5]
 ; CHECK-NEXT:    s_waitcnt vmcnt(0) lgkmcnt(0)
-; CHECK-NEXT:    v_lshlrev_b64 v[2:3], v6, v[2:3]
-; CHECK-NEXT:    v_lshlrev_b32_e32 v1, v4, v0
+; CHECK-NEXT:    v_lshlrev_b32_e32 v1, v3, v0
+; CHECK-NEXT:    v_lshlrev_b32_e32 v3, v5, v2
 ; CHECK-NEXT:    v_mov_b32_e32 v0, 0
+; CHECK-NEXT:    v_mov_b32_e32 v2, 0
 ; CHECK-NEXT:    s_setpc_b64 s[30:31]
   %shift.amt = load <2 x i64>, ptr %arg1.ptr, !range !0
   %shl = shl <2 x i64> %arg0, %shift.amt
@@ -49,12 +50,15 @@ define <3 x i64> @shl_v3_metadata(<3 x i64> %arg0, ptr %arg1.ptr) {
 ; CHECK-LABEL: shl_v3_metadata:
 ; CHECK:       ; %bb.0:
 ; CHECK-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
-; CHECK-NEXT:    flat_load_dword v12, v[6:7] offset:16
+; CHECK-NEXT:    flat_load_dword v1, v[6:7] offset:16
 ; CHECK-NEXT:    flat_load_dwordx4 v[8:11], v[6:7]
 ; CHECK-NEXT:    s_waitcnt vmcnt(0) lgkmcnt(0)
-; CHECK-NEXT:    v_lshlrev_b64 v[4:5], v12, v[4:5]
-; CHECK-NEXT:    v_lshlrev_b64 v[0:1], v8, v[0:1]
-; CHECK-NEXT:    v_lshlrev_b64 v[2:3], v10, v[2:3]
+; CHECK-NEXT:    v_lshlrev_b32_e32 v5, v1, v4
+; CHECK-NEXT:    v_lshlrev_b32_e32 v1, v8, v0
+; CHECK-NEXT:    v_lshlrev_b32_e32 v3, v10, v2
+; CHECK-NEXT:    v_mov_b32_e32 v0, 0
+; CHECK-NEXT:    v_mov_b32_e32 v2, 0
+; CHECK-NEXT:    v_mov_b32_e32 v4, 0
 ; CHECK-NEXT:    s_setpc_b64 s[30:31]
   %shift.amt = load <3 x i64>, ptr %arg1.ptr, !range !0
   %shl = shl <3 x i64> %arg0, %shift.amt
@@ -69,11 +73,15 @@ define <4 x i64> @shl_v4_metadata(<4 x i64> %arg0, ptr %arg1.ptr) {
 ; CHECK-NEXT:    s_waitcnt vmcnt(0) lgkmcnt(0)
 ; CHECK-NEXT:    flat_load_dwordx4 v[13:16], v[8:9] offset:16
 ; CHECK-NEXT:    ; kill: killed $vgpr8 killed $vgpr9
-; CHECK-NEXT:    v_lshlrev_b64 v[0:1], v10, v[0:1]
-; CHECK-NEXT:    v_lshlrev_b64 v[2:3], v12, v[2:3]
+; CHECK-NEXT:    v_lshlrev_b32_e32 v1, v10, v0
+; CHECK-NEXT:    v_lshlrev_b32_e32 v3, v12, v2
 ; CHECK-NEXT:    s_waitcnt vmcnt(0) lgkmcnt(0)
-; CHECK-NEXT:    v_lshlrev_b64 v[4:5], v13, v[4:5]
-; CHECK-NEXT:    v_lshlrev_b64 v[6:7], v15, v[6:7]
+; CHECK-NEXT:    v_lshlrev_b32_e32 v5, v13, v4
+; CHECK-NEXT:    v_lshlrev_b32_e32 v7, v15, v6
+; CHECK-NEXT:    v_mov_b32_e32 v0, 0
+; CHECK-NEXT:    v_mov_b32_e32 v2, 0
+; CHECK-NEXT:    v_mov_b32_e32 v4, 0
+; CHECK-NEXT:    v_mov_b32_e32 v6, 0
 ; CHECK-NEXT:    s_setpc_b64 s[30:31]
   %shift.amt = load <4 x i64>, ptr %arg1.ptr, !range !0
   %shl = shl <4 x i64> %arg0, %shift.amt

>From 8b8949c491ce17197b30ec1d8f677e5ab0ed4463 Mon Sep 17 00:00:00 2001
From: John Lu <John.Lu at amd.com>
Date: Tue, 11 Mar 2025 10:40:51 -0500
Subject: [PATCH 3/7] Undo AMDGPU changes.  Will be done in separate PR. Remove
 FIXME from wrong place.

Signed-off-by: John Lu <John.Lu at amd.com>
---
 .../lib/CodeGen/SelectionDAG/SelectionDAG.cpp |  3 --
 llvm/lib/Target/AMDGPU/AMDGPUISelLowering.cpp | 46 +++++--------------
 llvm/test/CodeGen/AMDGPU/shl64_reduce.ll      | 31 +++++--------
 3 files changed, 22 insertions(+), 58 deletions(-)

diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
index f588c6307c437..7a5e86370255d 100644
--- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
@@ -4017,9 +4017,6 @@ KnownBits SelectionDAG::computeKnownBits(SDValue Op, const APInt &DemandedElts,
       if (const MDNode *MD = LD->getRanges()) {
         ConstantInt *Lower = mdconst::extract<ConstantInt>(MD->getOperand(0));
 
-        // FIXME: If loads are modified (e.g. type legalization)
-        // so that the load type no longer matches the range metadata type, the
-        // range metadata should be updated to match the new load width.
         Known0 = Known0.trunc(Lower->getBitWidth());
         computeKnownBitsFromRangeMetadata(*MD, Known0);
         if (VT.isVector()) {
diff --git a/llvm/lib/Target/AMDGPU/AMDGPUISelLowering.cpp b/llvm/lib/Target/AMDGPU/AMDGPUISelLowering.cpp
index ecc5ca3436ccf..ade81f17ecca5 100644
--- a/llvm/lib/Target/AMDGPU/AMDGPUISelLowering.cpp
+++ b/llvm/lib/Target/AMDGPU/AMDGPUISelLowering.cpp
@@ -4084,7 +4084,7 @@ SDValue AMDGPUTargetLowering::performShlCombine(SDNode *N,
     }
   }
 
-  if (VT.getScalarType() != MVT::i64)
+  if (VT != MVT::i64)
     return SDValue();
 
   // i64 (shl x, C) -> (build_pair 0, (shl x, C -32))
@@ -4092,24 +4092,21 @@ SDValue AMDGPUTargetLowering::performShlCombine(SDNode *N,
   // On some subtargets, 64-bit shift is a quarter rate instruction. In the
   // common case, splitting this into a move and a 32-bit shift is faster and
   // the same code size.
+  EVT TargetType = VT.getHalfSizedIntegerVT(*DAG.getContext());
+  EVT TargetVecPairType = EVT::getVectorVT(*DAG.getContext(), TargetType, 2);
   KnownBits Known = DAG.computeKnownBits(RHS);
 
-  EVT ElementType = VT.getScalarType();
-  EVT TargetScalarType = ElementType.getHalfSizedIntegerVT(*DAG.getContext());
-  EVT TargetType = (VT.isVector() ? VT.changeVectorElementType(TargetScalarType)
-                                  : TargetScalarType);
-
-  if (Known.getMinValue().getZExtValue() < TargetScalarType.getSizeInBits())
+  if (Known.getMinValue().getZExtValue() < TargetType.getSizeInBits())
     return SDValue();
   SDValue ShiftAmt;
 
   if (CRHS) {
-    ShiftAmt = DAG.getConstant(RHSVal - TargetScalarType.getSizeInBits(), SL,
-                               TargetType);
+    ShiftAmt =
+        DAG.getConstant(RHSVal - TargetType.getSizeInBits(), SL, TargetType);
   } else {
     SDValue truncShiftAmt = DAG.getNode(ISD::TRUNCATE, SL, TargetType, RHS);
     const SDValue ShiftMask =
-        DAG.getConstant(TargetScalarType.getSizeInBits() - 1, SL, TargetType);
+        DAG.getConstant(TargetType.getSizeInBits() - 1, SL, TargetType);
     // This AND instruction will clamp out of bounds shift values.
     // It will also be removed during later instruction selection.
     ShiftAmt = DAG.getNode(ISD::AND, SL, TargetType, truncShiftAmt, ShiftMask);
@@ -4119,24 +4116,9 @@ SDValue AMDGPUTargetLowering::performShlCombine(SDNode *N,
   SDValue NewShift =
       DAG.getNode(ISD::SHL, SL, TargetType, Lo, ShiftAmt, N->getFlags());
 
-  const SDValue Zero = DAG.getConstant(0, SL, TargetScalarType);
-  SDValue Vec;
-
-  if (VT.isVector()) {
-    EVT ConcatType = TargetType.getDoubleNumVectorElementsVT(*DAG.getContext());
-    SmallVector<SDValue, 8> Ops;
-    for (unsigned I = 0, E = TargetType.getVectorNumElements(); I != E; ++I) {
-      SDValue Index = DAG.getConstant(I, SL, MVT::i32);
-      Ops.push_back(Zero);
-      SDValue Elt = DAG.getNode(ISD::EXTRACT_VECTOR_ELT, SL, TargetScalarType,
-                                NewShift, Index);
-      Ops.push_back(Elt);
-    }
-    Vec = DAG.getNode(ISD::BUILD_VECTOR, SL, ConcatType, Ops);
-  } else {
-    EVT ConcatType = EVT::getVectorVT(*DAG.getContext(), TargetType, 2);
-    Vec = DAG.getBuildVector(ConcatType, SL, {Zero, NewShift});
-  }
+  const SDValue Zero = DAG.getConstant(0, SL, TargetType);
+
+  SDValue Vec = DAG.getBuildVector(TargetVecPairType, SL, {Zero, NewShift});
   return DAG.getNode(ISD::BITCAST, SL, VT, Vec);
 }
 
@@ -5200,13 +5182,7 @@ SDValue AMDGPUTargetLowering::PerformDAGCombine(SDNode *N,
     break;
   }
   case ISD::SHL: {
-    // Range metadata can be invalidated when loads are converted to legal types
-    // (e.g. v2i64 -> v4i32).
-    // Try to convert vector shl before type legalization so that range metadata
-    // can be utilized.
-    if (!(N->getValueType(0).isVector() &&
-          DCI.getDAGCombineLevel() == BeforeLegalizeTypes) &&
-        DCI.getDAGCombineLevel() < AfterLegalizeDAG)
+    if (DCI.getDAGCombineLevel() < AfterLegalizeDAG)
       break;
 
     return performShlCombine(N, DCI);
diff --git a/llvm/test/CodeGen/AMDGPU/shl64_reduce.ll b/llvm/test/CodeGen/AMDGPU/shl64_reduce.ll
index 378c5d2316704..05430213c17d2 100644
--- a/llvm/test/CodeGen/AMDGPU/shl64_reduce.ll
+++ b/llvm/test/CodeGen/AMDGPU/shl64_reduce.ll
@@ -34,12 +34,10 @@ define <2 x i64> @shl_v2_metadata(<2 x i64> %arg0, ptr %arg1.ptr) {
 ; CHECK-LABEL: shl_v2_metadata:
 ; CHECK:       ; %bb.0:
 ; CHECK-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
-; CHECK-NEXT:    flat_load_dwordx4 v[3:6], v[4:5]
+; CHECK-NEXT:    flat_load_dwordx4 v[4:7], v[4:5]
 ; CHECK-NEXT:    s_waitcnt vmcnt(0) lgkmcnt(0)
-; CHECK-NEXT:    v_lshlrev_b32_e32 v1, v3, v0
-; CHECK-NEXT:    v_lshlrev_b32_e32 v3, v5, v2
-; CHECK-NEXT:    v_mov_b32_e32 v0, 0
-; CHECK-NEXT:    v_mov_b32_e32 v2, 0
+; CHECK-NEXT:    v_lshlrev_b64 v[0:1], v4, v[0:1]
+; CHECK-NEXT:    v_lshlrev_b64 v[2:3], v6, v[2:3]
 ; CHECK-NEXT:    s_setpc_b64 s[30:31]
   %shift.amt = load <2 x i64>, ptr %arg1.ptr, !range !0
   %shl = shl <2 x i64> %arg0, %shift.amt
@@ -50,15 +48,12 @@ define <3 x i64> @shl_v3_metadata(<3 x i64> %arg0, ptr %arg1.ptr) {
 ; CHECK-LABEL: shl_v3_metadata:
 ; CHECK:       ; %bb.0:
 ; CHECK-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
-; CHECK-NEXT:    flat_load_dword v1, v[6:7] offset:16
+; CHECK-NEXT:    flat_load_dword v12, v[6:7] offset:16
 ; CHECK-NEXT:    flat_load_dwordx4 v[8:11], v[6:7]
 ; CHECK-NEXT:    s_waitcnt vmcnt(0) lgkmcnt(0)
-; CHECK-NEXT:    v_lshlrev_b32_e32 v5, v1, v4
-; CHECK-NEXT:    v_lshlrev_b32_e32 v1, v8, v0
-; CHECK-NEXT:    v_lshlrev_b32_e32 v3, v10, v2
-; CHECK-NEXT:    v_mov_b32_e32 v0, 0
-; CHECK-NEXT:    v_mov_b32_e32 v2, 0
-; CHECK-NEXT:    v_mov_b32_e32 v4, 0
+; CHECK-NEXT:    v_lshlrev_b64 v[4:5], v12, v[4:5]
+; CHECK-NEXT:    v_lshlrev_b64 v[0:1], v8, v[0:1]
+; CHECK-NEXT:    v_lshlrev_b64 v[2:3], v10, v[2:3]
 ; CHECK-NEXT:    s_setpc_b64 s[30:31]
   %shift.amt = load <3 x i64>, ptr %arg1.ptr, !range !0
   %shl = shl <3 x i64> %arg0, %shift.amt
@@ -73,15 +68,11 @@ define <4 x i64> @shl_v4_metadata(<4 x i64> %arg0, ptr %arg1.ptr) {
 ; CHECK-NEXT:    s_waitcnt vmcnt(0) lgkmcnt(0)
 ; CHECK-NEXT:    flat_load_dwordx4 v[13:16], v[8:9] offset:16
 ; CHECK-NEXT:    ; kill: killed $vgpr8 killed $vgpr9
-; CHECK-NEXT:    v_lshlrev_b32_e32 v1, v10, v0
-; CHECK-NEXT:    v_lshlrev_b32_e32 v3, v12, v2
+; CHECK-NEXT:    v_lshlrev_b64 v[0:1], v10, v[0:1]
+; CHECK-NEXT:    v_lshlrev_b64 v[2:3], v12, v[2:3]
 ; CHECK-NEXT:    s_waitcnt vmcnt(0) lgkmcnt(0)
-; CHECK-NEXT:    v_lshlrev_b32_e32 v5, v13, v4
-; CHECK-NEXT:    v_lshlrev_b32_e32 v7, v15, v6
-; CHECK-NEXT:    v_mov_b32_e32 v0, 0
-; CHECK-NEXT:    v_mov_b32_e32 v2, 0
-; CHECK-NEXT:    v_mov_b32_e32 v4, 0
-; CHECK-NEXT:    v_mov_b32_e32 v6, 0
+; CHECK-NEXT:    v_lshlrev_b64 v[4:5], v13, v[4:5]
+; CHECK-NEXT:    v_lshlrev_b64 v[6:7], v15, v[6:7]
 ; CHECK-NEXT:    s_setpc_b64 s[30:31]
   %shift.amt = load <4 x i64>, ptr %arg1.ptr, !range !0
   %shl = shl <4 x i64> %arg0, %shift.amt

>From a1a1a8b0a3a686e4b119ca33a21e736340a0c19e Mon Sep 17 00:00:00 2001
From: John Lu <John.Lu at amd.com>
Date: Wed, 12 Mar 2025 10:17:49 -0500
Subject: [PATCH 4/7] Use local KnownBits to get range metadata

Signed-off-by: John Lu <John.Lu at amd.com>
---
 llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
index 7a5e86370255d..06e3e6eae3e1b 100644
--- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
@@ -4017,8 +4017,9 @@ KnownBits SelectionDAG::computeKnownBits(SDValue Op, const APInt &DemandedElts,
       if (const MDNode *MD = LD->getRanges()) {
         ConstantInt *Lower = mdconst::extract<ConstantInt>(MD->getOperand(0));
 
-        Known0 = Known0.trunc(Lower->getBitWidth());
-        computeKnownBitsFromRangeMetadata(*MD, Known0);
+        KnownBits KnownMetadata(Lower->getBitWidth());
+        computeKnownBitsFromRangeMetadata(*MD, KnownMetadata);
+        Known0=KnownMetadata;
         if (VT.isVector()) {
           if (!getDataLayout().isLittleEndian())
             break;

>From f6ed89d182298b12923c10592d58cb7f103fe58c Mon Sep 17 00:00:00 2001
From: John Lu <John.Lu at amd.com>
Date: Wed, 12 Mar 2025 10:20:54 -0500
Subject: [PATCH 5/7] Undo ValueTracking.cpp changes.  Will be done in separate
 PR

Signed-off-by: John Lu <John.Lu at amd.com>
---
 llvm/lib/Analysis/ValueTracking.cpp | 4 ----
 1 file changed, 4 deletions(-)

diff --git a/llvm/lib/Analysis/ValueTracking.cpp b/llvm/lib/Analysis/ValueTracking.cpp
index a0500e221188e..2920738445d5b 100644
--- a/llvm/lib/Analysis/ValueTracking.cpp
+++ b/llvm/lib/Analysis/ValueTracking.cpp
@@ -429,14 +429,10 @@ void llvm::computeKnownBitsFromRangeMetadata(const MDNode &Ranges,
     ConstantInt *Upper =
         mdconst::extract<ConstantInt>(Ranges.getOperand(2 * i + 1));
     ConstantRange Range(Lower->getValue(), Upper->getValue());
-    unsigned RangeBitWidth = Lower->getBitWidth();
 
     // The first CommonPrefixBits of all values in Range are equal.
     unsigned CommonPrefixBits =
         (Range.getUnsignedMax() ^ Range.getUnsignedMin()).countl_zero();
-    // BitWidth must equal RangeBitWidth.  Otherwise Mask will be set
-    // incorrectly.
-    assert(BitWidth == RangeBitWidth && "BitWidth must equal RangeBitWidth");
     APInt Mask = APInt::getHighBitsSet(BitWidth, CommonPrefixBits);
     APInt UnsignedMax = Range.getUnsignedMax().zextOrTrunc(BitWidth);
     Known.One &= UnsignedMax & Mask;

>From 2f36d8a033e2f4d00cd588b37bb004f349a7a2c1 Mon Sep 17 00:00:00 2001
From: John Lu <John.Lu at amd.com>
Date: Wed, 12 Mar 2025 10:31:43 -0500
Subject: [PATCH 6/7] Fix formatting

Signed-off-by: John Lu <John.Lu at amd.com>
---
 llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
index 06e3e6eae3e1b..d4848cafe46c3 100644
--- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
@@ -4019,7 +4019,7 @@ KnownBits SelectionDAG::computeKnownBits(SDValue Op, const APInt &DemandedElts,
 
         KnownBits KnownMetadata(Lower->getBitWidth());
         computeKnownBitsFromRangeMetadata(*MD, KnownMetadata);
-        Known0=KnownMetadata;
+        Known0 = KnownMetadata;
         if (VT.isVector()) {
           if (!getDataLayout().isLittleEndian())
             break;

>From b7f46745fdcdb01fc6b70b667a5e4c29d56b4e14 Mon Sep 17 00:00:00 2001
From: John Lu <John.Lu at amd.com>
Date: Thu, 13 Mar 2025 09:26:02 -0500
Subject: [PATCH 7/7] Extend or truncate KnownMetadata to desired width

Signed-off-by: John Lu <John.Lu at amd.com>
---
 llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp | 9 +++++----
 1 file changed, 5 insertions(+), 4 deletions(-)

diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
index d4848cafe46c3..153c035b477b4 100644
--- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
@@ -4004,9 +4004,10 @@ KnownBits SelectionDAG::computeKnownBits(SDValue Op, const APInt &DemandedElts,
         }
       }
     } else if (Op.getResNo() == 0) {
-      KnownBits Known0(!LD->getMemoryVT().isScalableVT()
-                           ? LD->getMemoryVT().getFixedSizeInBits()
-                           : BitWidth);
+      unsigned MemorySize = !LD->getMemoryVT().isScalableVT()
+                                ? LD->getMemoryVT().getFixedSizeInBits()
+                                : BitWidth;
+      KnownBits Known0(MemorySize);
       EVT VT = Op.getValueType();
       // Fill in any known bits from range information. There are 3 types being
       // used. The results VT (same vector elt size as BitWidth), the loaded
@@ -4019,7 +4020,7 @@ KnownBits SelectionDAG::computeKnownBits(SDValue Op, const APInt &DemandedElts,
 
         KnownBits KnownMetadata(Lower->getBitWidth());
         computeKnownBitsFromRangeMetadata(*MD, KnownMetadata);
-        Known0 = KnownMetadata;
+        Known0 = KnownMetadata.anyextOrTrunc(MemorySize);
         if (VT.isVector()) {
           if (!getDataLayout().isLittleEndian())
             break;



More information about the llvm-commits mailing list