[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