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

Tomas Matheson via llvm-commits llvm-commits at lists.llvm.org
Thu Jun 11 03:38:08 PDT 2026


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

>From 424e232f05a4cbb4eae1034d1973d93ebb3fdd70 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    | 25 +++++
 .../AArch64/sve-intrinsic-mla-one.ll          | 97 +++++++++++++++++++
 2 files changed, 122 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 6a5a31fcfeef9..e133848a42082 100644
--- a/llvm/lib/Target/AArch64/AArch64TargetTransformInfo.cpp
+++ b/llvm/lib/Target/AArch64/AArch64TargetTransformInfo.cpp
@@ -2511,6 +2511,29 @@ instCombineSVEVectorBinOp(InstCombiner &IC, IntrinsicInst &II) {
   return IC.replaceInstUsesWith(II, BinOp);
 }
 
+static std::optional<Instruction *>
+instCombineSVEVectorMlaU(InstCombiner &IC, IntrinsicInst &II) {
+  assert(II.getIntrinsicID() == Intrinsic::aarch64_sve_mla_u &&
+         "Expected MLA_U intrinsic");
+  Value *Acc = II.getArgOperand(1);
+  Value *MulOp0 = II.getArgOperand(2);
+  Value *MulOp1 = II.getArgOperand(3);
+
+  // For mla_u, inactive lanes are undefined, so it is valid to drop the
+  // predicate when replacing mla_u(acc, x, 1) with add(acc, x) or
+  // mla_u(acc, x, -1) with sub(acc, x).
+  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 +3096,8 @@ AArch64TTIImpl::instCombineIntrinsic(InstCombiner &IC,
     return instCombineSVEVectorFuseMulAddSub<Intrinsic::aarch64_sve_mul_u,
                                              Intrinsic::aarch64_sve_mla_u>(
         IC, II, true);
+  case Intrinsic::aarch64_sve_mla_u:
+    return instCombineSVEVectorMlaU(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..a839d1ddc1d52
--- /dev/null
+++ b/llvm/test/Transforms/InstCombine/AArch64/sve-intrinsic-mla-one.ll
@@ -0,0 +1,97 @@
+; 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
+}



More information about the llvm-commits mailing list