[llvm] [AArch64][SVE] Use ADD/ADR instead of MUL/MLA for x*N (PR #198566)

Paul Walker via llvm-commits llvm-commits at lists.llvm.org
Fri Jun 12 05:09:03 PDT 2026


================
@@ -0,0 +1,233 @@
+; RUN: llc -mtriple=aarch64-linux-gnu -mattr=+sve < %s | FileCheck %s
+
+define <vscale x 4 x i32> @mul_i32_by_2(<vscale x 4 x i32> %x) {
+; CHECK-LABEL: mul_i32_by_2:
+; CHECK:       // %bb.0:
+; CHECK-NEXT:    lsl z0.s, z0.s, #1
+; CHECK-NEXT:    ret
+  %out = mul <vscale x 4 x i32> %x, splat(i32 2)
+  ret <vscale x 4 x i32> %out
+}
+
+define <vscale x 4 x i32> @mul_i32_by_3(<vscale x 4 x i32> %x) {
+; CHECK-LABEL: mul_i32_by_3:
+; CHECK:       // %bb.0:
+; CHECK-NEXT:    adr z0.s, [z0.s, z0.s, lsl #1]
+; CHECK-NEXT:    ret
+  %out = mul <vscale x 4 x i32> %x, splat(i32 3)
+  ret <vscale x 4 x i32> %out
+}
+
+define <vscale x 4 x i32> @mul_i32_by_5(<vscale x 4 x i32> %x) {
+; CHECK-LABEL: mul_i32_by_5:
+; CHECK:       // %bb.0:
+; CHECK-NEXT:    adr z0.s, [z0.s, z0.s, lsl #2]
+; CHECK-NEXT:    ret
+  %out = mul <vscale x 4 x i32> %x, splat(i32 5)
+  ret <vscale x 4 x i32> %out
+}
+
+define <vscale x 4 x i32> @mul_i32_by_9(<vscale x 4 x i32> %x) {
+; CHECK-LABEL: mul_i32_by_9:
+; CHECK:       // %bb.0:
+; CHECK-NEXT:    adr z0.s, [z0.s, z0.s, lsl #3]
+; CHECK-NEXT:    ret
+  %out = mul <vscale x 4 x i32> %x, splat(i32 9)
+  ret <vscale x 4 x i32> %out
+}
+
+define <vscale x 2 x i64> @mul_i64_by_5_commuted(<vscale x 2 x i64> %x) {
+; CHECK-LABEL: mul_i64_by_5_commuted:
+; CHECK:       // %bb.0:
+; CHECK-NEXT:    adr z0.d, [z0.d, z0.d, lsl #2]
+; CHECK-NEXT:    ret
+  %out = mul <vscale x 2 x i64> splat(i64 5), %x
+  ret <vscale x 2 x i64> %out
+}
+
+define <vscale x 4 x i32> @mla_i32_by_2(<vscale x 4 x i32> %a,
+                                        <vscale x 4 x i32> %x) {
+; CHECK-LABEL: mla_i32_by_2:
+; CHECK:       // %bb.0:
+; CHECK-NEXT:    adr z0.s, [z0.s, z1.s, lsl #1]
+; CHECK-NEXT:    ret
+  %mul = mul <vscale x 4 x i32> %x, splat(i32 2)
+  %out = add <vscale x 4 x i32> %a, %mul
+  ret <vscale x 4 x i32> %out
+}
+
+define <vscale x 4 x i32> @mla_i32_by_4(<vscale x 4 x i32> %a,
+                                        <vscale x 4 x i32> %x) {
+; CHECK-LABEL: mla_i32_by_4:
+; CHECK:       // %bb.0:
+; CHECK-NEXT:    adr z0.s, [z0.s, z1.s, lsl #2]
+; CHECK-NEXT:    ret
+  %mul = mul <vscale x 4 x i32> %x, splat(i32 4)
+  %out = add <vscale x 4 x i32> %a, %mul
+  ret <vscale x 4 x i32> %out
+}
+
+define <vscale x 4 x i32> @mla_i32_by_8(<vscale x 4 x i32> %a,
+                                        <vscale x 4 x i32> %x) {
+; CHECK-LABEL: mla_i32_by_8:
+; CHECK:       // %bb.0:
+; CHECK-NEXT:    adr z0.s, [z0.s, z1.s, lsl #3]
+; CHECK-NEXT:    ret
+  %mul = mul <vscale x 4 x i32> %x, splat(i32 8)
+  %out = add <vscale x 4 x i32> %a, %mul
+  ret <vscale x 4 x i32> %out
+}
+
+define <vscale x 2 x i64> @mla_i64_by_4_commuted(<vscale x 2 x i64> %a,
+                                                 <vscale x 2 x i64> %x) {
+; CHECK-LABEL: mla_i64_by_4_commuted:
+; CHECK:       // %bb.0:
+; CHECK-NEXT:    adr z0.d, [z0.d, z1.d, lsl #2]
+; CHECK-NEXT:    ret
+  %mul = mul <vscale x 2 x i64> splat(i64 4), %x
+  %out = add <vscale x 2 x i64> %a, %mul
+  ret <vscale x 2 x i64> %out
+}
+
+define <vscale x 4 x i32> @svmul_u_i32_by_5(<vscale x 4 x i1> %pg,
+                                            <vscale x 4 x i32> %x) {
+; CHECK-LABEL: svmul_u_i32_by_5:
+; CHECK:       // %bb.0:
+; CHECK-NEXT:    adr z0.s, [z0.s, z0.s, lsl #2]
+; CHECK-NEXT:    ret
+  %out = call <vscale x 4 x i32> @llvm.aarch64.sve.mul.u.nxv4i32(
+      <vscale x 4 x i1> %pg,
+      <vscale x 4 x i32> %x,
+      <vscale x 4 x i32> splat(i32 5))
+  ret <vscale x 4 x i32> %out
+}
+
+define <vscale x 4 x i32> @svmul_m_partial_i32_by_5(<vscale x 4 x i1> %pg,
+                                                    <vscale x 4 x i32> %x) {
+; CHECK-LABEL: svmul_m_partial_i32_by_5:
+; CHECK:       // %bb.0:
+; CHECK-NEXT:    mov z1.s, #5
+; CHECK-NEXT:    mul z0.s, p0/m, z0.s, z1.s
+; CHECK-NEXT:    ret
+  %out = call <vscale x 4 x i32> @llvm.aarch64.sve.mul.nxv4i32(
+      <vscale x 4 x i1> %pg,
+      <vscale x 4 x i32> %x,
+      <vscale x 4 x i32> splat(i32 5))
+  ret <vscale x 4 x i32> %out
+}
+
+define <vscale x 4 x i32> @svmul_u_i32_by_2(<vscale x 4 x i1> %pg,
+                                            <vscale x 4 x i32> %x) {
+; CHECK-LABEL: svmul_u_i32_by_2:
+; CHECK:       // %bb.0:
+; CHECK-NEXT:    add z0.s, z0.s, z0.s
+; CHECK-NEXT:    ret
+  %out = call <vscale x 4 x i32> @llvm.aarch64.sve.mul.u.nxv4i32(
+      <vscale x 4 x i1> %pg,
+      <vscale x 4 x i32> %x,
+      <vscale x 4 x i32> splat(i32 2))
+  ret <vscale x 4 x i32> %out
+}
+
+define <vscale x 4 x i32> @svmul_u_i32_by_9_commuted(<vscale x 4 x i1> %pg,
+                                                     <vscale x 4 x i32> %x) {
+; CHECK-LABEL: svmul_u_i32_by_9_commuted:
+; CHECK:       // %bb.0:
+; CHECK-NEXT:    adr z0.s, [z0.s, z0.s, lsl #3]
+; CHECK-NEXT:    ret
+  %out = call <vscale x 4 x i32> @llvm.aarch64.sve.mul.u.nxv4i32(
+      <vscale x 4 x i1> %pg,
+      <vscale x 4 x i32> splat(i32 9),
+      <vscale x 4 x i32> %x)
+  ret <vscale x 4 x i32> %out
+}
+
+define <vscale x 4 x i32> @svmla_u_i32_by_2(<vscale x 4 x i1> %pg,
+                                            <vscale x 4 x i32> %a,
+                                            <vscale x 4 x i32> %x) {
+; CHECK-LABEL: svmla_u_i32_by_2:
+; CHECK:       // %bb.0:
+; CHECK-NEXT:    adr z0.s, [z0.s, z1.s, lsl #1]
+; CHECK-NEXT:    ret
+  %out = call <vscale x 4 x i32> @llvm.aarch64.sve.mla.u.nxv4i32(
+      <vscale x 4 x i1> %pg,
+      <vscale x 4 x i32> %a,
+      <vscale x 4 x i32> %x,
+      <vscale x 4 x i32> splat(i32 2))
+  ret <vscale x 4 x i32> %out
+}
+
+define <vscale x 4 x i32> @svmla_u_i32_by_8_commuted(
+    <vscale x 4 x i1> %pg, <vscale x 4 x i32> %a,
+    <vscale x 4 x i32> %x) {
+; CHECK-LABEL: svmla_u_i32_by_8_commuted:
+; CHECK:       // %bb.0:
+; CHECK-NEXT:    adr z0.s, [z0.s, z1.s, lsl #3]
+; CHECK-NEXT:    ret
+  %out = call <vscale x 4 x i32> @llvm.aarch64.sve.mla.u.nxv4i32(
+      <vscale x 4 x i1> %pg,
+      <vscale x 4 x i32> %a,
+      <vscale x 4 x i32> splat(i32 8),
+      <vscale x 4 x i32> %x)
+  ret <vscale x 4 x i32> %out
+}
+
+define <vscale x 4 x i32> @svmla_m_partial_i32_by_4(<vscale x 4 x i1> %pg,
+                                                    <vscale x 4 x i32> %a,
+                                                    <vscale x 4 x i32> %x) {
+; CHECK-LABEL: svmla_m_partial_i32_by_4:
+; CHECK:       // %bb.0:
+; CHECK-NEXT:    mov z2.s, #4
+; CHECK-NEXT:    mla z0.s, p0/m, z1.s, z2.s
+; CHECK-NEXT:    ret
+  %out = call <vscale x 4 x i32> @llvm.aarch64.sve.mla.nxv4i32(
+      <vscale x 4 x i1> %pg,
+      <vscale x 4 x i32> %a,
+      <vscale x 4 x i32> %x,
+      <vscale x 4 x i32> splat(i32 4))
+  ret <vscale x 4 x i32> %out
+}
+
+define <vscale x 4 x i32> @svmla_u_i32_by_4(<vscale x 4 x i1> %pg,
+                                            <vscale x 4 x i32> %a,
+                                            <vscale x 4 x i32> %x) {
+; CHECK-LABEL: svmla_u_i32_by_4:
+; CHECK:       // %bb.0:
+; CHECK-NEXT:    adr z0.s, [z0.s, z1.s, lsl #2]
+; CHECK-NEXT:    ret
+  %out = call <vscale x 4 x i32> @llvm.aarch64.sve.mla.u.nxv4i32(
+      <vscale x 4 x i1> %pg,
+      <vscale x 4 x i32> %a,
+      <vscale x 4 x i32> %x,
+      <vscale x 4 x i32> splat(i32 4))
+  ret <vscale x 4 x i32> %out
+}
+
+define <vscale x 2 x i64> @svmla_u_i64_by_8(<vscale x 2 x i1> %pg,
+                                            <vscale x 2 x i64> %a,
+                                            <vscale x 2 x i64> %x) {
+; CHECK-LABEL: svmla_u_i64_by_8:
+; CHECK:       // %bb.0:
+; CHECK-NEXT:    adr z0.d, [z0.d, z1.d, lsl #3]
+; CHECK-NEXT:    ret
+  %out = call <vscale x 2 x i64> @llvm.aarch64.sve.mla.u.nxv2i64(
+      <vscale x 2 x i1> %pg,
+      <vscale x 2 x i64> %a,
+      <vscale x 2 x i64> %x,
+      <vscale x 2 x i64> splat(i64 8))
+  ret <vscale x 2 x i64> %out
+}
+
+declare <vscale x 4 x i32> @llvm.aarch64.sve.mul.nxv4i32(
+    <vscale x 4 x i1>, <vscale x 4 x i32>, <vscale x 4 x i32>)
+declare <vscale x 4 x i32> @llvm.aarch64.sve.mul.u.nxv4i32(
+    <vscale x 4 x i1>, <vscale x 4 x i32>, <vscale x 4 x 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>)
+declare <vscale x 2 x i64> @llvm.aarch64.sve.mla.u.nxv2i64(
+    <vscale x 2 x i1>, <vscale x 2 x i64>, <vscale x 2 x i64>,
+    <vscale x 2 x i64>)
----------------
paulwalker-arm wrote:

We don't need these anymore.

https://github.com/llvm/llvm-project/pull/198566


More information about the llvm-commits mailing list