[llvm] b3a1838 - [AArch64] Suboptimal assembly for u128 x * x (#214796)
via llvm-commits
llvm-commits at lists.llvm.org
Wed Aug 26 07:56:00 PDT 2026
Author: Durgesh Nandan Mohanty
Date: 2026-08-26T15:55:54+01:00
New Revision: b3a1838a5851d3c0e9371a0484e51d5c82557789
URL: https://github.com/llvm/llvm-project/commit/b3a1838a5851d3c0e9371a0484e51d5c82557789
DIFF: https://github.com/llvm/llvm-project/commit/b3a1838a5851d3c0e9371a0484e51d5c82557789.diff
LOG: [AArch64] Suboptimal assembly for u128 x * x (#214796)
This PR optimizes the AArch64 backend for 128-bit integer squaring
(`u128 x * x`).
It updates the instruction selection logic to combine `(A + B) + B` into
`A + (B << 1)`. This allows the compiler to emit a single, optimal `add
... lsl #1` instruction instead of multiple separate `add` instructions.
A baseline test was added in the first commit, and the optimization is
provided in the second commit to clearly highlight the codegen
improvements.
Fixes #213775
Added:
llvm/test/CodeGen/AArch64/u128-square.ll
Modified:
llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
llvm/test/CodeGen/AArch64/pr72777.ll
llvm/test/CodeGen/AArch64/reassocmls.ll
Removed:
################################################################################
diff --git a/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp b/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
index b6878d979cd99..e5c419c42fd2c 100644
--- a/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
+++ b/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
@@ -24547,7 +24547,35 @@ static SDValue performSubNegAndOneCombine(SDNode *N, SelectionDAG &DAG) {
SDLoc DL(N);
return DAG.getSetCC(DL, VT, And, DAG.getConstant(0, DL, VT), ISD::SETNE);
}
+static SDValue performAddAddCombine(SDNode *N, SelectionDAG &DAG) {
+ if (N->getOpcode() != ISD::ADD)
+ return SDValue();
+
+ EVT VT = N->getValueType(0);
+
+ if (!VT.isScalarInteger())
+ return SDValue();
+
+ SDValue Op0 = N->getOperand(0);
+ SDValue Op1 = N->getOperand(1);
+ SDValue A, B;
+
+ if (Op0.getOpcode() == ISD::ADD && Op0.hasOneUse() &&
+ (Op0.getOperand(0) == Op1 || Op0.getOperand(1) == Op1)) {
+ A = (Op0.getOperand(0) == Op1) ? Op0.getOperand(1) : Op0.getOperand(0);
+ B = Op1;
+ } else if (Op1.getOpcode() == ISD::ADD && Op1.hasOneUse() &&
+ (Op1.getOperand(0) == Op0 || Op1.getOperand(1) == Op0)) {
+ A = (Op1.getOperand(0) == Op0) ? Op1.getOperand(1) : Op1.getOperand(0);
+ B = Op0;
+ } else {
+ return SDValue();
+ }
+ SDLoc DL(N);
+ SDValue ShiftB = DAG.getNode(ISD::SHL, DL, VT, B, DAG.getConstant(1, DL, VT));
+ return DAG.getNode(ISD::ADD, DL, VT, A, ShiftB);
+}
// Fold ADD(SBC(Y, 0, W), C) -> SBC(Y, -C, W)
// SBC(Y, 0, W) = Y - 0 - ~carry = Y + carry - 1
// Adding C: Y + carry - 1 + C = Y - (-C) - ~carry = SBC(Y, -C, W)
@@ -24576,6 +24604,8 @@ static SDValue performAddWithSBCCombine(SDNode *N, SelectionDAG &DAG) {
static SDValue performAddSubCombine(SDNode *N,
TargetLowering::DAGCombinerInfo &DCI) {
// Try to change sum of two reductions.
+ if (SDValue Val = performAddAddCombine(N, DCI.DAG))
+ return Val;
if (SDValue Val = performAddUADDVCombine(N, DCI.DAG))
return Val;
if (SDValue Val = performAddDotCombine(N, DCI.DAG))
diff --git a/llvm/test/CodeGen/AArch64/pr72777.ll b/llvm/test/CodeGen/AArch64/pr72777.ll
index fa9f82f8c93c2..27ba1302ffd0c 100644
--- a/llvm/test/CodeGen/AArch64/pr72777.ll
+++ b/llvm/test/CodeGen/AArch64/pr72777.ll
@@ -5,11 +5,10 @@ define i64 @f(i64 %0, i64 %1) {
; CHECK-LABEL: f:
; CHECK: // %bb.0:
; CHECK-NEXT: orr x8, x1, #0x1
-; CHECK-NEXT: add x9, x0, x0
; CHECK-NEXT: mov x10, #-9223372036854775808 // =0x8000000000000000
-; CHECK-NEXT: adds x8, x8, x9
-; CHECK-NEXT: lsl x9, x8, #1
+; CHECK-NEXT: adds x8, x8, x0, lsl #1
; CHECK-NEXT: cinv x10, x10, pl
+; CHECK-NEXT: lsl x9, x8, #1
; CHECK-NEXT: cmp x8, x9, asr #1
; CHECK-NEXT: csel x0, x10, x9, ne
; CHECK-NEXT: ret
diff --git a/llvm/test/CodeGen/AArch64/reassocmls.ll b/llvm/test/CodeGen/AArch64/reassocmls.ll
index c199f832c57ac..ca4393b0b8387 100644
--- a/llvm/test/CodeGen/AArch64/reassocmls.ll
+++ b/llvm/test/CodeGen/AArch64/reassocmls.ll
@@ -174,12 +174,19 @@ define i64 @mla_i64_uses(i64 %a, i64 %b, i64 %c, i64 %d, i64 %e) {
}
define i64 @mla_i64_mul(i64 %a, i64 %b, i64 %c, i64 %d, i64 %e) {
-; CHECK-LABEL: mla_i64_mul:
-; CHECK: // %bb.0:
-; CHECK-NEXT: mul x8, x2, x1
-; CHECK-NEXT: madd x9, x4, x3, x8
-; CHECK-NEXT: add x0, x8, x9
-; CHECK-NEXT: ret
+; CHECK-SD-LABEL: mla_i64_mul:
+; CHECK-SD: // %bb.0:
+; CHECK-SD-NEXT: mul x8, x4, x3
+; CHECK-SD-NEXT: mul x9, x2, x1
+; CHECK-SD-NEXT: add x0, x8, x9, lsl #1
+; CHECK-SD-NEXT: ret
+;
+; CHECK-GI-LABEL: mla_i64_mul:
+; CHECK-GI: // %bb.0:
+; CHECK-GI-NEXT: mul x8, x2, x1
+; CHECK-GI-NEXT: madd x9, x4, x3, x8
+; CHECK-GI-NEXT: add x0, x8, x9
+; CHECK-GI-NEXT: ret
%m1.neg = mul i64 %c, %b
%m2.neg = mul i64 %e, %d
%reass.add = add i64 %m2.neg, %m1.neg
diff --git a/llvm/test/CodeGen/AArch64/u128-square.ll b/llvm/test/CodeGen/AArch64/u128-square.ll
new file mode 100644
index 0000000000000..9e8504c49ad48
--- /dev/null
+++ b/llvm/test/CodeGen/AArch64/u128-square.ll
@@ -0,0 +1,15 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 6
+; RUN: llc -mtriple=aarch64 -verify-machineinstrs %s -o - | FileCheck %s
+
+define i128 @square(i128 %x) {
+; CHECK-LABEL: square:
+; CHECK: // %bb.0: // %entry
+; CHECK-NEXT: mul x8, x0, x1
+; CHECK-NEXT: umulh x9, x0, x0
+; CHECK-NEXT: mul x0, x0, x0
+; CHECK-NEXT: add x1, x9, x8, lsl #1
+; CHECK-NEXT: ret
+entry:
+ %mul = mul i128 %x, %x
+ ret i128 %mul
+}
\ No newline at end of file
More information about the llvm-commits
mailing list