[llvm] [AArch64][SVE] add missing instcombine x+1 -> x (PR #201851)

Tomas Matheson via llvm-commits llvm-commits at lists.llvm.org
Tue Jun 9 07:47:33 PDT 2026


https://github.com/tommat01 updated https://github.com/llvm/llvm-project/pull/201851

>From 5402aa2c26b5318e562e18eed44ed49b12890a2a Mon Sep 17 00:00:00 2001
From: Tomas Matheson <tomas.matheson at arm.com>
Date: Tue, 2 Jun 2026 16:35:23 +0100
Subject: [PATCH] [AArch64][SVE] add missing instcombine x+1 -> x

Split out from #198566
---
 .../AArch64/AArch64TargetTransformInfo.cpp    |  30 ++++++
 .../AArch64/sve-intrinsic-mla-one.ll          | 101 ++++++++++++++++++
 2 files changed, 131 insertions(+)
 create mode 100644 llvm/test/Transforms/InstCombine/AArch64/sve-intrinsic-mla-one.ll

diff --git a/llvm/lib/Target/AArch64/AArch64TargetTransformInfo.cpp b/llvm/lib/Target/AArch64/AArch64TargetTransformInfo.cpp
index 730bec428a38e..f39711f5bd4d7 100644
--- a/llvm/lib/Target/AArch64/AArch64TargetTransformInfo.cpp
+++ b/llvm/lib/Target/AArch64/AArch64TargetTransformInfo.cpp
@@ -2511,6 +2511,33 @@ instCombineSVEVectorBinOp(InstCombiner &IC, IntrinsicInst &II) {
   return IC.replaceInstUsesWith(II, BinOp);
 }
 
+static std::optional<Instruction *> instCombineSVEVectorMla(InstCombiner &IC,
+                                                            IntrinsicInst &II) {
+  bool InactiveLanesAreUndefined =
+      II.getIntrinsicID() == Intrinsic::aarch64_sve_mla_u;
+  Value *Pred = II.getOperand(0);
+  if (!InactiveLanesAreUndefined && !isAllActivePredicate(Pred))
+    return std::nullopt;
+
+  Value *Acc = II.getArgOperand(1);
+  Value *MulOp0 = II.getArgOperand(2);
+  Value *MulOp1 = II.getArgOperand(3);
+
+  // For all-active predicates, mla(acc, x, 1) is add(acc, x) and
+  // mla(acc, x, -1) is sub(acc, x). For mla_u,
+  // inactive lanes are undefined, so it is also valid to drop the predicate.
+  if (match(MulOp0, m_One()))
+    return IC.replaceInstUsesWith(II, IC.Builder.CreateAdd(Acc, MulOp1));
+  if (match(MulOp1, m_One()))
+    return IC.replaceInstUsesWith(II, IC.Builder.CreateAdd(Acc, MulOp0));
+  if (match(MulOp0, m_AllOnes()))
+    return IC.replaceInstUsesWith(II, IC.Builder.CreateSub(Acc, MulOp1));
+  if (match(MulOp1, m_AllOnes()))
+    return IC.replaceInstUsesWith(II, IC.Builder.CreateSub(Acc, MulOp0));
+
+  return std::nullopt;
+}
+
 static std::optional<Instruction *> instCombineSVEVectorAdd(InstCombiner &IC,
                                                             IntrinsicInst &II) {
   if (auto MLA = instCombineSVEVectorFuseMulAddSub<Intrinsic::aarch64_sve_mul,
@@ -3073,6 +3100,9 @@ AArch64TTIImpl::instCombineIntrinsic(InstCombiner &IC,
     return instCombineSVEVectorFuseMulAddSub<Intrinsic::aarch64_sve_mul_u,
                                              Intrinsic::aarch64_sve_mla_u>(
         IC, II, true);
+  case Intrinsic::aarch64_sve_mla:
+  case Intrinsic::aarch64_sve_mla_u:
+    return instCombineSVEVectorMla(IC, II);
   case Intrinsic::aarch64_sve_sub:
     return instCombineSVEVectorSub(IC, II);
   case Intrinsic::aarch64_sve_sub_u:
diff --git a/llvm/test/Transforms/InstCombine/AArch64/sve-intrinsic-mla-one.ll b/llvm/test/Transforms/InstCombine/AArch64/sve-intrinsic-mla-one.ll
new file mode 100644
index 0000000000000..268e69e96368a
--- /dev/null
+++ b/llvm/test/Transforms/InstCombine/AArch64/sve-intrinsic-mla-one.ll
@@ -0,0 +1,101 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt -S -passes=instcombine < %s | FileCheck %s
+
+target triple = "aarch64-unknown-linux-gnu"
+
+define <vscale x 4 x i32> @mla_one_rhs_splat_true(<vscale x 4 x i32> %acc, <vscale x 4 x i32> %x) {
+; CHECK-LABEL: @mla_one_rhs_splat_true(
+; CHECK-NEXT:    [[R:%.*]] = add <vscale x 4 x i32> [[ACC:%.*]], [[X:%.*]]
+; CHECK-NEXT:    ret <vscale x 4 x i32> [[R]]
+;
+  %r = call <vscale x 4 x i32> @llvm.aarch64.sve.mla.nxv4i32(<vscale x 4 x i1> splat (i1 true), <vscale x 4 x i32> %acc, <vscale x 4 x i32> %x, <vscale x 4 x i32> splat (i32 1))
+  ret <vscale x 4 x i32> %r
+}
+
+define <vscale x 4 x i32> @mla_one_lhs_splat_true(<vscale x 4 x i32> %acc, <vscale x 4 x i32> %x) {
+; CHECK-LABEL: @mla_one_lhs_splat_true(
+; CHECK-NEXT:    [[R:%.*]] = add <vscale x 4 x i32> [[ACC:%.*]], [[X:%.*]]
+; CHECK-NEXT:    ret <vscale x 4 x i32> [[R]]
+;
+  %r = call <vscale x 4 x i32> @llvm.aarch64.sve.mla.nxv4i32(<vscale x 4 x i1> splat (i1 true), <vscale x 4 x i32> %acc, <vscale x 4 x i32> splat (i32 1), <vscale x 4 x i32> %x)
+  ret <vscale x 4 x i32> %r
+}
+
+define <vscale x 4 x i32> @mla_allones_rhs_splat_true(<vscale x 4 x i32> %acc, <vscale x 4 x i32> %x) {
+; CHECK-LABEL: @mla_allones_rhs_splat_true(
+; CHECK-NEXT:    [[R:%.*]] = sub <vscale x 4 x i32> [[ACC:%.*]], [[X:%.*]]
+; CHECK-NEXT:    ret <vscale x 4 x i32> [[R]]
+;
+  %r = call <vscale x 4 x i32> @llvm.aarch64.sve.mla.nxv4i32(<vscale x 4 x i1> splat (i1 true), <vscale x 4 x i32> %acc, <vscale x 4 x i32> %x, <vscale x 4 x i32> splat (i32 -1))
+  ret <vscale x 4 x i32> %r
+}
+
+define <vscale x 4 x i32> @mla_allones_lhs_splat_true(<vscale x 4 x i32> %acc, <vscale x 4 x i32> %x) {
+; CHECK-LABEL: @mla_allones_lhs_splat_true(
+; CHECK-NEXT:    [[R:%.*]] = sub <vscale x 4 x i32> [[ACC:%.*]], [[X:%.*]]
+; CHECK-NEXT:    ret <vscale x 4 x i32> [[R]]
+;
+  %r = call <vscale x 4 x i32> @llvm.aarch64.sve.mla.nxv4i32(<vscale x 4 x i1> splat (i1 true), <vscale x 4 x i32> %acc, <vscale x 4 x i32> splat (i32 -1), <vscale x 4 x i32> %x)
+  ret <vscale x 4 x i32> %r
+}
+
+define <vscale x 4 x i32> @mla_one_rhs_ptrue_all(<vscale x 4 x i32> %acc, <vscale x 4 x i32> %x) {
+; CHECK-LABEL: @mla_one_rhs_ptrue_all(
+; CHECK-NEXT:    [[R:%.*]] = add <vscale x 4 x i32> [[ACC:%.*]], [[X:%.*]]
+; CHECK-NEXT:    ret <vscale x 4 x i32> [[R]]
+;
+  %pg = call <vscale x 4 x i1> @llvm.aarch64.sve.ptrue.nxv4i1(i32 31)
+  %r = call <vscale x 4 x i32> @llvm.aarch64.sve.mla.nxv4i32(<vscale x 4 x i1> %pg, <vscale x 4 x i32> %acc, <vscale x 4 x i32> %x, <vscale x 4 x i32> splat (i32 1))
+  ret <vscale x 4 x i32> %r
+}
+
+define <vscale x 4 x i32> @mla_one_rhs_ptrue_vl1(<vscale x 4 x i32> %acc, <vscale x 4 x i32> %x) {
+; CHECK-LABEL: @mla_one_rhs_ptrue_vl1(
+; CHECK-NEXT:    [[PG:%.*]] = call <vscale x 4 x i1> @llvm.aarch64.sve.ptrue.nxv4i1(i32 1)
+; CHECK-NEXT:    [[R:%.*]] = call <vscale x 4 x i32> @llvm.aarch64.sve.mla.nxv4i32(<vscale x 4 x i1> [[PG]], <vscale x 4 x i32> [[ACC:%.*]], <vscale x 4 x i32> [[X:%.*]], <vscale x 4 x i32> splat (i32 1))
+; CHECK-NEXT:    ret <vscale x 4 x i32> [[R]]
+;
+  %pg = call <vscale x 4 x i1> @llvm.aarch64.sve.ptrue.nxv4i1(i32 1)
+  %r = call <vscale x 4 x i32> @llvm.aarch64.sve.mla.nxv4i32(<vscale x 4 x i1> %pg, <vscale x 4 x i32> %acc, <vscale x 4 x i32> %x, <vscale x 4 x i32> splat (i32 1))
+  ret <vscale x 4 x i32> %r
+}
+
+define <vscale x 4 x i32> @mla_one_rhs_unknown_predicate(<vscale x 4 x i1> %pg, <vscale x 4 x i32> %acc, <vscale x 4 x i32> %x) {
+; CHECK-LABEL: @mla_one_rhs_unknown_predicate(
+; CHECK-NEXT:    [[R:%.*]] = call <vscale x 4 x i32> @llvm.aarch64.sve.mla.nxv4i32(<vscale x 4 x i1> [[PG:%.*]], <vscale x 4 x i32> [[ACC:%.*]], <vscale x 4 x i32> [[X:%.*]], <vscale x 4 x i32> splat (i32 1))
+; CHECK-NEXT:    ret <vscale x 4 x i32> [[R]]
+;
+  %r = call <vscale x 4 x i32> @llvm.aarch64.sve.mla.nxv4i32(<vscale x 4 x i1> %pg, <vscale x 4 x i32> %acc, <vscale x 4 x i32> %x, <vscale x 4 x i32> splat (i32 1))
+  ret <vscale x 4 x i32> %r
+}
+
+define <vscale x 4 x i32> @mla_allones_rhs_unknown_predicate(<vscale x 4 x i1> %pg, <vscale x 4 x i32> %acc, <vscale x 4 x i32> %x) {
+; CHECK-LABEL: @mla_allones_rhs_unknown_predicate(
+; CHECK-NEXT:    [[R:%.*]] = call <vscale x 4 x i32> @llvm.aarch64.sve.mla.nxv4i32(<vscale x 4 x i1> [[PG:%.*]], <vscale x 4 x i32> [[ACC:%.*]], <vscale x 4 x i32> [[X:%.*]], <vscale x 4 x i32> splat (i32 -1))
+; CHECK-NEXT:    ret <vscale x 4 x i32> [[R]]
+;
+  %r = call <vscale x 4 x i32> @llvm.aarch64.sve.mla.nxv4i32(<vscale x 4 x i1> %pg, <vscale x 4 x i32> %acc, <vscale x 4 x i32> %x, <vscale x 4 x i32> splat (i32 -1))
+  ret <vscale x 4 x i32> %r
+}
+
+define <vscale x 4 x i32> @mla_u_one_rhs_unknown_predicate(<vscale x 4 x i1> %pg, <vscale x 4 x i32> %acc, <vscale x 4 x i32> %x) {
+; CHECK-LABEL: @mla_u_one_rhs_unknown_predicate(
+; CHECK-NEXT:    [[R:%.*]] = add <vscale x 4 x i32> [[ACC:%.*]], [[X:%.*]]
+; CHECK-NEXT:    ret <vscale x 4 x i32> [[R]]
+;
+  %r = call <vscale x 4 x i32> @llvm.aarch64.sve.mla.u.nxv4i32(<vscale x 4 x i1> %pg, <vscale x 4 x i32> %acc, <vscale x 4 x i32> %x, <vscale x 4 x i32> splat (i32 1))
+  ret <vscale x 4 x i32> %r
+}
+
+define <vscale x 4 x i32> @mla_u_allones_rhs_unknown_predicate(<vscale x 4 x i1> %pg, <vscale x 4 x i32> %acc, <vscale x 4 x i32> %x) {
+; CHECK-LABEL: @mla_u_allones_rhs_unknown_predicate(
+; CHECK-NEXT:    [[R:%.*]] = sub <vscale x 4 x i32> [[ACC:%.*]], [[X:%.*]]
+; CHECK-NEXT:    ret <vscale x 4 x i32> [[R]]
+;
+  %r = call <vscale x 4 x i32> @llvm.aarch64.sve.mla.u.nxv4i32(<vscale x 4 x i1> %pg, <vscale x 4 x i32> %acc, <vscale x 4 x i32> %x, <vscale x 4 x i32> splat (i32 -1))
+  ret <vscale x 4 x i32> %r
+}
+
+declare <vscale x 4 x i1> @llvm.aarch64.sve.ptrue.nxv4i1(i32)
+declare <vscale x 4 x i32> @llvm.aarch64.sve.mla.nxv4i32(<vscale x 4 x i1>, <vscale x 4 x i32>, <vscale x 4 x i32>, <vscale x 4 x i32>)
+declare <vscale x 4 x i32> @llvm.aarch64.sve.mla.u.nxv4i32(<vscale x 4 x i1>, <vscale x 4 x i32>, <vscale x 4 x i32>, <vscale x 4 x i32>)



More information about the llvm-commits mailing list