[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