[llvm] [RISCV] Select (add C, x) -> (add.uw C|0xffffffff00000000, x) (PR #143375)

Piotr Fusik via llvm-commits llvm-commits at lists.llvm.org
Mon Jun 9 09:13:48 PDT 2025


https://github.com/pfusik updated https://github.com/llvm/llvm-project/pull/143375

>From abfd912deb4862b888327985d8137d5b6aeb029a Mon Sep 17 00:00:00 2001
From: Piotr Fusik <p.fusik at samsung.com>
Date: Mon, 9 Jun 2025 13:48:04 +0200
Subject: [PATCH 1/6] [RISCV][test] Add tests for add.uw with a constant

---
 llvm/test/CodeGen/RISCV/rv64zba.ll | 119 +++++++++++++++++++++++++++++
 1 file changed, 119 insertions(+)

diff --git a/llvm/test/CodeGen/RISCV/rv64zba.ll b/llvm/test/CodeGen/RISCV/rv64zba.ll
index e71117739b125..8f4c6b24a40d2 100644
--- a/llvm/test/CodeGen/RISCV/rv64zba.ll
+++ b/llvm/test/CodeGen/RISCV/rv64zba.ll
@@ -4411,3 +4411,122 @@ define ptr @udiv1280_gep(ptr %p, i16 zeroext %i) {
   %add.ptr = getelementptr i64, ptr %p, i64 %idx.ext
   ret ptr %add.ptr
 }
+
+define i64 @adduw_m1(i64 %x) {
+; CHECK-LABEL: adduw_m1:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    li a1, -1
+; CHECK-NEXT:    srli a1, a1, 32
+; CHECK-NEXT:    add a0, a0, a1
+; CHECK-NEXT:    ret
+  %a = add i64 %x, 4294967295
+  ret i64 %a
+}
+
+define i64 @adduw_m3(i64 %x) {
+; RV64I-LABEL: adduw_m3:
+; RV64I:       # %bb.0:
+; RV64I-NEXT:    li a1, 1
+; RV64I-NEXT:    slli a1, a1, 32
+; RV64I-NEXT:    addi a1, a1, -3
+; RV64I-NEXT:    add a0, a0, a1
+; RV64I-NEXT:    ret
+;
+; RV64ZBA-LABEL: adduw_m3:
+; RV64ZBA:       # %bb.0:
+; RV64ZBA-NEXT:    li a1, -3
+; RV64ZBA-NEXT:    zext.w a1, a1
+; RV64ZBA-NEXT:    add a0, a0, a1
+; RV64ZBA-NEXT:    ret
+;
+; RV64XANDESPERF-LABEL: adduw_m3:
+; RV64XANDESPERF:       # %bb.0:
+; RV64XANDESPERF-NEXT:    li a1, 1
+; RV64XANDESPERF-NEXT:    slli a1, a1, 32
+; RV64XANDESPERF-NEXT:    addi a1, a1, -3
+; RV64XANDESPERF-NEXT:    add a0, a0, a1
+; RV64XANDESPERF-NEXT:    ret
+  %a = add i64 %x, 4294967293
+  ret i64 %a
+}
+
+define i64 @adduw_3shl30(i64 %x) {
+; CHECK-LABEL: adduw_3shl30:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    li a1, 3
+; CHECK-NEXT:    slli a1, a1, 30
+; CHECK-NEXT:    add a0, a0, a1
+; CHECK-NEXT:    ret
+  %a = add i64 %x, 3221225472
+  ret i64 %a
+}
+
+define i64 @adduw_m3_multiuse(i64 %x, i64 %y) {
+; RV64I-LABEL: adduw_m3_multiuse:
+; RV64I:       # %bb.0:
+; RV64I-NEXT:    li a2, 1
+; RV64I-NEXT:    slli a2, a2, 32
+; RV64I-NEXT:    addi a2, a2, -3
+; RV64I-NEXT:    add a0, a0, a2
+; RV64I-NEXT:    add a1, a1, a2
+; RV64I-NEXT:    or a0, a0, a1
+; RV64I-NEXT:    ret
+;
+; RV64ZBA-LABEL: adduw_m3_multiuse:
+; RV64ZBA:       # %bb.0:
+; RV64ZBA-NEXT:    li a2, -3
+; RV64ZBA-NEXT:    zext.w a2, a2
+; RV64ZBA-NEXT:    add a0, a0, a2
+; RV64ZBA-NEXT:    add a1, a1, a2
+; RV64ZBA-NEXT:    or a0, a0, a1
+; RV64ZBA-NEXT:    ret
+;
+; RV64XANDESPERF-LABEL: adduw_m3_multiuse:
+; RV64XANDESPERF:       # %bb.0:
+; RV64XANDESPERF-NEXT:    li a2, 1
+; RV64XANDESPERF-NEXT:    slli a2, a2, 32
+; RV64XANDESPERF-NEXT:    addi a2, a2, -3
+; RV64XANDESPERF-NEXT:    add a0, a0, a2
+; RV64XANDESPERF-NEXT:    add a1, a1, a2
+; RV64XANDESPERF-NEXT:    or a0, a0, a1
+; RV64XANDESPERF-NEXT:    ret
+  %a = add i64 %x, 4294967293
+  %b = add i64 %y, 4294967293
+  %c = or i64 %a, %b
+  ret i64 %c
+}
+
+define i64 @add_or_m3(i64 %x) {
+; RV64I-LABEL: add_or_m3:
+; RV64I:       # %bb.0:
+; RV64I-NEXT:    li a1, 1
+; RV64I-NEXT:    slli a1, a1, 32
+; RV64I-NEXT:    addi a1, a1, -3
+; RV64I-NEXT:    or a2, a0, a1
+; RV64I-NEXT:    add a0, a0, a1
+; RV64I-NEXT:    add a0, a0, a2
+; RV64I-NEXT:    ret
+;
+; RV64ZBA-LABEL: add_or_m3:
+; RV64ZBA:       # %bb.0:
+; RV64ZBA-NEXT:    li a1, -3
+; RV64ZBA-NEXT:    zext.w a1, a1
+; RV64ZBA-NEXT:    or a2, a0, a1
+; RV64ZBA-NEXT:    add a0, a0, a1
+; RV64ZBA-NEXT:    add a0, a0, a2
+; RV64ZBA-NEXT:    ret
+;
+; RV64XANDESPERF-LABEL: add_or_m3:
+; RV64XANDESPERF:       # %bb.0:
+; RV64XANDESPERF-NEXT:    li a1, 1
+; RV64XANDESPERF-NEXT:    slli a1, a1, 32
+; RV64XANDESPERF-NEXT:    addi a1, a1, -3
+; RV64XANDESPERF-NEXT:    or a2, a0, a1
+; RV64XANDESPERF-NEXT:    add a0, a0, a1
+; RV64XANDESPERF-NEXT:    add a0, a0, a2
+; RV64XANDESPERF-NEXT:    ret
+  %a = add i64 %x, 4294967293
+  %o = or i64 %x, 4294967293
+  %c = add i64 %a, %o
+  ret i64 %c
+}

>From 94236aa0ea3064bdf41e761fae63022c10e1818a Mon Sep 17 00:00:00 2001
From: Piotr Fusik <p.fusik at samsung.com>
Date: Mon, 9 Jun 2025 13:48:39 +0200
Subject: [PATCH 2/6] [RISCV] Select (add C, x) -> (add.uw
 C|0xffffffff00000000, x)

Emits fewer instructions for certain constants.
---
 llvm/lib/Target/RISCV/RISCVISelDAGToDAG.cpp | 25 ++++++++
 llvm/lib/Target/RISCV/RISCVISelDAGToDAG.h   |  1 +
 llvm/lib/Target/RISCV/RISCVInstrInfoZb.td   |  4 ++
 llvm/test/CodeGen/RISCV/rv64zba.ll          | 70 +++++++++++++--------
 4 files changed, 74 insertions(+), 26 deletions(-)

diff --git a/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.cpp b/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.cpp
index 494d6ed03292a..2c442e760919f 100644
--- a/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.cpp
+++ b/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.cpp
@@ -3296,6 +3296,31 @@ bool RISCVDAGToDAGISel::selectSHXADD_UWOp(SDValue N, unsigned ShAmt,
   return false;
 }
 
+bool RISCVDAGToDAGISel::selectZExtImm32(SDValue N, SDValue &Val) {
+  if (!isa<ConstantSDNode>(N))
+    return false;
+  int64_t Imm = cast<ConstantSDNode>(N)->getSExtValue();
+  if ((Imm >> 31) != 1)
+    return false;
+
+  if (any_of(N->users(),
+             [](const SDNode *U) { return U->getOpcode() != ISD::ADD; }))
+    return false;
+
+  int64_t LeadingOnesImm = 0xffffffff00000000 | Imm;
+  int OrigImmCost = RISCVMatInt::getIntMatCost(APInt(64, Imm), 64, *Subtarget,
+                                               /*CompressionCost=*/true);
+  int LeadingOnesImmCost =
+      RISCVMatInt::getIntMatCost(APInt(64, LeadingOnesImm), 64, *Subtarget,
+                                 /*CompressionCost=*/true);
+  if (OrigImmCost <= LeadingOnesImmCost)
+    return false;
+
+  Val = selectImm(CurDAG, SDLoc(N), N->getSimpleValueType(0), LeadingOnesImm,
+                  *Subtarget);
+  return true;
+}
+
 bool RISCVDAGToDAGISel::selectNegImm(SDValue N, SDValue &Val) {
   if (!isa<ConstantSDNode>(N))
     return false;
diff --git a/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.h b/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.h
index f199c2031b9a9..ef99d2317bc72 100644
--- a/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.h
+++ b/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.h
@@ -118,6 +118,7 @@ class RISCVDAGToDAGISel : public SelectionDAGISel {
     return selectSHXADD_UWOp(N, ShAmt, Val);
   }
 
+  bool selectZExtImm32(SDValue N, SDValue &Val);
   bool selectNegImm(SDValue N, SDValue &Val);
   bool selectInvLogicImm(SDValue N, SDValue &Val);
 
diff --git a/llvm/lib/Target/RISCV/RISCVInstrInfoZb.td b/llvm/lib/Target/RISCV/RISCVInstrInfoZb.td
index 4353e94bdb1d0..4806bcc1d63de 100644
--- a/llvm/lib/Target/RISCV/RISCVInstrInfoZb.td
+++ b/llvm/lib/Target/RISCV/RISCVInstrInfoZb.td
@@ -704,9 +704,13 @@ def : CSImm12MulBy4Pat<SH2ADD>;
 def : CSImm12MulBy8Pat<SH3ADD>;
 } // Predicates = [HasStdExtZba]
 
+def zExtImm32 : ComplexPattern<i64, 1, "selectZExtImm32", [], [], 0>;
+
 multiclass ADD_UWPat<Instruction add_uw> {
   def : Pat<(i64 (add_like_non_imm12 (and GPR:$rs1, 0xFFFFFFFF), GPR:$rs2)),
             (add_uw GPR:$rs1, GPR:$rs2)>;
+  def : Pat<(i64 (add_like zExtImm32:$rs1, GPR:$rs2)),
+            (add_uw zExtImm32:$rs1, GPR:$rs2)>;
   def : Pat<(i64 (and GPR:$rs, 0xFFFFFFFF)), (add_uw GPR:$rs, (XLenVT X0))>;
 }
 
diff --git a/llvm/test/CodeGen/RISCV/rv64zba.ll b/llvm/test/CodeGen/RISCV/rv64zba.ll
index 8f4c6b24a40d2..5668ec1f230c2 100644
--- a/llvm/test/CodeGen/RISCV/rv64zba.ll
+++ b/llvm/test/CodeGen/RISCV/rv64zba.ll
@@ -4413,12 +4413,24 @@ define ptr @udiv1280_gep(ptr %p, i16 zeroext %i) {
 }
 
 define i64 @adduw_m1(i64 %x) {
-; CHECK-LABEL: adduw_m1:
-; CHECK:       # %bb.0:
-; CHECK-NEXT:    li a1, -1
-; CHECK-NEXT:    srli a1, a1, 32
-; CHECK-NEXT:    add a0, a0, a1
-; CHECK-NEXT:    ret
+; RV64I-LABEL: adduw_m1:
+; RV64I:       # %bb.0:
+; RV64I-NEXT:    li a1, -1
+; RV64I-NEXT:    srli a1, a1, 32
+; RV64I-NEXT:    add a0, a0, a1
+; RV64I-NEXT:    ret
+;
+; RV64ZBA-LABEL: adduw_m1:
+; RV64ZBA:       # %bb.0:
+; RV64ZBA-NEXT:    li a1, -1
+; RV64ZBA-NEXT:    add.uw a0, a1, a0
+; RV64ZBA-NEXT:    ret
+;
+; RV64XANDESPERF-LABEL: adduw_m1:
+; RV64XANDESPERF:       # %bb.0:
+; RV64XANDESPERF-NEXT:    li a1, -1
+; RV64XANDESPERF-NEXT:    nds.lea.b.ze a0, a0, a1
+; RV64XANDESPERF-NEXT:    ret
   %a = add i64 %x, 4294967295
   ret i64 %a
 }
@@ -4435,28 +4447,37 @@ define i64 @adduw_m3(i64 %x) {
 ; RV64ZBA-LABEL: adduw_m3:
 ; RV64ZBA:       # %bb.0:
 ; RV64ZBA-NEXT:    li a1, -3
-; RV64ZBA-NEXT:    zext.w a1, a1
-; RV64ZBA-NEXT:    add a0, a0, a1
+; RV64ZBA-NEXT:    add.uw a0, a1, a0
 ; RV64ZBA-NEXT:    ret
 ;
 ; RV64XANDESPERF-LABEL: adduw_m3:
 ; RV64XANDESPERF:       # %bb.0:
-; RV64XANDESPERF-NEXT:    li a1, 1
-; RV64XANDESPERF-NEXT:    slli a1, a1, 32
-; RV64XANDESPERF-NEXT:    addi a1, a1, -3
-; RV64XANDESPERF-NEXT:    add a0, a0, a1
+; RV64XANDESPERF-NEXT:    li a1, -3
+; RV64XANDESPERF-NEXT:    nds.lea.b.ze a0, a0, a1
 ; RV64XANDESPERF-NEXT:    ret
   %a = add i64 %x, 4294967293
   ret i64 %a
 }
 
 define i64 @adduw_3shl30(i64 %x) {
-; CHECK-LABEL: adduw_3shl30:
-; CHECK:       # %bb.0:
-; CHECK-NEXT:    li a1, 3
-; CHECK-NEXT:    slli a1, a1, 30
-; CHECK-NEXT:    add a0, a0, a1
-; CHECK-NEXT:    ret
+; RV64I-LABEL: adduw_3shl30:
+; RV64I:       # %bb.0:
+; RV64I-NEXT:    li a1, 3
+; RV64I-NEXT:    slli a1, a1, 30
+; RV64I-NEXT:    add a0, a0, a1
+; RV64I-NEXT:    ret
+;
+; RV64ZBA-LABEL: adduw_3shl30:
+; RV64ZBA:       # %bb.0:
+; RV64ZBA-NEXT:    lui a1, 786432
+; RV64ZBA-NEXT:    add.uw a0, a1, a0
+; RV64ZBA-NEXT:    ret
+;
+; RV64XANDESPERF-LABEL: adduw_3shl30:
+; RV64XANDESPERF:       # %bb.0:
+; RV64XANDESPERF-NEXT:    lui a1, 786432
+; RV64XANDESPERF-NEXT:    nds.lea.b.ze a0, a0, a1
+; RV64XANDESPERF-NEXT:    ret
   %a = add i64 %x, 3221225472
   ret i64 %a
 }
@@ -4475,19 +4496,16 @@ define i64 @adduw_m3_multiuse(i64 %x, i64 %y) {
 ; RV64ZBA-LABEL: adduw_m3_multiuse:
 ; RV64ZBA:       # %bb.0:
 ; RV64ZBA-NEXT:    li a2, -3
-; RV64ZBA-NEXT:    zext.w a2, a2
-; RV64ZBA-NEXT:    add a0, a0, a2
-; RV64ZBA-NEXT:    add a1, a1, a2
+; RV64ZBA-NEXT:    add.uw a0, a2, a0
+; RV64ZBA-NEXT:    add.uw a1, a2, a1
 ; RV64ZBA-NEXT:    or a0, a0, a1
 ; RV64ZBA-NEXT:    ret
 ;
 ; RV64XANDESPERF-LABEL: adduw_m3_multiuse:
 ; RV64XANDESPERF:       # %bb.0:
-; RV64XANDESPERF-NEXT:    li a2, 1
-; RV64XANDESPERF-NEXT:    slli a2, a2, 32
-; RV64XANDESPERF-NEXT:    addi a2, a2, -3
-; RV64XANDESPERF-NEXT:    add a0, a0, a2
-; RV64XANDESPERF-NEXT:    add a1, a1, a2
+; RV64XANDESPERF-NEXT:    li a2, -3
+; RV64XANDESPERF-NEXT:    nds.lea.b.ze a0, a0, a2
+; RV64XANDESPERF-NEXT:    nds.lea.b.ze a1, a1, a2
 ; RV64XANDESPERF-NEXT:    or a0, a0, a1
 ; RV64XANDESPERF-NEXT:    ret
   %a = add i64 %x, 4294967293

>From 2ef4c91daf431fdff8078b46002f4109d964f547 Mon Sep 17 00:00:00 2001
From: Piotr Fusik <p.fusik at samsung.com>
Date: Mon, 9 Jun 2025 14:21:36 +0200
Subject: [PATCH 3/6] [RISCV][NFC] Refactor duplicate code into
 selectImm64IfCheaper

---
 llvm/lib/Target/RISCV/RISCVISelDAGToDAG.cpp | 54 +++++++++------------
 llvm/lib/Target/RISCV/RISCVISelDAGToDAG.h   |  2 +
 2 files changed, 24 insertions(+), 32 deletions(-)

diff --git a/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.cpp b/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.cpp
index 2c442e760919f..5be03bb33d3f5 100644
--- a/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.cpp
+++ b/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.cpp
@@ -3296,6 +3296,19 @@ bool RISCVDAGToDAGISel::selectSHXADD_UWOp(SDValue N, unsigned ShAmt,
   return false;
 }
 
+bool RISCVDAGToDAGISel::selectImm64IfCheaper(int64_t Imm, int64_t OrigImm,
+                                             SDValue N, SDValue &Val) {
+  int OrigCost = RISCVMatInt::getIntMatCost(APInt(64, OrigImm), 64, *Subtarget,
+                                            /*CompressionCost=*/true);
+  int Cost = RISCVMatInt::getIntMatCost(APInt(64, Imm), 64, *Subtarget,
+                                        /*CompressionCost=*/true);
+  if (OrigCost <= Cost)
+    return false;
+
+  Val = selectImm(CurDAG, SDLoc(N), N->getSimpleValueType(0), Imm, *Subtarget);
+  return true;
+}
+
 bool RISCVDAGToDAGISel::selectZExtImm32(SDValue N, SDValue &Val) {
   if (!isa<ConstantSDNode>(N))
     return false;
@@ -3307,18 +3320,7 @@ bool RISCVDAGToDAGISel::selectZExtImm32(SDValue N, SDValue &Val) {
              [](const SDNode *U) { return U->getOpcode() != ISD::ADD; }))
     return false;
 
-  int64_t LeadingOnesImm = 0xffffffff00000000 | Imm;
-  int OrigImmCost = RISCVMatInt::getIntMatCost(APInt(64, Imm), 64, *Subtarget,
-                                               /*CompressionCost=*/true);
-  int LeadingOnesImmCost =
-      RISCVMatInt::getIntMatCost(APInt(64, LeadingOnesImm), 64, *Subtarget,
-                                 /*CompressionCost=*/true);
-  if (OrigImmCost <= LeadingOnesImmCost)
-    return false;
-
-  Val = selectImm(CurDAG, SDLoc(N), N->getSimpleValueType(0), LeadingOnesImm,
-                  *Subtarget);
-  return true;
+  return selectImm64IfCheaper(0xffffffff00000000 | Imm, Imm, N, Val);
 }
 
 bool RISCVDAGToDAGISel::selectNegImm(SDValue N, SDValue &Val) {
@@ -3344,15 +3346,7 @@ bool RISCVDAGToDAGISel::selectNegImm(SDValue N, SDValue &Val) {
     }
   }
 
-  int OrigImmCost = RISCVMatInt::getIntMatCost(APInt(64, Imm), 64, *Subtarget,
-                                               /*CompressionCost=*/true);
-  int NegImmCost = RISCVMatInt::getIntMatCost(APInt(64, -Imm), 64, *Subtarget,
-                                              /*CompressionCost=*/true);
-  if (OrigImmCost <= NegImmCost)
-    return false;
-
-  Val = selectImm(CurDAG, SDLoc(N), N->getSimpleValueType(0), -Imm, *Subtarget);
-  return true;
+  return selectImm64IfCheaper(-Imm, Imm, N, Val);
 }
 
 bool RISCVDAGToDAGISel::selectInvLogicImm(SDValue N, SDValue &Val) {
@@ -3387,19 +3381,15 @@ bool RISCVDAGToDAGISel::selectInvLogicImm(SDValue N, SDValue &Val) {
     }
   }
 
-  // For 64-bit constants, the instruction sequences get complex,
-  // so we select inverted only if it's cheaper.
-  if (!isInt<32>(Imm)) {
-    int OrigImmCost = RISCVMatInt::getIntMatCost(APInt(64, Imm), 64, *Subtarget,
-                                                 /*CompressionCost=*/true);
-    int NegImmCost = RISCVMatInt::getIntMatCost(APInt(64, ~Imm), 64, *Subtarget,
-                                                /*CompressionCost=*/true);
-    if (OrigImmCost <= NegImmCost)
-      return false;
+  if (isInt<32>(Imm)) {
+    Val =
+        selectImm(CurDAG, SDLoc(N), N->getSimpleValueType(0), ~Imm, *Subtarget);
+    return true;
   }
 
-  Val = selectImm(CurDAG, SDLoc(N), N->getSimpleValueType(0), ~Imm, *Subtarget);
-  return true;
+  // For 64-bit constants, the instruction sequences get complex,
+  // so we select inverted only if it's cheaper.
+  return selectImm64IfCheaper(~Imm, Imm, N, Val);
 }
 
 static bool vectorPseudoHasAllNBitUsers(SDNode *User, unsigned UserOpNo,
diff --git a/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.h b/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.h
index ef99d2317bc72..45e39614f21b8 100644
--- a/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.h
+++ b/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.h
@@ -200,6 +200,8 @@ class RISCVDAGToDAGISel : public SelectionDAGISel {
   bool doPeepholeMergeVVMFold();
   bool doPeepholeNoRegPassThru();
   bool performCombineVMergeAndVOps(SDNode *N);
+  bool selectImm64IfCheaper(int64_t Imm, int64_t OrigImm, SDValue N,
+                            SDValue &Val);
 };
 
 class RISCVDAGToDAGISelLegacy : public SelectionDAGISelLegacy {

>From 5103b5ed86795c672f2a4301dc46a7d47ec16453 Mon Sep 17 00:00:00 2001
From: Piotr Fusik <p.fusik at samsung.com>
Date: Mon, 9 Jun 2025 17:50:40 +0200
Subject: [PATCH 4/6] [RISCV][test] Test "or is add"

---
 llvm/test/CodeGen/RISCV/rv64zba.ll | 13 +++++++++++++
 1 file changed, 13 insertions(+)

diff --git a/llvm/test/CodeGen/RISCV/rv64zba.ll b/llvm/test/CodeGen/RISCV/rv64zba.ll
index 5668ec1f230c2..06bd28f763fa1 100644
--- a/llvm/test/CodeGen/RISCV/rv64zba.ll
+++ b/llvm/test/CodeGen/RISCV/rv64zba.ll
@@ -4548,3 +4548,16 @@ define i64 @add_or_m3(i64 %x) {
   %c = add i64 %a, %o
   ret i64 %c
 }
+
+define i64 @append_32ones(i64 %x) {
+; CHECK-LABEL: append_32ones:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    slli a0, a0, 32
+; CHECK-NEXT:    li a1, -1
+; CHECK-NEXT:    srli a1, a1, 32
+; CHECK-NEXT:    or a0, a0, a1
+; CHECK-NEXT:    ret
+  %s = shl i64 %x, 32
+  %o = or i64 %s, 4294967295
+  ret i64 %o
+}

>From ebf3be13bd7ac29105236c40e824115aaa7a4a6b Mon Sep 17 00:00:00 2001
From: Piotr Fusik <p.fusik at samsung.com>
Date: Mon, 9 Jun 2025 18:07:23 +0200
Subject: [PATCH 5/6] [RISCV] Accept or_is_add

---
 llvm/lib/Target/RISCV/RISCVISelDAGToDAG.cpp | 23 +++++++++++++--
 llvm/lib/Target/RISCV/RISCVISelDAGToDAG.h   |  1 +
 llvm/test/CodeGen/RISCV/rv64zba.ll          | 31 +++++++++++++++------
 3 files changed, 44 insertions(+), 11 deletions(-)

diff --git a/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.cpp b/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.cpp
index 5be03bb33d3f5..f0e80a7098702 100644
--- a/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.cpp
+++ b/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.cpp
@@ -3296,6 +3296,14 @@ bool RISCVDAGToDAGISel::selectSHXADD_UWOp(SDValue N, unsigned ShAmt,
   return false;
 }
 
+bool RISCVDAGToDAGISel::orIsAdd(const SDNode *N) const {
+  if (N->getFlags().hasDisjoint())
+    return true;
+  KnownBits Known0 = CurDAG->computeKnownBits(N->getOperand(0), 0);
+  KnownBits Known1 = CurDAG->computeKnownBits(N->getOperand(1), 0);
+  return KnownBits::haveNoCommonBitsSet(Known0, Known1);
+}
+
 bool RISCVDAGToDAGISel::selectImm64IfCheaper(int64_t Imm, int64_t OrigImm,
                                              SDValue N, SDValue &Val) {
   int OrigCost = RISCVMatInt::getIntMatCost(APInt(64, OrigImm), 64, *Subtarget,
@@ -3316,9 +3324,18 @@ bool RISCVDAGToDAGISel::selectZExtImm32(SDValue N, SDValue &Val) {
   if ((Imm >> 31) != 1)
     return false;
 
-  if (any_of(N->users(),
-             [](const SDNode *U) { return U->getOpcode() != ISD::ADD; }))
-    return false;
+  for (const SDNode *U : N->users()) {
+    switch (U->getOpcode()) {
+    case ISD::ADD:
+      break;
+    case ISD::OR:
+      if (orIsAdd(U))
+        break;
+      return false;
+    default:
+      return false;
+    }
+  }
 
   return selectImm64IfCheaper(0xffffffff00000000 | Imm, Imm, N, Val);
 }
diff --git a/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.h b/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.h
index 45e39614f21b8..9b16da2deffec 100644
--- a/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.h
+++ b/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.h
@@ -122,6 +122,7 @@ class RISCVDAGToDAGISel : public SelectionDAGISel {
   bool selectNegImm(SDValue N, SDValue &Val);
   bool selectInvLogicImm(SDValue N, SDValue &Val);
 
+  bool orIsAdd(const SDNode *Node) const;
   bool hasAllNBitUsers(SDNode *Node, unsigned Bits,
                        const unsigned Depth = 0) const;
   bool hasAllBUsers(SDNode *Node) const { return hasAllNBitUsers(Node, 8); }
diff --git a/llvm/test/CodeGen/RISCV/rv64zba.ll b/llvm/test/CodeGen/RISCV/rv64zba.ll
index 06bd28f763fa1..fdff4a39932b9 100644
--- a/llvm/test/CodeGen/RISCV/rv64zba.ll
+++ b/llvm/test/CodeGen/RISCV/rv64zba.ll
@@ -4260,10 +4260,11 @@ define i64 @add_u32simm32_zextw(i64 %x) nounwind {
 ;
 ; RV64XANDESPERF-LABEL: add_u32simm32_zextw:
 ; RV64XANDESPERF:       # %bb.0: # %entry
+; RV64XANDESPERF-NEXT:    li a1, -2
+; RV64XANDESPERF-NEXT:    nds.lea.b.ze a0, a0, a1
 ; RV64XANDESPERF-NEXT:    li a1, 1
 ; RV64XANDESPERF-NEXT:    slli a1, a1, 32
 ; RV64XANDESPERF-NEXT:    addi a1, a1, -2
-; RV64XANDESPERF-NEXT:    add a0, a0, a1
 ; RV64XANDESPERF-NEXT:    addi a1, a1, 1
 ; RV64XANDESPERF-NEXT:    and a0, a0, a1
 ; RV64XANDESPERF-NEXT:    ret
@@ -4550,13 +4551,27 @@ define i64 @add_or_m3(i64 %x) {
 }
 
 define i64 @append_32ones(i64 %x) {
-; CHECK-LABEL: append_32ones:
-; CHECK:       # %bb.0:
-; CHECK-NEXT:    slli a0, a0, 32
-; CHECK-NEXT:    li a1, -1
-; CHECK-NEXT:    srli a1, a1, 32
-; CHECK-NEXT:    or a0, a0, a1
-; CHECK-NEXT:    ret
+; RV64I-LABEL: append_32ones:
+; RV64I:       # %bb.0:
+; RV64I-NEXT:    slli a0, a0, 32
+; RV64I-NEXT:    li a1, -1
+; RV64I-NEXT:    srli a1, a1, 32
+; RV64I-NEXT:    or a0, a0, a1
+; RV64I-NEXT:    ret
+;
+; RV64ZBA-LABEL: append_32ones:
+; RV64ZBA:       # %bb.0:
+; RV64ZBA-NEXT:    slli a0, a0, 32
+; RV64ZBA-NEXT:    li a1, -1
+; RV64ZBA-NEXT:    add.uw a0, a1, a0
+; RV64ZBA-NEXT:    ret
+;
+; RV64XANDESPERF-LABEL: append_32ones:
+; RV64XANDESPERF:       # %bb.0:
+; RV64XANDESPERF-NEXT:    slli a0, a0, 32
+; RV64XANDESPERF-NEXT:    li a1, -1
+; RV64XANDESPERF-NEXT:    nds.lea.b.ze a0, a0, a1
+; RV64XANDESPERF-NEXT:    ret
   %s = shl i64 %x, 32
   %o = or i64 %s, 4294967295
   ret i64 %o

>From 8ae889e7ceb4edb1c70854bafc0c46b342e14bfa Mon Sep 17 00:00:00 2001
From: Piotr Fusik <p.fusik at samsung.com>
Date: Mon, 9 Jun 2025 18:12:32 +0200
Subject: [PATCH 6/6] [RISCV][NFC] Refactor duplicate code with orIsAdd

---
 llvm/lib/Target/RISCV/RISCVInstrInfo.td            | 6 +-----
 llvm/lib/Target/RISCV/RISCVInstrInfoVVLPatterns.td | 6 +-----
 2 files changed, 2 insertions(+), 10 deletions(-)

diff --git a/llvm/lib/Target/RISCV/RISCVInstrInfo.td b/llvm/lib/Target/RISCV/RISCVInstrInfo.td
index b18a550b01912..0d1ff09f4da3a 100644
--- a/llvm/lib/Target/RISCV/RISCVInstrInfo.td
+++ b/llvm/lib/Target/RISCV/RISCVInstrInfo.td
@@ -1445,11 +1445,7 @@ def : PatGprUimmLog2XLen<sra, SRAI>;
 // Select 'or' as ADDI if the immediate bits are known to be 0 in $rs1. This
 // can improve compressibility.
 def or_is_add : PatFrag<(ops node:$lhs, node:$rhs), (or node:$lhs, node:$rhs),[{
-  if (N->getFlags().hasDisjoint())
-    return true;
-  KnownBits Known0 = CurDAG->computeKnownBits(N->getOperand(0), 0);
-  KnownBits Known1 = CurDAG->computeKnownBits(N->getOperand(1), 0);
-  return KnownBits::haveNoCommonBitsSet(Known0, Known1);
+  return orIsAdd(N);
 }]>;
 def : PatGprSimm12<or_is_add, ADDI>;
 
diff --git a/llvm/lib/Target/RISCV/RISCVInstrInfoVVLPatterns.td b/llvm/lib/Target/RISCV/RISCVInstrInfoVVLPatterns.td
index 1da4adc8c3125..b54c2b042b4dd 100644
--- a/llvm/lib/Target/RISCV/RISCVInstrInfoVVLPatterns.td
+++ b/llvm/lib/Target/RISCV/RISCVInstrInfoVVLPatterns.td
@@ -653,11 +653,7 @@ let HasOneUse = 1 in {
                                                node:$E),
                                           (riscv_or_vl node:$A, node:$B, node:$C,
                                                        node:$D, node:$E), [{
-    if (N->getFlags().hasDisjoint())
-      return true;
-    KnownBits Known0 = CurDAG->computeKnownBits(N->getOperand(0), 0);
-    KnownBits Known1 = CurDAG->computeKnownBits(N->getOperand(1), 0);
-    return KnownBits::haveNoCommonBitsSet(Known0, Known1);
+    return orIsAdd(N);
   }]>;
   def riscv_sub_vl_oneuse : PatFrag<(ops node:$A, node:$B, node:$C, node:$D,
                                          node:$E),



More information about the llvm-commits mailing list