[llvm] [RISCV] Use `experimental-p` extension for zero-extended narrow unsigned types (PR #213260)

Rajveer Singh Bharadwaj via llvm-commits llvm-commits at lists.llvm.org
Thu Sep 10 05:59:07 PDT 2026


https://github.com/Rajveer100 updated https://github.com/llvm/llvm-project/pull/213260

>From eabebe0cb9375959b699a1bba470458ad3ef4ca9 Mon Sep 17 00:00:00 2001
From: Rajveer <rajveer.developer at icloud.com>
Date: Fri, 31 Jul 2026 17:41:45 +0530
Subject: [PATCH 1/6] [RISCV] Use `experimental-p` extension for zero-extended
 narrow unsigned types

Resolves #211361

The bits `31:8` remain zero after packed addition due to `padd.b`
carry-out as per ABI, hence we can generate more optimised code instead
of `zext.b` + `add`.
---
 llvm/lib/Target/RISCV/RISCVISelDAGToDAG.cpp   | 89 ++++++++++++++++++
 llvm/lib/Target/RISCV/RISCVISelDAGToDAG.h     |  1 +
 ...-p-extension-narrow-unsigned-arithmetic.ll | 91 +++++++++++++++++++
 3 files changed, 181 insertions(+)
 create mode 100644 llvm/test/CodeGen/RISCV/experimental-p-extension-narrow-unsigned-arithmetic.ll

diff --git a/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.cpp b/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.cpp
index d263d0320839b..eff4e63fdab5b 100644
--- a/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.cpp
+++ b/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.cpp
@@ -23,6 +23,7 @@
 #include "llvm/Support/Debug.h"
 #include "llvm/Support/MathExtras.h"
 #include "llvm/Support/raw_ostream.h"
+#include <queue>
 
 using namespace llvm;
 
@@ -557,6 +558,91 @@ void RISCVDAGToDAGISel::selectXSfmmVSET(SDNode *Node) {
   }
 }
 
+bool RISCVDAGToDAGISel::tryPExtNarrowUnsigned(SDNode *Node) {
+  using namespace SDPatternMatch;
+
+  EVT VT = Node->getValueType(0);
+  SDLoc DL(Node);
+
+  APInt ConstMask;
+
+  // auto m_AddOrSub = [](Value_match N0 = m_Value(), Value_match N1 =
+  // m_Value(),
+  //                      Value_match N2 = m_Value(), Value_match N3 =
+  //                      m_Value()) {
+  //   return m_AnyOf(m_Add(N0, N1), m_Sub(N2, N3));
+  // };
+
+  if (sd_match(Node,
+               m_And(m_Add(m_Value(), m_Value()), m_ConstInt(ConstMask)))) {
+    uint64_t ConstMaskVal = ConstMask.getZExtValue();
+    if (ConstMaskVal != 255 && ConstMaskVal != 65535)
+      return false;
+
+    uint64_t OpCode = (ConstMaskVal == 255) ? RISCV::PADD_B : RISCV::PADD_H;
+
+    std::queue<SDNode *> Worklist;
+    Worklist.push(Node->getOperand(0).getNode());
+
+    std::vector<SDNode *> Ops;
+    while (!Worklist.empty()) {
+      SDNode *CurNode = Worklist.front();
+      Worklist.pop();
+
+      SDValue N0, N1, N2, N3;
+      SDValue A0, A1;
+      if (sd_match(CurNode, m_Add(m_Add(m_Value(N0), m_Value(N1)),
+                                  m_Add(m_Value(N2), m_Value(N3))))) {
+        Worklist.push(N3.getNode());
+        Worklist.push(N2.getNode());
+        Worklist.push(N1.getNode());
+        Worklist.push(N0.getNode());
+      } else if (sd_match(CurNode, m_Add(m_Add(m_Value(N0), m_Value(N1)),
+                                         m_Node(ISD::AssertZext, m_Value(),
+                                                m_Value())))) {
+        Worklist.push(N1.getNode());
+        Worklist.push(N0.getNode());
+        Worklist.push(CurNode->getOperand(1).getNode());
+      } else if (sd_match(
+                     CurNode,
+                     m_Add(m_Node(ISD::AssertZext, m_Value(A0), m_Value()),
+                           m_Node(ISD::AssertZext, m_Value(A1), m_Value())))) {
+        Worklist.push(CurNode->getOperand(0).getNode());
+        Worklist.push(CurNode->getOperand(1).getNode());
+      } else if (sd_match(CurNode,
+                          m_Node(ISD::AssertZext, m_Value(A0), m_Value()))) {
+        Ops.push_back(A0.getNode());
+      }
+    }
+
+    uint64_t Idx = 0, NumOps = Ops.size();
+    bool IsFirst = true;
+
+    SDValue LastOp;
+    while (Idx < NumOps) {
+      SDNode *Op0 = Ops[Idx++];
+      SDValue PAddNode;
+      if (IsFirst) {
+        SDNode *Op1 = Ops[Idx++];
+        PAddNode =
+            SDValue(CurDAG->getMachineNode(OpCode, DL, VT, SDValue(Op0, 0),
+                                           SDValue(Op1, 0)),
+                    0);
+        IsFirst = false;
+      } else {
+        PAddNode = SDValue(
+            CurDAG->getMachineNode(OpCode, DL, VT, LastOp, SDValue(Op0, 0)), 0);
+      }
+      LastOp = PAddNode;
+    }
+
+    ReplaceNode(Node, LastOp.getNode());
+    return true;
+  }
+
+  return false;
+}
+
 bool RISCVDAGToDAGISel::tryShrinkShlLogicImm(SDNode *Node) {
   MVT VT = Node->getSimpleValueType(0);
   unsigned Opcode = Node->getOpcode();
@@ -1815,6 +1901,9 @@ void RISCVDAGToDAGISel::Select(SDNode *Node) {
     if (tryShrinkShlLogicImm(Node))
       return;
 
+    if (Subtarget->hasStdExtP() && tryPExtNarrowUnsigned(Node))
+      return;
+
     break;
   }
   case ISD::MUL: {
diff --git a/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.h b/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.h
index da08a6032d94f..21c87370da246 100644
--- a/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.h
+++ b/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.h
@@ -99,6 +99,7 @@ class RISCVDAGToDAGISel : public SelectionDAGISel {
 
   bool SelectAddrRegReg(SDValue Addr, SDValue &Base, SDValue &Offset);
 
+  bool tryPExtNarrowUnsigned(SDNode *Node);
   bool tryShrinkShlLogicImm(SDNode *Node);
   bool trySignedBitfieldExtract(SDNode *Node);
   bool trySignedBitfieldInsertInSign(SDNode *Node);
diff --git a/llvm/test/CodeGen/RISCV/experimental-p-extension-narrow-unsigned-arithmetic.ll b/llvm/test/CodeGen/RISCV/experimental-p-extension-narrow-unsigned-arithmetic.ll
new file mode 100644
index 0000000000000..f2862bad87652
--- /dev/null
+++ b/llvm/test/CodeGen/RISCV/experimental-p-extension-narrow-unsigned-arithmetic.ll
@@ -0,0 +1,91 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 6
+; RUN: llc -mtriple=riscv32 -mattr=+experimental-p \
+; RUN:   -verify-machineinstrs < %s | \
+; RUN:   FileCheck --check-prefixes=CHECK,RV32 %s
+
+define zeroext i8 @zexti8_paddb1(i8 zeroext %x, i8 zeroext %y) {
+; CHECK-LABEL: zexti8_paddb1:
+; CHECK:       # %bb.0: # %entry
+; CHECK-NEXT:    padd.b a0, a1, a0
+; CHECK-NEXT:    ret
+entry:
+  %add = add i8 %y, %x
+  ret i8 %add
+}
+
+define zeroext i32 @zexti32_padd_neg(i32 zeroext %x, i32 zeroext %y) {
+; CHECK-LABEL: zexti32_padd_neg:
+; CHECK:       # %bb.0: # %entry
+; CHECK-NEXT:    add a0, a1, a0
+; CHECK-NEXT:    ret
+entry:
+  %add = add i32 %y, %x
+  ret i32 %add
+}
+
+define zeroext i8 @zexti8_paddb2(i8 zeroext %x, i8 zeroext %y, i8 zeroext %z) {
+; CHECK-LABEL: zexti8_paddb2:
+; CHECK:       # %bb.0: # %entry
+; CHECK-NEXT:    padd.b a0, a0, a1
+; CHECK-NEXT:    padd.b a0, a0, a2
+; CHECK-NEXT:    ret
+entry:
+  %add = add i8 %y, %x
+  %add2 = add i8 %add, %z
+  ret i8 %add2
+}
+
+define zeroext i8 @zexti8_paddb3(i8 zeroext %a, i8 zeroext %b, i8 zeroext %c, i8 zeroext %d) {
+; CHECK-LABEL: zexti8_paddb3:
+; CHECK:       # %bb.0: # %entry
+; CHECK-NEXT:    padd.b a0, a0, a1
+; CHECK-NEXT:    padd.b a0, a0, a3
+; CHECK-NEXT:    padd.b a0, a0, a2
+; CHECK-NEXT:    ret
+entry:
+  %add = add i8 %b, %a
+  %add2 = add i8 %c, %d
+  %add3 = add i8 %add2, %add
+  ret i8 %add3
+}
+
+define zeroext i8 @zexti8_paddb4(i8 zeroext %a, i8 zeroext %b, i8 zeroext %c, i8 zeroext %d) {
+; CHECK-LABEL: zexti8_paddb4:
+; CHECK:       # %bb.0: # %entry
+; CHECK-NEXT:    padd.b a0, a0, a1
+; CHECK-NEXT:    padd.b a0, a0, a3
+; CHECK-NEXT:    padd.b a0, a0, a2
+; CHECK-NEXT:    ret
+entry:
+  %add = add i8 %b, %a
+  %add2 = add i8 %c, %d
+  %add3 = add i8 %add2, %add
+  ret i8 %add3
+}
+
+define zeroext i16 @zexti16_paddh1(i16 zeroext %x, i16 zeroext %y) {
+; CHECK-LABEL: zexti16_paddh1:
+; CHECK:       # %bb.0: # %entry
+; CHECK-NEXT:    padd.h a0, a1, a0
+; CHECK-NEXT:    ret
+entry:
+  %add = add i16 %y, %x
+  ret i16 %add
+}
+
+define zeroext i16 @zexti16_paddh2(i16 zeroext %a, i16 zeroext %b, i16 zeroext %c, i16 zeroext %d) {
+; CHECK-LABEL: zexti16_paddh2:
+; CHECK:       # %bb.0: # %entry
+; CHECK-NEXT:    padd.h a0, a0, a1
+; CHECK-NEXT:    padd.h a0, a0, a3
+; CHECK-NEXT:    padd.h a0, a0, a2
+; CHECK-NEXT:    ret
+entry:
+  %add = add i16 %b, %a
+  %add2 = add i16 %c, %d
+  %add3 = add i16 %add2, %add
+  ret i16 %add3
+}
+
+;; NOTE: These prefixes are unused and the list is autogenerated. Do not add tests below this line:
+; RV32: {{.*}}

>From ecebf45faaf623372f9a5dd56dba72cd4c3ba6d5 Mon Sep 17 00:00:00 2001
From: Rajveer <rajveer.developer at icloud.com>
Date: Thu, 3 Sep 2026 18:31:07 +0530
Subject: [PATCH 2/6] Check for enough zero bits in AssertZext, multi-use
 checks, flags for size/performance

---
 llvm/lib/Target/RISCV/RISCVISelDAGToDAG.cpp   | 62 ++++++++++++-------
 ...-p-extension-narrow-unsigned-arithmetic.ll | 17 +++++
 2 files changed, 58 insertions(+), 21 deletions(-)

diff --git a/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.cpp b/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.cpp
index eff4e63fdab5b..680459107028e 100644
--- a/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.cpp
+++ b/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.cpp
@@ -566,20 +566,21 @@ bool RISCVDAGToDAGISel::tryPExtNarrowUnsigned(SDNode *Node) {
 
   APInt ConstMask;
 
-  // auto m_AddOrSub = [](Value_match N0 = m_Value(), Value_match N1 =
-  // m_Value(),
-  //                      Value_match N2 = m_Value(), Value_match N3 =
-  //                      m_Value()) {
-  //   return m_AnyOf(m_Add(N0, N1), m_Sub(N2, N3));
-  // };
-
   if (sd_match(Node,
                m_And(m_Add(m_Value(), m_Value()), m_ConstInt(ConstMask)))) {
     uint64_t ConstMaskVal = ConstMask.getZExtValue();
     if (ConstMaskVal != 255 && ConstMaskVal != 65535)
       return false;
 
-    uint64_t OpCode = (ConstMaskVal == 255) ? RISCV::PADD_B : RISCV::PADD_H;
+    uint64_t PAddOpcode = (ConstMaskVal == 255) ? RISCV::PADD_B : RISCV::PADD_H;
+    uint64_t MinZeroBits = (ConstMaskVal == 255) ? 24 : 16;
+
+    auto hasEnoughZeroBits = [MinZeroBits](SDNode *Node, SDValue Op) -> bool {
+      VTSDNode *ChainedNode = dyn_cast<VTSDNode>(Op);
+      EVT FromTy = ChainedNode->getVT();
+      EVT ToTy = Node->getValueType(0);
+      return (ToTy.getSizeInBits() - FromTy.getSizeInBits()) >= MinZeroBits;
+    };
 
     std::queue<SDNode *> Worklist;
     Worklist.push(Node->getOperand(0).getNode());
@@ -590,28 +591,45 @@ bool RISCVDAGToDAGISel::tryPExtNarrowUnsigned(SDNode *Node) {
       Worklist.pop();
 
       SDValue N0, N1, N2, N3;
-      SDValue A0, A1;
+      SDValue A0, A1, V0, V1;
       if (sd_match(CurNode, m_Add(m_Add(m_Value(N0), m_Value(N1)),
                                   m_Add(m_Value(N2), m_Value(N3))))) {
+        SDValue Inner0 = CurNode->getOperand(0);
+        SDValue Inner1 = CurNode->getOperand(1);
+        if (!Inner0.hasOneUse() || !Inner1.hasOneUse())
+          return false;
+
         Worklist.push(N3.getNode());
         Worklist.push(N2.getNode());
         Worklist.push(N1.getNode());
         Worklist.push(N0.getNode());
       } else if (sd_match(CurNode, m_Add(m_Add(m_Value(N0), m_Value(N1)),
-                                         m_Node(ISD::AssertZext, m_Value(),
-                                                m_Value())))) {
+                                         m_Node(ISD::AssertZext, m_Value(V1),
+                                                m_Value(A1))))) {
+        SDValue Inner0 = CurNode->getOperand(0);
+        if (!Inner0.hasOneUse())
+          return false;
+
+        if (!hasEnoughZeroBits(V1.getNode(), A1))
+          return false;
+
         Worklist.push(N1.getNode());
         Worklist.push(N0.getNode());
         Worklist.push(CurNode->getOperand(1).getNode());
-      } else if (sd_match(
-                     CurNode,
-                     m_Add(m_Node(ISD::AssertZext, m_Value(A0), m_Value()),
-                           m_Node(ISD::AssertZext, m_Value(A1), m_Value())))) {
+      } else if (sd_match(CurNode, m_Add(m_Node(ISD::AssertZext, m_Value(V0),
+                                                m_Value(A0)),
+                                         m_Node(ISD::AssertZext, m_Value(V1),
+                                                m_Value(A1))))) {
+        if (!hasEnoughZeroBits(V1.getNode(), A1) ||
+            !hasEnoughZeroBits(V0.getNode(), A0))
+          return false;
         Worklist.push(CurNode->getOperand(0).getNode());
         Worklist.push(CurNode->getOperand(1).getNode());
       } else if (sd_match(CurNode,
-                          m_Node(ISD::AssertZext, m_Value(A0), m_Value()))) {
-        Ops.push_back(A0.getNode());
+                          m_Node(ISD::AssertZext, m_Value(V0), m_Value(A1)))) {
+        if (!hasEnoughZeroBits(V0.getNode(), A1))
+          return false;
+        Ops.push_back(V0.getNode());
       }
     }
 
@@ -625,13 +643,14 @@ bool RISCVDAGToDAGISel::tryPExtNarrowUnsigned(SDNode *Node) {
       if (IsFirst) {
         SDNode *Op1 = Ops[Idx++];
         PAddNode =
-            SDValue(CurDAG->getMachineNode(OpCode, DL, VT, SDValue(Op0, 0),
+            SDValue(CurDAG->getMachineNode(PAddOpcode, DL, VT, SDValue(Op0, 0),
                                            SDValue(Op1, 0)),
                     0);
         IsFirst = false;
       } else {
         PAddNode = SDValue(
-            CurDAG->getMachineNode(OpCode, DL, VT, LastOp, SDValue(Op0, 0)), 0);
+            CurDAG->getMachineNode(PAddOpcode, DL, VT, LastOp, SDValue(Op0, 0)),
+            0);
       }
       LastOp = PAddNode;
     }
@@ -1901,8 +1920,9 @@ void RISCVDAGToDAGISel::Select(SDNode *Node) {
     if (tryShrinkShlLogicImm(Node))
       return;
 
-    if (Subtarget->hasStdExtP() && tryPExtNarrowUnsigned(Node))
-      return;
+    if (!CurDAG->getMachineFunction().getFunction().hasMinSize())
+      if (Subtarget->hasStdExtP() && tryPExtNarrowUnsigned(Node))
+        return;
 
     break;
   }
diff --git a/llvm/test/CodeGen/RISCV/experimental-p-extension-narrow-unsigned-arithmetic.ll b/llvm/test/CodeGen/RISCV/experimental-p-extension-narrow-unsigned-arithmetic.ll
index f2862bad87652..27c7f35b1351a 100644
--- a/llvm/test/CodeGen/RISCV/experimental-p-extension-narrow-unsigned-arithmetic.ll
+++ b/llvm/test/CodeGen/RISCV/experimental-p-extension-narrow-unsigned-arithmetic.ll
@@ -87,5 +87,22 @@ entry:
   ret i16 %add3
 }
 
+define zeroext i16 @zexti16_paddh2_neg_minsize(i16 zeroext %a, i16 zeroext %b, i16 zeroext %c, i16 zeroext %d) #0 {
+; CHECK-LABEL: zexti16_paddh2_neg_minsize:
+; CHECK:       # %bb.0: # %entry
+; CHECK-NEXT:    add a0, a1, a0
+; CHECK-NEXT:    add a2, a2, a3
+; CHECK-NEXT:    add a0, a2, a0
+; CHECK-NEXT:    zext.h a0, a0
+; CHECK-NEXT:    ret
+entry:
+  %add = add i16 %b, %a
+  %add2 = add i16 %c, %d
+  %add3 = add i16 %add2, %add
+  ret i16 %add3
+}
+
+attributes #0 = { minsize }
+
 ;; NOTE: These prefixes are unused and the list is autogenerated. Do not add tests below this line:
 ; RV32: {{.*}}

>From 97646bb656117937520babb69e40ba8dcec32fc7 Mon Sep 17 00:00:00 2001
From: Rajveer Singh Bharadwaj <rajveer.developer at icloud.com>
Date: Thu, 3 Sep 2026 19:33:17 +0530
Subject: [PATCH 3/6] Fix SDPatternMatch namespace

---
 llvm/lib/Target/RISCV/RISCVISelDAGToDAG.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.cpp b/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.cpp
index 680459107028e..61a35b08bc1c0 100644
--- a/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.cpp
+++ b/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.cpp
@@ -559,7 +559,7 @@ void RISCVDAGToDAGISel::selectXSfmmVSET(SDNode *Node) {
 }
 
 bool RISCVDAGToDAGISel::tryPExtNarrowUnsigned(SDNode *Node) {
-  using namespace SDPatternMatch;
+  using namespace llvm::SDPatternMatch;
 
   EVT VT = Node->getValueType(0);
   SDLoc DL(Node);

>From 1b298cc4b0095deb8eac9f3c344b6100056e7367 Mon Sep 17 00:00:00 2001
From: Rajveer Singh Bharadwaj <rajveer.developer at icloud.com>
Date: Thu, 3 Sep 2026 19:56:39 +0530
Subject: [PATCH 4/6] Fix namespace error

---
 llvm/lib/Target/RISCV/RISCVISelDAGToDAG.cpp | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.cpp b/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.cpp
index 61a35b08bc1c0..f785b9c2b7ae6 100644
--- a/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.cpp
+++ b/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.cpp
@@ -18,6 +18,7 @@
 #include "RISCVInstrInfo.h"
 #include "RISCVSelectionDAGInfo.h"
 #include "llvm/CodeGen/MachineFrameInfo.h"
+#include "llvm/CodeGen/SDPatternMatch.h"
 #include "llvm/IR/IntrinsicsRISCV.h"
 #include "llvm/Support/Alignment.h"
 #include "llvm/Support/Debug.h"
@@ -559,7 +560,7 @@ void RISCVDAGToDAGISel::selectXSfmmVSET(SDNode *Node) {
 }
 
 bool RISCVDAGToDAGISel::tryPExtNarrowUnsigned(SDNode *Node) {
-  using namespace llvm::SDPatternMatch;
+  using namespace SDPatternMatch;
 
   EVT VT = Node->getValueType(0);
   SDLoc DL(Node);

>From 0f895a72f70bc15594f7dd0c567b40836b18c2fc Mon Sep 17 00:00:00 2001
From: Rajveer <rajveer.developer at icloud.com>
Date: Tue, 8 Sep 2026 00:43:42 +0530
Subject: [PATCH 5/6] Check `dyn_cast`

---
 llvm/lib/Target/RISCV/RISCVISelDAGToDAG.cpp | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.cpp b/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.cpp
index f785b9c2b7ae6..76fe81c0ef6c2 100644
--- a/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.cpp
+++ b/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.cpp
@@ -578,6 +578,9 @@ bool RISCVDAGToDAGISel::tryPExtNarrowUnsigned(SDNode *Node) {
 
     auto hasEnoughZeroBits = [MinZeroBits](SDNode *Node, SDValue Op) -> bool {
       VTSDNode *ChainedNode = dyn_cast<VTSDNode>(Op);
+      if (!ChainedNode)
+        return false;
+
       EVT FromTy = ChainedNode->getVT();
       EVT ToTy = Node->getValueType(0);
       return (ToTy.getSizeInBits() - FromTy.getSizeInBits()) >= MinZeroBits;

>From 6198a7aea87a00c8cf5033e8abbd6be5668ec6bf Mon Sep 17 00:00:00 2001
From: Rajveer <rajveer.developer at icloud.com>
Date: Thu, 10 Sep 2026 18:28:30 +0530
Subject: [PATCH 6/6] Adjust MinZeroBits for RV64

---
 llvm/lib/Target/RISCV/RISCVISelDAGToDAG.cpp | 21 +++++++++++++++++----
 1 file changed, 17 insertions(+), 4 deletions(-)

diff --git a/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.cpp b/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.cpp
index 76fe81c0ef6c2..8b230b08f0a38 100644
--- a/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.cpp
+++ b/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.cpp
@@ -570,11 +570,24 @@ bool RISCVDAGToDAGISel::tryPExtNarrowUnsigned(SDNode *Node) {
   if (sd_match(Node,
                m_And(m_Add(m_Value(), m_Value()), m_ConstInt(ConstMask)))) {
     uint64_t ConstMaskVal = ConstMask.getZExtValue();
-    if (ConstMaskVal != 255 && ConstMaskVal != 65535)
-      return false;
 
-    uint64_t PAddOpcode = (ConstMaskVal == 255) ? RISCV::PADD_B : RISCV::PADD_H;
-    uint64_t MinZeroBits = (ConstMaskVal == 255) ? 24 : 16;
+    uint64_t PAddOpcode;
+    uint64_t MinZeroBits;
+
+    bool IsRV32 = Subtarget->isRV32();
+
+    switch (ConstMaskVal) {
+    case ((1ll << 8) - 1):
+      PAddOpcode = RISCV::PADD_B;
+      MinZeroBits = (IsRV32 ? 24 : 56);
+      break;
+    case ((1ll << 16) - 1):
+      PAddOpcode = RISCV::PADD_H;
+      MinZeroBits = (IsRV32 ? 16 : 48);
+      break;
+    default:
+      return false;
+    }
 
     auto hasEnoughZeroBits = [MinZeroBits](SDNode *Node, SDValue Op) -> bool {
       VTSDNode *ChainedNode = dyn_cast<VTSDNode>(Op);



More information about the llvm-commits mailing list