[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