[llvm] [RISCV] Select (add x, C) -> (sub x, -C) if -C cheaper to materialize (PR #137309)

Piotr Fusik via llvm-commits llvm-commits at lists.llvm.org
Fri Apr 25 09:49:30 PDT 2025


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

>From 29b5e48f6bbfe3fec83d1dfb2935592c8df3b00c Mon Sep 17 00:00:00 2001
From: Piotr Fusik <p.fusik at samsung.com>
Date: Fri, 25 Apr 2025 12:28:45 +0200
Subject: [PATCH 1/3] [RISCV][test] Add (add x, C) -> (sub x, -C) tests

---
 llvm/test/CodeGen/RISCV/add-imm64-to-sub.ll | 57 +++++++++++++++++++++
 1 file changed, 57 insertions(+)
 create mode 100644 llvm/test/CodeGen/RISCV/add-imm64-to-sub.ll

diff --git a/llvm/test/CodeGen/RISCV/add-imm64-to-sub.ll b/llvm/test/CodeGen/RISCV/add-imm64-to-sub.ll
new file mode 100644
index 0000000000000..4f6555393eb03
--- /dev/null
+++ b/llvm/test/CodeGen/RISCV/add-imm64-to-sub.ll
@@ -0,0 +1,57 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 5
+; RUN: llc -mtriple=riscv64 < %s | FileCheck %s --check-prefixes=CHECK,NOZBS
+; RUN: llc -mtriple=riscv64 -mattr=+zbs < %s | FileCheck %s --check-prefixes=CHECK,ZBS
+
+define i64 @add_b31(i64 %x) {
+; NOZBS-LABEL: add_b31:
+; NOZBS:       # %bb.0:
+; NOZBS-NEXT:    li a1, 1
+; NOZBS-NEXT:    slli a1, a1, 31
+; NOZBS-NEXT:    add a0, a0, a1
+; NOZBS-NEXT:    ret
+;
+; ZBS-LABEL: add_b31:
+; ZBS:       # %bb.0:
+; ZBS-NEXT:    bseti a1, zero, 31
+; ZBS-NEXT:    add a0, a0, a1
+; ZBS-NEXT:    ret
+  %add = add i64 %x, 2147483648
+  ret i64 %add
+}
+
+define i64 @add_b32(i64 %x) {
+; CHECK-LABEL: add_b32:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    li a1, -1
+; CHECK-NEXT:    slli a1, a1, 32
+; CHECK-NEXT:    add a0, a0, a1
+; CHECK-NEXT:    ret
+  %add = add i64 %x, -4294967296
+  ret i64 %add
+}
+
+define i64 @sub_0xffffffffff(i64 %x) {
+; CHECK-LABEL: sub_0xffffffffff:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    li a1, -1
+; CHECK-NEXT:    slli a1, a1, 40
+; CHECK-NEXT:    addi a1, a1, 1
+; CHECK-NEXT:    add a0, a0, a1
+; CHECK-NEXT:    ret
+  %sub = sub i64 %x, 1099511627775
+  ret i64 %sub
+}
+
+define i64 @add_multiuse(i64 %x) {
+; CHECK-LABEL: add_multiuse:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    li a1, -1
+; CHECK-NEXT:    slli a1, a1, 40
+; CHECK-NEXT:    addi a1, a1, 1
+; CHECK-NEXT:    add a0, a0, a1
+; CHECK-NEXT:    and a0, a0, a1
+; CHECK-NEXT:    ret
+  %add = add i64 %x, -1099511627775
+  %xor = and i64 %add, -1099511627775
+  ret i64 %xor
+}

>From 7e3540d42dad3226983f011db342a903f4558085 Mon Sep 17 00:00:00 2001
From: Piotr Fusik <p.fusik at samsung.com>
Date: Fri, 25 Apr 2025 12:34:44 +0200
Subject: [PATCH 2/3] [RISCV] Select (add x, C) -> (sub x, -C) if -C cheaper to
 materialize

RV64 only. For 32-bit constants, a negated constant is never cheaper.

This change is similar to how #120221 selects inverted bitwise instructions.
---
 llvm/lib/Target/RISCV/RISCVISelDAGToDAG.cpp | 17 +++++++++++++
 llvm/lib/Target/RISCV/RISCVISelDAGToDAG.h   |  1 +
 llvm/lib/Target/RISCV/RISCVInstrInfo.td     |  5 ++++
 llvm/test/CodeGen/RISCV/add-imm64-to-sub.ll | 28 ++++++++++++---------
 4 files changed, 39 insertions(+), 12 deletions(-)

diff --git a/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.cpp b/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.cpp
index ad77106d386c9..86bdb4c7fd24c 100644
--- a/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.cpp
+++ b/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.cpp
@@ -3206,6 +3206,23 @@ bool RISCVDAGToDAGISel::selectSHXADD_UWOp(SDValue N, unsigned ShAmt,
   return false;
 }
 
+bool RISCVDAGToDAGISel::selectNegImm(SDValue N, SDValue &Val) {
+  if (!isa<ConstantSDNode>(N) || !N.hasOneUse())
+    return false;
+  int64_t Imm = cast<ConstantSDNode>(N)->getSExtValue();
+  if (isInt<32>(Imm))
+    return false;
+  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;
+}
+
 bool RISCVDAGToDAGISel::selectInvLogicImm(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 82a47a9a52501..0672b6ad8829e 100644
--- a/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.h
+++ b/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.h
@@ -120,6 +120,7 @@ class RISCVDAGToDAGISel : public SelectionDAGISel {
     return selectSHXADD_UWOp(N, ShAmt, Val);
   }
 
+  bool selectNegImm(SDValue N, SDValue &Val);
   bool selectInvLogicImm(SDValue N, SDValue &Val);
 
   bool hasAllNBitUsers(SDNode *Node, unsigned Bits,
diff --git a/llvm/lib/Target/RISCV/RISCVInstrInfo.td b/llvm/lib/Target/RISCV/RISCVInstrInfo.td
index baf2bae367df1..5431e554f5df6 100644
--- a/llvm/lib/Target/RISCV/RISCVInstrInfo.td
+++ b/llvm/lib/Target/RISCV/RISCVInstrInfo.td
@@ -2120,11 +2120,16 @@ def : Pat<(XLenVT (add GPR:$rs1, immop_oneuse<AddiPair>:$rs2)),
           (ADDI (XLenVT (ADDI GPR:$rs1, (AddiPairImmLarge imm:$rs2))),
                 (AddiPairImmSmall imm:$rs2))>;
 
+def negImm : ComplexPattern<XLenVT, 1, "selectNegImm", [], [], 0>;
+
 let Predicates = [IsRV64] in {
 // Select W instructions if only the lower 32-bits of the result are used.
 def : Pat<(binop_allwusers<add> GPR:$rs1, immop_oneuse<AddiPair>:$rs2),
           (ADDIW (i64 (ADDIW GPR:$rs1, (AddiPairImmLarge imm:$rs2))),
                  (AddiPairImmSmall imm:$rs2))>;
+
+// Select SUB if the negated constant is cheaper to materialize.
+def : Pat<(XLenVT (add GPR:$rs1, negImm:$rs2)), (SUB GPR:$rs1, negImm:$rs2)>;
 }
 
 //===----------------------------------------------------------------------===//
diff --git a/llvm/test/CodeGen/RISCV/add-imm64-to-sub.ll b/llvm/test/CodeGen/RISCV/add-imm64-to-sub.ll
index 4f6555393eb03..ddcf4e1a8aa77 100644
--- a/llvm/test/CodeGen/RISCV/add-imm64-to-sub.ll
+++ b/llvm/test/CodeGen/RISCV/add-imm64-to-sub.ll
@@ -5,9 +5,8 @@
 define i64 @add_b31(i64 %x) {
 ; NOZBS-LABEL: add_b31:
 ; NOZBS:       # %bb.0:
-; NOZBS-NEXT:    li a1, 1
-; NOZBS-NEXT:    slli a1, a1, 31
-; NOZBS-NEXT:    add a0, a0, a1
+; NOZBS-NEXT:    lui a1, 524288
+; NOZBS-NEXT:    sub a0, a0, a1
 ; NOZBS-NEXT:    ret
 ;
 ; ZBS-LABEL: add_b31:
@@ -20,12 +19,18 @@ define i64 @add_b31(i64 %x) {
 }
 
 define i64 @add_b32(i64 %x) {
-; CHECK-LABEL: add_b32:
-; CHECK:       # %bb.0:
-; CHECK-NEXT:    li a1, -1
-; CHECK-NEXT:    slli a1, a1, 32
-; CHECK-NEXT:    add a0, a0, a1
-; CHECK-NEXT:    ret
+; NOZBS-LABEL: add_b32:
+; NOZBS:       # %bb.0:
+; NOZBS-NEXT:    li a1, -1
+; NOZBS-NEXT:    slli a1, a1, 32
+; NOZBS-NEXT:    add a0, a0, a1
+; NOZBS-NEXT:    ret
+;
+; ZBS-LABEL: add_b32:
+; ZBS:       # %bb.0:
+; ZBS-NEXT:    bseti a1, zero, 32
+; ZBS-NEXT:    sub a0, a0, a1
+; ZBS-NEXT:    ret
   %add = add i64 %x, -4294967296
   ret i64 %add
 }
@@ -34,9 +39,8 @@ define i64 @sub_0xffffffffff(i64 %x) {
 ; CHECK-LABEL: sub_0xffffffffff:
 ; CHECK:       # %bb.0:
 ; CHECK-NEXT:    li a1, -1
-; CHECK-NEXT:    slli a1, a1, 40
-; CHECK-NEXT:    addi a1, a1, 1
-; CHECK-NEXT:    add a0, a0, a1
+; CHECK-NEXT:    srli a1, a1, 24
+; CHECK-NEXT:    sub a0, a0, a1
 ; CHECK-NEXT:    ret
   %sub = sub i64 %x, 1099511627775
   ret i64 %sub

>From 1f51e372febfb8fc2e1976e0e65ddbab9c9f57b8 Mon Sep 17 00:00:00 2001
From: Piotr Fusik <p.fusik at samsung.com>
Date: Fri, 25 Apr 2025 18:48:52 +0200
Subject: [PATCH 3/3] [RISCV] XLenVT -> i64

---
 llvm/lib/Target/RISCV/RISCVInstrInfo.td | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/llvm/lib/Target/RISCV/RISCVInstrInfo.td b/llvm/lib/Target/RISCV/RISCVInstrInfo.td
index 5431e554f5df6..6e6877079eac3 100644
--- a/llvm/lib/Target/RISCV/RISCVInstrInfo.td
+++ b/llvm/lib/Target/RISCV/RISCVInstrInfo.td
@@ -2120,7 +2120,7 @@ def : Pat<(XLenVT (add GPR:$rs1, immop_oneuse<AddiPair>:$rs2)),
           (ADDI (XLenVT (ADDI GPR:$rs1, (AddiPairImmLarge imm:$rs2))),
                 (AddiPairImmSmall imm:$rs2))>;
 
-def negImm : ComplexPattern<XLenVT, 1, "selectNegImm", [], [], 0>;
+def negImm : ComplexPattern<i64, 1, "selectNegImm", [], [], 0>;
 
 let Predicates = [IsRV64] in {
 // Select W instructions if only the lower 32-bits of the result are used.
@@ -2129,7 +2129,7 @@ def : Pat<(binop_allwusers<add> GPR:$rs1, immop_oneuse<AddiPair>:$rs2),
                  (AddiPairImmSmall imm:$rs2))>;
 
 // Select SUB if the negated constant is cheaper to materialize.
-def : Pat<(XLenVT (add GPR:$rs1, negImm:$rs2)), (SUB GPR:$rs1, negImm:$rs2)>;
+def : Pat<(i64 (add GPR:$rs1, negImm:$rs2)), (SUB GPR:$rs1, negImm:$rs2)>;
 }
 
 //===----------------------------------------------------------------------===//



More information about the llvm-commits mailing list