[llvm-branch-commits] [RISCV] Cost i64 accumulator for Zvdot4a8i partial reductions (PR #216992)
via llvm-branch-commits
llvm-branch-commits at lists.llvm.org
Tue Aug 18 04:23:47 PDT 2026
llvmorg-github-actions[bot] wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-backend-risc-v
Author: Pengcheng Wang (wangpc-pp)
<details>
<summary>Changes</summary>
Now that `lowerPARTIAL_REDUCE_MLA` can lower an i64 accumulator with
i8 inputs using the dot-product instructions, teach the cost model
to price it so the vectorizer will form it.
- `getPartialReductionCost` accepts an i64 accumulator (reduction
factor 8), costing the `vdot4a*` plus the extra i32->i64 widen
and accumulate.
The i64 case requires a wide enough VF (LMUL) to reach the scale-8 factor,
matching how AArch64 only forms it under SVE.
Assisted-by: TRAE CLI (Opus 4.8)
---
Full diff: https://github.com/llvm/llvm-project/pull/216992.diff
2 Files Affected:
- (modified) llvm/lib/Target/RISCV/RISCVTargetTransformInfo.cpp (+26-5)
- (added) llvm/test/Transforms/LoopVectorize/RISCV/partial-reduce-dot-product-costs.ll (+120)
``````````diff
diff --git a/llvm/lib/Target/RISCV/RISCVTargetTransformInfo.cpp b/llvm/lib/Target/RISCV/RISCVTargetTransformInfo.cpp
index 0f636d078324c..772b72708f5dd 100644
--- a/llvm/lib/Target/RISCV/RISCVTargetTransformInfo.cpp
+++ b/llvm/lib/Target/RISCV/RISCVTargetTransformInfo.cpp
@@ -353,17 +353,38 @@ InstructionCost RISCVTTIImpl::getPartialReductionCost(
// zve32x is broken for partial_reduce_umla, but let's make sure we
// don't generate them.
+ // vdot4a* reduces four i8 products into an i32 result; an i64 accumulator is
+ // additionally supported by widening the i32 partial sums to i64 (see
+ // lowerPARTIAL_REDUCE_MLA). VF is the number of i8 input elements, so the
+ // reduction factor is AccumBits / 8 (4 for i32, 8 for i64).
if (!ST->hasStdExtZvdot4a8i() || ST->getELen() < 64 ||
Opcode != Instruction::Add || !BinOp || *BinOp != Instruction::Mul ||
InputTypeA != InputTypeB || !InputTypeA->isIntegerTy(8) ||
- !AccumType->isIntegerTy(32) || !VF.isKnownMultipleOf(4))
+ (!AccumType->isIntegerTy(32) && !AccumType->isIntegerTy(64)))
return InstructionCost::getInvalid();
- Type *Tp = VectorType::get(AccumType, VF.divideCoefficientBy(4));
- std::pair<InstructionCost, MVT> LT = getTypeLegalizationCost(Tp);
+ unsigned Ratio = AccumType->getScalarSizeInBits() / 8;
+ if (!VF.isKnownMultipleOf(Ratio))
+ return InstructionCost::getInvalid();
+
+ // Cost of the vdot4a* itself, which operates on the i32 intermediate type
+ // holding VF/4 elements.
+ Type *DotTp = VectorType::get(Type::getInt32Ty(AccumType->getContext()),
+ VF.divideCoefficientBy(4));
+ std::pair<InstructionCost, MVT> DotLT = getTypeLegalizationCost(DotTp);
// Note: Asuming all vdot4a* variants are equal cost
- return LT.first *
- getRISCVInstructionCost(RISCV::VDOT4A_VV, LT.second, CostKind);
+ InstructionCost Cost =
+ DotLT.first *
+ getRISCVInstructionCost(RISCV::VDOT4A_VV, DotLT.second, CostKind);
+
+ // Account for the widening extend + accumulate needed for an i64 result.
+ if (AccumType->isIntegerTy(64)) {
+ Type *AccTp = VectorType::get(AccumType, VF.divideCoefficientBy(Ratio));
+ std::pair<InstructionCost, MVT> AccLT = getTypeLegalizationCost(AccTp);
+ Cost += AccLT.first * 2;
+ }
+
+ return Cost;
}
bool RISCVTTIImpl::shouldExpandReduction(const IntrinsicInst *II) const {
diff --git a/llvm/test/Transforms/LoopVectorize/RISCV/partial-reduce-dot-product-costs.ll b/llvm/test/Transforms/LoopVectorize/RISCV/partial-reduce-dot-product-costs.ll
new file mode 100644
index 0000000000000..6a766748522ce
--- /dev/null
+++ b/llvm/test/Transforms/LoopVectorize/RISCV/partial-reduce-dot-product-costs.ll
@@ -0,0 +1,120 @@
+; NOTE: Assertions have been autogenerated by utils/update_analyze_test_checks.py UTC_ARGS: --filter "Cost.of.*EXPRESSION" --version 6
+; RUN: opt -passes=loop-vectorize -mattr=+v,+experimental-zvdot4a8i \
+; RUN: -tail-folding-policy=dont-fold-tail -debug-only=loop-vectorize \
+; RUN: -disable-output < %s 2>&1 | FileCheck %s
+
+; TODO: Remove -tail-folding-policy=dont-fold-tail when partial reductions with
+; EVL tail folding is supported.
+
+; REQUIRES: asserts
+target triple = "riscv64-none-unknown-elf"
+
+; vdot4a*: i8 inputs into an i32 accumulator (scale-4 partial reduction).
+define i32 @dot_i32(ptr %a, ptr %b) {
+; CHECK-LABEL: 'dot_i32'
+; CHECK: Cost of 1 for VF 8: EXPRESSION vp<[[VP8:%[0-9]+]]> = ir<%acc> + partial.reduce.add (mul (ir<%la> sext to i32), (ir<%lb> sext to i32))
+; CHECK: Cost of 1 for VF 8: EXPRESSION vp<[[VP8]]> = ir<%acc> + partial.reduce.add (mul (ir<%la> sext to i32), (ir<%lb> sext to i32))
+;
+entry:
+ br label %loop
+loop:
+ %iv = phi i64 [ 0, %entry ], [ %iv.next, %loop ]
+ %acc = phi i32 [ 0, %entry ], [ %add, %loop ]
+ %ga = getelementptr i8, ptr %a, i64 %iv
+ %la = load i8, ptr %ga, align 1
+ %ea = sext i8 %la to i32
+ %gb = getelementptr i8, ptr %b, i64 %iv
+ %lb = load i8, ptr %gb, align 1
+ %eb = sext i8 %lb to i32
+ %mul = mul i32 %ea, %eb
+ %add = add i32 %mul, %acc
+ %iv.next = add i64 %iv, 1
+ %ec = icmp eq i64 %iv.next, 1024
+ br i1 %ec, label %exit, label %loop, !llvm.loop !0
+exit:
+ ret i32 %add
+}
+
+; i8 inputs into an i64 accumulator, both operands sign-extended (scale-8
+; partial reduction). Costs the vdot4a* plus the extra i32->i64 widen and
+; accumulate.
+define i64 @dot_i64_ss(ptr %a, ptr %b) {
+; CHECK-LABEL: 'dot_i64_ss'
+; CHECK: Cost of 3 for VF 8: EXPRESSION vp<[[VP8:%[0-9]+]]> = ir<%acc> + partial.reduce.add (mul (ir<%la> sext to i64), (ir<%lb> sext to i64))
+; CHECK: Cost of 3 for VF 8: EXPRESSION vp<[[VP8]]> = ir<%acc> + partial.reduce.add (mul (ir<%la> sext to i64), (ir<%lb> sext to i64))
+;
+entry:
+ br label %loop
+loop:
+ %iv = phi i64 [ 0, %entry ], [ %iv.next, %loop ]
+ %acc = phi i64 [ 0, %entry ], [ %add, %loop ]
+ %ga = getelementptr i8, ptr %a, i64 %iv
+ %la = load i8, ptr %ga, align 1
+ %ea = sext i8 %la to i32
+ %gb = getelementptr i8, ptr %b, i64 %iv
+ %lb = load i8, ptr %gb, align 1
+ %eb = sext i8 %lb to i32
+ %mul = mul i32 %ea, %eb
+ %conv = sext i32 %mul to i64
+ %add = add i64 %conv, %acc
+ %iv.next = add i64 %iv, 1
+ %ec = icmp eq i64 %iv.next, 1024
+ br i1 %ec, label %exit, label %loop, !llvm.loop !0
+exit:
+ ret i64 %add
+}
+
+; Same as above but both operands zero-extended.
+define i64 @dot_i64_uu(ptr %a, ptr %b) {
+; CHECK-LABEL: 'dot_i64_uu'
+; CHECK: Cost of 3 for VF 8: EXPRESSION vp<[[VP8:%[0-9]+]]> = ir<%acc> + partial.reduce.add (mul (ir<%la> zext to i64), (ir<%lb> zext to i64))
+; CHECK: Cost of 3 for VF 8: EXPRESSION vp<[[VP8]]> = ir<%acc> + partial.reduce.add (mul (ir<%la> zext to i64), (ir<%lb> zext to i64))
+;
+entry:
+ br label %loop
+loop:
+ %iv = phi i64 [ 0, %entry ], [ %iv.next, %loop ]
+ %acc = phi i64 [ 0, %entry ], [ %add, %loop ]
+ %ga = getelementptr i8, ptr %a, i64 %iv
+ %la = load i8, ptr %ga, align 1
+ %ea = zext i8 %la to i32
+ %gb = getelementptr i8, ptr %b, i64 %iv
+ %lb = load i8, ptr %gb, align 1
+ %eb = zext i8 %lb to i32
+ %mul = mul i32 %ea, %eb
+ %conv = zext i32 %mul to i64
+ %add = add i64 %conv, %acc
+ %iv.next = add i64 %iv, 1
+ %ec = icmp eq i64 %iv.next, 1024
+ br i1 %ec, label %exit, label %loop, !llvm.loop !0
+exit:
+ ret i64 %add
+}
+
+; Mixed sign/zero extension is not a supported dot-product form, so no
+; partial reduction is created for the i64 accumulator.
+define i64 @dot_i64_su(ptr %a, ptr %b) {
+; CHECK-LABEL: 'dot_i64_su'
+entry:
+ br label %loop
+loop:
+ %iv = phi i64 [ 0, %entry ], [ %iv.next, %loop ]
+ %acc = phi i64 [ 0, %entry ], [ %add, %loop ]
+ %ga = getelementptr i8, ptr %a, i64 %iv
+ %la = load i8, ptr %ga, align 1
+ %ea = sext i8 %la to i32
+ %gb = getelementptr i8, ptr %b, i64 %iv
+ %lb = load i8, ptr %gb, align 1
+ %eb = zext i8 %lb to i32
+ %mul = mul i32 %ea, %eb
+ %conv = sext i32 %mul to i64
+ %add = add i64 %conv, %acc
+ %iv.next = add i64 %iv, 1
+ %ec = icmp eq i64 %iv.next, 1024
+ br i1 %ec, label %exit, label %loop, !llvm.loop !0
+exit:
+ ret i64 %add
+}
+
+!0 = distinct !{!0, !1}
+!1 = !{!"llvm.loop.vectorize.width", i32 8}
``````````
</details>
https://github.com/llvm/llvm-project/pull/216992
More information about the llvm-branch-commits
mailing list