[llvm] [RISCV] Rewrite ADD to SUB to reuse a materialized negated constant (PR #221027)

Piotr Fusik via llvm-commits llvm-commits at lists.llvm.org
Mon Sep 7 14:11:31 PDT 2026


================
@@ -128,6 +128,77 @@ void RISCVDAGToDAGISel::PreprocessISelDAG() {
                                TrueMask, VLMAX);
       break;
     }
+    case ISD::ADD: {
+      // Turn (add X, C) into (sub X, -C) when a constant node holding -C
+      // already exists in the DAG, so both share one materialization. Do this
+      // before selection, while both are still ConstantSDNodes: by selection
+      // time -C may already have been selected into instructions.
+      //
+      // ADD is commutative, but getNode canonicalizes constants to the RHS, so
+      // the constant is always operand 1.
+      auto *N1C = dyn_cast<ConstantSDNode>(N->getOperand(1));
+      if (!N1C)
+        break;
+      MVT VT = N->getSimpleValueType(0);
+      if (VT != Subtarget->getXLenVT())
+        break;
+      int64_t Imm = N1C->getSExtValue();
+      // Only worthwhile for wide constants: values that fit in 32 bits take at
+      // most two instructions to materialize, matching the threshold used by
+      // selectNegImm. Skip INT64_MIN too, whose negation is itself.
+      if (isInt<32>(Imm) || Imm == INT64_MIN)
+        break;
+      // Look for existing constant nodes for Imm and -Imm, and whether either
+      // has a user other than an ADD, i.e. is materialized regardless of this
+      // fold.
+      bool NegExists = false, NegAnchored = false, PosAnchored = false;
+      for (const SDNode &Node : CurDAG->allnodes()) {
+        auto *C = dyn_cast<ConstantSDNode>(&Node);
+        if (!C || C->getSimpleValueType(0) != VT)
+          continue;
+        int64_t V = C->getSExtValue();
+        if (V != Imm && V != -Imm)
+          continue;
+        bool NonAddUser = any_of(Node.users(), [](const SDNode *U) {
----------------
pfusik wrote:

Are constant values unique? If so, `NonAddUser` runs at most twice.
Still, we could do the positive checks on `N1C`, break early, and break early here on the negated constant.

https://github.com/llvm/llvm-project/pull/221027


More information about the llvm-commits mailing list