[llvm] [AArch64] Optimize vector multiplications by certain constants for v2i64 (PR #183827)
David Green via llvm-commits
llvm-commits at lists.llvm.org
Wed Mar 18 02:17:06 PDT 2026
================
@@ -5919,6 +5919,75 @@ static unsigned selectUmullSmull(SDValue &N0, SDValue &N1, SelectionDAG &DAG,
return 0;
}
+// Transform mul<v2i64, splat(const)> into a SHL and ADD/SUB
+// (1) multiply-by-(power-of-2 +/- 1) into shift and add/sub.
+// mul x, (2^N + 1) --> add (shl x, N), x
+// mul x, (2^N - 1) --> sub (shl x, N), x
+// Examples: x * 33 --> (x << 5) + x
+// x * 15 --> (x << 4) - x
+// x * -33 --> -((x << 5) + x)
+// x * -15 --> -((x << 4) - x) ; this reduces --> x - (x << 4)
+// (2) multiply-by-(power-of-2 +/- power-of-2) into shifts and add/sub.
+// mul x, (2^N + 2^M) --> (add (shl x, N), (shl x, M))
+// mul x, (2^N - 2^M) --> (sub (shl x, N), (shl x, M))
+// Examples: x * 0x8800 --> (x << 15) + (x << 11)
+// x * 0xf800 --> (x << 16) - (x << 11)
+// x * -0x8800 --> -((x << 15) + (x << 11))
+// x * -0xf800 --> -((x << 16) - (x << 11)) ; (x << 11) - (x << 16)
+static SDValue convertMulToShlAdd(SDNode *N, SelectionDAG &DAG) {
+ const SDNode *Operand = N->getOperand(1).getNode();
+ APInt SplatValue;
+
+ // Not a constant splat so should just stay as a multiplication operation
+ if (!ISD::isConstantSplatVector(Operand, SplatValue) ||
+ !SplatValue.getBoolValue())
+ return SDValue();
+
+ bool IsNegative = SplatValue.isNegative();
+ SplatValue = SplatValue.abs();
+ // Placeholder for MathOp
+ unsigned MathOp = ISD::DELETED_NODE;
+ // The constant `2` should be treated as (2^0 + 1).
+ unsigned TZeros = SplatValue == 2 ? 0 : SplatValue.countr_zero();
+
+ // Shift the splat value by all the zeros , this won't affect the parrity
+ // this will help us find the first and second multiple to use.
+ SplatValue.lshrInPlace(TZeros);
+
+ if ((SplatValue - 1).isPowerOf2())
+ MathOp = ISD::ADD;
+ else if ((SplatValue + 1).isPowerOf2())
+ MathOp = ISD::SUB;
+
+ // If the constant is not (2^n + 1) or (2^n - 1), it would require
+ // more than one addition/subtraction. For v2i64, the cost of
+ // multiple vector adds/shifts often exceeds the cost of
+ // scalarization (moving to GPRs to use a single MUL).
+ if (MathOp != ISD::DELETED_NODE) {
+ SDLoc DL(N);
+ EVT VT = N->getValueType(0);
+ SDValue LHS = N->getOperand(0);
+
+ unsigned ShiftAmt = MathOp == ISD::ADD ? (SplatValue - 1).logBase2()
+ : (SplatValue + 1).logBase2();
+ ShiftAmt += TZeros;
+
+ // assert(ShiftAmt < BitWidth &&
+ // "multiply-by-constant generated out of bounds shift");
----------------
davemgreen wrote:
Sometimes these edge cases only come up in very complex cases, where normal simplification and canonicalization doesn't happen. I would not expect to see a all zeros multiply in DAG, but it can be good to add checks in case they do and at least have tests for cases like -1.
https://github.com/llvm/llvm-project/pull/183827
More information about the llvm-commits
mailing list