[llvm] [SLP][NFC] Add precommit test for dot-product reduction costing (PR #224590)

Madhur Amilkanthwar via llvm-commits llvm-commits at lists.llvm.org
Fri Sep 18 04:06:25 PDT 2026


https://github.com/madhur13490 updated https://github.com/llvm/llvm-project/pull/224590

>From e331efd6d01a6462600556b60a1f1f7cd8c56d2d Mon Sep 17 00:00:00 2001
From: Madhur Amilkanthwar <madhura at nvidia.com>
Date: Thu, 17 Sep 2026 04:13:14 -0700
Subject: [PATCH 1/2] [SLP][NFC] Add precommit test for dot-product reduction
 costing

Adds a test for reduce.add(mul(ext, ext)) with and without +dotprod at a threshold between the plain and fused costs. Baseline: both stay scalar; a later change makes the +dotprod case vectorize.
---
 .../AArch64/reduce-add-dotprod.ll             | 273 ++++++++++++++++++
 1 file changed, 273 insertions(+)
 create mode 100644 llvm/test/Transforms/SLPVectorizer/AArch64/reduce-add-dotprod.ll

diff --git a/llvm/test/Transforms/SLPVectorizer/AArch64/reduce-add-dotprod.ll b/llvm/test/Transforms/SLPVectorizer/AArch64/reduce-add-dotprod.ll
new file mode 100644
index 0000000000000..36d2a0f797280
--- /dev/null
+++ b/llvm/test/Transforms/SLPVectorizer/AArch64/reduce-add-dotprod.ll
@@ -0,0 +1,273 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt -passes=slp-vectorizer -slp-threshold=28 -S -mtriple=aarch64 < %s | FileCheck %s
+
+; The reduce.add(mul(ext, ext)) idiom lowers to a single dot-product
+; reduction (UDOT/SDOT) when the target supports it. The threshold is set
+; between the plain reduction cost and the fused dot-product cost so the
+; reduction is profitable only when the dot-product cost applies: the
+; +dotprod function vectorizes, the plain function stays scalar.
+
+target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128-Fn32"
+target triple = "aarch64"
+
+define i32 @mla_v8i8_i32_dotprod(ptr %x, ptr %y) "target-features"="+dotprod" {
+; CHECK-LABEL: @mla_v8i8_i32_dotprod(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[TMP0:%.*]] = load i8, ptr [[X:%.*]], align 1
+; CHECK-NEXT:    [[CONV:%.*]] = sext i8 [[TMP0]] to i32
+; CHECK-NEXT:    [[TMP1:%.*]] = load i8, ptr [[Y:%.*]], align 1
+; CHECK-NEXT:    [[CONV3:%.*]] = sext i8 [[TMP1]] to i32
+; CHECK-NEXT:    [[MUL:%.*]] = mul nsw i32 [[CONV3]], [[CONV]]
+; CHECK-NEXT:    [[ARRAYIDX_1:%.*]] = getelementptr inbounds nuw i8, ptr [[X]], i64 1
+; CHECK-NEXT:    [[TMP2:%.*]] = load i8, ptr [[ARRAYIDX_1]], align 1
+; CHECK-NEXT:    [[CONV_1:%.*]] = sext i8 [[TMP2]] to i32
+; CHECK-NEXT:    [[ARRAYIDX2_1:%.*]] = getelementptr inbounds nuw i8, ptr [[Y]], i64 1
+; CHECK-NEXT:    [[TMP3:%.*]] = load i8, ptr [[ARRAYIDX2_1]], align 1
+; CHECK-NEXT:    [[CONV3_1:%.*]] = sext i8 [[TMP3]] to i32
+; CHECK-NEXT:    [[MUL_1:%.*]] = mul nsw i32 [[CONV3_1]], [[CONV_1]]
+; CHECK-NEXT:    [[ADD_1:%.*]] = add nsw i32 [[MUL_1]], [[MUL]]
+; CHECK-NEXT:    [[ARRAYIDX_2:%.*]] = getelementptr inbounds nuw i8, ptr [[X]], i64 2
+; CHECK-NEXT:    [[TMP4:%.*]] = load i8, ptr [[ARRAYIDX_2]], align 1
+; CHECK-NEXT:    [[CONV_2:%.*]] = sext i8 [[TMP4]] to i32
+; CHECK-NEXT:    [[ARRAYIDX2_2:%.*]] = getelementptr inbounds nuw i8, ptr [[Y]], i64 2
+; CHECK-NEXT:    [[TMP16:%.*]] = load i8, ptr [[ARRAYIDX2_2]], align 1
+; CHECK-NEXT:    [[CONV3_2:%.*]] = sext i8 [[TMP16]] to i32
+; CHECK-NEXT:    [[MUL_2:%.*]] = mul nsw i32 [[CONV3_2]], [[CONV_2]]
+; CHECK-NEXT:    [[ADD_2:%.*]] = add nsw i32 [[MUL_2]], [[ADD_1]]
+; CHECK-NEXT:    [[ARRAYIDX_3:%.*]] = getelementptr inbounds nuw i8, ptr [[X]], i64 3
+; CHECK-NEXT:    [[TMP6:%.*]] = load i8, ptr [[ARRAYIDX_3]], align 1
+; CHECK-NEXT:    [[CONV_3:%.*]] = sext i8 [[TMP6]] to i32
+; CHECK-NEXT:    [[ARRAYIDX2_3:%.*]] = getelementptr inbounds nuw i8, ptr [[Y]], i64 3
+; CHECK-NEXT:    [[TMP7:%.*]] = load i8, ptr [[ARRAYIDX2_3]], align 1
+; CHECK-NEXT:    [[CONV3_3:%.*]] = sext i8 [[TMP7]] to i32
+; CHECK-NEXT:    [[MUL_3:%.*]] = mul nsw i32 [[CONV3_3]], [[CONV_3]]
+; CHECK-NEXT:    [[ADD_3:%.*]] = add nsw i32 [[MUL_3]], [[ADD_2]]
+; CHECK-NEXT:    [[ARRAYIDX_4:%.*]] = getelementptr inbounds nuw i8, ptr [[X]], i64 4
+; CHECK-NEXT:    [[TMP8:%.*]] = load i8, ptr [[ARRAYIDX_4]], align 1
+; CHECK-NEXT:    [[CONV_4:%.*]] = sext i8 [[TMP8]] to i32
+; CHECK-NEXT:    [[ARRAYIDX2_4:%.*]] = getelementptr inbounds nuw i8, ptr [[Y]], i64 4
+; CHECK-NEXT:    [[TMP9:%.*]] = load i8, ptr [[ARRAYIDX2_4]], align 1
+; CHECK-NEXT:    [[CONV3_4:%.*]] = sext i8 [[TMP9]] to i32
+; CHECK-NEXT:    [[MUL_4:%.*]] = mul nsw i32 [[CONV3_4]], [[CONV_4]]
+; CHECK-NEXT:    [[ADD_4:%.*]] = add nsw i32 [[MUL_4]], [[ADD_3]]
+; CHECK-NEXT:    [[ARRAYIDX_5:%.*]] = getelementptr inbounds nuw i8, ptr [[X]], i64 5
+; CHECK-NEXT:    [[TMP10:%.*]] = load i8, ptr [[ARRAYIDX_5]], align 1
+; CHECK-NEXT:    [[CONV_5:%.*]] = sext i8 [[TMP10]] to i32
+; CHECK-NEXT:    [[ARRAYIDX2_5:%.*]] = getelementptr inbounds nuw i8, ptr [[Y]], i64 5
+; CHECK-NEXT:    [[TMP11:%.*]] = load i8, ptr [[ARRAYIDX2_5]], align 1
+; CHECK-NEXT:    [[CONV3_5:%.*]] = sext i8 [[TMP11]] to i32
+; CHECK-NEXT:    [[MUL_5:%.*]] = mul nsw i32 [[CONV3_5]], [[CONV_5]]
+; CHECK-NEXT:    [[ADD_5:%.*]] = add nsw i32 [[MUL_5]], [[ADD_4]]
+; CHECK-NEXT:    [[ARRAYIDX_6:%.*]] = getelementptr inbounds nuw i8, ptr [[X]], i64 6
+; CHECK-NEXT:    [[TMP12:%.*]] = load i8, ptr [[ARRAYIDX_6]], align 1
+; CHECK-NEXT:    [[CONV_6:%.*]] = sext i8 [[TMP12]] to i32
+; CHECK-NEXT:    [[ARRAYIDX2_6:%.*]] = getelementptr inbounds nuw i8, ptr [[Y]], i64 6
+; CHECK-NEXT:    [[TMP13:%.*]] = load i8, ptr [[ARRAYIDX2_6]], align 1
+; CHECK-NEXT:    [[CONV3_6:%.*]] = sext i8 [[TMP13]] to i32
+; CHECK-NEXT:    [[MUL_6:%.*]] = mul nsw i32 [[CONV3_6]], [[CONV_6]]
+; CHECK-NEXT:    [[ADD_6:%.*]] = add nsw i32 [[MUL_6]], [[ADD_5]]
+; CHECK-NEXT:    [[ARRAYIDX_7:%.*]] = getelementptr inbounds nuw i8, ptr [[X]], i64 7
+; CHECK-NEXT:    [[TMP14:%.*]] = load i8, ptr [[ARRAYIDX_7]], align 1
+; CHECK-NEXT:    [[CONV_7:%.*]] = sext i8 [[TMP14]] to i32
+; CHECK-NEXT:    [[ARRAYIDX2_7:%.*]] = getelementptr inbounds nuw i8, ptr [[Y]], i64 7
+; CHECK-NEXT:    [[TMP15:%.*]] = load i8, ptr [[ARRAYIDX2_7]], align 1
+; CHECK-NEXT:    [[CONV3_7:%.*]] = sext i8 [[TMP15]] to i32
+; CHECK-NEXT:    [[MUL_7:%.*]] = mul nsw i32 [[CONV3_7]], [[CONV_7]]
+; CHECK-NEXT:    [[TMP5:%.*]] = add nsw i32 [[MUL_7]], [[ADD_6]]
+; CHECK-NEXT:    ret i32 [[TMP5]]
+;
+entry:
+  %0 = load i8, ptr %x
+  %conv = sext i8 %0 to i32
+  %1 = load i8, ptr %y
+  %conv3 = sext i8 %1 to i32
+  %mul = mul nsw i32 %conv3, %conv
+  %arrayidx.1 = getelementptr inbounds nuw i8, ptr %x, i64 1
+  %2 = load i8, ptr %arrayidx.1
+  %conv.1 = sext i8 %2 to i32
+  %arrayidx2.1 = getelementptr inbounds nuw i8, ptr %y, i64 1
+  %3 = load i8, ptr %arrayidx2.1
+  %conv3.1 = sext i8 %3 to i32
+  %mul.1 = mul nsw i32 %conv3.1, %conv.1
+  %add.1 = add nsw i32 %mul.1, %mul
+  %arrayidx.2 = getelementptr inbounds nuw i8, ptr %x, i64 2
+  %4 = load i8, ptr %arrayidx.2
+  %conv.2 = sext i8 %4 to i32
+  %arrayidx2.2 = getelementptr inbounds nuw i8, ptr %y, i64 2
+  %5 = load i8, ptr %arrayidx2.2
+  %conv3.2 = sext i8 %5 to i32
+  %mul.2 = mul nsw i32 %conv3.2, %conv.2
+  %add.2 = add nsw i32 %mul.2, %add.1
+  %arrayidx.3 = getelementptr inbounds nuw i8, ptr %x, i64 3
+  %6 = load i8, ptr %arrayidx.3
+  %conv.3 = sext i8 %6 to i32
+  %arrayidx2.3 = getelementptr inbounds nuw i8, ptr %y, i64 3
+  %7 = load i8, ptr %arrayidx2.3
+  %conv3.3 = sext i8 %7 to i32
+  %mul.3 = mul nsw i32 %conv3.3, %conv.3
+  %add.3 = add nsw i32 %mul.3, %add.2
+  %arrayidx.4 = getelementptr inbounds nuw i8, ptr %x, i64 4
+  %8 = load i8, ptr %arrayidx.4
+  %conv.4 = sext i8 %8 to i32
+  %arrayidx2.4 = getelementptr inbounds nuw i8, ptr %y, i64 4
+  %9 = load i8, ptr %arrayidx2.4
+  %conv3.4 = sext i8 %9 to i32
+  %mul.4 = mul nsw i32 %conv3.4, %conv.4
+  %add.4 = add nsw i32 %mul.4, %add.3
+  %arrayidx.5 = getelementptr inbounds nuw i8, ptr %x, i64 5
+  %10 = load i8, ptr %arrayidx.5
+  %conv.5 = sext i8 %10 to i32
+  %arrayidx2.5 = getelementptr inbounds nuw i8, ptr %y, i64 5
+  %11 = load i8, ptr %arrayidx2.5
+  %conv3.5 = sext i8 %11 to i32
+  %mul.5 = mul nsw i32 %conv3.5, %conv.5
+  %add.5 = add nsw i32 %mul.5, %add.4
+  %arrayidx.6 = getelementptr inbounds nuw i8, ptr %x, i64 6
+  %12 = load i8, ptr %arrayidx.6
+  %conv.6 = sext i8 %12 to i32
+  %arrayidx2.6 = getelementptr inbounds nuw i8, ptr %y, i64 6
+  %13 = load i8, ptr %arrayidx2.6
+  %conv3.6 = sext i8 %13 to i32
+  %mul.6 = mul nsw i32 %conv3.6, %conv.6
+  %add.6 = add nsw i32 %mul.6, %add.5
+  %arrayidx.7 = getelementptr inbounds nuw i8, ptr %x, i64 7
+  %14 = load i8, ptr %arrayidx.7
+  %conv.7 = sext i8 %14 to i32
+  %arrayidx2.7 = getelementptr inbounds nuw i8, ptr %y, i64 7
+  %15 = load i8, ptr %arrayidx2.7
+  %conv3.7 = sext i8 %15 to i32
+  %mul.7 = mul nsw i32 %conv3.7, %conv.7
+  %add.7 = add nsw i32 %mul.7, %add.6
+  ret i32 %add.7
+}
+
+define i32 @mla_v8i8_i32_no_dotprod(ptr %x, ptr %y) {
+; CHECK-LABEL: @mla_v8i8_i32_no_dotprod(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[TMP0:%.*]] = load i8, ptr [[X:%.*]], align 1
+; CHECK-NEXT:    [[CONV:%.*]] = sext i8 [[TMP0]] to i32
+; CHECK-NEXT:    [[TMP1:%.*]] = load i8, ptr [[Y:%.*]], align 1
+; CHECK-NEXT:    [[CONV3:%.*]] = sext i8 [[TMP1]] to i32
+; CHECK-NEXT:    [[MUL:%.*]] = mul nsw i32 [[CONV3]], [[CONV]]
+; CHECK-NEXT:    [[ARRAYIDX_1:%.*]] = getelementptr inbounds nuw i8, ptr [[X]], i64 1
+; CHECK-NEXT:    [[TMP2:%.*]] = load i8, ptr [[ARRAYIDX_1]], align 1
+; CHECK-NEXT:    [[CONV_1:%.*]] = sext i8 [[TMP2]] to i32
+; CHECK-NEXT:    [[ARRAYIDX2_1:%.*]] = getelementptr inbounds nuw i8, ptr [[Y]], i64 1
+; CHECK-NEXT:    [[TMP3:%.*]] = load i8, ptr [[ARRAYIDX2_1]], align 1
+; CHECK-NEXT:    [[CONV3_1:%.*]] = sext i8 [[TMP3]] to i32
+; CHECK-NEXT:    [[MUL_1:%.*]] = mul nsw i32 [[CONV3_1]], [[CONV_1]]
+; CHECK-NEXT:    [[ADD_1:%.*]] = add nsw i32 [[MUL_1]], [[MUL]]
+; CHECK-NEXT:    [[ARRAYIDX_2:%.*]] = getelementptr inbounds nuw i8, ptr [[X]], i64 2
+; CHECK-NEXT:    [[TMP4:%.*]] = load i8, ptr [[ARRAYIDX_2]], align 1
+; CHECK-NEXT:    [[CONV_2:%.*]] = sext i8 [[TMP4]] to i32
+; CHECK-NEXT:    [[ARRAYIDX2_2:%.*]] = getelementptr inbounds nuw i8, ptr [[Y]], i64 2
+; CHECK-NEXT:    [[TMP5:%.*]] = load i8, ptr [[ARRAYIDX2_2]], align 1
+; CHECK-NEXT:    [[CONV3_2:%.*]] = sext i8 [[TMP5]] to i32
+; CHECK-NEXT:    [[MUL_2:%.*]] = mul nsw i32 [[CONV3_2]], [[CONV_2]]
+; CHECK-NEXT:    [[ADD_2:%.*]] = add nsw i32 [[MUL_2]], [[ADD_1]]
+; CHECK-NEXT:    [[ARRAYIDX_3:%.*]] = getelementptr inbounds nuw i8, ptr [[X]], i64 3
+; CHECK-NEXT:    [[TMP6:%.*]] = load i8, ptr [[ARRAYIDX_3]], align 1
+; CHECK-NEXT:    [[CONV_3:%.*]] = sext i8 [[TMP6]] to i32
+; CHECK-NEXT:    [[ARRAYIDX2_3:%.*]] = getelementptr inbounds nuw i8, ptr [[Y]], i64 3
+; CHECK-NEXT:    [[TMP7:%.*]] = load i8, ptr [[ARRAYIDX2_3]], align 1
+; CHECK-NEXT:    [[CONV3_3:%.*]] = sext i8 [[TMP7]] to i32
+; CHECK-NEXT:    [[MUL_3:%.*]] = mul nsw i32 [[CONV3_3]], [[CONV_3]]
+; CHECK-NEXT:    [[ADD_3:%.*]] = add nsw i32 [[MUL_3]], [[ADD_2]]
+; CHECK-NEXT:    [[ARRAYIDX_4:%.*]] = getelementptr inbounds nuw i8, ptr [[X]], i64 4
+; CHECK-NEXT:    [[TMP8:%.*]] = load i8, ptr [[ARRAYIDX_4]], align 1
+; CHECK-NEXT:    [[CONV_4:%.*]] = sext i8 [[TMP8]] to i32
+; CHECK-NEXT:    [[ARRAYIDX2_4:%.*]] = getelementptr inbounds nuw i8, ptr [[Y]], i64 4
+; CHECK-NEXT:    [[TMP9:%.*]] = load i8, ptr [[ARRAYIDX2_4]], align 1
+; CHECK-NEXT:    [[CONV3_4:%.*]] = sext i8 [[TMP9]] to i32
+; CHECK-NEXT:    [[MUL_4:%.*]] = mul nsw i32 [[CONV3_4]], [[CONV_4]]
+; CHECK-NEXT:    [[ADD_4:%.*]] = add nsw i32 [[MUL_4]], [[ADD_3]]
+; CHECK-NEXT:    [[ARRAYIDX_5:%.*]] = getelementptr inbounds nuw i8, ptr [[X]], i64 5
+; CHECK-NEXT:    [[TMP10:%.*]] = load i8, ptr [[ARRAYIDX_5]], align 1
+; CHECK-NEXT:    [[CONV_5:%.*]] = sext i8 [[TMP10]] to i32
+; CHECK-NEXT:    [[ARRAYIDX2_5:%.*]] = getelementptr inbounds nuw i8, ptr [[Y]], i64 5
+; CHECK-NEXT:    [[TMP11:%.*]] = load i8, ptr [[ARRAYIDX2_5]], align 1
+; CHECK-NEXT:    [[CONV3_5:%.*]] = sext i8 [[TMP11]] to i32
+; CHECK-NEXT:    [[MUL_5:%.*]] = mul nsw i32 [[CONV3_5]], [[CONV_5]]
+; CHECK-NEXT:    [[ADD_5:%.*]] = add nsw i32 [[MUL_5]], [[ADD_4]]
+; CHECK-NEXT:    [[ARRAYIDX_6:%.*]] = getelementptr inbounds nuw i8, ptr [[X]], i64 6
+; CHECK-NEXT:    [[TMP12:%.*]] = load i8, ptr [[ARRAYIDX_6]], align 1
+; CHECK-NEXT:    [[CONV_6:%.*]] = sext i8 [[TMP12]] to i32
+; CHECK-NEXT:    [[ARRAYIDX2_6:%.*]] = getelementptr inbounds nuw i8, ptr [[Y]], i64 6
+; CHECK-NEXT:    [[TMP13:%.*]] = load i8, ptr [[ARRAYIDX2_6]], align 1
+; CHECK-NEXT:    [[CONV3_6:%.*]] = sext i8 [[TMP13]] to i32
+; CHECK-NEXT:    [[MUL_6:%.*]] = mul nsw i32 [[CONV3_6]], [[CONV_6]]
+; CHECK-NEXT:    [[ADD_6:%.*]] = add nsw i32 [[MUL_6]], [[ADD_5]]
+; CHECK-NEXT:    [[ARRAYIDX_7:%.*]] = getelementptr inbounds nuw i8, ptr [[X]], i64 7
+; CHECK-NEXT:    [[TMP14:%.*]] = load i8, ptr [[ARRAYIDX_7]], align 1
+; CHECK-NEXT:    [[CONV_7:%.*]] = sext i8 [[TMP14]] to i32
+; CHECK-NEXT:    [[ARRAYIDX2_7:%.*]] = getelementptr inbounds nuw i8, ptr [[Y]], i64 7
+; CHECK-NEXT:    [[TMP15:%.*]] = load i8, ptr [[ARRAYIDX2_7]], align 1
+; CHECK-NEXT:    [[CONV3_7:%.*]] = sext i8 [[TMP15]] to i32
+; CHECK-NEXT:    [[MUL_7:%.*]] = mul nsw i32 [[CONV3_7]], [[CONV_7]]
+; CHECK-NEXT:    [[ADD_7:%.*]] = add nsw i32 [[MUL_7]], [[ADD_6]]
+; CHECK-NEXT:    ret i32 [[ADD_7]]
+;
+entry:
+  %0 = load i8, ptr %x
+  %conv = sext i8 %0 to i32
+  %1 = load i8, ptr %y
+  %conv3 = sext i8 %1 to i32
+  %mul = mul nsw i32 %conv3, %conv
+  %arrayidx.1 = getelementptr inbounds nuw i8, ptr %x, i64 1
+  %2 = load i8, ptr %arrayidx.1
+  %conv.1 = sext i8 %2 to i32
+  %arrayidx2.1 = getelementptr inbounds nuw i8, ptr %y, i64 1
+  %3 = load i8, ptr %arrayidx2.1
+  %conv3.1 = sext i8 %3 to i32
+  %mul.1 = mul nsw i32 %conv3.1, %conv.1
+  %add.1 = add nsw i32 %mul.1, %mul
+  %arrayidx.2 = getelementptr inbounds nuw i8, ptr %x, i64 2
+  %4 = load i8, ptr %arrayidx.2
+  %conv.2 = sext i8 %4 to i32
+  %arrayidx2.2 = getelementptr inbounds nuw i8, ptr %y, i64 2
+  %5 = load i8, ptr %arrayidx2.2
+  %conv3.2 = sext i8 %5 to i32
+  %mul.2 = mul nsw i32 %conv3.2, %conv.2
+  %add.2 = add nsw i32 %mul.2, %add.1
+  %arrayidx.3 = getelementptr inbounds nuw i8, ptr %x, i64 3
+  %6 = load i8, ptr %arrayidx.3
+  %conv.3 = sext i8 %6 to i32
+  %arrayidx2.3 = getelementptr inbounds nuw i8, ptr %y, i64 3
+  %7 = load i8, ptr %arrayidx2.3
+  %conv3.3 = sext i8 %7 to i32
+  %mul.3 = mul nsw i32 %conv3.3, %conv.3
+  %add.3 = add nsw i32 %mul.3, %add.2
+  %arrayidx.4 = getelementptr inbounds nuw i8, ptr %x, i64 4
+  %8 = load i8, ptr %arrayidx.4
+  %conv.4 = sext i8 %8 to i32
+  %arrayidx2.4 = getelementptr inbounds nuw i8, ptr %y, i64 4
+  %9 = load i8, ptr %arrayidx2.4
+  %conv3.4 = sext i8 %9 to i32
+  %mul.4 = mul nsw i32 %conv3.4, %conv.4
+  %add.4 = add nsw i32 %mul.4, %add.3
+  %arrayidx.5 = getelementptr inbounds nuw i8, ptr %x, i64 5
+  %10 = load i8, ptr %arrayidx.5
+  %conv.5 = sext i8 %10 to i32
+  %arrayidx2.5 = getelementptr inbounds nuw i8, ptr %y, i64 5
+  %11 = load i8, ptr %arrayidx2.5
+  %conv3.5 = sext i8 %11 to i32
+  %mul.5 = mul nsw i32 %conv3.5, %conv.5
+  %add.5 = add nsw i32 %mul.5, %add.4
+  %arrayidx.6 = getelementptr inbounds nuw i8, ptr %x, i64 6
+  %12 = load i8, ptr %arrayidx.6
+  %conv.6 = sext i8 %12 to i32
+  %arrayidx2.6 = getelementptr inbounds nuw i8, ptr %y, i64 6
+  %13 = load i8, ptr %arrayidx2.6
+  %conv3.6 = sext i8 %13 to i32
+  %mul.6 = mul nsw i32 %conv3.6, %conv.6
+  %add.6 = add nsw i32 %mul.6, %add.5
+  %arrayidx.7 = getelementptr inbounds nuw i8, ptr %x, i64 7
+  %14 = load i8, ptr %arrayidx.7
+  %conv.7 = sext i8 %14 to i32
+  %arrayidx2.7 = getelementptr inbounds nuw i8, ptr %y, i64 7
+  %15 = load i8, ptr %arrayidx2.7
+  %conv3.7 = sext i8 %15 to i32
+  %mul.7 = mul nsw i32 %conv3.7, %conv.7
+  %add.7 = add nsw i32 %mul.7, %add.6
+  ret i32 %add.7
+}

>From b6ef1cdae75158cd8a37eb5b061c975b95645ebf Mon Sep 17 00:00:00 2001
From: Madhur Amilkanthwar <madhura at nvidia.com>
Date: Fri, 18 Sep 2026 04:00:23 -0700
Subject: [PATCH 2/2] fixup! [SLP][NFC] Add precommit test for dot-product
 reduction costing

---
 .../AArch64/reduce-add-dotprod.ll             | 147 ++----------------
 1 file changed, 9 insertions(+), 138 deletions(-)

diff --git a/llvm/test/Transforms/SLPVectorizer/AArch64/reduce-add-dotprod.ll b/llvm/test/Transforms/SLPVectorizer/AArch64/reduce-add-dotprod.ll
index 36d2a0f797280..4339610179600 100644
--- a/llvm/test/Transforms/SLPVectorizer/AArch64/reduce-add-dotprod.ll
+++ b/llvm/test/Transforms/SLPVectorizer/AArch64/reduce-add-dotprod.ll
@@ -1,148 +1,16 @@
 ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
-; RUN: opt -passes=slp-vectorizer -slp-threshold=28 -S -mtriple=aarch64 < %s | FileCheck %s
+; RUN: opt -passes=slp-vectorizer -slp-threshold=28 -S -mtriple=aarch64 -mattr=+dotprod < %s | FileCheck %s --check-prefixes=CHECK,DOTPROD
+; RUN: opt -passes=slp-vectorizer -slp-threshold=28 -S -mtriple=aarch64 < %s | FileCheck %s --check-prefixes=CHECK,NODOTPROD
 
 ; The reduce.add(mul(ext, ext)) idiom lowers to a single dot-product
 ; reduction (UDOT/SDOT) when the target supports it. The threshold is set
 ; between the plain reduction cost and the fused dot-product cost so the
-; reduction is profitable only when the dot-product cost applies: the
-; +dotprod function vectorizes, the plain function stays scalar.
+; reduction is profitable only when the dot-product cost applies: with
+; +dotprod the reduction vectorizes, without it the code stays scalar.
 
-target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128-Fn32"
-target triple = "aarch64"
-
-define i32 @mla_v8i8_i32_dotprod(ptr %x, ptr %y) "target-features"="+dotprod" {
-; CHECK-LABEL: @mla_v8i8_i32_dotprod(
-; CHECK-NEXT:  entry:
-; CHECK-NEXT:    [[TMP0:%.*]] = load i8, ptr [[X:%.*]], align 1
-; CHECK-NEXT:    [[CONV:%.*]] = sext i8 [[TMP0]] to i32
-; CHECK-NEXT:    [[TMP1:%.*]] = load i8, ptr [[Y:%.*]], align 1
-; CHECK-NEXT:    [[CONV3:%.*]] = sext i8 [[TMP1]] to i32
-; CHECK-NEXT:    [[MUL:%.*]] = mul nsw i32 [[CONV3]], [[CONV]]
-; CHECK-NEXT:    [[ARRAYIDX_1:%.*]] = getelementptr inbounds nuw i8, ptr [[X]], i64 1
-; CHECK-NEXT:    [[TMP2:%.*]] = load i8, ptr [[ARRAYIDX_1]], align 1
-; CHECK-NEXT:    [[CONV_1:%.*]] = sext i8 [[TMP2]] to i32
-; CHECK-NEXT:    [[ARRAYIDX2_1:%.*]] = getelementptr inbounds nuw i8, ptr [[Y]], i64 1
-; CHECK-NEXT:    [[TMP3:%.*]] = load i8, ptr [[ARRAYIDX2_1]], align 1
-; CHECK-NEXT:    [[CONV3_1:%.*]] = sext i8 [[TMP3]] to i32
-; CHECK-NEXT:    [[MUL_1:%.*]] = mul nsw i32 [[CONV3_1]], [[CONV_1]]
-; CHECK-NEXT:    [[ADD_1:%.*]] = add nsw i32 [[MUL_1]], [[MUL]]
-; CHECK-NEXT:    [[ARRAYIDX_2:%.*]] = getelementptr inbounds nuw i8, ptr [[X]], i64 2
-; CHECK-NEXT:    [[TMP4:%.*]] = load i8, ptr [[ARRAYIDX_2]], align 1
-; CHECK-NEXT:    [[CONV_2:%.*]] = sext i8 [[TMP4]] to i32
-; CHECK-NEXT:    [[ARRAYIDX2_2:%.*]] = getelementptr inbounds nuw i8, ptr [[Y]], i64 2
-; CHECK-NEXT:    [[TMP16:%.*]] = load i8, ptr [[ARRAYIDX2_2]], align 1
-; CHECK-NEXT:    [[CONV3_2:%.*]] = sext i8 [[TMP16]] to i32
-; CHECK-NEXT:    [[MUL_2:%.*]] = mul nsw i32 [[CONV3_2]], [[CONV_2]]
-; CHECK-NEXT:    [[ADD_2:%.*]] = add nsw i32 [[MUL_2]], [[ADD_1]]
-; CHECK-NEXT:    [[ARRAYIDX_3:%.*]] = getelementptr inbounds nuw i8, ptr [[X]], i64 3
-; CHECK-NEXT:    [[TMP6:%.*]] = load i8, ptr [[ARRAYIDX_3]], align 1
-; CHECK-NEXT:    [[CONV_3:%.*]] = sext i8 [[TMP6]] to i32
-; CHECK-NEXT:    [[ARRAYIDX2_3:%.*]] = getelementptr inbounds nuw i8, ptr [[Y]], i64 3
-; CHECK-NEXT:    [[TMP7:%.*]] = load i8, ptr [[ARRAYIDX2_3]], align 1
-; CHECK-NEXT:    [[CONV3_3:%.*]] = sext i8 [[TMP7]] to i32
-; CHECK-NEXT:    [[MUL_3:%.*]] = mul nsw i32 [[CONV3_3]], [[CONV_3]]
-; CHECK-NEXT:    [[ADD_3:%.*]] = add nsw i32 [[MUL_3]], [[ADD_2]]
-; CHECK-NEXT:    [[ARRAYIDX_4:%.*]] = getelementptr inbounds nuw i8, ptr [[X]], i64 4
-; CHECK-NEXT:    [[TMP8:%.*]] = load i8, ptr [[ARRAYIDX_4]], align 1
-; CHECK-NEXT:    [[CONV_4:%.*]] = sext i8 [[TMP8]] to i32
-; CHECK-NEXT:    [[ARRAYIDX2_4:%.*]] = getelementptr inbounds nuw i8, ptr [[Y]], i64 4
-; CHECK-NEXT:    [[TMP9:%.*]] = load i8, ptr [[ARRAYIDX2_4]], align 1
-; CHECK-NEXT:    [[CONV3_4:%.*]] = sext i8 [[TMP9]] to i32
-; CHECK-NEXT:    [[MUL_4:%.*]] = mul nsw i32 [[CONV3_4]], [[CONV_4]]
-; CHECK-NEXT:    [[ADD_4:%.*]] = add nsw i32 [[MUL_4]], [[ADD_3]]
-; CHECK-NEXT:    [[ARRAYIDX_5:%.*]] = getelementptr inbounds nuw i8, ptr [[X]], i64 5
-; CHECK-NEXT:    [[TMP10:%.*]] = load i8, ptr [[ARRAYIDX_5]], align 1
-; CHECK-NEXT:    [[CONV_5:%.*]] = sext i8 [[TMP10]] to i32
-; CHECK-NEXT:    [[ARRAYIDX2_5:%.*]] = getelementptr inbounds nuw i8, ptr [[Y]], i64 5
-; CHECK-NEXT:    [[TMP11:%.*]] = load i8, ptr [[ARRAYIDX2_5]], align 1
-; CHECK-NEXT:    [[CONV3_5:%.*]] = sext i8 [[TMP11]] to i32
-; CHECK-NEXT:    [[MUL_5:%.*]] = mul nsw i32 [[CONV3_5]], [[CONV_5]]
-; CHECK-NEXT:    [[ADD_5:%.*]] = add nsw i32 [[MUL_5]], [[ADD_4]]
-; CHECK-NEXT:    [[ARRAYIDX_6:%.*]] = getelementptr inbounds nuw i8, ptr [[X]], i64 6
-; CHECK-NEXT:    [[TMP12:%.*]] = load i8, ptr [[ARRAYIDX_6]], align 1
-; CHECK-NEXT:    [[CONV_6:%.*]] = sext i8 [[TMP12]] to i32
-; CHECK-NEXT:    [[ARRAYIDX2_6:%.*]] = getelementptr inbounds nuw i8, ptr [[Y]], i64 6
-; CHECK-NEXT:    [[TMP13:%.*]] = load i8, ptr [[ARRAYIDX2_6]], align 1
-; CHECK-NEXT:    [[CONV3_6:%.*]] = sext i8 [[TMP13]] to i32
-; CHECK-NEXT:    [[MUL_6:%.*]] = mul nsw i32 [[CONV3_6]], [[CONV_6]]
-; CHECK-NEXT:    [[ADD_6:%.*]] = add nsw i32 [[MUL_6]], [[ADD_5]]
-; CHECK-NEXT:    [[ARRAYIDX_7:%.*]] = getelementptr inbounds nuw i8, ptr [[X]], i64 7
-; CHECK-NEXT:    [[TMP14:%.*]] = load i8, ptr [[ARRAYIDX_7]], align 1
-; CHECK-NEXT:    [[CONV_7:%.*]] = sext i8 [[TMP14]] to i32
-; CHECK-NEXT:    [[ARRAYIDX2_7:%.*]] = getelementptr inbounds nuw i8, ptr [[Y]], i64 7
-; CHECK-NEXT:    [[TMP15:%.*]] = load i8, ptr [[ARRAYIDX2_7]], align 1
-; CHECK-NEXT:    [[CONV3_7:%.*]] = sext i8 [[TMP15]] to i32
-; CHECK-NEXT:    [[MUL_7:%.*]] = mul nsw i32 [[CONV3_7]], [[CONV_7]]
-; CHECK-NEXT:    [[TMP5:%.*]] = add nsw i32 [[MUL_7]], [[ADD_6]]
-; CHECK-NEXT:    ret i32 [[TMP5]]
+define i32 @mla_v8i8_i32(ptr %x, ptr %y) {
 ;
-entry:
-  %0 = load i8, ptr %x
-  %conv = sext i8 %0 to i32
-  %1 = load i8, ptr %y
-  %conv3 = sext i8 %1 to i32
-  %mul = mul nsw i32 %conv3, %conv
-  %arrayidx.1 = getelementptr inbounds nuw i8, ptr %x, i64 1
-  %2 = load i8, ptr %arrayidx.1
-  %conv.1 = sext i8 %2 to i32
-  %arrayidx2.1 = getelementptr inbounds nuw i8, ptr %y, i64 1
-  %3 = load i8, ptr %arrayidx2.1
-  %conv3.1 = sext i8 %3 to i32
-  %mul.1 = mul nsw i32 %conv3.1, %conv.1
-  %add.1 = add nsw i32 %mul.1, %mul
-  %arrayidx.2 = getelementptr inbounds nuw i8, ptr %x, i64 2
-  %4 = load i8, ptr %arrayidx.2
-  %conv.2 = sext i8 %4 to i32
-  %arrayidx2.2 = getelementptr inbounds nuw i8, ptr %y, i64 2
-  %5 = load i8, ptr %arrayidx2.2
-  %conv3.2 = sext i8 %5 to i32
-  %mul.2 = mul nsw i32 %conv3.2, %conv.2
-  %add.2 = add nsw i32 %mul.2, %add.1
-  %arrayidx.3 = getelementptr inbounds nuw i8, ptr %x, i64 3
-  %6 = load i8, ptr %arrayidx.3
-  %conv.3 = sext i8 %6 to i32
-  %arrayidx2.3 = getelementptr inbounds nuw i8, ptr %y, i64 3
-  %7 = load i8, ptr %arrayidx2.3
-  %conv3.3 = sext i8 %7 to i32
-  %mul.3 = mul nsw i32 %conv3.3, %conv.3
-  %add.3 = add nsw i32 %mul.3, %add.2
-  %arrayidx.4 = getelementptr inbounds nuw i8, ptr %x, i64 4
-  %8 = load i8, ptr %arrayidx.4
-  %conv.4 = sext i8 %8 to i32
-  %arrayidx2.4 = getelementptr inbounds nuw i8, ptr %y, i64 4
-  %9 = load i8, ptr %arrayidx2.4
-  %conv3.4 = sext i8 %9 to i32
-  %mul.4 = mul nsw i32 %conv3.4, %conv.4
-  %add.4 = add nsw i32 %mul.4, %add.3
-  %arrayidx.5 = getelementptr inbounds nuw i8, ptr %x, i64 5
-  %10 = load i8, ptr %arrayidx.5
-  %conv.5 = sext i8 %10 to i32
-  %arrayidx2.5 = getelementptr inbounds nuw i8, ptr %y, i64 5
-  %11 = load i8, ptr %arrayidx2.5
-  %conv3.5 = sext i8 %11 to i32
-  %mul.5 = mul nsw i32 %conv3.5, %conv.5
-  %add.5 = add nsw i32 %mul.5, %add.4
-  %arrayidx.6 = getelementptr inbounds nuw i8, ptr %x, i64 6
-  %12 = load i8, ptr %arrayidx.6
-  %conv.6 = sext i8 %12 to i32
-  %arrayidx2.6 = getelementptr inbounds nuw i8, ptr %y, i64 6
-  %13 = load i8, ptr %arrayidx2.6
-  %conv3.6 = sext i8 %13 to i32
-  %mul.6 = mul nsw i32 %conv3.6, %conv.6
-  %add.6 = add nsw i32 %mul.6, %add.5
-  %arrayidx.7 = getelementptr inbounds nuw i8, ptr %x, i64 7
-  %14 = load i8, ptr %arrayidx.7
-  %conv.7 = sext i8 %14 to i32
-  %arrayidx2.7 = getelementptr inbounds nuw i8, ptr %y, i64 7
-  %15 = load i8, ptr %arrayidx2.7
-  %conv3.7 = sext i8 %15 to i32
-  %mul.7 = mul nsw i32 %conv3.7, %conv.7
-  %add.7 = add nsw i32 %mul.7, %add.6
-  ret i32 %add.7
-}
-
-define i32 @mla_v8i8_i32_no_dotprod(ptr %x, ptr %y) {
-; CHECK-LABEL: @mla_v8i8_i32_no_dotprod(
+; CHECK-LABEL: @mla_v8i8_i32(
 ; CHECK-NEXT:  entry:
 ; CHECK-NEXT:    [[TMP0:%.*]] = load i8, ptr [[X:%.*]], align 1
 ; CHECK-NEXT:    [[CONV:%.*]] = sext i8 [[TMP0]] to i32
@@ -271,3 +139,6 @@ entry:
   %add.7 = add nsw i32 %mul.7, %add.6
   ret i32 %add.7
 }
+;; NOTE: These prefixes are unused and the list is autogenerated. Do not add tests below this line:
+; DOTPROD: {{.*}}
+; NODOTPROD: {{.*}}



More information about the llvm-commits mailing list