[llvm] [LV] Support EVL for partial reduction and VPExpressionRecipe. (PR #205741)
Elvis Wang via llvm-commits
llvm-commits at lists.llvm.org
Tue Jun 30 17:21:10 PDT 2026
https://github.com/ElvisWang123 updated https://github.com/llvm/llvm-project/pull/205741
>From f3e04d569329dc09b1786b564c13d7eabd0f3219 Mon Sep 17 00:00:00 2001
From: Elvis Wang <elvis.wang at sifive.com>
Date: Tue, 23 Jun 2026 23:05:44 -0700
Subject: [PATCH 1/5] precommit tests.
---
.../VPlan/RISCV/partial-reduce-dot-product.ll | 100 ++
.../VPlan/RISCV/reductions-evl.ll | 1261 +++++++++++++++++
2 files changed, 1361 insertions(+)
create mode 100644 llvm/test/Transforms/LoopVectorize/VPlan/RISCV/partial-reduce-dot-product.ll
create mode 100644 llvm/test/Transforms/LoopVectorize/VPlan/RISCV/reductions-evl.ll
diff --git a/llvm/test/Transforms/LoopVectorize/VPlan/RISCV/partial-reduce-dot-product.ll b/llvm/test/Transforms/LoopVectorize/VPlan/RISCV/partial-reduce-dot-product.ll
new file mode 100644
index 0000000000000..582c5d3d783ee
--- /dev/null
+++ b/llvm/test/Transforms/LoopVectorize/VPlan/RISCV/partial-reduce-dot-product.ll
@@ -0,0 +1,100 @@
+; NOTE: Assertions have been autogenerated by utils/update_analyze_test_checks.py UTC_ARGS: --version 6
+; RUN: opt -passes=loop-vectorize -force-vector-width=4 -scalable-vectorization=on -mattr=+v,+experimental-zvdot4a8i -disable-output 2>&1 -vplan-print-after=optimizeEVLMasks < %s | FileCheck %s
+; RUN: opt -passes=loop-vectorize -mattr=+v,+experimental-zvdot4a8i -disable-output 2>&1 -vplan-print-after=optimizeEVLMasks < %s | FileCheck %s --check-prefixes=NON-VLA
+
+target triple = "riscv64-none-unknown-elf"
+
+define i32 @vdota4(ptr %a, ptr %b) #0 {
+; CHECK-LABEL: VPlan for loop in 'vdota4'
+; CHECK: VPlan 'Initial VPlan for VF={vscale x 4},UF={1}' {
+; CHECK-NEXT: Live-in vp<[[VP0:%[0-9]+]]> = VF * UF
+; CHECK-NEXT: Live-in vp<[[VP1:%[0-9]+]]> = vector-trip-count
+; CHECK-NEXT: Live-in ir<1024> = original trip-count
+; CHECK-EMPTY:
+; CHECK-NEXT: ir-bb<entry>:
+; CHECK-NEXT: Successor(s): scalar.ph, vector.ph
+; CHECK-EMPTY:
+; CHECK-NEXT: vector.ph:
+; CHECK-NEXT: EMIT vp<[[VP3:%[0-9]+]]> = reduction-start-vector ir<0>, ir<0>, ir<1>
+; CHECK-NEXT: Successor(s): vector loop
+; CHECK-EMPTY:
+; CHECK-NEXT: <x1> vector loop: {
+; CHECK-NEXT: vp<[[VP4:%[0-9]+]]> = CANONICAL-IV
+; CHECK-EMPTY:
+; CHECK-NEXT: vector.body:
+; CHECK-NEXT: CURRENT-ITERATION-PHI vp<[[VP5:%[0-9]+]]> = phi ir<0>, vp<%current.iteration.next>
+; CHECK-NEXT: WIDEN-REDUCTION-PHI ir<%accum> = phi (add) vp<[[VP3]]>, vp<[[VP10:%[0-9]+]]>
+; CHECK-NEXT: EMIT-SCALAR vp<%avl> = phi [ ir<1024>, vector.ph ], [ vp<%avl.next>, vector.body ]
+; CHECK-NEXT: EMIT-SCALAR vp<%evl> = EXPLICIT-VECTOR-LENGTH vp<%avl>
+; CHECK-NEXT: EMIT-SCALAR vp<[[VP6:%[0-9]+]]> = zext vp<%evl> to i64
+; CHECK-NEXT: vp<[[VP7:%[0-9]+]]> = SCALAR-STEPS vp<[[VP5]]>, ir<1>, vp<[[VP6]]>
+; CHECK-NEXT: CLONE ir<%gep.a> = getelementptr ir<%a>, vp<[[VP7]]>
+; CHECK-NEXT: vp<[[VP8:%[0-9]+]]> = vector-pointer ir<%gep.a>, ir<1>
+; CHECK-NEXT: WIDEN ir<%load.a> = vp.load vp<[[VP8]]>, vp<%evl>
+; CHECK-NEXT: WIDEN-CAST ir<%ext.a> = sext ir<%load.a> to i32
+; CHECK-NEXT: CLONE ir<%gep.b> = getelementptr ir<%b>, vp<[[VP7]]>
+; CHECK-NEXT: vp<[[VP9:%[0-9]+]]> = vector-pointer ir<%gep.b>, ir<1>
+; CHECK-NEXT: WIDEN ir<%load.b> = vp.load vp<[[VP9]]>, vp<%evl>
+; CHECK-NEXT: WIDEN-CAST ir<%ext.b> = zext ir<%load.b> to i32
+; CHECK-NEXT: WIDEN ir<%mul> = mul ir<%ext.b>, ir<%ext.a>
+; CHECK-NEXT: WIDEN ir<%add> = add ir<%mul>, ir<%accum>
+; CHECK-NEXT: WIDEN-INTRINSIC vp<[[VP10]]> = call llvm.vp.merge(ir<true>, ir<%add>, ir<%accum>, vp<%evl>)
+; CHECK-NEXT: EMIT-SCALAR vp<[[VP11:%[0-9]+]]> = zext vp<%evl> to i64
+; CHECK-NEXT: EMIT vp<%current.iteration.next> = add nuw vp<[[VP11]]>, vp<[[VP5]]>
+; CHECK-NEXT: EMIT vp<%avl.next> = sub nuw vp<%avl>, vp<[[VP11]]>
+; CHECK-NEXT: EMIT vp<%index.next> = add nuw vp<[[VP4]]>, vp<[[VP0]]>
+; CHECK-NEXT: EMIT branch-on-count vp<%index.next>, vp<[[VP1]]>
+; CHECK-NEXT: No successors
+; CHECK-NEXT: }
+; CHECK-NEXT: Successor(s): middle.block
+; CHECK-EMPTY:
+; CHECK-NEXT: middle.block:
+; CHECK-NEXT: EMIT vp<[[VP13:%[0-9]+]]> = compute-reduction-result (add) vp<[[VP10]]>
+; CHECK-NEXT: Successor(s): ir-bb<for.exit>
+; CHECK-EMPTY:
+; CHECK-NEXT: ir-bb<for.exit>:
+; CHECK-NEXT: IR %add.lcssa = phi i32 [ %add, %for.body ] (extra operand: vp<[[VP13]]> from middle.block)
+; CHECK-NEXT: No successors
+; CHECK-EMPTY:
+; CHECK-NEXT: scalar.ph:
+; CHECK-NEXT: Successor(s): ir-bb<for.body>
+; CHECK-EMPTY:
+; CHECK-NEXT: ir-bb<for.body>:
+; CHECK-NEXT: IR %iv = phi i64 [ 0, %entry ], [ %iv.next, %for.body ] (extra operand: ir<0> from scalar.ph)
+; CHECK-NEXT: IR %accum = phi i32 [ 0, %entry ], [ %add, %for.body ] (extra operand: ir<0> from scalar.ph)
+; CHECK-NEXT: IR %gep.a = getelementptr i8, ptr %a, i64 %iv
+; CHECK-NEXT: IR %load.a = load i8, ptr %gep.a, align 1
+; CHECK-NEXT: IR %ext.a = sext i8 %load.a to i32
+; CHECK-NEXT: IR %gep.b = getelementptr i8, ptr %b, i64 %iv
+; CHECK-NEXT: IR %load.b = load i8, ptr %gep.b, align 1
+; CHECK-NEXT: IR %ext.b = zext i8 %load.b to i32
+; CHECK-NEXT: IR %mul = mul i32 %ext.b, %ext.a
+; CHECK-NEXT: IR %add = add i32 %mul, %accum
+; CHECK-NEXT: IR %iv.next = add i64 %iv, 1
+; CHECK-NEXT: IR %exitcond.not = icmp eq i64 %iv.next, 1024
+; CHECK-NEXT: No successors
+; CHECK-NEXT: }
+;
+entry:
+ br label %for.body
+
+for.body: ; preds = %for.body, %entry
+ %iv = phi i64 [ 0, %entry ], [ %iv.next, %for.body ]
+ %accum = phi i32 [ 0, %entry ], [ %add, %for.body ]
+ %gep.a = getelementptr i8, ptr %a, i64 %iv
+ %load.a = load i8, ptr %gep.a, align 1
+ %ext.a = sext i8 %load.a to i32
+ %gep.b = getelementptr i8, ptr %b, i64 %iv
+ %load.b = load i8, ptr %gep.b, align 1
+ %ext.b = zext i8 %load.b to i32
+ %mul = mul i32 %ext.b, %ext.a
+ %add = add i32 %mul, %accum
+ %iv.next = add i64 %iv, 1
+ %exitcond.not = icmp eq i64 %iv.next, 1024
+ br i1 %exitcond.not, label %for.exit, label %for.body
+
+for.exit: ; preds = %for.body
+ ret i32 %add
+}
+;; NOTE: These prefixes are unused and the list is autogenerated. Do not add tests below this line:
+; NON-VLA: {{.*}}
diff --git a/llvm/test/Transforms/LoopVectorize/VPlan/RISCV/reductions-evl.ll b/llvm/test/Transforms/LoopVectorize/VPlan/RISCV/reductions-evl.ll
new file mode 100644
index 0000000000000..dbee5a169e264
--- /dev/null
+++ b/llvm/test/Transforms/LoopVectorize/VPlan/RISCV/reductions-evl.ll
@@ -0,0 +1,1261 @@
+; NOTE: Assertions have been autogenerated by utils/update_analyze_test_checks.py UTC_ARGS: --version 6
+; RUN: opt -passes=loop-vectorize -vplan-print-after="optimizeEVLMasks" -mtriple riscv64 -mattr=+v,+experimental-zvdot4a8i -force-vector-width=4 -scalable-vectorization=on -prefer-inloop-reductions -disable-output %s 2>&1 | FileCheck %s
+
+; Tests for printing VPlans with reductions.
+
+define float @print_reduction(i64 %n, ptr noalias %y) {
+; CHECK-LABEL: VPlan for loop in 'print_reduction'
+; CHECK: VPlan 'Initial VPlan for VF={vscale x 4},UF={1}' {
+; CHECK-NEXT: Live-in vp<[[VP0:%[0-9]+]]> = VF * UF
+; CHECK-NEXT: Live-in vp<[[VP1:%[0-9]+]]> = vector-trip-count
+; CHECK-NEXT: Live-in ir<%n> = original trip-count
+; CHECK-EMPTY:
+; CHECK-NEXT: ir-bb<entry>:
+; CHECK-NEXT: Successor(s): scalar.ph, vector.ph
+; CHECK-EMPTY:
+; CHECK-NEXT: vector.ph:
+; CHECK-NEXT: EMIT vp<[[VP3:%[0-9]+]]> = reduction-start-vector fast ir<0.000000e+00>, ir<0.000000e+00>, ir<1>
+; CHECK-NEXT: Successor(s): vector loop
+; CHECK-EMPTY:
+; CHECK-NEXT: <x1> vector loop: {
+; CHECK-NEXT: vp<[[VP4:%[0-9]+]]> = CANONICAL-IV
+; CHECK-EMPTY:
+; CHECK-NEXT: vector.body:
+; CHECK-NEXT: CURRENT-ITERATION-PHI vp<[[VP5:%[0-9]+]]> = phi ir<0>, vp<%current.iteration.next>
+; CHECK-NEXT: WIDEN-REDUCTION-PHI ir<%red> = phi (fadd) fast vp<[[VP3]]>, ir<%red.next>
+; CHECK-NEXT: EMIT-SCALAR vp<%avl> = phi [ ir<%n>, vector.ph ], [ vp<%avl.next>, vector.body ]
+; CHECK-NEXT: EMIT-SCALAR vp<%evl> = EXPLICIT-VECTOR-LENGTH vp<%avl>
+; CHECK-NEXT: EMIT-SCALAR vp<[[VP6:%[0-9]+]]> = zext vp<%evl> to i64
+; CHECK-NEXT: vp<[[VP7:%[0-9]+]]> = SCALAR-STEPS vp<[[VP5]]>, ir<1>, vp<[[VP6]]>
+; CHECK-NEXT: CLONE ir<%arrayidx> = getelementptr inbounds ir<%y>, vp<[[VP7]]>
+; CHECK-NEXT: vp<[[VP8:%[0-9]+]]> = vector-pointer inbounds ir<%arrayidx>, ir<1>
+; CHECK-NEXT: WIDEN ir<%lv> = vp.load vp<[[VP8]]>, vp<%evl>
+; CHECK-NEXT: REDUCE ir<%red.next> = ir<%red> + fast vp.reduce.fadd (ir<%lv>, vp<%evl>)
+; CHECK-NEXT: EMIT-SCALAR vp<[[VP9:%[0-9]+]]> = zext vp<%evl> to i64
+; CHECK-NEXT: EMIT vp<%current.iteration.next> = add vp<[[VP9]]>, vp<[[VP5]]>
+; CHECK-NEXT: EMIT vp<%avl.next> = sub nuw vp<%avl>, vp<[[VP9]]>
+; CHECK-NEXT: EMIT vp<%index.next> = add vp<[[VP4]]>, vp<[[VP0]]>
+; CHECK-NEXT: EMIT branch-on-count vp<%index.next>, vp<[[VP1]]>
+; CHECK-NEXT: No successors
+; CHECK-NEXT: }
+; CHECK-NEXT: Successor(s): middle.block
+; CHECK-EMPTY:
+; CHECK-NEXT: middle.block:
+; CHECK-NEXT: EMIT vp<[[VP11:%[0-9]+]]> = compute-reduction-result (fadd, in-loop) fast ir<%red.next>
+; CHECK-NEXT: Successor(s): ir-bb<exit>
+; CHECK-EMPTY:
+; CHECK-NEXT: ir-bb<exit>:
+; CHECK-NEXT: IR %red.next.lcssa = phi float [ %red.next, %loop ] (extra operand: vp<[[VP11]]> from middle.block)
+; CHECK-NEXT: No successors
+; CHECK-EMPTY:
+; CHECK-NEXT: scalar.ph:
+; CHECK-NEXT: Successor(s): ir-bb<loop>
+; CHECK-EMPTY:
+; CHECK-NEXT: ir-bb<loop>:
+; CHECK-NEXT: IR %iv = phi i64 [ %iv.next, %loop ], [ 0, %entry ] (extra operand: ir<0> from scalar.ph)
+; CHECK-NEXT: IR %red = phi float [ %red.next, %loop ], [ 0.000000e+00, %entry ] (extra operand: ir<0.000000e+00> from scalar.ph)
+; CHECK-NEXT: IR %arrayidx = getelementptr inbounds float, ptr %y, i64 %iv
+; CHECK-NEXT: IR %lv = load float, ptr %arrayidx, align 4
+; CHECK-NEXT: IR %red.next = fadd fast float %lv, %red
+; CHECK-NEXT: IR %iv.next = add i64 %iv, 1
+; CHECK-NEXT: IR %exitcond = icmp eq i64 %iv.next, %n
+; CHECK-NEXT: No successors
+; CHECK-NEXT: }
+;
+entry:
+ br label %loop
+
+loop: ; preds = %entry, %loop
+ %iv = phi i64 [ %iv.next, %loop ], [ 0, %entry ]
+ %red = phi float [ %red.next, %loop ], [ 0.0, %entry ]
+ %arrayidx = getelementptr inbounds float, ptr %y, i64 %iv
+ %lv = load float, ptr %arrayidx, align 4
+ %red.next = fadd fast float %lv, %red
+ %iv.next = add i64 %iv, 1
+ %exitcond = icmp eq i64 %iv.next, %n
+ br i1 %exitcond, label %exit, label %loop
+
+exit: ; preds = %loop, %entry
+ ret float %red.next
+}
+
+define void @print_reduction_with_invariant_store(i64 %n, ptr noalias %y, ptr noalias %dst) {
+; CHECK-LABEL: VPlan for loop in 'print_reduction_with_invariant_store'
+; CHECK: VPlan 'Initial VPlan for VF={vscale x 4},UF={1}' {
+; CHECK-NEXT: Live-in vp<[[VP0:%[0-9]+]]> = VF * UF
+; CHECK-NEXT: Live-in vp<[[VP1:%[0-9]+]]> = vector-trip-count
+; CHECK-NEXT: Live-in ir<%n> = original trip-count
+; CHECK-EMPTY:
+; CHECK-NEXT: ir-bb<entry>:
+; CHECK-NEXT: Successor(s): scalar.ph, vector.ph
+; CHECK-EMPTY:
+; CHECK-NEXT: vector.ph:
+; CHECK-NEXT: EMIT vp<[[VP3:%[0-9]+]]> = reduction-start-vector fast ir<0.000000e+00>, ir<0.000000e+00>, ir<1>
+; CHECK-NEXT: Successor(s): vector loop
+; CHECK-EMPTY:
+; CHECK-NEXT: <x1> vector loop: {
+; CHECK-NEXT: vp<[[VP4:%[0-9]+]]> = CANONICAL-IV
+; CHECK-EMPTY:
+; CHECK-NEXT: vector.body:
+; CHECK-NEXT: CURRENT-ITERATION-PHI vp<[[VP5:%[0-9]+]]> = phi ir<0>, vp<%current.iteration.next>
+; CHECK-NEXT: WIDEN-REDUCTION-PHI ir<%red> = phi (fadd) fast vp<[[VP3]]>, ir<%red.next>
+; CHECK-NEXT: EMIT-SCALAR vp<%avl> = phi [ ir<%n>, vector.ph ], [ vp<%avl.next>, vector.body ]
+; CHECK-NEXT: EMIT-SCALAR vp<%evl> = EXPLICIT-VECTOR-LENGTH vp<%avl>
+; CHECK-NEXT: EMIT-SCALAR vp<[[VP6:%[0-9]+]]> = zext vp<%evl> to i64
+; CHECK-NEXT: vp<[[VP7:%[0-9]+]]> = SCALAR-STEPS vp<[[VP5]]>, ir<1>, vp<[[VP6]]>
+; CHECK-NEXT: CLONE ir<%arrayidx> = getelementptr inbounds ir<%y>, vp<[[VP7]]>
+; CHECK-NEXT: vp<[[VP8:%[0-9]+]]> = vector-pointer inbounds ir<%arrayidx>, ir<1>
+; CHECK-NEXT: WIDEN ir<%lv> = vp.load vp<[[VP8]]>, vp<%evl>
+; CHECK-NEXT: REDUCE ir<%red.next> = ir<%red> + fast vp.reduce.fadd (ir<%lv>, vp<%evl>)
+; CHECK-NEXT: EMIT-SCALAR vp<[[VP9:%[0-9]+]]> = zext vp<%evl> to i64
+; CHECK-NEXT: EMIT vp<%current.iteration.next> = add vp<[[VP9]]>, vp<[[VP5]]>
+; CHECK-NEXT: EMIT vp<%avl.next> = sub nuw vp<%avl>, vp<[[VP9]]>
+; CHECK-NEXT: EMIT vp<%index.next> = add vp<[[VP4]]>, vp<[[VP0]]>
+; CHECK-NEXT: EMIT branch-on-count vp<%index.next>, vp<[[VP1]]>
+; CHECK-NEXT: No successors
+; CHECK-NEXT: }
+; CHECK-NEXT: Successor(s): middle.block
+; CHECK-EMPTY:
+; CHECK-NEXT: middle.block:
+; CHECK-NEXT: EMIT vp<[[VP11:%[0-9]+]]> = compute-reduction-result (fadd, in-loop) fast ir<%red.next>
+; CHECK-NEXT: CLONE store vp<[[VP11]]>, ir<%dst>
+; CHECK-NEXT: Successor(s): ir-bb<exit>
+; CHECK-EMPTY:
+; CHECK-NEXT: ir-bb<exit>:
+; CHECK-NEXT: No successors
+; CHECK-EMPTY:
+; CHECK-NEXT: scalar.ph:
+; CHECK-NEXT: Successor(s): ir-bb<loop>
+; CHECK-EMPTY:
+; CHECK-NEXT: ir-bb<loop>:
+; CHECK-NEXT: IR %iv = phi i64 [ %iv.next, %loop ], [ 0, %entry ] (extra operand: ir<0> from scalar.ph)
+; CHECK-NEXT: IR %red = phi float [ %red.next, %loop ], [ 0.000000e+00, %entry ] (extra operand: ir<0.000000e+00> from scalar.ph)
+; CHECK-NEXT: IR %arrayidx = getelementptr inbounds float, ptr %y, i64 %iv
+; CHECK-NEXT: IR %lv = load float, ptr %arrayidx, align 4
+; CHECK-NEXT: IR %red.next = fadd fast float %lv, %red
+; CHECK-NEXT: IR store float %red.next, ptr %dst, align 4
+; CHECK-NEXT: IR %iv.next = add i64 %iv, 1
+; CHECK-NEXT: IR %exitcond = icmp eq i64 %iv.next, %n
+; CHECK-NEXT: No successors
+; CHECK-NEXT: }
+;
+entry:
+ br label %loop
+
+loop: ; preds = %entry, %loop
+ %iv = phi i64 [ %iv.next, %loop ], [ 0, %entry ]
+ %red = phi float [ %red.next, %loop ], [ 0.0, %entry ]
+ %arrayidx = getelementptr inbounds float, ptr %y, i64 %iv
+ %lv = load float, ptr %arrayidx, align 4
+ %red.next = fadd fast float %lv, %red
+ store float %red.next, ptr %dst, align 4
+ %iv.next = add i64 %iv, 1
+ %exitcond = icmp eq i64 %iv.next, %n
+ br i1 %exitcond, label %exit, label %loop
+
+exit: ; preds = %loop, %entry
+ ret void
+}
+
+define float @print_fmuladd_strict(ptr %a, ptr %b, i64 %n) {
+; CHECK-LABEL: VPlan for loop in 'print_fmuladd_strict'
+; CHECK: VPlan 'Initial VPlan for VF={vscale x 4},UF={1}' {
+; CHECK-NEXT: Live-in vp<[[VP0:%[0-9]+]]> = VF * UF
+; CHECK-NEXT: Live-in vp<[[VP1:%[0-9]+]]> = vector-trip-count
+; CHECK-NEXT: Live-in ir<%n> = original trip-count
+; CHECK-EMPTY:
+; CHECK-NEXT: ir-bb<entry>:
+; CHECK-NEXT: Successor(s): scalar.ph, vector.ph
+; CHECK-EMPTY:
+; CHECK-NEXT: vector.ph:
+; CHECK-NEXT: EMIT vp<[[VP3:%[0-9]+]]> = reduction-start-vector reassoc nnan ninf nsz ir<0.000000e+00>, ir<0.000000e+00>, ir<1>
+; CHECK-NEXT: Successor(s): vector loop
+; CHECK-EMPTY:
+; CHECK-NEXT: <x1> vector loop: {
+; CHECK-NEXT: vp<[[VP4:%[0-9]+]]> = CANONICAL-IV
+; CHECK-EMPTY:
+; CHECK-NEXT: vector.body:
+; CHECK-NEXT: CURRENT-ITERATION-PHI vp<[[VP5:%[0-9]+]]> = phi ir<0>, vp<%current.iteration.next>
+; CHECK-NEXT: WIDEN-REDUCTION-PHI ir<%sum.07> = phi (fmuladd) reassoc nnan ninf nsz vp<[[VP3]]>, ir<%muladd>
+; CHECK-NEXT: EMIT-SCALAR vp<%avl> = phi [ ir<%n>, vector.ph ], [ vp<%avl.next>, vector.body ]
+; CHECK-NEXT: EMIT-SCALAR vp<%evl> = EXPLICIT-VECTOR-LENGTH vp<%avl>
+; CHECK-NEXT: EMIT-SCALAR vp<[[VP6:%[0-9]+]]> = zext vp<%evl> to i64
+; CHECK-NEXT: vp<[[VP7:%[0-9]+]]> = SCALAR-STEPS vp<[[VP5]]>, ir<1>, vp<[[VP6]]>
+; CHECK-NEXT: CLONE ir<%arrayidx> = getelementptr inbounds ir<%a>, vp<[[VP7]]>
+; CHECK-NEXT: vp<[[VP8:%[0-9]+]]> = vector-pointer inbounds ir<%arrayidx>, ir<1>
+; CHECK-NEXT: WIDEN ir<%l.a> = vp.load vp<[[VP8]]>, vp<%evl>
+; CHECK-NEXT: CLONE ir<%arrayidx2> = getelementptr inbounds ir<%b>, vp<[[VP7]]>
+; CHECK-NEXT: vp<[[VP9:%[0-9]+]]> = vector-pointer inbounds ir<%arrayidx2>, ir<1>
+; CHECK-NEXT: WIDEN ir<%l.b> = vp.load vp<[[VP9]]>, vp<%evl>
+; CHECK-NEXT: EMIT vp<[[VP10:%[0-9]+]]> = fmul reassoc nnan ninf nsz ir<%l.a>, ir<%l.b>
+; CHECK-NEXT: REDUCE ir<%muladd> = ir<%sum.07> + reassoc nnan ninf nsz vp.reduce.fadd (vp<[[VP10]]>, vp<%evl>)
+; CHECK-NEXT: EMIT-SCALAR vp<[[VP11:%[0-9]+]]> = zext vp<%evl> to i64
+; CHECK-NEXT: EMIT vp<%current.iteration.next> = add vp<[[VP11]]>, vp<[[VP5]]>
+; CHECK-NEXT: EMIT vp<%avl.next> = sub nuw vp<%avl>, vp<[[VP11]]>
+; CHECK-NEXT: EMIT vp<%index.next> = add vp<[[VP4]]>, vp<[[VP0]]>
+; CHECK-NEXT: EMIT branch-on-count vp<%index.next>, vp<[[VP1]]>
+; CHECK-NEXT: No successors
+; CHECK-NEXT: }
+; CHECK-NEXT: Successor(s): middle.block
+; CHECK-EMPTY:
+; CHECK-NEXT: middle.block:
+; CHECK-NEXT: EMIT vp<[[VP13:%[0-9]+]]> = compute-reduction-result (fmuladd, in-loop) reassoc nnan ninf nsz ir<%muladd>
+; CHECK-NEXT: Successor(s): ir-bb<exit>
+; CHECK-EMPTY:
+; CHECK-NEXT: ir-bb<exit>:
+; CHECK-NEXT: IR %muladd.lcssa = phi float [ %muladd, %loop ] (extra operand: vp<[[VP13]]> from middle.block)
+; CHECK-NEXT: No successors
+; CHECK-EMPTY:
+; CHECK-NEXT: scalar.ph:
+; CHECK-NEXT: Successor(s): ir-bb<loop>
+; CHECK-EMPTY:
+; CHECK-NEXT: ir-bb<loop>:
+; CHECK-NEXT: IR %iv = phi i64 [ 0, %entry ], [ %iv.next, %loop ] (extra operand: ir<0> from scalar.ph)
+; CHECK-NEXT: IR %sum.07 = phi float [ 0.000000e+00, %entry ], [ %muladd, %loop ] (extra operand: ir<0.000000e+00> from scalar.ph)
+; CHECK-NEXT: IR %arrayidx = getelementptr inbounds float, ptr %a, i64 %iv
+; CHECK-NEXT: IR %l.a = load float, ptr %arrayidx, align 4
+; CHECK-NEXT: IR %arrayidx2 = getelementptr inbounds float, ptr %b, i64 %iv
+; CHECK-NEXT: IR %l.b = load float, ptr %arrayidx2, align 4
+; CHECK-NEXT: IR %muladd = tail call reassoc nnan ninf nsz float @llvm.fmuladd.f32(float %l.a, float %l.b, float %sum.07)
+; CHECK-NEXT: IR %iv.next = add nuw nsw i64 %iv, 1
+; CHECK-NEXT: IR %exitcond.not = icmp eq i64 %iv.next, %n
+; CHECK-NEXT: No successors
+; CHECK-NEXT: }
+;
+entry:
+ br label %loop
+
+loop:
+ %iv = phi i64 [ 0, %entry ], [ %iv.next, %loop ]
+ %sum.07 = phi float [ 0.000000e+00, %entry ], [ %muladd, %loop ]
+ %arrayidx = getelementptr inbounds float, ptr %a, i64 %iv
+ %l.a = load float, ptr %arrayidx, align 4
+ %arrayidx2 = getelementptr inbounds float, ptr %b, i64 %iv
+ %l.b = load float, ptr %arrayidx2, align 4
+ ; SIFIVE_CUSTOMIZATION
+ ; Add reassoc due to customization from https://github.com/sifive/riscv-llvm-internal/pull/820.
+ %muladd = tail call nnan ninf nsz reassoc float @llvm.fmuladd.f32(float %l.a, float %l.b, float %sum.07)
+ ; End SIFIVE_CUSTOMIZATION
+ %iv.next = add nuw nsw i64 %iv, 1
+ %exitcond.not = icmp eq i64 %iv.next, %n
+ br i1 %exitcond.not, label %exit, label %loop
+
+exit:
+ ret float %muladd
+}
+
+define i64 @find_last_iv(ptr %a, i64 %n, i64 %start) {
+; CHECK-LABEL: VPlan for loop in 'find_last_iv'
+; CHECK: VPlan 'Initial VPlan for VF={vscale x 4},UF={1}' {
+; CHECK-NEXT: Live-in vp<[[VP0:%[0-9]+]]> = VF * UF
+; CHECK-NEXT: Live-in vp<[[VP1:%[0-9]+]]> = vector-trip-count
+; CHECK-NEXT: Live-in ir<%n> = original trip-count
+; CHECK-EMPTY:
+; CHECK-NEXT: ir-bb<entry>:
+; CHECK-NEXT: Successor(s): scalar.ph, vector.ph
+; CHECK-EMPTY:
+; CHECK-NEXT: vector.ph:
+; CHECK-NEXT: Successor(s): vector loop
+; CHECK-EMPTY:
+; CHECK-NEXT: <x1> vector loop: {
+; CHECK-NEXT: vp<[[VP3:%[0-9]+]]> = CANONICAL-IV
+; CHECK-EMPTY:
+; CHECK-NEXT: vector.body:
+; CHECK-NEXT: CURRENT-ITERATION-PHI vp<[[VP4:%[0-9]+]]> = phi ir<0>, vp<%current.iteration.next>
+; CHECK-NEXT: ir<%iv> = WIDEN-INDUCTION nuw nsw ir<0>, ir<1>, vp<[[VP5:%[0-9]+]]>
+; CHECK-NEXT: WIDEN-REDUCTION-PHI ir<%rdx> = phi (find-iv) ir<-9223372036854775808>, vp<[[VP8:%[0-9]+]]>
+; CHECK-NEXT: EMIT-SCALAR vp<%avl> = phi [ ir<%n>, vector.ph ], [ vp<%avl.next>, vector.body ]
+; CHECK-NEXT: EMIT-SCALAR vp<%evl> = EXPLICIT-VECTOR-LENGTH vp<%avl>
+; CHECK-NEXT: EMIT-SCALAR vp<[[VP5]]> = zext vp<%evl> to i64
+; CHECK-NEXT: vp<[[VP6:%[0-9]+]]> = SCALAR-STEPS vp<[[VP4]]>, ir<1>, vp<[[VP5]]>
+; CHECK-NEXT: CLONE ir<%gep.a> = getelementptr inbounds ir<%a>, vp<[[VP6]]>
+; CHECK-NEXT: vp<[[VP7:%[0-9]+]]> = vector-pointer inbounds ir<%gep.a>, ir<1>
+; CHECK-NEXT: WIDEN ir<%l.a> = vp.load vp<[[VP7]]>, vp<%evl>
+; CHECK-NEXT: WIDEN ir<%cmp2> = icmp eq ir<%l.a>, ir<%start>
+; CHECK-NEXT: WIDEN ir<%cond> = select ir<%cmp2>, ir<%iv>, ir<%rdx>
+; CHECK-NEXT: WIDEN-INTRINSIC vp<[[VP8]]> = call llvm.vp.merge(ir<true>, ir<%cond>, ir<%rdx>, vp<%evl>)
+; CHECK-NEXT: EMIT-SCALAR vp<[[VP9:%[0-9]+]]> = zext vp<%evl> to i64
+; CHECK-NEXT: EMIT vp<%current.iteration.next> = add vp<[[VP9]]>, vp<[[VP4]]>
+; CHECK-NEXT: EMIT vp<%avl.next> = sub nuw vp<%avl>, vp<[[VP9]]>
+; CHECK-NEXT: EMIT vp<%index.next> = add vp<[[VP3]]>, vp<[[VP0]]>
+; CHECK-NEXT: EMIT branch-on-count vp<%index.next>, vp<[[VP1]]>
+; CHECK-NEXT: No successors
+; CHECK-NEXT: }
+; CHECK-NEXT: Successor(s): middle.block
+; CHECK-EMPTY:
+; CHECK-NEXT: middle.block:
+; CHECK-NEXT: EMIT vp<[[VP11:%[0-9]+]]> = compute-reduction-result (smax) vp<[[VP8]]>
+; CHECK-NEXT: EMIT vp<[[VP12:%[0-9]+]]> = icmp ne vp<[[VP11]]>, ir<-9223372036854775808>
+; CHECK-NEXT: EMIT vp<[[VP13:%[0-9]+]]> = select vp<[[VP12]]>, vp<[[VP11]]>, ir<%start>
+; CHECK-NEXT: Successor(s): ir-bb<exit>
+; CHECK-EMPTY:
+; CHECK-NEXT: ir-bb<exit>:
+; CHECK-NEXT: IR %cond.lcssa = phi i64 [ %cond, %loop ] (extra operand: vp<[[VP13]]> from middle.block)
+; CHECK-NEXT: No successors
+; CHECK-EMPTY:
+; CHECK-NEXT: scalar.ph:
+; CHECK-NEXT: Successor(s): ir-bb<loop>
+; CHECK-EMPTY:
+; CHECK-NEXT: ir-bb<loop>:
+; CHECK-NEXT: IR %iv = phi i64 [ 0, %entry ], [ %inc, %loop ] (extra operand: ir<0> from scalar.ph)
+; CHECK-NEXT: IR %rdx = phi i64 [ %start, %entry ], [ %cond, %loop ] (extra operand: ir<%start> from scalar.ph)
+; CHECK-NEXT: IR %gep.a = getelementptr inbounds i64, ptr %a, i64 %iv
+; CHECK-NEXT: IR %l.a = load i64, ptr %gep.a, align 8
+; CHECK-NEXT: IR %cmp2 = icmp eq i64 %l.a, %start
+; CHECK-NEXT: IR %cond = select i1 %cmp2, i64 %iv, i64 %rdx
+; CHECK-NEXT: IR %inc = add nuw nsw i64 %iv, 1
+; CHECK-NEXT: IR %exitcond.not = icmp eq i64 %inc, %n
+; CHECK-NEXT: No successors
+; CHECK-NEXT: }
+;
+entry:
+ br label %loop
+
+loop:
+ %iv = phi i64 [ 0, %entry ], [ %inc, %loop ]
+ %rdx = phi i64 [ %start, %entry ], [ %cond, %loop ]
+ %gep.a = getelementptr inbounds i64, ptr %a, i64 %iv
+ %l.a = load i64, ptr %gep.a, align 8
+ %cmp2 = icmp eq i64 %l.a, %start
+ %cond = select i1 %cmp2, i64 %iv, i64 %rdx
+ %inc = add nuw nsw i64 %iv, 1
+ %exitcond.not = icmp eq i64 %inc, %n
+ br i1 %exitcond.not, label %exit, label %loop
+
+exit:
+ ret i64 %cond
+}
+
+define i64 @print_extended_reduction(ptr nocapture readonly %x, ptr nocapture readonly %y, i32 %n) {
+; CHECK-LABEL: VPlan for loop in 'print_extended_reduction'
+; CHECK: VPlan 'Initial VPlan for VF={vscale x 4},UF={1}' {
+; CHECK-NEXT: Live-in vp<[[VP0:%[0-9]+]]> = VF * UF
+; CHECK-NEXT: Live-in vp<[[VP1:%[0-9]+]]> = vector-trip-count
+; CHECK-NEXT: Live-in ir<%n> = original trip-count
+; CHECK-EMPTY:
+; CHECK-NEXT: ir-bb<entry>:
+; CHECK-NEXT: Successor(s): scalar.ph, vector.ph
+; CHECK-EMPTY:
+; CHECK-NEXT: vector.ph:
+; CHECK-NEXT: EMIT vp<[[VP3:%[0-9]+]]> = reduction-start-vector ir<0>, ir<0>, ir<1>
+; CHECK-NEXT: Successor(s): vector loop
+; CHECK-EMPTY:
+; CHECK-NEXT: <x1> vector loop: {
+; CHECK-NEXT: vp<[[VP4:%[0-9]+]]> = CANONICAL-IV
+; CHECK-EMPTY:
+; CHECK-NEXT: vector.body:
+; CHECK-NEXT: CURRENT-ITERATION-PHI vp<[[VP5:%[0-9]+]]> = phi ir<0>, vp<%current.iteration.next>
+; CHECK-NEXT: WIDEN-REDUCTION-PHI ir<%rdx> = phi (add) vp<[[VP3]]>, ir<%rdx.next>
+; CHECK-NEXT: EMIT-SCALAR vp<%avl> = phi [ ir<%n>, vector.ph ], [ vp<%avl.next>, vector.body ]
+; CHECK-NEXT: EMIT-SCALAR vp<%evl> = EXPLICIT-VECTOR-LENGTH vp<%avl>
+; CHECK-NEXT: vp<[[VP6:%[0-9]+]]> = SCALAR-STEPS vp<[[VP5]]>, ir<1>, vp<%evl>
+; CHECK-NEXT: CLONE ir<%arrayidx> = getelementptr inbounds ir<%x>, vp<[[VP6]]>
+; CHECK-NEXT: vp<[[VP7:%[0-9]+]]> = vector-pointer inbounds ir<%arrayidx>, ir<1>
+; CHECK-NEXT: WIDEN ir<%load0> = vp.load vp<[[VP7]]>, vp<%evl>
+; CHECK-NEXT: WIDEN-CAST ir<%conv0> = zext ir<%load0> to i64
+; CHECK-NEXT: REDUCE ir<%rdx.next> = ir<%rdx> + vp.reduce.add (ir<%conv0>, vp<%evl>)
+; CHECK-NEXT: EMIT vp<%current.iteration.next> = add vp<%evl>, vp<[[VP5]]>
+; CHECK-NEXT: EMIT vp<%avl.next> = sub nuw vp<%avl>, vp<%evl>
+; CHECK-NEXT: EMIT vp<%index.next> = add vp<[[VP4]]>, vp<[[VP0]]>
+; CHECK-NEXT: EMIT branch-on-count vp<%index.next>, vp<[[VP1]]>
+; CHECK-NEXT: No successors
+; CHECK-NEXT: }
+; CHECK-NEXT: Successor(s): middle.block
+; CHECK-EMPTY:
+; CHECK-NEXT: middle.block:
+; CHECK-NEXT: EMIT vp<[[VP9:%[0-9]+]]> = compute-reduction-result (add, in-loop) ir<%rdx.next>
+; CHECK-NEXT: Successor(s): ir-bb<exit>
+; CHECK-EMPTY:
+; CHECK-NEXT: ir-bb<exit>:
+; CHECK-NEXT: IR %r.0.lcssa = phi i64 [ %rdx.next, %loop ] (extra operand: vp<[[VP9]]> from middle.block)
+; CHECK-NEXT: No successors
+; CHECK-EMPTY:
+; CHECK-NEXT: scalar.ph:
+; CHECK-NEXT: Successor(s): ir-bb<loop>
+; CHECK-EMPTY:
+; CHECK-NEXT: ir-bb<loop>:
+; CHECK-NEXT: IR %iv = phi i32 [ %iv.next, %loop ], [ 0, %entry ] (extra operand: ir<0> from scalar.ph)
+; CHECK-NEXT: IR %rdx = phi i64 [ %rdx.next, %loop ], [ 0, %entry ] (extra operand: ir<0> from scalar.ph)
+; CHECK-NEXT: IR %arrayidx = getelementptr inbounds i32, ptr %x, i32 %iv
+; CHECK-NEXT: IR %load0 = load i32, ptr %arrayidx, align 4
+; CHECK-NEXT: IR %conv0 = zext i32 %load0 to i64
+; CHECK-NEXT: IR %rdx.next = add nsw i64 %rdx, %conv0
+; CHECK-NEXT: IR %iv.next = add nuw nsw i32 %iv, 1
+; CHECK-NEXT: IR %exitcond = icmp eq i32 %iv.next, %n
+; CHECK-NEXT: No successors
+; CHECK-NEXT: }
+;
+entry:
+ br label %loop
+
+loop:
+ %iv = phi i32 [ %iv.next, %loop ], [ 0, %entry ]
+ %rdx = phi i64 [ %rdx.next, %loop ], [ 0, %entry ]
+ %arrayidx = getelementptr inbounds i32, ptr %x, i32 %iv
+ %load0 = load i32, ptr %arrayidx, align 4
+ %conv0 = zext i32 %load0 to i64
+ %rdx.next = add nsw i64 %rdx, %conv0
+ %iv.next = add nuw nsw i32 %iv, 1
+ %exitcond = icmp eq i32 %iv.next, %n
+ br i1 %exitcond, label %exit, label %loop
+
+exit:
+ %r.0.lcssa = phi i64 [ %rdx.next, %loop ]
+ ret i64 %r.0.lcssa
+}
+
+define i64 @print_mulacc(ptr nocapture readonly %x, ptr nocapture readonly %y, i32 %n) {
+; CHECK-LABEL: VPlan for loop in 'print_mulacc'
+; CHECK: VPlan 'Initial VPlan for VF={vscale x 4},UF={1}' {
+; CHECK-NEXT: Live-in vp<[[VP0:%[0-9]+]]> = VF * UF
+; CHECK-NEXT: Live-in vp<[[VP1:%[0-9]+]]> = vector-trip-count
+; CHECK-NEXT: Live-in ir<%n> = original trip-count
+; CHECK-EMPTY:
+; CHECK-NEXT: ir-bb<entry>:
+; CHECK-NEXT: Successor(s): scalar.ph, vector.ph
+; CHECK-EMPTY:
+; CHECK-NEXT: vector.ph:
+; CHECK-NEXT: EMIT vp<[[VP3:%[0-9]+]]> = reduction-start-vector ir<0>, ir<0>, ir<1>
+; CHECK-NEXT: Successor(s): vector loop
+; CHECK-EMPTY:
+; CHECK-NEXT: <x1> vector loop: {
+; CHECK-NEXT: vp<[[VP4:%[0-9]+]]> = CANONICAL-IV
+; CHECK-EMPTY:
+; CHECK-NEXT: vector.body:
+; CHECK-NEXT: CURRENT-ITERATION-PHI vp<[[VP5:%[0-9]+]]> = phi ir<0>, vp<%current.iteration.next>
+; CHECK-NEXT: WIDEN-REDUCTION-PHI ir<%rdx> = phi (add) vp<[[VP3]]>, ir<%rdx.next>
+; CHECK-NEXT: EMIT-SCALAR vp<%avl> = phi [ ir<%n>, vector.ph ], [ vp<%avl.next>, vector.body ]
+; CHECK-NEXT: EMIT-SCALAR vp<%evl> = EXPLICIT-VECTOR-LENGTH vp<%avl>
+; CHECK-NEXT: vp<[[VP6:%[0-9]+]]> = SCALAR-STEPS vp<[[VP5]]>, ir<1>, vp<%evl>
+; CHECK-NEXT: CLONE ir<%arrayidx> = getelementptr inbounds ir<%x>, vp<[[VP6]]>
+; CHECK-NEXT: vp<[[VP7:%[0-9]+]]> = vector-pointer inbounds ir<%arrayidx>, ir<1>
+; CHECK-NEXT: WIDEN ir<%load0> = vp.load vp<[[VP7]]>, vp<%evl>
+; CHECK-NEXT: CLONE ir<%arrayidx1> = getelementptr inbounds ir<%y>, vp<[[VP6]]>
+; CHECK-NEXT: vp<[[VP8:%[0-9]+]]> = vector-pointer inbounds ir<%arrayidx1>, ir<1>
+; CHECK-NEXT: WIDEN ir<%load1> = vp.load vp<[[VP8]]>, vp<%evl>
+; CHECK-NEXT: WIDEN ir<%mul> = mul nsw ir<%load0>, ir<%load1>
+; CHECK-NEXT: REDUCE ir<%rdx.next> = ir<%rdx> + vp.reduce.add (ir<%mul>, vp<%evl>)
+; CHECK-NEXT: EMIT vp<%current.iteration.next> = add vp<%evl>, vp<[[VP5]]>
+; CHECK-NEXT: EMIT vp<%avl.next> = sub nuw vp<%avl>, vp<%evl>
+; CHECK-NEXT: EMIT vp<%index.next> = add vp<[[VP4]]>, vp<[[VP0]]>
+; CHECK-NEXT: EMIT branch-on-count vp<%index.next>, vp<[[VP1]]>
+; CHECK-NEXT: No successors
+; CHECK-NEXT: }
+; CHECK-NEXT: Successor(s): middle.block
+; CHECK-EMPTY:
+; CHECK-NEXT: middle.block:
+; CHECK-NEXT: EMIT vp<[[VP10:%[0-9]+]]> = compute-reduction-result (add, in-loop) ir<%rdx.next>
+; CHECK-NEXT: Successor(s): ir-bb<exit>
+; CHECK-EMPTY:
+; CHECK-NEXT: ir-bb<exit>:
+; CHECK-NEXT: IR %r.0.lcssa = phi i64 [ %rdx.next, %loop ] (extra operand: vp<[[VP10]]> from middle.block)
+; CHECK-NEXT: No successors
+; CHECK-EMPTY:
+; CHECK-NEXT: scalar.ph:
+; CHECK-NEXT: Successor(s): ir-bb<loop>
+; CHECK-EMPTY:
+; CHECK-NEXT: ir-bb<loop>:
+; CHECK-NEXT: IR %iv = phi i32 [ %iv.next, %loop ], [ 0, %entry ] (extra operand: ir<0> from scalar.ph)
+; CHECK-NEXT: IR %rdx = phi i64 [ %rdx.next, %loop ], [ 0, %entry ] (extra operand: ir<0> from scalar.ph)
+; CHECK-NEXT: IR %arrayidx = getelementptr inbounds i64, ptr %x, i32 %iv
+; CHECK-NEXT: IR %load0 = load i64, ptr %arrayidx, align 8
+; CHECK-NEXT: IR %arrayidx1 = getelementptr inbounds i64, ptr %y, i32 %iv
+; CHECK-NEXT: IR %load1 = load i64, ptr %arrayidx1, align 8
+; CHECK-NEXT: IR %mul = mul nsw i64 %load0, %load1
+; CHECK-NEXT: IR %rdx.next = add nsw i64 %rdx, %mul
+; CHECK-NEXT: IR %iv.next = add nuw nsw i32 %iv, 1
+; CHECK-NEXT: IR %exitcond = icmp eq i32 %iv.next, %n
+; CHECK-NEXT: No successors
+; CHECK-NEXT: }
+;
+entry:
+ br label %loop
+
+loop:
+ %iv = phi i32 [ %iv.next, %loop ], [ 0, %entry ]
+ %rdx = phi i64 [ %rdx.next, %loop ], [ 0, %entry ]
+ %arrayidx = getelementptr inbounds i64, ptr %x, i32 %iv
+ %load0 = load i64, ptr %arrayidx, align 8
+ %arrayidx1 = getelementptr inbounds i64, ptr %y, i32 %iv
+ %load1 = load i64, ptr %arrayidx1, align 8
+ %mul = mul nsw i64 %load0, %load1
+ %rdx.next = add nsw i64 %rdx, %mul
+ %iv.next = add nuw nsw i32 %iv, 1
+ %exitcond = icmp eq i32 %iv.next, %n
+ br i1 %exitcond, label %exit, label %loop
+
+exit:
+ %r.0.lcssa = phi i64 [ %rdx.next, %loop ]
+ ret i64 %r.0.lcssa
+}
+
+define i64 @print_mulacc_extended(ptr nocapture readonly %x, ptr nocapture readonly %y, i32 %n) {
+; CHECK-LABEL: VPlan for loop in 'print_mulacc_extended'
+; CHECK: VPlan 'Initial VPlan for VF={vscale x 4},UF={1}' {
+; CHECK-NEXT: Live-in vp<[[VP0:%[0-9]+]]> = VF * UF
+; CHECK-NEXT: Live-in vp<[[VP1:%[0-9]+]]> = vector-trip-count
+; CHECK-NEXT: Live-in ir<%n> = original trip-count
+; CHECK-EMPTY:
+; CHECK-NEXT: ir-bb<entry>:
+; CHECK-NEXT: Successor(s): scalar.ph, vector.ph
+; CHECK-EMPTY:
+; CHECK-NEXT: vector.ph:
+; CHECK-NEXT: EMIT vp<[[VP3:%[0-9]+]]> = reduction-start-vector ir<0>, ir<0>, ir<1>
+; CHECK-NEXT: Successor(s): vector loop
+; CHECK-EMPTY:
+; CHECK-NEXT: <x1> vector loop: {
+; CHECK-NEXT: vp<[[VP4:%[0-9]+]]> = CANONICAL-IV
+; CHECK-EMPTY:
+; CHECK-NEXT: vector.body:
+; CHECK-NEXT: CURRENT-ITERATION-PHI vp<[[VP5:%[0-9]+]]> = phi ir<0>, vp<%current.iteration.next>
+; CHECK-NEXT: WIDEN-REDUCTION-PHI ir<%rdx> = phi (add) vp<[[VP3]]>, ir<%rdx.next>
+; CHECK-NEXT: EMIT-SCALAR vp<%avl> = phi [ ir<%n>, vector.ph ], [ vp<%avl.next>, vector.body ]
+; CHECK-NEXT: EMIT-SCALAR vp<%evl> = EXPLICIT-VECTOR-LENGTH vp<%avl>
+; CHECK-NEXT: vp<[[VP6:%[0-9]+]]> = SCALAR-STEPS vp<[[VP5]]>, ir<1>, vp<%evl>
+; CHECK-NEXT: CLONE ir<%arrayidx> = getelementptr inbounds ir<%x>, vp<[[VP6]]>
+; CHECK-NEXT: vp<[[VP7:%[0-9]+]]> = vector-pointer inbounds ir<%arrayidx>, ir<1>
+; CHECK-NEXT: WIDEN ir<%load0> = vp.load vp<[[VP7]]>, vp<%evl>
+; CHECK-NEXT: CLONE ir<%arrayidx1> = getelementptr inbounds ir<%y>, vp<[[VP6]]>
+; CHECK-NEXT: vp<[[VP8:%[0-9]+]]> = vector-pointer inbounds ir<%arrayidx1>, ir<1>
+; CHECK-NEXT: WIDEN ir<%load1> = vp.load vp<[[VP8]]>, vp<%evl>
+; CHECK-NEXT: WIDEN-CAST ir<%conv0> = sext ir<%load0> to i32
+; CHECK-NEXT: WIDEN-CAST ir<%conv1> = sext ir<%load1> to i32
+; CHECK-NEXT: WIDEN ir<%mul> = mul nsw ir<%conv0>, ir<%conv1>
+; CHECK-NEXT: WIDEN-CAST ir<%conv> = sext ir<%mul> to i64
+; CHECK-NEXT: REDUCE ir<%rdx.next> = ir<%rdx> + vp.reduce.add (ir<%conv>, vp<%evl>)
+; CHECK-NEXT: EMIT vp<%current.iteration.next> = add vp<%evl>, vp<[[VP5]]>
+; CHECK-NEXT: EMIT vp<%avl.next> = sub nuw vp<%avl>, vp<%evl>
+; CHECK-NEXT: EMIT vp<%index.next> = add vp<[[VP4]]>, vp<[[VP0]]>
+; CHECK-NEXT: EMIT branch-on-count vp<%index.next>, vp<[[VP1]]>
+; CHECK-NEXT: No successors
+; CHECK-NEXT: }
+; CHECK-NEXT: Successor(s): middle.block
+; CHECK-EMPTY:
+; CHECK-NEXT: middle.block:
+; CHECK-NEXT: EMIT vp<[[VP10:%[0-9]+]]> = compute-reduction-result (add, in-loop) ir<%rdx.next>
+; CHECK-NEXT: Successor(s): ir-bb<exit>
+; CHECK-EMPTY:
+; CHECK-NEXT: ir-bb<exit>:
+; CHECK-NEXT: IR %r.0.lcssa = phi i64 [ %rdx.next, %loop ] (extra operand: vp<[[VP10]]> from middle.block)
+; CHECK-NEXT: No successors
+; CHECK-EMPTY:
+; CHECK-NEXT: scalar.ph:
+; CHECK-NEXT: Successor(s): ir-bb<loop>
+; CHECK-EMPTY:
+; CHECK-NEXT: ir-bb<loop>:
+; CHECK-NEXT: IR %iv = phi i32 [ %iv.next, %loop ], [ 0, %entry ] (extra operand: ir<0> from scalar.ph)
+; CHECK-NEXT: IR %rdx = phi i64 [ %rdx.next, %loop ], [ 0, %entry ] (extra operand: ir<0> from scalar.ph)
+; CHECK-NEXT: IR %arrayidx = getelementptr inbounds i16, ptr %x, i32 %iv
+; CHECK-NEXT: IR %load0 = load i16, ptr %arrayidx, align 8
+; CHECK-NEXT: IR %arrayidx1 = getelementptr inbounds i16, ptr %y, i32 %iv
+; CHECK-NEXT: IR %load1 = load i16, ptr %arrayidx1, align 8
+; CHECK-NEXT: IR %conv0 = sext i16 %load0 to i32
+; CHECK-NEXT: IR %conv1 = sext i16 %load1 to i32
+; CHECK-NEXT: IR %mul = mul nsw i32 %conv0, %conv1
+; CHECK-NEXT: IR %conv = sext i32 %mul to i64
+; CHECK-NEXT: IR %rdx.next = add nsw i64 %rdx, %conv
+; CHECK-NEXT: IR %iv.next = add nuw nsw i32 %iv, 1
+; CHECK-NEXT: IR %exitcond = icmp eq i32 %iv.next, %n
+; CHECK-NEXT: No successors
+; CHECK-NEXT: }
+;
+entry:
+ br label %loop
+
+loop:
+ %iv = phi i32 [ %iv.next, %loop ], [ 0, %entry ]
+ %rdx = phi i64 [ %rdx.next, %loop ], [ 0, %entry ]
+ %arrayidx = getelementptr inbounds i16, ptr %x, i32 %iv
+ %load0 = load i16, ptr %arrayidx, align 8
+ %arrayidx1 = getelementptr inbounds i16, ptr %y, i32 %iv
+ %load1 = load i16, ptr %arrayidx1, align 8
+ %conv0 = sext i16 %load0 to i32
+ %conv1 = sext i16 %load1 to i32
+ %mul = mul nsw i32 %conv0, %conv1
+ %conv = sext i32 %mul to i64
+ %rdx.next = add nsw i64 %rdx, %conv
+ %iv.next = add nuw nsw i32 %iv, 1
+ %exitcond = icmp eq i32 %iv.next, %n
+ br i1 %exitcond, label %exit, label %loop
+
+exit:
+ %r.0.lcssa = phi i64 [ %rdx.next, %loop ]
+ ret i64 %r.0.lcssa
+}
+
+define i32 @print_mulacc_negated(ptr %a, ptr %b) {
+; CHECK-LABEL: VPlan for loop in 'print_mulacc_negated'
+; CHECK: VPlan 'Initial VPlan for VF={vscale x 4},UF={1}' {
+; CHECK-NEXT: Live-in vp<[[VP0:%[0-9]+]]> = VF * UF
+; CHECK-NEXT: Live-in vp<[[VP1:%[0-9]+]]> = vector-trip-count
+; CHECK-NEXT: Live-in ir<1024> = original trip-count
+; CHECK-EMPTY:
+; CHECK-NEXT: ir-bb<entry>:
+; CHECK-NEXT: Successor(s): scalar.ph, vector.ph
+; CHECK-EMPTY:
+; CHECK-NEXT: vector.ph:
+; CHECK-NEXT: EMIT vp<[[VP3:%[0-9]+]]> = reduction-start-vector ir<0>, ir<0>, ir<1>
+; CHECK-NEXT: Successor(s): vector loop
+; CHECK-EMPTY:
+; CHECK-NEXT: <x1> vector loop: {
+; CHECK-NEXT: vp<[[VP4:%[0-9]+]]> = CANONICAL-IV
+; CHECK-EMPTY:
+; CHECK-NEXT: vector.body:
+; CHECK-NEXT: CURRENT-ITERATION-PHI vp<[[VP5:%[0-9]+]]> = phi ir<0>, vp<%current.iteration.next>
+; CHECK-NEXT: WIDEN-REDUCTION-PHI ir<%accum> = phi (add) vp<[[VP3]]>, ir<%add>
+; CHECK-NEXT: EMIT-SCALAR vp<%avl> = phi [ ir<1024>, vector.ph ], [ vp<%avl.next>, vector.body ]
+; CHECK-NEXT: EMIT-SCALAR vp<%evl> = EXPLICIT-VECTOR-LENGTH vp<%avl>
+; CHECK-NEXT: EMIT-SCALAR vp<[[VP6:%[0-9]+]]> = zext vp<%evl> to i64
+; CHECK-NEXT: vp<[[VP7:%[0-9]+]]> = SCALAR-STEPS vp<[[VP5]]>, ir<1>, vp<[[VP6]]>
+; CHECK-NEXT: CLONE ir<%gep.a> = getelementptr ir<%a>, vp<[[VP7]]>
+; CHECK-NEXT: vp<[[VP8:%[0-9]+]]> = vector-pointer ir<%gep.a>, ir<1>
+; CHECK-NEXT: WIDEN ir<%load.a> = vp.load vp<[[VP8]]>, vp<%evl>
+; CHECK-NEXT: WIDEN-CAST ir<%ext.a> = zext ir<%load.a> to i32
+; CHECK-NEXT: CLONE ir<%gep.b> = getelementptr ir<%b>, vp<[[VP7]]>
+; CHECK-NEXT: vp<[[VP9:%[0-9]+]]> = vector-pointer ir<%gep.b>, ir<1>
+; CHECK-NEXT: WIDEN ir<%load.b> = vp.load vp<[[VP9]]>, vp<%evl>
+; CHECK-NEXT: WIDEN-CAST ir<%ext.b> = zext ir<%load.b> to i32
+; CHECK-NEXT: WIDEN ir<%mul> = mul ir<%ext.b>, ir<%ext.a>
+; CHECK-NEXT: WIDEN ir<%sub> = sub ir<0>, ir<%mul>
+; CHECK-NEXT: REDUCE ir<%add> = ir<%accum> + vp.reduce.add (ir<%sub>, vp<%evl>)
+; CHECK-NEXT: EMIT-SCALAR vp<[[VP10:%[0-9]+]]> = zext vp<%evl> to i64
+; CHECK-NEXT: EMIT vp<%current.iteration.next> = add nuw vp<[[VP10]]>, vp<[[VP5]]>
+; CHECK-NEXT: EMIT vp<%avl.next> = sub nuw vp<%avl>, vp<[[VP10]]>
+; CHECK-NEXT: EMIT vp<%index.next> = add nuw vp<[[VP4]]>, vp<[[VP0]]>
+; CHECK-NEXT: EMIT branch-on-count vp<%index.next>, vp<[[VP1]]>
+; CHECK-NEXT: No successors
+; CHECK-NEXT: }
+; CHECK-NEXT: Successor(s): middle.block
+; CHECK-EMPTY:
+; CHECK-NEXT: middle.block:
+; CHECK-NEXT: EMIT vp<[[VP12:%[0-9]+]]> = compute-reduction-result (add, in-loop) ir<%add>
+; CHECK-NEXT: Successor(s): ir-bb<exit>
+; CHECK-EMPTY:
+; CHECK-NEXT: ir-bb<exit>:
+; CHECK-NEXT: IR %add.lcssa = phi i32 [ %add, %loop ] (extra operand: vp<[[VP12]]> from middle.block)
+; CHECK-NEXT: No successors
+; CHECK-EMPTY:
+; CHECK-NEXT: scalar.ph:
+; CHECK-NEXT: Successor(s): ir-bb<loop>
+; CHECK-EMPTY:
+; CHECK-NEXT: ir-bb<loop>:
+; CHECK-NEXT: IR %iv = phi i64 [ 0, %entry ], [ %iv.next, %loop ] (extra operand: ir<0> from scalar.ph)
+; CHECK-NEXT: IR %accum = phi i32 [ 0, %entry ], [ %add, %loop ] (extra operand: ir<0> from scalar.ph)
+; CHECK-NEXT: IR %gep.a = getelementptr i8, ptr %a, i64 %iv
+; CHECK-NEXT: IR %load.a = load i8, ptr %gep.a, align 1
+; CHECK-NEXT: IR %ext.a = zext i8 %load.a to i32
+; CHECK-NEXT: IR %gep.b = getelementptr i8, ptr %b, i64 %iv
+; CHECK-NEXT: IR %load.b = load i8, ptr %gep.b, align 1
+; CHECK-NEXT: IR %ext.b = zext i8 %load.b to i32
+; CHECK-NEXT: IR %mul = mul i32 %ext.b, %ext.a
+; CHECK-NEXT: IR %sub = sub i32 0, %mul
+; CHECK-NEXT: IR %add = add i32 %accum, %sub
+; CHECK-NEXT: IR %iv.next = add i64 %iv, 1
+; CHECK-NEXT: IR %exitcond.not = icmp eq i64 %iv.next, 1024
+; CHECK-NEXT: No successors
+; CHECK-NEXT: }
+;
+entry:
+ br label %loop
+
+loop:
+ %iv = phi i64 [ 0, %entry ], [ %iv.next, %loop ]
+ %accum = phi i32 [ 0, %entry ], [ %add, %loop ]
+ %gep.a = getelementptr i8, ptr %a, i64 %iv
+ %load.a = load i8, ptr %gep.a, align 1
+ %ext.a = zext i8 %load.a to i32
+ %gep.b = getelementptr i8, ptr %b, i64 %iv
+ %load.b = load i8, ptr %gep.b, align 1
+ %ext.b = zext i8 %load.b to i32
+ %mul = mul i32 %ext.b, %ext.a
+ %sub = sub i32 0, %mul
+ %add = add i32 %accum, %sub
+ %iv.next = add i64 %iv, 1
+ %exitcond.not = icmp eq i64 %iv.next, 1024
+ br i1 %exitcond.not, label %exit, label %loop
+
+exit:
+ ret i32 %add
+}
+
+define i32 @print_mulacc_extended_const(ptr %start, ptr %end) {
+; CHECK-LABEL: VPlan for loop in 'print_mulacc_extended_const'
+; CHECK: VPlan 'Initial VPlan for VF={vscale x 4},UF={1}' {
+; CHECK-NEXT: Live-in vp<[[VP0:%[0-9]+]]> = VF * UF
+; CHECK-NEXT: Live-in vp<[[VP1:%[0-9]+]]> = vector-trip-count
+; CHECK-NEXT: vp<[[VP3:%[0-9]+]]> = original trip-count
+; CHECK-EMPTY:
+; CHECK-NEXT: ir-bb<entry>:
+; CHECK-NEXT: EMIT vp<[[VP3]]> = EXPAND SCEV (1 + (-1 * (ptrtoint ptr %start to i64)) + (ptrtoint ptr %end to i64))
+; CHECK-NEXT: Successor(s): scalar.ph, vector.ph
+; CHECK-EMPTY:
+; CHECK-NEXT: vector.ph:
+; CHECK-NEXT: EMIT vp<[[VP4:%[0-9]+]]> = reduction-start-vector ir<0>, ir<0>, ir<1>
+; CHECK-NEXT: Successor(s): vector loop
+; CHECK-EMPTY:
+; CHECK-NEXT: <x1> vector loop: {
+; CHECK-NEXT: vp<[[VP5:%[0-9]+]]> = CANONICAL-IV
+; CHECK-EMPTY:
+; CHECK-NEXT: vector.body:
+; CHECK-NEXT: CURRENT-ITERATION-PHI vp<[[VP6:%[0-9]+]]> = phi ir<0>, vp<%current.iteration.next>
+; CHECK-NEXT: WIDEN-REDUCTION-PHI ir<%red> = phi (add) vp<[[VP4]]>, ir<%red.next>
+; CHECK-NEXT: EMIT-SCALAR vp<%avl> = phi [ vp<[[VP3]]>, vector.ph ], [ vp<%avl.next>, vector.body ]
+; CHECK-NEXT: EMIT-SCALAR vp<%evl> = EXPLICIT-VECTOR-LENGTH vp<%avl>
+; CHECK-NEXT: EMIT-SCALAR vp<[[VP7:%[0-9]+]]> = zext vp<%evl> to i64
+; CHECK-NEXT: vp<[[VP8:%[0-9]+]]> = SCALAR-STEPS vp<[[VP6]]>, ir<1>, vp<[[VP7]]>
+; CHECK-NEXT: EMIT vp<%next.gep> = ptradd ir<%start>, vp<[[VP8]]>
+; CHECK-NEXT: vp<[[VP9:%[0-9]+]]> = vector-pointer vp<%next.gep>, ir<1>
+; CHECK-NEXT: WIDEN ir<%l> = vp.load vp<[[VP9]]>, vp<%evl>
+; CHECK-NEXT: WIDEN-CAST ir<%l.ext> = zext ir<%l> to i32
+; CHECK-NEXT: WIDEN ir<%mul> = mul ir<%l.ext>, ir<63>
+; CHECK-NEXT: REDUCE ir<%red.next> = ir<%red> + vp.reduce.add (ir<%mul>, vp<%evl>)
+; CHECK-NEXT: EMIT-SCALAR vp<[[VP10:%[0-9]+]]> = zext vp<%evl> to i64
+; CHECK-NEXT: EMIT vp<%current.iteration.next> = add vp<[[VP10]]>, vp<[[VP6]]>
+; CHECK-NEXT: EMIT vp<%avl.next> = sub nuw vp<%avl>, vp<[[VP10]]>
+; CHECK-NEXT: EMIT vp<%index.next> = add vp<[[VP5]]>, vp<[[VP0]]>
+; CHECK-NEXT: EMIT branch-on-count vp<%index.next>, vp<[[VP1]]>
+; CHECK-NEXT: No successors
+; CHECK-NEXT: }
+; CHECK-NEXT: Successor(s): middle.block
+; CHECK-EMPTY:
+; CHECK-NEXT: middle.block:
+; CHECK-NEXT: EMIT vp<[[VP12:%[0-9]+]]> = compute-reduction-result (add, in-loop) ir<%red.next>
+; CHECK-NEXT: Successor(s): ir-bb<exit>
+; CHECK-EMPTY:
+; CHECK-NEXT: ir-bb<exit>:
+; CHECK-NEXT: IR %red.next.lcssa = phi i32 [ %red.next, %loop ] (extra operand: vp<[[VP12]]> from middle.block)
+; CHECK-NEXT: No successors
+; CHECK-EMPTY:
+; CHECK-NEXT: scalar.ph:
+; CHECK-NEXT: Successor(s): ir-bb<loop>
+; CHECK-EMPTY:
+; CHECK-NEXT: ir-bb<loop>:
+; CHECK-NEXT: IR %ptr.iv = phi ptr [ %start, %entry ], [ %gep.iv.next, %loop ] (extra operand: ir<%start> from scalar.ph)
+; CHECK-NEXT: IR %red = phi i32 [ 0, %entry ], [ %red.next, %loop ] (extra operand: ir<0> from scalar.ph)
+; CHECK-NEXT: IR %l = load i8, ptr %ptr.iv, align 1
+; CHECK-NEXT: IR %l.ext = zext i8 %l to i32
+; CHECK-NEXT: IR %mul = mul i32 %l.ext, 63
+; CHECK-NEXT: IR %red.next = add i32 %red, %mul
+; CHECK-NEXT: IR %gep.iv.next = getelementptr i8, ptr %ptr.iv, i64 1
+; CHECK-NEXT: IR %ec = icmp eq ptr %ptr.iv, %end
+; CHECK-NEXT: No successors
+; CHECK-NEXT: }
+;
+entry:
+ br label %loop
+
+loop:
+ %ptr.iv = phi ptr [ %start, %entry ], [ %gep.iv.next, %loop ]
+ %red = phi i32 [ 0, %entry ], [ %red.next, %loop ]
+ %l = load i8, ptr %ptr.iv, align 1
+ %l.ext = zext i8 %l to i32
+ %mul = mul i32 %l.ext, 63
+ %red.next = add i32 %red, %mul
+ %gep.iv.next = getelementptr i8, ptr %ptr.iv, i64 1
+ %ec = icmp eq ptr %ptr.iv, %end
+ br i1 %ec, label %exit, label %loop
+
+exit:
+ ret i32 %red.next
+}
+
+define i32 @print_mulacc_extended_const_lhs(ptr %start, ptr %end) {
+; CHECK-LABEL: VPlan for loop in 'print_mulacc_extended_const_lhs'
+; CHECK: VPlan 'Initial VPlan for VF={vscale x 4},UF={1}' {
+; CHECK-NEXT: Live-in vp<[[VP0:%[0-9]+]]> = VF * UF
+; CHECK-NEXT: Live-in vp<[[VP1:%[0-9]+]]> = vector-trip-count
+; CHECK-NEXT: vp<[[VP3:%[0-9]+]]> = original trip-count
+; CHECK-EMPTY:
+; CHECK-NEXT: ir-bb<entry>:
+; CHECK-NEXT: EMIT vp<[[VP3]]> = EXPAND SCEV (1 + (-1 * (ptrtoint ptr %start to i64)) + (ptrtoint ptr %end to i64))
+; CHECK-NEXT: Successor(s): scalar.ph, vector.ph
+; CHECK-EMPTY:
+; CHECK-NEXT: vector.ph:
+; CHECK-NEXT: EMIT vp<[[VP4:%[0-9]+]]> = reduction-start-vector ir<0>, ir<0>, ir<1>
+; CHECK-NEXT: Successor(s): vector loop
+; CHECK-EMPTY:
+; CHECK-NEXT: <x1> vector loop: {
+; CHECK-NEXT: vp<[[VP5:%[0-9]+]]> = CANONICAL-IV
+; CHECK-EMPTY:
+; CHECK-NEXT: vector.body:
+; CHECK-NEXT: CURRENT-ITERATION-PHI vp<[[VP6:%[0-9]+]]> = phi ir<0>, vp<%current.iteration.next>
+; CHECK-NEXT: WIDEN-REDUCTION-PHI ir<%red> = phi (add) vp<[[VP4]]>, ir<%red.next>
+; CHECK-NEXT: EMIT-SCALAR vp<%avl> = phi [ vp<[[VP3]]>, vector.ph ], [ vp<%avl.next>, vector.body ]
+; CHECK-NEXT: EMIT-SCALAR vp<%evl> = EXPLICIT-VECTOR-LENGTH vp<%avl>
+; CHECK-NEXT: EMIT-SCALAR vp<[[VP7:%[0-9]+]]> = zext vp<%evl> to i64
+; CHECK-NEXT: vp<[[VP8:%[0-9]+]]> = SCALAR-STEPS vp<[[VP6]]>, ir<1>, vp<[[VP7]]>
+; CHECK-NEXT: EMIT vp<%next.gep> = ptradd ir<%start>, vp<[[VP8]]>
+; CHECK-NEXT: vp<[[VP9:%[0-9]+]]> = vector-pointer vp<%next.gep>, ir<1>
+; CHECK-NEXT: WIDEN ir<%l> = vp.load vp<[[VP9]]>, vp<%evl>
+; CHECK-NEXT: WIDEN-CAST ir<%l.ext> = zext ir<%l> to i32
+; CHECK-NEXT: WIDEN ir<%mul> = mul ir<63>, ir<%l.ext>
+; CHECK-NEXT: REDUCE ir<%red.next> = ir<%red> + vp.reduce.add (ir<%mul>, vp<%evl>)
+; CHECK-NEXT: EMIT-SCALAR vp<[[VP10:%[0-9]+]]> = zext vp<%evl> to i64
+; CHECK-NEXT: EMIT vp<%current.iteration.next> = add vp<[[VP10]]>, vp<[[VP6]]>
+; CHECK-NEXT: EMIT vp<%avl.next> = sub nuw vp<%avl>, vp<[[VP10]]>
+; CHECK-NEXT: EMIT vp<%index.next> = add vp<[[VP5]]>, vp<[[VP0]]>
+; CHECK-NEXT: EMIT branch-on-count vp<%index.next>, vp<[[VP1]]>
+; CHECK-NEXT: No successors
+; CHECK-NEXT: }
+; CHECK-NEXT: Successor(s): middle.block
+; CHECK-EMPTY:
+; CHECK-NEXT: middle.block:
+; CHECK-NEXT: EMIT vp<[[VP12:%[0-9]+]]> = compute-reduction-result (add, in-loop) ir<%red.next>
+; CHECK-NEXT: Successor(s): ir-bb<exit>
+; CHECK-EMPTY:
+; CHECK-NEXT: ir-bb<exit>:
+; CHECK-NEXT: IR %red.next.lcssa = phi i32 [ %red.next, %loop ] (extra operand: vp<[[VP12]]> from middle.block)
+; CHECK-NEXT: No successors
+; CHECK-EMPTY:
+; CHECK-NEXT: scalar.ph:
+; CHECK-NEXT: Successor(s): ir-bb<loop>
+; CHECK-EMPTY:
+; CHECK-NEXT: ir-bb<loop>:
+; CHECK-NEXT: IR %ptr.iv = phi ptr [ %start, %entry ], [ %gep.iv.next, %loop ] (extra operand: ir<%start> from scalar.ph)
+; CHECK-NEXT: IR %red = phi i32 [ 0, %entry ], [ %red.next, %loop ] (extra operand: ir<0> from scalar.ph)
+; CHECK-NEXT: IR %l = load i8, ptr %ptr.iv, align 1
+; CHECK-NEXT: IR %l.ext = zext i8 %l to i32
+; CHECK-NEXT: IR %mul = mul i32 63, %l.ext
+; CHECK-NEXT: IR %red.next = add i32 %red, %mul
+; CHECK-NEXT: IR %gep.iv.next = getelementptr i8, ptr %ptr.iv, i64 1
+; CHECK-NEXT: IR %ec = icmp eq ptr %ptr.iv, %end
+; CHECK-NEXT: No successors
+; CHECK-NEXT: }
+;
+entry:
+ br label %loop
+
+loop:
+ %ptr.iv = phi ptr [ %start, %entry ], [ %gep.iv.next, %loop ]
+ %red = phi i32 [ 0, %entry ], [ %red.next, %loop ]
+ %l = load i8, ptr %ptr.iv, align 1
+ %l.ext = zext i8 %l to i32
+ %mul = mul i32 63, %l.ext
+ %red.next = add i32 %red, %mul
+ %gep.iv.next = getelementptr i8, ptr %ptr.iv, i64 1
+ %ec = icmp eq ptr %ptr.iv, %end
+ br i1 %ec, label %exit, label %loop
+
+exit:
+ ret i32 %red.next
+}
+
+; Constants >= 128 cannot be treated as sign-extended, so the expression shouldn't extend 128
+define i32 @print_mulacc_not_extended_const(ptr %start, ptr %end) {
+; CHECK-LABEL: VPlan for loop in 'print_mulacc_not_extended_const'
+; CHECK: VPlan 'Initial VPlan for VF={vscale x 4},UF={1}' {
+; CHECK-NEXT: Live-in vp<[[VP0:%[0-9]+]]> = VF * UF
+; CHECK-NEXT: Live-in vp<[[VP1:%[0-9]+]]> = vector-trip-count
+; CHECK-NEXT: vp<[[VP3:%[0-9]+]]> = original trip-count
+; CHECK-EMPTY:
+; CHECK-NEXT: ir-bb<entry>:
+; CHECK-NEXT: EMIT vp<[[VP3]]> = EXPAND SCEV (1 + (-1 * (ptrtoint ptr %start to i64)) + (ptrtoint ptr %end to i64))
+; CHECK-NEXT: Successor(s): scalar.ph, vector.ph
+; CHECK-EMPTY:
+; CHECK-NEXT: vector.ph:
+; CHECK-NEXT: EMIT vp<[[VP4:%[0-9]+]]> = reduction-start-vector ir<0>, ir<0>, ir<1>
+; CHECK-NEXT: Successor(s): vector loop
+; CHECK-EMPTY:
+; CHECK-NEXT: <x1> vector loop: {
+; CHECK-NEXT: vp<[[VP5:%[0-9]+]]> = CANONICAL-IV
+; CHECK-EMPTY:
+; CHECK-NEXT: vector.body:
+; CHECK-NEXT: CURRENT-ITERATION-PHI vp<[[VP6:%[0-9]+]]> = phi ir<0>, vp<%current.iteration.next>
+; CHECK-NEXT: WIDEN-REDUCTION-PHI ir<%red> = phi (add) vp<[[VP4]]>, ir<%red.next>
+; CHECK-NEXT: EMIT-SCALAR vp<%avl> = phi [ vp<[[VP3]]>, vector.ph ], [ vp<%avl.next>, vector.body ]
+; CHECK-NEXT: EMIT-SCALAR vp<%evl> = EXPLICIT-VECTOR-LENGTH vp<%avl>
+; CHECK-NEXT: EMIT-SCALAR vp<[[VP7:%[0-9]+]]> = zext vp<%evl> to i64
+; CHECK-NEXT: vp<[[VP8:%[0-9]+]]> = SCALAR-STEPS vp<[[VP6]]>, ir<1>, vp<[[VP7]]>
+; CHECK-NEXT: EMIT vp<%next.gep> = ptradd ir<%start>, vp<[[VP8]]>
+; CHECK-NEXT: vp<[[VP9:%[0-9]+]]> = vector-pointer vp<%next.gep>, ir<1>
+; CHECK-NEXT: WIDEN ir<%l> = vp.load vp<[[VP9]]>, vp<%evl>
+; CHECK-NEXT: WIDEN-CAST ir<%l.ext> = sext ir<%l> to i32
+; CHECK-NEXT: EMIT vp<[[VP10:%[0-9]+]]> = shl ir<%l.ext>, ir<7>
+; CHECK-NEXT: REDUCE ir<%red.next> = ir<%red> + vp.reduce.add (vp<[[VP10]]>, vp<%evl>)
+; CHECK-NEXT: EMIT-SCALAR vp<[[VP11:%[0-9]+]]> = zext vp<%evl> to i64
+; CHECK-NEXT: EMIT vp<%current.iteration.next> = add vp<[[VP11]]>, vp<[[VP6]]>
+; CHECK-NEXT: EMIT vp<%avl.next> = sub nuw vp<%avl>, vp<[[VP11]]>
+; CHECK-NEXT: EMIT vp<%index.next> = add vp<[[VP5]]>, vp<[[VP0]]>
+; CHECK-NEXT: EMIT branch-on-count vp<%index.next>, vp<[[VP1]]>
+; CHECK-NEXT: No successors
+; CHECK-NEXT: }
+; CHECK-NEXT: Successor(s): middle.block
+; CHECK-EMPTY:
+; CHECK-NEXT: middle.block:
+; CHECK-NEXT: EMIT vp<[[VP13:%[0-9]+]]> = compute-reduction-result (add, in-loop) ir<%red.next>
+; CHECK-NEXT: Successor(s): ir-bb<exit>
+; CHECK-EMPTY:
+; CHECK-NEXT: ir-bb<exit>:
+; CHECK-NEXT: IR %red.next.lcssa = phi i32 [ %red.next, %loop ] (extra operand: vp<[[VP13]]> from middle.block)
+; CHECK-NEXT: No successors
+; CHECK-EMPTY:
+; CHECK-NEXT: scalar.ph:
+; CHECK-NEXT: Successor(s): ir-bb<loop>
+; CHECK-EMPTY:
+; CHECK-NEXT: ir-bb<loop>:
+; CHECK-NEXT: IR %ptr.iv = phi ptr [ %start, %entry ], [ %gep.iv.next, %loop ] (extra operand: ir<%start> from scalar.ph)
+; CHECK-NEXT: IR %red = phi i32 [ 0, %entry ], [ %red.next, %loop ] (extra operand: ir<0> from scalar.ph)
+; CHECK-NEXT: IR %l = load i8, ptr %ptr.iv, align 1
+; CHECK-NEXT: IR %l.ext = sext i8 %l to i32
+; CHECK-NEXT: IR %mul = mul i32 %l.ext, 128
+; CHECK-NEXT: IR %red.next = add i32 %red, %mul
+; CHECK-NEXT: IR %gep.iv.next = getelementptr i8, ptr %ptr.iv, i64 1
+; CHECK-NEXT: IR %ec = icmp eq ptr %ptr.iv, %end
+; CHECK-NEXT: No successors
+; CHECK-NEXT: }
+;
+entry:
+ br label %loop
+
+loop:
+ %ptr.iv = phi ptr [ %start, %entry ], [ %gep.iv.next, %loop ]
+ %red = phi i32 [ 0, %entry ], [ %red.next, %loop ]
+ %l = load i8, ptr %ptr.iv, align 1
+ %l.ext = sext i8 %l to i32
+ %mul = mul i32 %l.ext, 128
+ %red.next = add i32 %red, %mul
+ %gep.iv.next = getelementptr i8, ptr %ptr.iv, i64 1
+ %ec = icmp eq ptr %ptr.iv, %end
+ br i1 %ec, label %exit, label %loop
+
+exit:
+ %red.next.lcssa = phi i32 [ %red.next, %loop ]
+ ret i32 %red.next.lcssa
+}
+
+define i64 @print_ext_mulacc_extended_const(ptr %start, ptr %end) {
+; CHECK-LABEL: VPlan for loop in 'print_ext_mulacc_extended_const'
+; CHECK: VPlan 'Initial VPlan for VF={vscale x 4},UF={1}' {
+; CHECK-NEXT: Live-in vp<[[VP0:%[0-9]+]]> = VF * UF
+; CHECK-NEXT: Live-in vp<[[VP1:%[0-9]+]]> = vector-trip-count
+; CHECK-NEXT: vp<[[VP3:%[0-9]+]]> = original trip-count
+; CHECK-EMPTY:
+; CHECK-NEXT: ir-bb<entry>:
+; CHECK-NEXT: EMIT vp<[[VP3]]> = EXPAND SCEV (1 + (-1 * (ptrtoint ptr %start to i64)) + (ptrtoint ptr %end to i64))
+; CHECK-NEXT: Successor(s): scalar.ph, vector.ph
+; CHECK-EMPTY:
+; CHECK-NEXT: vector.ph:
+; CHECK-NEXT: EMIT vp<[[VP4:%[0-9]+]]> = reduction-start-vector ir<0>, ir<0>, ir<1>
+; CHECK-NEXT: Successor(s): vector loop
+; CHECK-EMPTY:
+; CHECK-NEXT: <x1> vector loop: {
+; CHECK-NEXT: vp<[[VP5:%[0-9]+]]> = CANONICAL-IV
+; CHECK-EMPTY:
+; CHECK-NEXT: vector.body:
+; CHECK-NEXT: CURRENT-ITERATION-PHI vp<[[VP6:%[0-9]+]]> = phi ir<0>, vp<%current.iteration.next>
+; CHECK-NEXT: WIDEN-REDUCTION-PHI ir<%red> = phi (add) vp<[[VP4]]>, ir<%red.next>
+; CHECK-NEXT: EMIT-SCALAR vp<%avl> = phi [ vp<[[VP3]]>, vector.ph ], [ vp<%avl.next>, vector.body ]
+; CHECK-NEXT: EMIT-SCALAR vp<%evl> = EXPLICIT-VECTOR-LENGTH vp<%avl>
+; CHECK-NEXT: EMIT-SCALAR vp<[[VP7:%[0-9]+]]> = zext vp<%evl> to i64
+; CHECK-NEXT: vp<[[VP8:%[0-9]+]]> = SCALAR-STEPS vp<[[VP6]]>, ir<1>, vp<[[VP7]]>
+; CHECK-NEXT: EMIT vp<%next.gep> = ptradd ir<%start>, vp<[[VP8]]>
+; CHECK-NEXT: vp<[[VP9:%[0-9]+]]> = vector-pointer vp<%next.gep>, ir<1>
+; CHECK-NEXT: WIDEN ir<%l> = vp.load vp<[[VP9]]>, vp<%evl>
+; CHECK-NEXT: WIDEN-CAST ir<%l.ext> = zext ir<%l> to i32
+; CHECK-NEXT: WIDEN ir<%mul> = mul ir<%l.ext>, ir<63>
+; CHECK-NEXT: WIDEN-CAST ir<%mul.ext> = zext ir<%mul> to i64
+; CHECK-NEXT: REDUCE ir<%red.next> = ir<%red> + vp.reduce.add (ir<%mul.ext>, vp<%evl>)
+; CHECK-NEXT: EMIT-SCALAR vp<[[VP10:%[0-9]+]]> = zext vp<%evl> to i64
+; CHECK-NEXT: EMIT vp<%current.iteration.next> = add vp<[[VP10]]>, vp<[[VP6]]>
+; CHECK-NEXT: EMIT vp<%avl.next> = sub nuw vp<%avl>, vp<[[VP10]]>
+; CHECK-NEXT: EMIT vp<%index.next> = add vp<[[VP5]]>, vp<[[VP0]]>
+; CHECK-NEXT: EMIT branch-on-count vp<%index.next>, vp<[[VP1]]>
+; CHECK-NEXT: No successors
+; CHECK-NEXT: }
+; CHECK-NEXT: Successor(s): middle.block
+; CHECK-EMPTY:
+; CHECK-NEXT: middle.block:
+; CHECK-NEXT: EMIT vp<[[VP12:%[0-9]+]]> = compute-reduction-result (add, in-loop) ir<%red.next>
+; CHECK-NEXT: Successor(s): ir-bb<exit>
+; CHECK-EMPTY:
+; CHECK-NEXT: ir-bb<exit>:
+; CHECK-NEXT: IR %red.next.lcssa = phi i64 [ %red.next, %loop ] (extra operand: vp<[[VP12]]> from middle.block)
+; CHECK-NEXT: No successors
+; CHECK-EMPTY:
+; CHECK-NEXT: scalar.ph:
+; CHECK-NEXT: Successor(s): ir-bb<loop>
+; CHECK-EMPTY:
+; CHECK-NEXT: ir-bb<loop>:
+; CHECK-NEXT: IR %ptr.iv = phi ptr [ %start, %entry ], [ %gep.iv.next, %loop ] (extra operand: ir<%start> from scalar.ph)
+; CHECK-NEXT: IR %red = phi i64 [ 0, %entry ], [ %red.next, %loop ] (extra operand: ir<0> from scalar.ph)
+; CHECK-NEXT: IR %l = load i8, ptr %ptr.iv, align 1
+; CHECK-NEXT: IR %l.ext = zext i8 %l to i32
+; CHECK-NEXT: IR %mul = mul i32 %l.ext, 63
+; CHECK-NEXT: IR %mul.ext = zext i32 %mul to i64
+; CHECK-NEXT: IR %red.next = add i64 %red, %mul.ext
+; CHECK-NEXT: IR %gep.iv.next = getelementptr i8, ptr %ptr.iv, i64 1
+; CHECK-NEXT: IR %ec = icmp eq ptr %ptr.iv, %end
+; CHECK-NEXT: No successors
+; CHECK-NEXT: }
+;
+entry:
+ br label %loop
+
+loop:
+ %ptr.iv = phi ptr [ %start, %entry ], [ %gep.iv.next, %loop ]
+ %red = phi i64 [ 0, %entry ], [ %red.next, %loop ]
+ %l = load i8, ptr %ptr.iv, align 1
+ %l.ext = zext i8 %l to i32
+ %mul = mul i32 %l.ext, 63
+ %mul.ext = zext i32 %mul to i64
+ %red.next = add i64 %red, %mul.ext
+ %gep.iv.next = getelementptr i8, ptr %ptr.iv, i64 1
+ %ec = icmp eq ptr %ptr.iv, %end
+ br i1 %ec, label %exit, label %loop
+
+exit:
+ ret i64 %red.next
+}
+
+; Constants >= 128 cannot be treated as sign-extended, so the expression shouldn't extend 128
+define i64 @print_ext_mulacc_not_extended_const(ptr %start, ptr %end) {
+; CHECK-LABEL: VPlan for loop in 'print_ext_mulacc_not_extended_const'
+; CHECK: VPlan 'Initial VPlan for VF={vscale x 4},UF={1}' {
+; CHECK-NEXT: Live-in vp<[[VP0:%[0-9]+]]> = VF * UF
+; CHECK-NEXT: Live-in vp<[[VP1:%[0-9]+]]> = vector-trip-count
+; CHECK-NEXT: vp<[[VP3:%[0-9]+]]> = original trip-count
+; CHECK-EMPTY:
+; CHECK-NEXT: ir-bb<entry>:
+; CHECK-NEXT: EMIT vp<[[VP3]]> = EXPAND SCEV (1 + (-1 * (ptrtoint ptr %start to i64)) + (ptrtoint ptr %end to i64))
+; CHECK-NEXT: Successor(s): scalar.ph, vector.ph
+; CHECK-EMPTY:
+; CHECK-NEXT: vector.ph:
+; CHECK-NEXT: EMIT vp<[[VP4:%[0-9]+]]> = reduction-start-vector ir<0>, ir<0>, ir<1>
+; CHECK-NEXT: Successor(s): vector loop
+; CHECK-EMPTY:
+; CHECK-NEXT: <x1> vector loop: {
+; CHECK-NEXT: vp<[[VP5:%[0-9]+]]> = CANONICAL-IV
+; CHECK-EMPTY:
+; CHECK-NEXT: vector.body:
+; CHECK-NEXT: CURRENT-ITERATION-PHI vp<[[VP6:%[0-9]+]]> = phi ir<0>, vp<%current.iteration.next>
+; CHECK-NEXT: WIDEN-REDUCTION-PHI ir<%red> = phi (add) vp<[[VP4]]>, ir<%red.next>
+; CHECK-NEXT: EMIT-SCALAR vp<%avl> = phi [ vp<[[VP3]]>, vector.ph ], [ vp<%avl.next>, vector.body ]
+; CHECK-NEXT: EMIT-SCALAR vp<%evl> = EXPLICIT-VECTOR-LENGTH vp<%avl>
+; CHECK-NEXT: EMIT-SCALAR vp<[[VP7:%[0-9]+]]> = zext vp<%evl> to i64
+; CHECK-NEXT: vp<[[VP8:%[0-9]+]]> = SCALAR-STEPS vp<[[VP6]]>, ir<1>, vp<[[VP7]]>
+; CHECK-NEXT: EMIT vp<%next.gep> = ptradd ir<%start>, vp<[[VP8]]>
+; CHECK-NEXT: vp<[[VP9:%[0-9]+]]> = vector-pointer vp<%next.gep>, ir<1>
+; CHECK-NEXT: WIDEN ir<%l> = vp.load vp<[[VP9]]>, vp<%evl>
+; CHECK-NEXT: WIDEN-CAST ir<%l.ext> = sext ir<%l> to i32
+; CHECK-NEXT: EMIT vp<[[VP10:%[0-9]+]]> = shl ir<%l.ext>, ir<7>
+; CHECK-NEXT: WIDEN-CAST ir<%mul.ext> = sext vp<[[VP10]]> to i64
+; CHECK-NEXT: REDUCE ir<%red.next> = ir<%red> + vp.reduce.add (ir<%mul.ext>, vp<%evl>)
+; CHECK-NEXT: EMIT-SCALAR vp<[[VP11:%[0-9]+]]> = zext vp<%evl> to i64
+; CHECK-NEXT: EMIT vp<%current.iteration.next> = add vp<[[VP11]]>, vp<[[VP6]]>
+; CHECK-NEXT: EMIT vp<%avl.next> = sub nuw vp<%avl>, vp<[[VP11]]>
+; CHECK-NEXT: EMIT vp<%index.next> = add vp<[[VP5]]>, vp<[[VP0]]>
+; CHECK-NEXT: EMIT branch-on-count vp<%index.next>, vp<[[VP1]]>
+; CHECK-NEXT: No successors
+; CHECK-NEXT: }
+; CHECK-NEXT: Successor(s): middle.block
+; CHECK-EMPTY:
+; CHECK-NEXT: middle.block:
+; CHECK-NEXT: EMIT vp<[[VP13:%[0-9]+]]> = compute-reduction-result (add, in-loop) ir<%red.next>
+; CHECK-NEXT: Successor(s): ir-bb<exit>
+; CHECK-EMPTY:
+; CHECK-NEXT: ir-bb<exit>:
+; CHECK-NEXT: IR %red.next.lcssa = phi i64 [ %red.next, %loop ] (extra operand: vp<[[VP13]]> from middle.block)
+; CHECK-NEXT: No successors
+; CHECK-EMPTY:
+; CHECK-NEXT: scalar.ph:
+; CHECK-NEXT: Successor(s): ir-bb<loop>
+; CHECK-EMPTY:
+; CHECK-NEXT: ir-bb<loop>:
+; CHECK-NEXT: IR %ptr.iv = phi ptr [ %start, %entry ], [ %gep.iv.next, %loop ] (extra operand: ir<%start> from scalar.ph)
+; CHECK-NEXT: IR %red = phi i64 [ 0, %entry ], [ %red.next, %loop ] (extra operand: ir<0> from scalar.ph)
+; CHECK-NEXT: IR %l = load i8, ptr %ptr.iv, align 1
+; CHECK-NEXT: IR %l.ext = sext i8 %l to i32
+; CHECK-NEXT: IR %mul = mul i32 %l.ext, 128
+; CHECK-NEXT: IR %mul.ext = sext i32 %mul to i64
+; CHECK-NEXT: IR %red.next = add i64 %red, %mul.ext
+; CHECK-NEXT: IR %gep.iv.next = getelementptr i8, ptr %ptr.iv, i64 1
+; CHECK-NEXT: IR %ec = icmp eq ptr %ptr.iv, %end
+; CHECK-NEXT: No successors
+; CHECK-NEXT: }
+;
+entry:
+ br label %loop
+
+loop:
+ %ptr.iv = phi ptr [ %start, %entry ], [ %gep.iv.next, %loop ]
+ %red = phi i64 [ 0, %entry ], [ %red.next, %loop ]
+ %l = load i8, ptr %ptr.iv, align 1
+ %l.ext = sext i8 %l to i32
+ %mul = mul i32 %l.ext, 128
+ %mul.ext = sext i32 %mul to i64
+ %red.next = add i64 %red, %mul.ext
+ %gep.iv.next = getelementptr i8, ptr %ptr.iv, i64 1
+ %ec = icmp eq ptr %ptr.iv, %end
+ br i1 %ec, label %exit, label %loop
+
+exit:
+ %red.next.lcssa = phi i64 [ %red.next, %loop ]
+ ret i64 %red.next.lcssa
+}
+
+; This reduce.add(ext(mul(ext(A), ext(B)))) can't be turned into an
+; ExtMulAccReduction VPExpressionRecipe since the mul has two users.
+; It can however be turned into an ExtendedReduction since that one doesn't
+; modify the mul's operands.
+define i64 @print_ext_mul_two_uses(i64 %n, ptr %a, i16 %b, i32 %c) {
+; CHECK-LABEL: VPlan for loop in 'print_ext_mul_two_uses'
+; CHECK: VPlan 'Initial VPlan for VF={vscale x 4},UF={1}' {
+; CHECK-NEXT: Live-in vp<[[VP0:%[0-9]+]]> = VF * UF
+; CHECK-NEXT: Live-in vp<[[VP1:%[0-9]+]]> = vector-trip-count
+; CHECK-NEXT: vp<[[VP3:%[0-9]+]]> = original trip-count
+; CHECK-EMPTY:
+; CHECK-NEXT: ir-bb<entry>:
+; CHECK-NEXT: EMIT vp<[[VP3]]> = EXPAND SCEV (1 + %n)
+; CHECK-NEXT: Successor(s): scalar.ph, vector.ph
+; CHECK-EMPTY:
+; CHECK-NEXT: vector.ph:
+; CHECK-NEXT: EMIT vp<[[VP4:%[0-9]+]]> = reduction-start-vector ir<0>, ir<0>, ir<1>
+; CHECK-NEXT: WIDEN-CAST ir<%conv> = sext ir<%b> to i32
+; CHECK-NEXT: WIDEN ir<%mul> = mul ir<%conv>, ir<%conv>
+; CHECK-NEXT: WIDEN-CAST ir<%mul.ext> = zext ir<%mul> to i64
+; CHECK-NEXT: Successor(s): vector loop
+; CHECK-EMPTY:
+; CHECK-NEXT: <x1> vector loop: {
+; CHECK-NEXT: vp<[[VP5:%[0-9]+]]> = CANONICAL-IV
+; CHECK-EMPTY:
+; CHECK-NEXT: vector.body:
+; CHECK-NEXT: CURRENT-ITERATION-PHI vp<[[VP6:%[0-9]+]]> = phi ir<0>, vp<%current.iteration.next>
+; CHECK-NEXT: WIDEN-REDUCTION-PHI ir<%res2> = phi (add) vp<[[VP4]]>, ir<%add>
+; CHECK-NEXT: EMIT-SCALAR vp<%avl> = phi [ vp<[[VP3]]>, vector.ph ], [ vp<%avl.next>, vector.body ]
+; CHECK-NEXT: EMIT-SCALAR vp<%evl> = EXPLICIT-VECTOR-LENGTH vp<%avl>
+; CHECK-NEXT: REDUCE ir<%add> = ir<%res2> + vp.reduce.add (ir<%mul.ext>, vp<%evl>)
+; CHECK-NEXT: EMIT-SCALAR vp<[[VP7:%[0-9]+]]> = zext vp<%evl> to i64
+; CHECK-NEXT: EMIT vp<%current.iteration.next> = add vp<[[VP7]]>, vp<[[VP6]]>
+; CHECK-NEXT: EMIT vp<%avl.next> = sub nuw vp<%avl>, vp<[[VP7]]>
+; CHECK-NEXT: EMIT vp<%index.next> = add vp<[[VP5]]>, vp<[[VP0]]>
+; CHECK-NEXT: EMIT branch-on-count vp<%index.next>, vp<[[VP1]]>
+; CHECK-NEXT: No successors
+; CHECK-NEXT: }
+; CHECK-NEXT: Successor(s): middle.block
+; CHECK-EMPTY:
+; CHECK-NEXT: middle.block:
+; CHECK-NEXT: EMIT vp<[[VP9:%[0-9]+]]> = compute-reduction-result (add, in-loop) ir<%add>
+; CHECK-NEXT: Successor(s): ir-bb<exit>
+; CHECK-EMPTY:
+; CHECK-NEXT: ir-bb<exit>:
+; CHECK-NEXT: IR %add.lcssa = phi i64 [ %add, %loop ] (extra operand: vp<[[VP9]]> from middle.block)
+; CHECK-NEXT: No successors
+; CHECK-EMPTY:
+; CHECK-NEXT: scalar.ph:
+; CHECK-NEXT: Successor(s): ir-bb<loop>
+; CHECK-EMPTY:
+; CHECK-NEXT: ir-bb<loop>:
+; CHECK-NEXT: IR %iv = phi i64 [ 0, %entry ], [ %iv.next, %loop ] (extra operand: ir<0> from scalar.ph)
+; CHECK-NEXT: IR %res1 = phi i64 [ 0, %entry ], [ %load.ext.ext, %loop ] (extra operand: ir<0> from scalar.ph)
+; CHECK-NEXT: IR %res2 = phi i64 [ 0, %entry ], [ %add, %loop ] (extra operand: ir<0> from scalar.ph)
+; CHECK-NEXT: IR %load = load i16, ptr %a, align 2
+; CHECK-NEXT: IR %iv.next = add i64 %iv, 1
+; CHECK-NEXT: IR %conv = sext i16 %b to i32
+; CHECK-NEXT: IR %mul = mul i32 %conv, %conv
+; CHECK-NEXT: IR %mul.ext = zext i32 %mul to i64
+; CHECK-NEXT: IR %add = add i64 %res2, %mul.ext
+; CHECK-NEXT: IR %second_use = or i32 %mul, %c
+; CHECK-NEXT: IR %load.ext = sext i16 %load to i32
+; CHECK-NEXT: IR %load.ext.ext = sext i32 %load.ext to i64
+; CHECK-NEXT: IR %exitcond740.not = icmp eq i64 %iv, %n
+; CHECK-NEXT: No successors
+; CHECK-NEXT: }
+;
+entry:
+ br label %loop
+
+loop:
+ %iv = phi i64 [ 0, %entry ], [ %iv.next, %loop ]
+ %res1 = phi i64 [ 0, %entry ], [ %load.ext.ext, %loop ]
+ %res2 = phi i64 [ 0, %entry ], [ %add, %loop ]
+ %load = load i16, ptr %a, align 2
+ %iv.next = add i64 %iv, 1
+ %conv = sext i16 %b to i32
+ %mul = mul i32 %conv, %conv
+ %mul.ext = zext i32 %mul to i64
+ %add = add i64 %res2, %mul.ext
+ %second_use = or i32 %mul, %c ; this value is otherwise unused, but that's sufficient for the test
+ %load.ext = sext i16 %load to i32
+ %load.ext.ext = sext i32 %load.ext to i64
+ %exitcond740.not = icmp eq i64 %iv, %n
+ br i1 %exitcond740.not, label %exit, label %loop
+
+exit:
+ ret i64 %add
+}
+
+define i32 @print_umax_reduction(ptr %y) {
+; CHECK-LABEL: VPlan for loop in 'print_umax_reduction'
+; CHECK: VPlan 'Initial VPlan for VF={vscale x 4},UF={1}' {
+; CHECK-NEXT: Live-in vp<[[VP0:%[0-9]+]]> = VF * UF
+; CHECK-NEXT: Live-in vp<[[VP1:%[0-9]+]]> = vector-trip-count
+; CHECK-NEXT: Live-in ir<100> = original trip-count
+; CHECK-EMPTY:
+; CHECK-NEXT: ir-bb<entry>:
+; CHECK-NEXT: Successor(s): scalar.ph, vector.ph
+; CHECK-EMPTY:
+; CHECK-NEXT: vector.ph:
+; CHECK-NEXT: Successor(s): vector loop
+; CHECK-EMPTY:
+; CHECK-NEXT: <x1> vector loop: {
+; CHECK-NEXT: vp<[[VP3:%[0-9]+]]> = CANONICAL-IV
+; CHECK-EMPTY:
+; CHECK-NEXT: vector.body:
+; CHECK-NEXT: CURRENT-ITERATION-PHI vp<[[VP4:%[0-9]+]]> = phi ir<0>, vp<%current.iteration.next>
+; CHECK-NEXT: WIDEN-REDUCTION-PHI ir<%red> = phi (umax) ir<0>, vp<[[VP8:%[0-9]+]]>
+; CHECK-NEXT: EMIT-SCALAR vp<%avl> = phi [ ir<100>, vector.ph ], [ vp<%avl.next>, vector.body ]
+; CHECK-NEXT: EMIT-SCALAR vp<%evl> = EXPLICIT-VECTOR-LENGTH vp<%avl>
+; CHECK-NEXT: EMIT-SCALAR vp<[[VP5:%[0-9]+]]> = zext vp<%evl> to i64
+; CHECK-NEXT: vp<[[VP6:%[0-9]+]]> = SCALAR-STEPS vp<[[VP4]]>, ir<1>, vp<[[VP5]]>
+; CHECK-NEXT: CLONE ir<%gep> = getelementptr inbounds ir<%y>, vp<[[VP6]]>
+; CHECK-NEXT: vp<[[VP7:%[0-9]+]]> = vector-pointer inbounds ir<%gep>, ir<1>
+; CHECK-NEXT: WIDEN ir<%lv> = vp.load vp<[[VP7]]>, vp<%evl>
+; CHECK-NEXT: WIDEN-INTRINSIC ir<%red.next> = call llvm.umax(ir<%lv>, ir<%red>)
+; CHECK-NEXT: WIDEN-INTRINSIC vp<[[VP8]]> = call llvm.vp.merge(ir<true>, ir<%red.next>, ir<%red>, vp<%evl>)
+; CHECK-NEXT: EMIT-SCALAR vp<[[VP9:%[0-9]+]]> = zext vp<%evl> to i64
+; CHECK-NEXT: EMIT vp<%current.iteration.next> = add nuw vp<[[VP9]]>, vp<[[VP4]]>
+; CHECK-NEXT: EMIT vp<%avl.next> = sub nuw vp<%avl>, vp<[[VP9]]>
+; CHECK-NEXT: EMIT vp<%index.next> = add nuw vp<[[VP3]]>, vp<[[VP0]]>
+; CHECK-NEXT: EMIT branch-on-count vp<%index.next>, vp<[[VP1]]>
+; CHECK-NEXT: No successors
+; CHECK-NEXT: }
+; CHECK-NEXT: Successor(s): middle.block
+; CHECK-EMPTY:
+; CHECK-NEXT: middle.block:
+; CHECK-NEXT: EMIT vp<[[VP11:%[0-9]+]]> = compute-reduction-result (umax) vp<[[VP8]]>
+; CHECK-NEXT: Successor(s): ir-bb<exit>
+; CHECK-EMPTY:
+; CHECK-NEXT: ir-bb<exit>:
+; CHECK-NEXT: IR %red.next.lcssa = phi i32 [ %red.next, %loop ] (extra operand: vp<[[VP11]]> from middle.block)
+; CHECK-NEXT: No successors
+; CHECK-EMPTY:
+; CHECK-NEXT: scalar.ph:
+; CHECK-NEXT: Successor(s): ir-bb<loop>
+; CHECK-EMPTY:
+; CHECK-NEXT: ir-bb<loop>:
+; CHECK-NEXT: IR %iv = phi i64 [ 0, %entry ], [ %iv.next, %loop ] (extra operand: ir<0> from scalar.ph)
+; CHECK-NEXT: IR %red = phi i32 [ 0, %entry ], [ %red.next, %loop ] (extra operand: ir<0> from scalar.ph)
+; CHECK-NEXT: IR %gep = getelementptr inbounds i32, ptr %y, i64 %iv
+; CHECK-NEXT: IR %lv = load i32, ptr %gep, align 4
+; CHECK-NEXT: IR %red.next = call i32 @llvm.umax.i32(i32 %lv, i32 %red)
+; CHECK-NEXT: IR %iv.next = add i64 %iv, 1
+; CHECK-NEXT: IR %ec = icmp eq i64 %iv.next, 100
+; CHECK-NEXT: No successors
+; CHECK-NEXT: }
+;
+entry:
+ br label %loop
+
+loop:
+ %iv = phi i64 [ 0, %entry ], [ %iv.next, %loop ]
+ %red = phi i32 [ 0, %entry ], [ %red.next, %loop ]
+ %gep = getelementptr inbounds i32, ptr %y, i64 %iv
+ %lv = load i32, ptr %gep, align 4
+ %red.next = call i32 @llvm.umax(i32 %lv, i32 %red)
+ %iv.next = add i64 %iv, 1
+ %ec = icmp eq i64 %iv.next, 100
+ br i1 %ec, label %exit, label %loop
+
+exit:
+ ret i32 %red.next
+}
>From 4aeadfbd2270cf659055b2cfb5a42b8090f6f032 Mon Sep 17 00:00:00 2001
From: Elvis Wang <elvis.wang at sifive.com>
Date: Wed, 24 Jun 2026 18:13:23 -0700
Subject: [PATCH 2/5] [LV] Support EVL partial reduction and
VPExpressionRecipe.
This patch adds the support for partial reduction with EVL tail-folding
by not creating a new VPExpressionEVLRecipes but just changing the last
expressionRecipes from VPReductionRecipe to VPReductionEVLRecipe.
Currently, all partial reductions will be converted to VPExpressionRecipe
when construction. So this patch also supports the VPExpressionRecipe
for EVL.
---
.../Transforms/Vectorize/LoopVectorize.cpp | 12 +--
llvm/lib/Transforms/Vectorize/VPlan.h | 9 +-
.../lib/Transforms/Vectorize/VPlanRecipes.cpp | 91 +++++++++++++++----
.../Transforms/Vectorize/VPlanTransforms.cpp | 5 +
.../RISCV/partial-reduce-dot-product.ll | 40 ++++----
.../VPlan/RISCV/partial-reduce-dot-product.ll | 10 +-
.../VPlan/RISCV/reductions-evl.ll | 63 ++++++-------
7 files changed, 141 insertions(+), 89 deletions(-)
diff --git a/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp b/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp
index f1ca4061bfd9e..61511bbbe6d96 100644
--- a/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp
+++ b/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp
@@ -6841,14 +6841,10 @@ VPlanPtr LoopVectorizationPlanner::tryToBuildVPlan(VPlanPtr Plan,
// Create partial reduction recipes for scaled reductions and transform
// recipes to abstract recipes if it is legal and beneficial and clamp the
// range for better cost estimation.
- // TODO: Enable following transform when the EVL-version of extended-reduction
- // and mulacc-reduction are implemented.
- if (!CM.foldTailWithEVL()) {
- RUN_VPLAN_PASS(VPlanTransforms::createPartialReductions, *Plan, CostCtx,
- Range);
- RUN_VPLAN_PASS(VPlanTransforms::convertToAbstractRecipes, *Plan, CostCtx,
- Range);
- }
+ RUN_VPLAN_PASS(VPlanTransforms::createPartialReductions, *Plan, CostCtx,
+ Range);
+ RUN_VPLAN_PASS(VPlanTransforms::convertToAbstractRecipes, *Plan, CostCtx,
+ Range);
// Interleave memory: for each Interleave Group we marked earlier as relevant
// for this VPlan, replace the Recipes widening its memory instructions with a
diff --git a/llvm/lib/Transforms/Vectorize/VPlan.h b/llvm/lib/Transforms/Vectorize/VPlan.h
index eaf9d1433aff7..7c52c483f5b05 100644
--- a/llvm/lib/Transforms/Vectorize/VPlan.h
+++ b/llvm/lib/Transforms/Vectorize/VPlan.h
@@ -3325,6 +3325,9 @@ class LLVM_ABI_FOR_TEST VPReductionRecipe : public VPRecipeWithIRFlags {
return Partial ? Partial->VFScaleFactor : 1;
}
+ /// The ReductionStyle of this recipe.
+ ReductionStyle getReductionStyle() const { return Style; }
+
protected:
#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
/// Print the recipe.
@@ -3345,8 +3348,7 @@ class LLVM_ABI_FOR_TEST VPReductionEVLRecipe : public VPReductionRecipe {
R.getFastMathFlagsOrNone(),
cast_or_null<Instruction>(R.getUnderlyingValue()),
{R.getChainOp(), R.getVecOp(), &EVL}, CondOp,
- getReductionStyle(/*InLoop=*/true, R.isOrdered(), 1),
- DL) {}
+ R.getReductionStyle(), DL) {}
~VPReductionEVLRecipe() override = default;
@@ -3655,6 +3657,9 @@ class VPExpressionRecipe : public VPSingleDefRecipe {
return getOperand(getNumOperands() - OpIdx);
}
+ /// Returns a new VPExpressionRecipe with VPReductionEVLRecipe.
+ VPExpressionRecipe *convertToEVL(VPValue &EVL, VPValue *Mask);
+
/// Insert the recipes of the expression back into the VPlan, directly before
/// the current recipe. Leaves the expression recipe empty, which must be
/// removed before codegen.
diff --git a/llvm/lib/Transforms/Vectorize/VPlanRecipes.cpp b/llvm/lib/Transforms/Vectorize/VPlanRecipes.cpp
index f45b9e4f6c35b..07635e12c53c7 100644
--- a/llvm/lib/Transforms/Vectorize/VPlanRecipes.cpp
+++ b/llvm/lib/Transforms/Vectorize/VPlanRecipes.cpp
@@ -3345,7 +3345,7 @@ void VPReductionEVLRecipe::execute(VPTransformState &State) {
Builder.setFastMathFlags(getFastMathFlagsOrNone());
RecurKind Kind = getRecurrenceKind();
- Value *Prev = State.get(getChainOp(), /*IsScalar*/ true);
+ Value *Prev = State.get(getChainOp(), !isPartialReduction());
Value *VecOp = State.get(getVecOp());
Value *EVL = State.get(getEVL(), VPLane(0));
@@ -3356,7 +3356,27 @@ void VPReductionEVLRecipe::execute(VPTransformState &State) {
Mask = Builder.CreateVectorSplat(State.VF, Builder.getTrue());
Value *NewRed;
- if (isOrdered()) {
+ if (isPartialReduction()) {
+ // For partial reduction, we need to generate the predicated select
+ // (vp.merge) since `@llvm.vector.partial.reduce()` doesn't have vector
+ // predicated version.
+ VectorType *VecTy = cast<VectorType>(VecOp->getType());
+ Value *Identity = getRecurrenceIdentity(Kind, VecTy->getElementType(),
+ getFastMathFlagsOrNone());
+ if (State.VF.isVector())
+ Identity =
+ State.Builder.CreateVectorSplat(VecTy->getElementCount(), Identity);
+
+ Value *NewVecOp = State.Builder.CreateIntrinsic(
+ VecTy, Intrinsic::vp_merge, {Mask, VecOp, Identity, EVL});
+ assert((Kind == RecurKind::Add || Kind == RecurKind::FAdd) &&
+ "Unexpected partial reduction kind");
+ NewRed = State.Builder.CreateIntrinsic(
+ Prev->getType(),
+ Kind == RecurKind::Add ? Intrinsic::vector_partial_reduce_add
+ : Intrinsic::vector_partial_reduce_fadd,
+ {Prev, NewVecOp}, State.Builder.getFastMathFlags(), "partial.reduce");
+ } else if (isOrdered()) {
NewRed = createOrderedReduction(Builder, Kind, VecOp, Prev, Mask, EVL);
} else {
NewRed = createSimpleReduction(Builder, VecOp, Kind, Mask, EVL);
@@ -3367,7 +3387,7 @@ void VPReductionEVLRecipe::execute(VPTransformState &State) {
(Instruction::BinaryOps)RecurrenceDescriptor::getOpcode(Kind), NewRed,
Prev);
}
- State.set(this, NewRed, /*IsScalar*/ true);
+ State.set(this, NewRed, !isPartialReduction());
}
InstructionCost VPReductionRecipe::computeCost(ElementCount VF,
@@ -3475,6 +3495,32 @@ VPExpressionRecipe::VPExpressionRecipe(
R->replaceUsesOfWith(LiveIn, Tmp);
}
+VPExpressionRecipe *VPExpressionRecipe::convertToEVL(VPValue &EVL,
+ VPValue *Mask) {
+ // Clone the VPExpressionRecipe.
+ SmallVector<VPSingleDefRecipe *, 4> NewExpressionRecipes;
+ for (auto *R : ExpressionRecipes)
+ NewExpressionRecipes.push_back(R->clone());
+ for (auto *New : NewExpressionRecipes) {
+ for (const auto &[Idx, Old] : enumerate(ExpressionRecipes))
+ New->replaceUsesOfWith(Old, NewExpressionRecipes[Idx]);
+ // Update placeholder operands in the cloned recipe to use the external
+ // operands, to be internalized when the evl expression is constructed.
+ for (const auto &[Placeholder, OutsideOp] :
+ zip(LiveInPlaceholders, operands()))
+ New->replaceUsesOfWith(Placeholder, OutsideOp);
+ }
+
+ // Transforms to EVL reduction.
+ auto *Red = cast<VPReductionRecipe>(NewExpressionRecipes.pop_back_val());
+ if (!Mask)
+ Mask = getParent()->getPlan()->getTrue();
+ auto *NewRed = new VPReductionEVLRecipe(*Red, EVL, Mask, Red->getDebugLoc());
+ delete Red;
+ NewExpressionRecipes.push_back(NewRed);
+ return new VPExpressionRecipe(ExpressionType, NewExpressionRecipes);
+}
+
void VPExpressionRecipe::decompose() {
for (auto *R : ExpressionRecipes)
// Since the list could contain duplicates, make sure the recipe hasn't
@@ -3594,8 +3640,23 @@ void VPExpressionRecipe::printRecipe(raw_ostream &O, const Twine &Indent,
O << " = ";
auto *Red = cast<VPReductionRecipe>(ExpressionRecipes.back());
unsigned Opcode = RecurrenceDescriptor::getOpcode(Red->getRecurrenceKind());
- VPValue *RdxStart =
- getOperand(getNumOperands() - (Red->isConditional() ? 2 : 1));
+ VPValue *Mask = getOperand(getNumOperands() - 1);
+ VPValue *EVL =
+ isa<VPReductionEVLRecipe>(Red)
+ ? getOperand(getNumOperands() - (Red->isConditional() ? 2 : 1))
+ : nullptr;
+ VPValue *RdxStart = getOperand(
+ getNumOperands() - (Red->isConditional() ? 2 : 1) - (EVL ? 1 : 0));
+ auto PrintEVLAndMask = [&]() {
+ if (EVL) {
+ O << ", ";
+ EVL->printAsOperand(O, SlotTracker);
+ }
+ if (Red->isConditional()) {
+ O << ", ";
+ Mask->printAsOperand(O, SlotTracker);
+ }
+ };
switch (ExpressionType) {
case ExpressionTypes::NegatedExtendedReduction:
@@ -3614,10 +3675,7 @@ void VPExpressionRecipe::printRecipe(raw_ostream &O, const Twine &Indent,
auto *Ext0 = cast<VPWidenCastRecipe>(ExpressionRecipes[0]);
O << Instruction::getOpcodeName(Ext0->getOpcode()) << " to "
<< *Ext0->getScalarType();
- if (Red->isConditional()) {
- O << ", ";
- getOperand(getNumOperands() - 1)->printAsOperand(O, SlotTracker);
- }
+ PrintEVLAndMask();
O << ")";
break;
}
@@ -3638,10 +3696,7 @@ void VPExpressionRecipe::printRecipe(raw_ostream &O, const Twine &Indent,
auto *Ext1 = cast<VPWidenCastRecipe>(ExpressionRecipes[1]);
O << " " << Instruction::getOpcodeName(Ext1->getOpcode()) << " to "
<< *Ext1->getScalarType() << ")";
- if (Red->isConditional()) {
- O << ", ";
- getOperand(getNumOperands() - 1)->printAsOperand(O, SlotTracker);
- }
+ PrintEVLAndMask();
O << "))";
break;
}
@@ -3673,10 +3728,7 @@ void VPExpressionRecipe::printRecipe(raw_ostream &O, const Twine &Indent,
O << " " << Instruction::getOpcodeName(Ext1->getOpcode()) << " to "
<< *Ext1->getScalarType() << ")";
}
- if (Red->isConditional()) {
- O << ", ";
- getOperand(getNumOperands() - 1)->printAsOperand(O, SlotTracker);
- }
+ PrintEVLAndMask();
O << ")";
break;
}
@@ -3707,7 +3759,10 @@ void VPReductionRecipe::printRecipe(raw_ostream &O, const Twine &Indent,
void VPReductionEVLRecipe::printRecipe(raw_ostream &O, const Twine &Indent,
VPSlotTracker &SlotTracker) const {
- O << Indent << "REDUCE ";
+ if (isPartialReduction())
+ O << Indent << "PARTIAL-REDUCE ";
+ else
+ O << Indent << "REDUCE ";
printAsOperand(O, SlotTracker);
O << " = ";
getChainOp()->printAsOperand(O, SlotTracker);
diff --git a/llvm/lib/Transforms/Vectorize/VPlanTransforms.cpp b/llvm/lib/Transforms/Vectorize/VPlanTransforms.cpp
index 5834f38e96b84..f2704849c0779 100644
--- a/llvm/lib/Transforms/Vectorize/VPlanTransforms.cpp
+++ b/llvm/lib/Transforms/Vectorize/VPlanTransforms.cpp
@@ -3157,6 +3157,11 @@ static VPRecipeBase *optimizeMaskToEVL(VPValue *HeaderMask,
Mask ? Mask : Plan->getTrue(), &EVL},
IntrR->getScalarType(), {}, {}, DL);
+ // Transforms the VPReductionRecipe inside the VPExpressionRecipe.
+ if (auto *ExpressionR = dyn_cast<VPExpressionRecipe>(&CurRecipe))
+ if (match(ExpressionR->getOperand(ExpressionR->getNumOperands() - 1),
+ m_RemoveMask(HeaderMask, Mask)))
+ return ExpressionR->convertToEVL(EVL, Mask);
return nullptr;
}
diff --git a/llvm/test/Transforms/LoopVectorize/RISCV/partial-reduce-dot-product.ll b/llvm/test/Transforms/LoopVectorize/RISCV/partial-reduce-dot-product.ll
index e80fc7a5328d2..2bb7d03a37e3e 100644
--- a/llvm/test/Transforms/LoopVectorize/RISCV/partial-reduce-dot-product.ll
+++ b/llvm/test/Transforms/LoopVectorize/RISCV/partial-reduce-dot-product.ll
@@ -158,25 +158,25 @@ define i32 @vdot4a(ptr %a, ptr %b) #0 {
; TAILFOLD-NEXT: br label [[VECTOR_BODY:%.*]]
; TAILFOLD: vector.body:
; TAILFOLD-NEXT: [[EVL_BASED_IV:%.*]] = phi i64 [ 0, [[VECTOR_PH]] ], [ [[INDEX_EVL_NEXT:%.*]], [[VECTOR_BODY]] ]
-; TAILFOLD-NEXT: [[VEC_PHI:%.*]] = phi <vscale x 4 x i32> [ zeroinitializer, [[VECTOR_PH]] ], [ [[TMP7:%.*]], [[VECTOR_BODY]] ]
+; TAILFOLD-NEXT: [[VEC_PHI:%.*]] = phi <vscale x 1 x i32> [ zeroinitializer, [[VECTOR_PH]] ], [ [[PARTIAL_REDUCE:%.*]], [[VECTOR_BODY]] ]
; TAILFOLD-NEXT: [[AVL:%.*]] = phi i64 [ 1024, [[VECTOR_PH]] ], [ [[AVL_NEXT:%.*]], [[VECTOR_BODY]] ]
; TAILFOLD-NEXT: [[TMP0:%.*]] = call i32 @llvm.experimental.get.vector.length.i64(i64 [[AVL]], i32 4, i1 true)
; TAILFOLD-NEXT: [[TMP1:%.*]] = getelementptr i8, ptr [[A]], i64 [[EVL_BASED_IV]]
; TAILFOLD-NEXT: [[VP_OP_LOAD:%.*]] = call <vscale x 4 x i8> @llvm.vp.load.nxv4i8.p0(ptr align 1 [[TMP1]], <vscale x 4 x i1> splat (i1 true), i32 [[TMP0]])
-; TAILFOLD-NEXT: [[TMP2:%.*]] = sext <vscale x 4 x i8> [[VP_OP_LOAD]] to <vscale x 4 x i32>
; TAILFOLD-NEXT: [[TMP3:%.*]] = getelementptr i8, ptr [[B]], i64 [[EVL_BASED_IV]]
; TAILFOLD-NEXT: [[VP_OP_LOAD1:%.*]] = call <vscale x 4 x i8> @llvm.vp.load.nxv4i8.p0(ptr align 1 [[TMP3]], <vscale x 4 x i1> splat (i1 true), i32 [[TMP0]])
; TAILFOLD-NEXT: [[TMP4:%.*]] = sext <vscale x 4 x i8> [[VP_OP_LOAD1]] to <vscale x 4 x i32>
+; TAILFOLD-NEXT: [[TMP2:%.*]] = sext <vscale x 4 x i8> [[VP_OP_LOAD]] to <vscale x 4 x i32>
; TAILFOLD-NEXT: [[TMP5:%.*]] = mul <vscale x 4 x i32> [[TMP4]], [[TMP2]]
-; TAILFOLD-NEXT: [[TMP6:%.*]] = add <vscale x 4 x i32> [[TMP5]], [[VEC_PHI]]
-; TAILFOLD-NEXT: [[TMP7]] = call <vscale x 4 x i32> @llvm.vp.merge.nxv4i32(<vscale x 4 x i1> splat (i1 true), <vscale x 4 x i32> [[TMP6]], <vscale x 4 x i32> [[VEC_PHI]], i32 [[TMP0]])
+; TAILFOLD-NEXT: [[TMP6:%.*]] = call <vscale x 4 x i32> @llvm.vp.merge.nxv4i32(<vscale x 4 x i1> splat (i1 true), <vscale x 4 x i32> [[TMP5]], <vscale x 4 x i32> zeroinitializer, i32 [[TMP0]])
+; TAILFOLD-NEXT: [[PARTIAL_REDUCE]] = call <vscale x 1 x i32> @llvm.vector.partial.reduce.add.nxv1i32.nxv4i32(<vscale x 1 x i32> [[VEC_PHI]], <vscale x 4 x i32> [[TMP6]])
; TAILFOLD-NEXT: [[TMP8:%.*]] = zext i32 [[TMP0]] to i64
; TAILFOLD-NEXT: [[INDEX_EVL_NEXT]] = add nuw i64 [[TMP8]], [[EVL_BASED_IV]]
; TAILFOLD-NEXT: [[AVL_NEXT]] = sub nuw i64 [[AVL]], [[TMP8]]
; TAILFOLD-NEXT: [[TMP9:%.*]] = icmp eq i64 [[AVL_NEXT]], 0
; TAILFOLD-NEXT: br i1 [[TMP9]], label [[MIDDLE_BLOCK:%.*]], label [[VECTOR_BODY]], !llvm.loop [[LOOP0:![0-9]+]]
; TAILFOLD: middle.block:
-; TAILFOLD-NEXT: [[TMP10:%.*]] = call i32 @llvm.vector.reduce.add.nxv4i32(<vscale x 4 x i32> [[TMP7]])
+; TAILFOLD-NEXT: [[TMP10:%.*]] = call i32 @llvm.vector.reduce.add.nxv1i32(<vscale x 1 x i32> [[PARTIAL_REDUCE]])
; TAILFOLD-NEXT: br label [[FOR_EXIT:%.*]]
; TAILFOLD: for.exit:
; TAILFOLD-NEXT: ret i32 [[TMP10]]
@@ -353,25 +353,25 @@ define i32 @vdot4au(ptr %a, ptr %b) #0 {
; TAILFOLD-NEXT: br label [[VECTOR_BODY:%.*]]
; TAILFOLD: vector.body:
; TAILFOLD-NEXT: [[EVL_BASED_IV:%.*]] = phi i64 [ 0, [[VECTOR_PH]] ], [ [[INDEX_EVL_NEXT:%.*]], [[VECTOR_BODY]] ]
-; TAILFOLD-NEXT: [[VEC_PHI:%.*]] = phi <vscale x 4 x i32> [ zeroinitializer, [[VECTOR_PH]] ], [ [[TMP7:%.*]], [[VECTOR_BODY]] ]
+; TAILFOLD-NEXT: [[VEC_PHI:%.*]] = phi <vscale x 1 x i32> [ zeroinitializer, [[VECTOR_PH]] ], [ [[PARTIAL_REDUCE:%.*]], [[VECTOR_BODY]] ]
; TAILFOLD-NEXT: [[AVL:%.*]] = phi i64 [ 1024, [[VECTOR_PH]] ], [ [[AVL_NEXT:%.*]], [[VECTOR_BODY]] ]
; TAILFOLD-NEXT: [[TMP0:%.*]] = call i32 @llvm.experimental.get.vector.length.i64(i64 [[AVL]], i32 4, i1 true)
; TAILFOLD-NEXT: [[TMP1:%.*]] = getelementptr i8, ptr [[A]], i64 [[EVL_BASED_IV]]
; TAILFOLD-NEXT: [[VP_OP_LOAD:%.*]] = call <vscale x 4 x i8> @llvm.vp.load.nxv4i8.p0(ptr align 1 [[TMP1]], <vscale x 4 x i1> splat (i1 true), i32 [[TMP0]])
-; TAILFOLD-NEXT: [[TMP2:%.*]] = zext <vscale x 4 x i8> [[VP_OP_LOAD]] to <vscale x 4 x i32>
; TAILFOLD-NEXT: [[TMP3:%.*]] = getelementptr i8, ptr [[B]], i64 [[EVL_BASED_IV]]
; TAILFOLD-NEXT: [[VP_OP_LOAD1:%.*]] = call <vscale x 4 x i8> @llvm.vp.load.nxv4i8.p0(ptr align 1 [[TMP3]], <vscale x 4 x i1> splat (i1 true), i32 [[TMP0]])
; TAILFOLD-NEXT: [[TMP4:%.*]] = zext <vscale x 4 x i8> [[VP_OP_LOAD1]] to <vscale x 4 x i32>
+; TAILFOLD-NEXT: [[TMP2:%.*]] = zext <vscale x 4 x i8> [[VP_OP_LOAD]] to <vscale x 4 x i32>
; TAILFOLD-NEXT: [[TMP5:%.*]] = mul <vscale x 4 x i32> [[TMP4]], [[TMP2]]
-; TAILFOLD-NEXT: [[TMP6:%.*]] = add <vscale x 4 x i32> [[TMP5]], [[VEC_PHI]]
-; TAILFOLD-NEXT: [[TMP7]] = call <vscale x 4 x i32> @llvm.vp.merge.nxv4i32(<vscale x 4 x i1> splat (i1 true), <vscale x 4 x i32> [[TMP6]], <vscale x 4 x i32> [[VEC_PHI]], i32 [[TMP0]])
+; TAILFOLD-NEXT: [[TMP6:%.*]] = call <vscale x 4 x i32> @llvm.vp.merge.nxv4i32(<vscale x 4 x i1> splat (i1 true), <vscale x 4 x i32> [[TMP5]], <vscale x 4 x i32> zeroinitializer, i32 [[TMP0]])
+; TAILFOLD-NEXT: [[PARTIAL_REDUCE]] = call <vscale x 1 x i32> @llvm.vector.partial.reduce.add.nxv1i32.nxv4i32(<vscale x 1 x i32> [[VEC_PHI]], <vscale x 4 x i32> [[TMP6]])
; TAILFOLD-NEXT: [[TMP8:%.*]] = zext i32 [[TMP0]] to i64
; TAILFOLD-NEXT: [[INDEX_EVL_NEXT]] = add nuw i64 [[TMP8]], [[EVL_BASED_IV]]
; TAILFOLD-NEXT: [[AVL_NEXT]] = sub nuw i64 [[AVL]], [[TMP8]]
; TAILFOLD-NEXT: [[TMP9:%.*]] = icmp eq i64 [[AVL_NEXT]], 0
; TAILFOLD-NEXT: br i1 [[TMP9]], label [[MIDDLE_BLOCK:%.*]], label [[VECTOR_BODY]], !llvm.loop [[LOOP3:![0-9]+]]
; TAILFOLD: middle.block:
-; TAILFOLD-NEXT: [[TMP10:%.*]] = call i32 @llvm.vector.reduce.add.nxv4i32(<vscale x 4 x i32> [[TMP7]])
+; TAILFOLD-NEXT: [[TMP10:%.*]] = call i32 @llvm.vector.reduce.add.nxv1i32(<vscale x 1 x i32> [[PARTIAL_REDUCE]])
; TAILFOLD-NEXT: br label [[FOR_EXIT:%.*]]
; TAILFOLD: for.exit:
; TAILFOLD-NEXT: ret i32 [[TMP10]]
@@ -548,25 +548,25 @@ define i32 @vdot4asu(ptr %a, ptr %b) #0 {
; TAILFOLD-NEXT: br label [[VECTOR_BODY:%.*]]
; TAILFOLD: vector.body:
; TAILFOLD-NEXT: [[EVL_BASED_IV:%.*]] = phi i64 [ 0, [[VECTOR_PH]] ], [ [[INDEX_EVL_NEXT:%.*]], [[VECTOR_BODY]] ]
-; TAILFOLD-NEXT: [[VEC_PHI:%.*]] = phi <vscale x 4 x i32> [ zeroinitializer, [[VECTOR_PH]] ], [ [[TMP7:%.*]], [[VECTOR_BODY]] ]
+; TAILFOLD-NEXT: [[VEC_PHI:%.*]] = phi <vscale x 1 x i32> [ zeroinitializer, [[VECTOR_PH]] ], [ [[PARTIAL_REDUCE:%.*]], [[VECTOR_BODY]] ]
; TAILFOLD-NEXT: [[AVL:%.*]] = phi i64 [ 1024, [[VECTOR_PH]] ], [ [[AVL_NEXT:%.*]], [[VECTOR_BODY]] ]
; TAILFOLD-NEXT: [[TMP0:%.*]] = call i32 @llvm.experimental.get.vector.length.i64(i64 [[AVL]], i32 4, i1 true)
; TAILFOLD-NEXT: [[TMP1:%.*]] = getelementptr i8, ptr [[A]], i64 [[EVL_BASED_IV]]
; TAILFOLD-NEXT: [[VP_OP_LOAD:%.*]] = call <vscale x 4 x i8> @llvm.vp.load.nxv4i8.p0(ptr align 1 [[TMP1]], <vscale x 4 x i1> splat (i1 true), i32 [[TMP0]])
-; TAILFOLD-NEXT: [[TMP2:%.*]] = zext <vscale x 4 x i8> [[VP_OP_LOAD]] to <vscale x 4 x i32>
; TAILFOLD-NEXT: [[TMP3:%.*]] = getelementptr i8, ptr [[B]], i64 [[EVL_BASED_IV]]
; TAILFOLD-NEXT: [[VP_OP_LOAD1:%.*]] = call <vscale x 4 x i8> @llvm.vp.load.nxv4i8.p0(ptr align 1 [[TMP3]], <vscale x 4 x i1> splat (i1 true), i32 [[TMP0]])
; TAILFOLD-NEXT: [[TMP4:%.*]] = sext <vscale x 4 x i8> [[VP_OP_LOAD1]] to <vscale x 4 x i32>
+; TAILFOLD-NEXT: [[TMP2:%.*]] = zext <vscale x 4 x i8> [[VP_OP_LOAD]] to <vscale x 4 x i32>
; TAILFOLD-NEXT: [[TMP5:%.*]] = mul <vscale x 4 x i32> [[TMP4]], [[TMP2]]
-; TAILFOLD-NEXT: [[TMP6:%.*]] = add <vscale x 4 x i32> [[TMP5]], [[VEC_PHI]]
-; TAILFOLD-NEXT: [[TMP7]] = call <vscale x 4 x i32> @llvm.vp.merge.nxv4i32(<vscale x 4 x i1> splat (i1 true), <vscale x 4 x i32> [[TMP6]], <vscale x 4 x i32> [[VEC_PHI]], i32 [[TMP0]])
+; TAILFOLD-NEXT: [[TMP6:%.*]] = call <vscale x 4 x i32> @llvm.vp.merge.nxv4i32(<vscale x 4 x i1> splat (i1 true), <vscale x 4 x i32> [[TMP5]], <vscale x 4 x i32> zeroinitializer, i32 [[TMP0]])
+; TAILFOLD-NEXT: [[PARTIAL_REDUCE]] = call <vscale x 1 x i32> @llvm.vector.partial.reduce.add.nxv1i32.nxv4i32(<vscale x 1 x i32> [[VEC_PHI]], <vscale x 4 x i32> [[TMP6]])
; TAILFOLD-NEXT: [[TMP8:%.*]] = zext i32 [[TMP0]] to i64
; TAILFOLD-NEXT: [[INDEX_EVL_NEXT]] = add nuw i64 [[TMP8]], [[EVL_BASED_IV]]
; TAILFOLD-NEXT: [[AVL_NEXT]] = sub nuw i64 [[AVL]], [[TMP8]]
; TAILFOLD-NEXT: [[TMP9:%.*]] = icmp eq i64 [[AVL_NEXT]], 0
; TAILFOLD-NEXT: br i1 [[TMP9]], label [[MIDDLE_BLOCK:%.*]], label [[VECTOR_BODY]], !llvm.loop [[LOOP4:![0-9]+]]
; TAILFOLD: middle.block:
-; TAILFOLD-NEXT: [[TMP10:%.*]] = call i32 @llvm.vector.reduce.add.nxv4i32(<vscale x 4 x i32> [[TMP7]])
+; TAILFOLD-NEXT: [[TMP10:%.*]] = call i32 @llvm.vector.reduce.add.nxv1i32(<vscale x 1 x i32> [[PARTIAL_REDUCE]])
; TAILFOLD-NEXT: br label [[FOR_EXIT:%.*]]
; TAILFOLD: for.exit:
; TAILFOLD-NEXT: ret i32 [[TMP10]]
@@ -742,25 +742,25 @@ define i32 @vdot4asu2(ptr %a, ptr %b) #0 {
; TAILFOLD-NEXT: br label [[VECTOR_BODY:%.*]]
; TAILFOLD: vector.body:
; TAILFOLD-NEXT: [[EVL_BASED_IV:%.*]] = phi i64 [ 0, [[VECTOR_PH]] ], [ [[INDEX_EVL_NEXT:%.*]], [[VECTOR_BODY]] ]
-; TAILFOLD-NEXT: [[VEC_PHI:%.*]] = phi <vscale x 4 x i32> [ zeroinitializer, [[VECTOR_PH]] ], [ [[TMP7:%.*]], [[VECTOR_BODY]] ]
+; TAILFOLD-NEXT: [[VEC_PHI:%.*]] = phi <vscale x 1 x i32> [ zeroinitializer, [[VECTOR_PH]] ], [ [[PARTIAL_REDUCE:%.*]], [[VECTOR_BODY]] ]
; TAILFOLD-NEXT: [[AVL:%.*]] = phi i64 [ 1024, [[VECTOR_PH]] ], [ [[AVL_NEXT:%.*]], [[VECTOR_BODY]] ]
; TAILFOLD-NEXT: [[TMP0:%.*]] = call i32 @llvm.experimental.get.vector.length.i64(i64 [[AVL]], i32 4, i1 true)
; TAILFOLD-NEXT: [[TMP1:%.*]] = getelementptr i8, ptr [[A]], i64 [[EVL_BASED_IV]]
; TAILFOLD-NEXT: [[VP_OP_LOAD:%.*]] = call <vscale x 4 x i8> @llvm.vp.load.nxv4i8.p0(ptr align 1 [[TMP1]], <vscale x 4 x i1> splat (i1 true), i32 [[TMP0]])
-; TAILFOLD-NEXT: [[TMP2:%.*]] = sext <vscale x 4 x i8> [[VP_OP_LOAD]] to <vscale x 4 x i32>
; TAILFOLD-NEXT: [[TMP3:%.*]] = getelementptr i8, ptr [[B]], i64 [[EVL_BASED_IV]]
; TAILFOLD-NEXT: [[VP_OP_LOAD1:%.*]] = call <vscale x 4 x i8> @llvm.vp.load.nxv4i8.p0(ptr align 1 [[TMP3]], <vscale x 4 x i1> splat (i1 true), i32 [[TMP0]])
; TAILFOLD-NEXT: [[TMP4:%.*]] = zext <vscale x 4 x i8> [[VP_OP_LOAD1]] to <vscale x 4 x i32>
+; TAILFOLD-NEXT: [[TMP2:%.*]] = sext <vscale x 4 x i8> [[VP_OP_LOAD]] to <vscale x 4 x i32>
; TAILFOLD-NEXT: [[TMP5:%.*]] = mul <vscale x 4 x i32> [[TMP4]], [[TMP2]]
-; TAILFOLD-NEXT: [[TMP6:%.*]] = add <vscale x 4 x i32> [[TMP5]], [[VEC_PHI]]
-; TAILFOLD-NEXT: [[TMP7]] = call <vscale x 4 x i32> @llvm.vp.merge.nxv4i32(<vscale x 4 x i1> splat (i1 true), <vscale x 4 x i32> [[TMP6]], <vscale x 4 x i32> [[VEC_PHI]], i32 [[TMP0]])
+; TAILFOLD-NEXT: [[TMP6:%.*]] = call <vscale x 4 x i32> @llvm.vp.merge.nxv4i32(<vscale x 4 x i1> splat (i1 true), <vscale x 4 x i32> [[TMP5]], <vscale x 4 x i32> zeroinitializer, i32 [[TMP0]])
+; TAILFOLD-NEXT: [[PARTIAL_REDUCE]] = call <vscale x 1 x i32> @llvm.vector.partial.reduce.add.nxv1i32.nxv4i32(<vscale x 1 x i32> [[VEC_PHI]], <vscale x 4 x i32> [[TMP6]])
; TAILFOLD-NEXT: [[TMP8:%.*]] = zext i32 [[TMP0]] to i64
; TAILFOLD-NEXT: [[INDEX_EVL_NEXT]] = add nuw i64 [[TMP8]], [[EVL_BASED_IV]]
; TAILFOLD-NEXT: [[AVL_NEXT]] = sub nuw i64 [[AVL]], [[TMP8]]
; TAILFOLD-NEXT: [[TMP9:%.*]] = icmp eq i64 [[AVL_NEXT]], 0
; TAILFOLD-NEXT: br i1 [[TMP9]], label [[MIDDLE_BLOCK:%.*]], label [[VECTOR_BODY]], !llvm.loop [[LOOP5:![0-9]+]]
; TAILFOLD: middle.block:
-; TAILFOLD-NEXT: [[TMP10:%.*]] = call i32 @llvm.vector.reduce.add.nxv4i32(<vscale x 4 x i32> [[TMP7]])
+; TAILFOLD-NEXT: [[TMP10:%.*]] = call i32 @llvm.vector.reduce.add.nxv1i32(<vscale x 1 x i32> [[PARTIAL_REDUCE]])
; TAILFOLD-NEXT: br label [[FOR_EXIT:%.*]]
; TAILFOLD: for.exit:
; TAILFOLD-NEXT: ret i32 [[TMP10]]
diff --git a/llvm/test/Transforms/LoopVectorize/VPlan/RISCV/partial-reduce-dot-product.ll b/llvm/test/Transforms/LoopVectorize/VPlan/RISCV/partial-reduce-dot-product.ll
index 582c5d3d783ee..5c761d465e01b 100644
--- a/llvm/test/Transforms/LoopVectorize/VPlan/RISCV/partial-reduce-dot-product.ll
+++ b/llvm/test/Transforms/LoopVectorize/VPlan/RISCV/partial-reduce-dot-product.ll
@@ -15,7 +15,7 @@ define i32 @vdota4(ptr %a, ptr %b) #0 {
; CHECK-NEXT: Successor(s): scalar.ph, vector.ph
; CHECK-EMPTY:
; CHECK-NEXT: vector.ph:
-; CHECK-NEXT: EMIT vp<[[VP3:%[0-9]+]]> = reduction-start-vector ir<0>, ir<0>, ir<1>
+; CHECK-NEXT: EMIT vp<[[VP3:%[0-9]+]]> = reduction-start-vector ir<0>, ir<0>, ir<4>
; CHECK-NEXT: Successor(s): vector loop
; CHECK-EMPTY:
; CHECK-NEXT: <x1> vector loop: {
@@ -23,7 +23,7 @@ define i32 @vdota4(ptr %a, ptr %b) #0 {
; CHECK-EMPTY:
; CHECK-NEXT: vector.body:
; CHECK-NEXT: CURRENT-ITERATION-PHI vp<[[VP5:%[0-9]+]]> = phi ir<0>, vp<%current.iteration.next>
-; CHECK-NEXT: WIDEN-REDUCTION-PHI ir<%accum> = phi (add) vp<[[VP3]]>, vp<[[VP10:%[0-9]+]]>
+; CHECK-NEXT: WIDEN-REDUCTION-PHI ir<%accum> = phi (add) vp<[[VP3]]>, vp<[[VP10:%[0-9]+]]> (VF scaled by 1/4)
; CHECK-NEXT: EMIT-SCALAR vp<%avl> = phi [ ir<1024>, vector.ph ], [ vp<%avl.next>, vector.body ]
; CHECK-NEXT: EMIT-SCALAR vp<%evl> = EXPLICIT-VECTOR-LENGTH vp<%avl>
; CHECK-NEXT: EMIT-SCALAR vp<[[VP6:%[0-9]+]]> = zext vp<%evl> to i64
@@ -31,14 +31,10 @@ define i32 @vdota4(ptr %a, ptr %b) #0 {
; CHECK-NEXT: CLONE ir<%gep.a> = getelementptr ir<%a>, vp<[[VP7]]>
; CHECK-NEXT: vp<[[VP8:%[0-9]+]]> = vector-pointer ir<%gep.a>, ir<1>
; CHECK-NEXT: WIDEN ir<%load.a> = vp.load vp<[[VP8]]>, vp<%evl>
-; CHECK-NEXT: WIDEN-CAST ir<%ext.a> = sext ir<%load.a> to i32
; CHECK-NEXT: CLONE ir<%gep.b> = getelementptr ir<%b>, vp<[[VP7]]>
; CHECK-NEXT: vp<[[VP9:%[0-9]+]]> = vector-pointer ir<%gep.b>, ir<1>
; CHECK-NEXT: WIDEN ir<%load.b> = vp.load vp<[[VP9]]>, vp<%evl>
-; CHECK-NEXT: WIDEN-CAST ir<%ext.b> = zext ir<%load.b> to i32
-; CHECK-NEXT: WIDEN ir<%mul> = mul ir<%ext.b>, ir<%ext.a>
-; CHECK-NEXT: WIDEN ir<%add> = add ir<%mul>, ir<%accum>
-; CHECK-NEXT: WIDEN-INTRINSIC vp<[[VP10]]> = call llvm.vp.merge(ir<true>, ir<%add>, ir<%accum>, vp<%evl>)
+; CHECK-NEXT: EXPRESSION vp<[[VP10]]> = ir<%accum> + partial.reduce.add (mul (ir<%load.b> zext to i32), (ir<%load.a> sext to i32), vp<%evl>, ir<true>)
; CHECK-NEXT: EMIT-SCALAR vp<[[VP11:%[0-9]+]]> = zext vp<%evl> to i64
; CHECK-NEXT: EMIT vp<%current.iteration.next> = add nuw vp<[[VP11]]>, vp<[[VP5]]>
; CHECK-NEXT: EMIT vp<%avl.next> = sub nuw vp<%avl>, vp<[[VP11]]>
diff --git a/llvm/test/Transforms/LoopVectorize/VPlan/RISCV/reductions-evl.ll b/llvm/test/Transforms/LoopVectorize/VPlan/RISCV/reductions-evl.ll
index dbee5a169e264..fd73cbd3a4c78 100644
--- a/llvm/test/Transforms/LoopVectorize/VPlan/RISCV/reductions-evl.ll
+++ b/llvm/test/Transforms/LoopVectorize/VPlan/RISCV/reductions-evl.ll
@@ -345,15 +345,14 @@ define i64 @print_extended_reduction(ptr nocapture readonly %x, ptr nocapture re
; CHECK-EMPTY:
; CHECK-NEXT: vector.body:
; CHECK-NEXT: CURRENT-ITERATION-PHI vp<[[VP5:%[0-9]+]]> = phi ir<0>, vp<%current.iteration.next>
-; CHECK-NEXT: WIDEN-REDUCTION-PHI ir<%rdx> = phi (add) vp<[[VP3]]>, ir<%rdx.next>
+; CHECK-NEXT: WIDEN-REDUCTION-PHI ir<%rdx> = phi (add) vp<[[VP3]]>, vp<[[VP8:%[0-9]+]]>
; CHECK-NEXT: EMIT-SCALAR vp<%avl> = phi [ ir<%n>, vector.ph ], [ vp<%avl.next>, vector.body ]
; CHECK-NEXT: EMIT-SCALAR vp<%evl> = EXPLICIT-VECTOR-LENGTH vp<%avl>
; CHECK-NEXT: vp<[[VP6:%[0-9]+]]> = SCALAR-STEPS vp<[[VP5]]>, ir<1>, vp<%evl>
; CHECK-NEXT: CLONE ir<%arrayidx> = getelementptr inbounds ir<%x>, vp<[[VP6]]>
; CHECK-NEXT: vp<[[VP7:%[0-9]+]]> = vector-pointer inbounds ir<%arrayidx>, ir<1>
; CHECK-NEXT: WIDEN ir<%load0> = vp.load vp<[[VP7]]>, vp<%evl>
-; CHECK-NEXT: WIDEN-CAST ir<%conv0> = zext ir<%load0> to i64
-; CHECK-NEXT: REDUCE ir<%rdx.next> = ir<%rdx> + vp.reduce.add (ir<%conv0>, vp<%evl>)
+; CHECK-NEXT: EXPRESSION vp<[[VP8]]> = ir<true> + reduce.add (ir<%load0> zext to i64, vp<%evl>, ir<true>)
; CHECK-NEXT: EMIT vp<%current.iteration.next> = add vp<%evl>, vp<[[VP5]]>
; CHECK-NEXT: EMIT vp<%avl.next> = sub nuw vp<%avl>, vp<%evl>
; CHECK-NEXT: EMIT vp<%index.next> = add vp<[[VP4]]>, vp<[[VP0]]>
@@ -363,11 +362,11 @@ define i64 @print_extended_reduction(ptr nocapture readonly %x, ptr nocapture re
; CHECK-NEXT: Successor(s): middle.block
; CHECK-EMPTY:
; CHECK-NEXT: middle.block:
-; CHECK-NEXT: EMIT vp<[[VP9:%[0-9]+]]> = compute-reduction-result (add, in-loop) ir<%rdx.next>
+; CHECK-NEXT: EMIT vp<[[VP10:%[0-9]+]]> = compute-reduction-result (add, in-loop) vp<[[VP8]]>
; CHECK-NEXT: Successor(s): ir-bb<exit>
; CHECK-EMPTY:
; CHECK-NEXT: ir-bb<exit>:
-; CHECK-NEXT: IR %r.0.lcssa = phi i64 [ %rdx.next, %loop ] (extra operand: vp<[[VP9]]> from middle.block)
+; CHECK-NEXT: IR %r.0.lcssa = phi i64 [ %rdx.next, %loop ] (extra operand: vp<[[VP10]]> from middle.block)
; CHECK-NEXT: No successors
; CHECK-EMPTY:
; CHECK-NEXT: scalar.ph:
@@ -508,7 +507,7 @@ define i64 @print_mulacc_extended(ptr nocapture readonly %x, ptr nocapture reado
; CHECK-EMPTY:
; CHECK-NEXT: vector.body:
; CHECK-NEXT: CURRENT-ITERATION-PHI vp<[[VP5:%[0-9]+]]> = phi ir<0>, vp<%current.iteration.next>
-; CHECK-NEXT: WIDEN-REDUCTION-PHI ir<%rdx> = phi (add) vp<[[VP3]]>, ir<%rdx.next>
+; CHECK-NEXT: WIDEN-REDUCTION-PHI ir<%rdx> = phi (add) vp<[[VP3]]>, vp<[[VP9:%[0-9]+]]>
; CHECK-NEXT: EMIT-SCALAR vp<%avl> = phi [ ir<%n>, vector.ph ], [ vp<%avl.next>, vector.body ]
; CHECK-NEXT: EMIT-SCALAR vp<%evl> = EXPLICIT-VECTOR-LENGTH vp<%avl>
; CHECK-NEXT: vp<[[VP6:%[0-9]+]]> = SCALAR-STEPS vp<[[VP5]]>, ir<1>, vp<%evl>
@@ -521,8 +520,7 @@ define i64 @print_mulacc_extended(ptr nocapture readonly %x, ptr nocapture reado
; CHECK-NEXT: WIDEN-CAST ir<%conv0> = sext ir<%load0> to i32
; CHECK-NEXT: WIDEN-CAST ir<%conv1> = sext ir<%load1> to i32
; CHECK-NEXT: WIDEN ir<%mul> = mul nsw ir<%conv0>, ir<%conv1>
-; CHECK-NEXT: WIDEN-CAST ir<%conv> = sext ir<%mul> to i64
-; CHECK-NEXT: REDUCE ir<%rdx.next> = ir<%rdx> + vp.reduce.add (ir<%conv>, vp<%evl>)
+; CHECK-NEXT: EXPRESSION vp<[[VP9]]> = ir<true> + reduce.add (ir<%mul> sext to i64, vp<%evl>, ir<true>)
; CHECK-NEXT: EMIT vp<%current.iteration.next> = add vp<%evl>, vp<[[VP5]]>
; CHECK-NEXT: EMIT vp<%avl.next> = sub nuw vp<%avl>, vp<%evl>
; CHECK-NEXT: EMIT vp<%index.next> = add vp<[[VP4]]>, vp<[[VP0]]>
@@ -532,11 +530,11 @@ define i64 @print_mulacc_extended(ptr nocapture readonly %x, ptr nocapture reado
; CHECK-NEXT: Successor(s): middle.block
; CHECK-EMPTY:
; CHECK-NEXT: middle.block:
-; CHECK-NEXT: EMIT vp<[[VP10:%[0-9]+]]> = compute-reduction-result (add, in-loop) ir<%rdx.next>
+; CHECK-NEXT: EMIT vp<[[VP11:%[0-9]+]]> = compute-reduction-result (add, in-loop) vp<[[VP9]]>
; CHECK-NEXT: Successor(s): ir-bb<exit>
; CHECK-EMPTY:
; CHECK-NEXT: ir-bb<exit>:
-; CHECK-NEXT: IR %r.0.lcssa = phi i64 [ %rdx.next, %loop ] (extra operand: vp<[[VP10]]> from middle.block)
+; CHECK-NEXT: IR %r.0.lcssa = phi i64 [ %rdx.next, %loop ] (extra operand: vp<[[VP11]]> from middle.block)
; CHECK-NEXT: No successors
; CHECK-EMPTY:
; CHECK-NEXT: scalar.ph:
@@ -943,7 +941,7 @@ define i64 @print_ext_mulacc_extended_const(ptr %start, ptr %end) {
; CHECK-EMPTY:
; CHECK-NEXT: vector.body:
; CHECK-NEXT: CURRENT-ITERATION-PHI vp<[[VP6:%[0-9]+]]> = phi ir<0>, vp<%current.iteration.next>
-; CHECK-NEXT: WIDEN-REDUCTION-PHI ir<%red> = phi (add) vp<[[VP4]]>, ir<%red.next>
+; CHECK-NEXT: WIDEN-REDUCTION-PHI ir<%red> = phi (add) vp<[[VP4]]>, vp<[[VP10:%[0-9]+]]>
; CHECK-NEXT: EMIT-SCALAR vp<%avl> = phi [ vp<[[VP3]]>, vector.ph ], [ vp<%avl.next>, vector.body ]
; CHECK-NEXT: EMIT-SCALAR vp<%evl> = EXPLICIT-VECTOR-LENGTH vp<%avl>
; CHECK-NEXT: EMIT-SCALAR vp<[[VP7:%[0-9]+]]> = zext vp<%evl> to i64
@@ -953,11 +951,10 @@ define i64 @print_ext_mulacc_extended_const(ptr %start, ptr %end) {
; CHECK-NEXT: WIDEN ir<%l> = vp.load vp<[[VP9]]>, vp<%evl>
; CHECK-NEXT: WIDEN-CAST ir<%l.ext> = zext ir<%l> to i32
; CHECK-NEXT: WIDEN ir<%mul> = mul ir<%l.ext>, ir<63>
-; CHECK-NEXT: WIDEN-CAST ir<%mul.ext> = zext ir<%mul> to i64
-; CHECK-NEXT: REDUCE ir<%red.next> = ir<%red> + vp.reduce.add (ir<%mul.ext>, vp<%evl>)
-; CHECK-NEXT: EMIT-SCALAR vp<[[VP10:%[0-9]+]]> = zext vp<%evl> to i64
-; CHECK-NEXT: EMIT vp<%current.iteration.next> = add vp<[[VP10]]>, vp<[[VP6]]>
-; CHECK-NEXT: EMIT vp<%avl.next> = sub nuw vp<%avl>, vp<[[VP10]]>
+; CHECK-NEXT: EXPRESSION vp<[[VP10]]> = ir<true> + reduce.add (ir<%mul> zext to i64, vp<%evl>, ir<true>)
+; CHECK-NEXT: EMIT-SCALAR vp<[[VP11:%[0-9]+]]> = zext vp<%evl> to i64
+; CHECK-NEXT: EMIT vp<%current.iteration.next> = add vp<[[VP11]]>, vp<[[VP6]]>
+; CHECK-NEXT: EMIT vp<%avl.next> = sub nuw vp<%avl>, vp<[[VP11]]>
; CHECK-NEXT: EMIT vp<%index.next> = add vp<[[VP5]]>, vp<[[VP0]]>
; CHECK-NEXT: EMIT branch-on-count vp<%index.next>, vp<[[VP1]]>
; CHECK-NEXT: No successors
@@ -965,11 +962,11 @@ define i64 @print_ext_mulacc_extended_const(ptr %start, ptr %end) {
; CHECK-NEXT: Successor(s): middle.block
; CHECK-EMPTY:
; CHECK-NEXT: middle.block:
-; CHECK-NEXT: EMIT vp<[[VP12:%[0-9]+]]> = compute-reduction-result (add, in-loop) ir<%red.next>
+; CHECK-NEXT: EMIT vp<[[VP13:%[0-9]+]]> = compute-reduction-result (add, in-loop) vp<[[VP10]]>
; CHECK-NEXT: Successor(s): ir-bb<exit>
; CHECK-EMPTY:
; CHECK-NEXT: ir-bb<exit>:
-; CHECK-NEXT: IR %red.next.lcssa = phi i64 [ %red.next, %loop ] (extra operand: vp<[[VP12]]> from middle.block)
+; CHECK-NEXT: IR %red.next.lcssa = phi i64 [ %red.next, %loop ] (extra operand: vp<[[VP13]]> from middle.block)
; CHECK-NEXT: No successors
; CHECK-EMPTY:
; CHECK-NEXT: scalar.ph:
@@ -1028,7 +1025,7 @@ define i64 @print_ext_mulacc_not_extended_const(ptr %start, ptr %end) {
; CHECK-EMPTY:
; CHECK-NEXT: vector.body:
; CHECK-NEXT: CURRENT-ITERATION-PHI vp<[[VP6:%[0-9]+]]> = phi ir<0>, vp<%current.iteration.next>
-; CHECK-NEXT: WIDEN-REDUCTION-PHI ir<%red> = phi (add) vp<[[VP4]]>, ir<%red.next>
+; CHECK-NEXT: WIDEN-REDUCTION-PHI ir<%red> = phi (add) vp<[[VP4]]>, vp<[[VP11:%[0-9]+]]>
; CHECK-NEXT: EMIT-SCALAR vp<%avl> = phi [ vp<[[VP3]]>, vector.ph ], [ vp<%avl.next>, vector.body ]
; CHECK-NEXT: EMIT-SCALAR vp<%evl> = EXPLICIT-VECTOR-LENGTH vp<%avl>
; CHECK-NEXT: EMIT-SCALAR vp<[[VP7:%[0-9]+]]> = zext vp<%evl> to i64
@@ -1038,11 +1035,10 @@ define i64 @print_ext_mulacc_not_extended_const(ptr %start, ptr %end) {
; CHECK-NEXT: WIDEN ir<%l> = vp.load vp<[[VP9]]>, vp<%evl>
; CHECK-NEXT: WIDEN-CAST ir<%l.ext> = sext ir<%l> to i32
; CHECK-NEXT: EMIT vp<[[VP10:%[0-9]+]]> = shl ir<%l.ext>, ir<7>
-; CHECK-NEXT: WIDEN-CAST ir<%mul.ext> = sext vp<[[VP10]]> to i64
-; CHECK-NEXT: REDUCE ir<%red.next> = ir<%red> + vp.reduce.add (ir<%mul.ext>, vp<%evl>)
-; CHECK-NEXT: EMIT-SCALAR vp<[[VP11:%[0-9]+]]> = zext vp<%evl> to i64
-; CHECK-NEXT: EMIT vp<%current.iteration.next> = add vp<[[VP11]]>, vp<[[VP6]]>
-; CHECK-NEXT: EMIT vp<%avl.next> = sub nuw vp<%avl>, vp<[[VP11]]>
+; CHECK-NEXT: EXPRESSION vp<[[VP11]]> = ir<true> + reduce.add (vp<[[VP10]]> sext to i64, vp<%evl>, ir<true>)
+; CHECK-NEXT: EMIT-SCALAR vp<[[VP12:%[0-9]+]]> = zext vp<%evl> to i64
+; CHECK-NEXT: EMIT vp<%current.iteration.next> = add vp<[[VP12]]>, vp<[[VP6]]>
+; CHECK-NEXT: EMIT vp<%avl.next> = sub nuw vp<%avl>, vp<[[VP12]]>
; CHECK-NEXT: EMIT vp<%index.next> = add vp<[[VP5]]>, vp<[[VP0]]>
; CHECK-NEXT: EMIT branch-on-count vp<%index.next>, vp<[[VP1]]>
; CHECK-NEXT: No successors
@@ -1050,11 +1046,11 @@ define i64 @print_ext_mulacc_not_extended_const(ptr %start, ptr %end) {
; CHECK-NEXT: Successor(s): middle.block
; CHECK-EMPTY:
; CHECK-NEXT: middle.block:
-; CHECK-NEXT: EMIT vp<[[VP13:%[0-9]+]]> = compute-reduction-result (add, in-loop) ir<%red.next>
+; CHECK-NEXT: EMIT vp<[[VP14:%[0-9]+]]> = compute-reduction-result (add, in-loop) vp<[[VP11]]>
; CHECK-NEXT: Successor(s): ir-bb<exit>
; CHECK-EMPTY:
; CHECK-NEXT: ir-bb<exit>:
-; CHECK-NEXT: IR %red.next.lcssa = phi i64 [ %red.next, %loop ] (extra operand: vp<[[VP13]]> from middle.block)
+; CHECK-NEXT: IR %red.next.lcssa = phi i64 [ %red.next, %loop ] (extra operand: vp<[[VP14]]> from middle.block)
; CHECK-NEXT: No successors
; CHECK-EMPTY:
; CHECK-NEXT: scalar.ph:
@@ -1112,7 +1108,6 @@ define i64 @print_ext_mul_two_uses(i64 %n, ptr %a, i16 %b, i32 %c) {
; CHECK-NEXT: EMIT vp<[[VP4:%[0-9]+]]> = reduction-start-vector ir<0>, ir<0>, ir<1>
; CHECK-NEXT: WIDEN-CAST ir<%conv> = sext ir<%b> to i32
; CHECK-NEXT: WIDEN ir<%mul> = mul ir<%conv>, ir<%conv>
-; CHECK-NEXT: WIDEN-CAST ir<%mul.ext> = zext ir<%mul> to i64
; CHECK-NEXT: Successor(s): vector loop
; CHECK-EMPTY:
; CHECK-NEXT: <x1> vector loop: {
@@ -1120,13 +1115,13 @@ define i64 @print_ext_mul_two_uses(i64 %n, ptr %a, i16 %b, i32 %c) {
; CHECK-EMPTY:
; CHECK-NEXT: vector.body:
; CHECK-NEXT: CURRENT-ITERATION-PHI vp<[[VP6:%[0-9]+]]> = phi ir<0>, vp<%current.iteration.next>
-; CHECK-NEXT: WIDEN-REDUCTION-PHI ir<%res2> = phi (add) vp<[[VP4]]>, ir<%add>
+; CHECK-NEXT: WIDEN-REDUCTION-PHI ir<%res2> = phi (add) vp<[[VP4]]>, vp<[[VP7:%[0-9]+]]>
; CHECK-NEXT: EMIT-SCALAR vp<%avl> = phi [ vp<[[VP3]]>, vector.ph ], [ vp<%avl.next>, vector.body ]
; CHECK-NEXT: EMIT-SCALAR vp<%evl> = EXPLICIT-VECTOR-LENGTH vp<%avl>
-; CHECK-NEXT: REDUCE ir<%add> = ir<%res2> + vp.reduce.add (ir<%mul.ext>, vp<%evl>)
-; CHECK-NEXT: EMIT-SCALAR vp<[[VP7:%[0-9]+]]> = zext vp<%evl> to i64
-; CHECK-NEXT: EMIT vp<%current.iteration.next> = add vp<[[VP7]]>, vp<[[VP6]]>
-; CHECK-NEXT: EMIT vp<%avl.next> = sub nuw vp<%avl>, vp<[[VP7]]>
+; CHECK-NEXT: EXPRESSION vp<[[VP7]]> = ir<true> + reduce.add (ir<%mul> zext to i64, vp<%evl>, ir<true>)
+; CHECK-NEXT: EMIT-SCALAR vp<[[VP8:%[0-9]+]]> = zext vp<%evl> to i64
+; CHECK-NEXT: EMIT vp<%current.iteration.next> = add vp<[[VP8]]>, vp<[[VP6]]>
+; CHECK-NEXT: EMIT vp<%avl.next> = sub nuw vp<%avl>, vp<[[VP8]]>
; CHECK-NEXT: EMIT vp<%index.next> = add vp<[[VP5]]>, vp<[[VP0]]>
; CHECK-NEXT: EMIT branch-on-count vp<%index.next>, vp<[[VP1]]>
; CHECK-NEXT: No successors
@@ -1134,11 +1129,11 @@ define i64 @print_ext_mul_two_uses(i64 %n, ptr %a, i16 %b, i32 %c) {
; CHECK-NEXT: Successor(s): middle.block
; CHECK-EMPTY:
; CHECK-NEXT: middle.block:
-; CHECK-NEXT: EMIT vp<[[VP9:%[0-9]+]]> = compute-reduction-result (add, in-loop) ir<%add>
+; CHECK-NEXT: EMIT vp<[[VP10:%[0-9]+]]> = compute-reduction-result (add, in-loop) vp<[[VP7]]>
; CHECK-NEXT: Successor(s): ir-bb<exit>
; CHECK-EMPTY:
; CHECK-NEXT: ir-bb<exit>:
-; CHECK-NEXT: IR %add.lcssa = phi i64 [ %add, %loop ] (extra operand: vp<[[VP9]]> from middle.block)
+; CHECK-NEXT: IR %add.lcssa = phi i64 [ %add, %loop ] (extra operand: vp<[[VP10]]> from middle.block)
; CHECK-NEXT: No successors
; CHECK-EMPTY:
; CHECK-NEXT: scalar.ph:
>From 9308f686a27f4810f844d0ea61b4be6287a62fe3 Mon Sep 17 00:00:00 2001
From: Elvis Wang <elvis.wang at sifive.com>
Date: Sun, 28 Jun 2026 22:25:18 -0700
Subject: [PATCH 3/5] Fixup, handle EVL conversion in VPlanTransforms.
---
llvm/lib/Transforms/Vectorize/VPlan.h | 8 ++---
.../lib/Transforms/Vectorize/VPlanRecipes.cpp | 26 ---------------
.../Transforms/Vectorize/VPlanTransforms.cpp | 32 ++++++++++++++++---
.../VPlan/RISCV/partial-reduce-dot-product.ll | 6 ++--
.../VPlan/RISCV/reductions-evl.ll | 5 +++
5 files changed, 40 insertions(+), 37 deletions(-)
diff --git a/llvm/lib/Transforms/Vectorize/VPlan.h b/llvm/lib/Transforms/Vectorize/VPlan.h
index 7c52c483f5b05..d21cef716f657 100644
--- a/llvm/lib/Transforms/Vectorize/VPlan.h
+++ b/llvm/lib/Transforms/Vectorize/VPlan.h
@@ -3567,6 +3567,7 @@ class VPExpressionRecipe : public VPSingleDefRecipe {
/// Type of the expression.
ExpressionTypes ExpressionType;
+public:
/// Construct a new VPExpressionRecipe by internalizing recipes in \p
/// ExpressionRecipes. External operands (i.e. not defined by another recipe
/// in the expression) are replaced by temporary VPValues and the original
@@ -3576,7 +3577,6 @@ class VPExpressionRecipe : public VPSingleDefRecipe {
VPExpressionRecipe(ExpressionTypes ExpressionType,
ArrayRef<VPSingleDefRecipe *> ExpressionRecipes);
-public:
VPExpressionRecipe(VPWidenCastRecipe *Ext, VPReductionRecipe *Red)
: VPExpressionRecipe(ExpressionTypes::ExtendedReduction, {Ext, Red}) {}
VPExpressionRecipe(VPWidenCastRecipe *Ext, VPWidenRecipe *Neg,
@@ -3657,14 +3657,14 @@ class VPExpressionRecipe : public VPSingleDefRecipe {
return getOperand(getNumOperands() - OpIdx);
}
- /// Returns a new VPExpressionRecipe with VPReductionEVLRecipe.
- VPExpressionRecipe *convertToEVL(VPValue &EVL, VPValue *Mask);
-
/// Insert the recipes of the expression back into the VPlan, directly before
/// the current recipe. Leaves the expression recipe empty, which must be
/// removed before codegen.
void decompose();
+ /// Returns the expression type of this recipe.
+ ExpressionTypes getExpressionType() const { return ExpressionType; }
+
unsigned getVFScaleFactor() const {
auto *PR = dyn_cast<VPReductionRecipe>(ExpressionRecipes.back());
return PR ? PR->getVFScaleFactor() : 1;
diff --git a/llvm/lib/Transforms/Vectorize/VPlanRecipes.cpp b/llvm/lib/Transforms/Vectorize/VPlanRecipes.cpp
index 07635e12c53c7..af33a6d6eb49d 100644
--- a/llvm/lib/Transforms/Vectorize/VPlanRecipes.cpp
+++ b/llvm/lib/Transforms/Vectorize/VPlanRecipes.cpp
@@ -3495,32 +3495,6 @@ VPExpressionRecipe::VPExpressionRecipe(
R->replaceUsesOfWith(LiveIn, Tmp);
}
-VPExpressionRecipe *VPExpressionRecipe::convertToEVL(VPValue &EVL,
- VPValue *Mask) {
- // Clone the VPExpressionRecipe.
- SmallVector<VPSingleDefRecipe *, 4> NewExpressionRecipes;
- for (auto *R : ExpressionRecipes)
- NewExpressionRecipes.push_back(R->clone());
- for (auto *New : NewExpressionRecipes) {
- for (const auto &[Idx, Old] : enumerate(ExpressionRecipes))
- New->replaceUsesOfWith(Old, NewExpressionRecipes[Idx]);
- // Update placeholder operands in the cloned recipe to use the external
- // operands, to be internalized when the evl expression is constructed.
- for (const auto &[Placeholder, OutsideOp] :
- zip(LiveInPlaceholders, operands()))
- New->replaceUsesOfWith(Placeholder, OutsideOp);
- }
-
- // Transforms to EVL reduction.
- auto *Red = cast<VPReductionRecipe>(NewExpressionRecipes.pop_back_val());
- if (!Mask)
- Mask = getParent()->getPlan()->getTrue();
- auto *NewRed = new VPReductionEVLRecipe(*Red, EVL, Mask, Red->getDebugLoc());
- delete Red;
- NewExpressionRecipes.push_back(NewRed);
- return new VPExpressionRecipe(ExpressionType, NewExpressionRecipes);
-}
-
void VPExpressionRecipe::decompose() {
for (auto *R : ExpressionRecipes)
// Since the list could contain duplicates, make sure the recipe hasn't
diff --git a/llvm/lib/Transforms/Vectorize/VPlanTransforms.cpp b/llvm/lib/Transforms/Vectorize/VPlanTransforms.cpp
index f2704849c0779..6717e28409973 100644
--- a/llvm/lib/Transforms/Vectorize/VPlanTransforms.cpp
+++ b/llvm/lib/Transforms/Vectorize/VPlanTransforms.cpp
@@ -3158,10 +3158,34 @@ static VPRecipeBase *optimizeMaskToEVL(VPValue *HeaderMask,
IntrR->getScalarType(), {}, {}, DL);
// Transforms the VPReductionRecipe inside the VPExpressionRecipe.
- if (auto *ExpressionR = dyn_cast<VPExpressionRecipe>(&CurRecipe))
- if (match(ExpressionR->getOperand(ExpressionR->getNumOperands() - 1),
- m_RemoveMask(HeaderMask, Mask)))
- return ExpressionR->convertToEVL(EVL, Mask);
+ if (auto *Expr = dyn_cast<VPExpressionRecipe>(&CurRecipe))
+ if (match(Expr->getOperand(Expr->getNumOperands() - 1),
+ m_RemoveMask(HeaderMask, Mask))) {
+ auto PrevR = std::prev(Expr->getIterator());
+ Expr->decompose();
+ VPReductionRecipe *Red =
+ cast<VPReductionRecipe>(&*std::prev(Expr->getIterator()));
+
+ // Collect the recipes contained by the ExpressionRecipe except the last
+ // VPReductionRecipe.
+ SmallVector<VPSingleDefRecipe *, 4> Expressions;
+ for (auto &R :
+ make_range(std::next(PrevR), std::prev(Expr->getIterator())))
+ Expressions.push_back(cast<VPSingleDefRecipe>(&R));
+
+ // Convert to VPReductionEVLRecipe.
+ auto *NewRed = new VPReductionEVLRecipe(
+ *Red, EVL, Mask ? Mask : Plan->getTrue(), Red->getDebugLoc());
+ NewRed->insertBefore(Expr);
+ Expressions.push_back(NewRed);
+ auto *NewExpr =
+ new VPExpressionRecipe(Expr->getExpressionType(), Expressions);
+
+ // Replace uses and remove the old non-EVL reduction.
+ Red->replaceAllUsesWith(NewExpr);
+ Red->eraseFromParent();
+ return NewExpr;
+ }
return nullptr;
}
diff --git a/llvm/test/Transforms/LoopVectorize/VPlan/RISCV/partial-reduce-dot-product.ll b/llvm/test/Transforms/LoopVectorize/VPlan/RISCV/partial-reduce-dot-product.ll
index 5c761d465e01b..5f1b2010d9a00 100644
--- a/llvm/test/Transforms/LoopVectorize/VPlan/RISCV/partial-reduce-dot-product.ll
+++ b/llvm/test/Transforms/LoopVectorize/VPlan/RISCV/partial-reduce-dot-product.ll
@@ -1,6 +1,5 @@
; NOTE: Assertions have been autogenerated by utils/update_analyze_test_checks.py UTC_ARGS: --version 6
; RUN: opt -passes=loop-vectorize -force-vector-width=4 -scalable-vectorization=on -mattr=+v,+experimental-zvdot4a8i -disable-output 2>&1 -vplan-print-after=optimizeEVLMasks < %s | FileCheck %s
-; RUN: opt -passes=loop-vectorize -mattr=+v,+experimental-zvdot4a8i -disable-output 2>&1 -vplan-print-after=optimizeEVLMasks < %s | FileCheck %s --check-prefixes=NON-VLA
target triple = "riscv64-none-unknown-elf"
@@ -34,6 +33,9 @@ define i32 @vdota4(ptr %a, ptr %b) #0 {
; CHECK-NEXT: CLONE ir<%gep.b> = getelementptr ir<%b>, vp<[[VP7]]>
; CHECK-NEXT: vp<[[VP9:%[0-9]+]]> = vector-pointer ir<%gep.b>, ir<1>
; CHECK-NEXT: WIDEN ir<%load.b> = vp.load vp<[[VP9]]>, vp<%evl>
+; CHECK-NEXT: WIDEN-CAST ir<%ext.b> = zext ir<%load.b> to i32
+; CHECK-NEXT: WIDEN-CAST ir<%ext.a> = sext ir<%load.a> to i32
+; CHECK-NEXT: WIDEN ir<%mul> = mul ir<%ext.b>, ir<%ext.a>
; CHECK-NEXT: EXPRESSION vp<[[VP10]]> = ir<%accum> + partial.reduce.add (mul (ir<%load.b> zext to i32), (ir<%load.a> sext to i32), vp<%evl>, ir<true>)
; CHECK-NEXT: EMIT-SCALAR vp<[[VP11:%[0-9]+]]> = zext vp<%evl> to i64
; CHECK-NEXT: EMIT vp<%current.iteration.next> = add nuw vp<[[VP11]]>, vp<[[VP5]]>
@@ -92,5 +94,3 @@ for.body: ; preds = %for.body, %entry
for.exit: ; preds = %for.body
ret i32 %add
}
-;; NOTE: These prefixes are unused and the list is autogenerated. Do not add tests below this line:
-; NON-VLA: {{.*}}
diff --git a/llvm/test/Transforms/LoopVectorize/VPlan/RISCV/reductions-evl.ll b/llvm/test/Transforms/LoopVectorize/VPlan/RISCV/reductions-evl.ll
index fd73cbd3a4c78..690f75f95d228 100644
--- a/llvm/test/Transforms/LoopVectorize/VPlan/RISCV/reductions-evl.ll
+++ b/llvm/test/Transforms/LoopVectorize/VPlan/RISCV/reductions-evl.ll
@@ -352,6 +352,7 @@ define i64 @print_extended_reduction(ptr nocapture readonly %x, ptr nocapture re
; CHECK-NEXT: CLONE ir<%arrayidx> = getelementptr inbounds ir<%x>, vp<[[VP6]]>
; CHECK-NEXT: vp<[[VP7:%[0-9]+]]> = vector-pointer inbounds ir<%arrayidx>, ir<1>
; CHECK-NEXT: WIDEN ir<%load0> = vp.load vp<[[VP7]]>, vp<%evl>
+; CHECK-NEXT: WIDEN-CAST ir<%conv0> = zext ir<%load0> to i64
; CHECK-NEXT: EXPRESSION vp<[[VP8]]> = ir<true> + reduce.add (ir<%load0> zext to i64, vp<%evl>, ir<true>)
; CHECK-NEXT: EMIT vp<%current.iteration.next> = add vp<%evl>, vp<[[VP5]]>
; CHECK-NEXT: EMIT vp<%avl.next> = sub nuw vp<%avl>, vp<%evl>
@@ -520,6 +521,7 @@ define i64 @print_mulacc_extended(ptr nocapture readonly %x, ptr nocapture reado
; CHECK-NEXT: WIDEN-CAST ir<%conv0> = sext ir<%load0> to i32
; CHECK-NEXT: WIDEN-CAST ir<%conv1> = sext ir<%load1> to i32
; CHECK-NEXT: WIDEN ir<%mul> = mul nsw ir<%conv0>, ir<%conv1>
+; CHECK-NEXT: WIDEN-CAST ir<%conv> = sext ir<%mul> to i64
; CHECK-NEXT: EXPRESSION vp<[[VP9]]> = ir<true> + reduce.add (ir<%mul> sext to i64, vp<%evl>, ir<true>)
; CHECK-NEXT: EMIT vp<%current.iteration.next> = add vp<%evl>, vp<[[VP5]]>
; CHECK-NEXT: EMIT vp<%avl.next> = sub nuw vp<%avl>, vp<%evl>
@@ -951,6 +953,7 @@ define i64 @print_ext_mulacc_extended_const(ptr %start, ptr %end) {
; CHECK-NEXT: WIDEN ir<%l> = vp.load vp<[[VP9]]>, vp<%evl>
; CHECK-NEXT: WIDEN-CAST ir<%l.ext> = zext ir<%l> to i32
; CHECK-NEXT: WIDEN ir<%mul> = mul ir<%l.ext>, ir<63>
+; CHECK-NEXT: WIDEN-CAST ir<%mul.ext> = zext ir<%mul> to i64
; CHECK-NEXT: EXPRESSION vp<[[VP10]]> = ir<true> + reduce.add (ir<%mul> zext to i64, vp<%evl>, ir<true>)
; CHECK-NEXT: EMIT-SCALAR vp<[[VP11:%[0-9]+]]> = zext vp<%evl> to i64
; CHECK-NEXT: EMIT vp<%current.iteration.next> = add vp<[[VP11]]>, vp<[[VP6]]>
@@ -1035,6 +1038,7 @@ define i64 @print_ext_mulacc_not_extended_const(ptr %start, ptr %end) {
; CHECK-NEXT: WIDEN ir<%l> = vp.load vp<[[VP9]]>, vp<%evl>
; CHECK-NEXT: WIDEN-CAST ir<%l.ext> = sext ir<%l> to i32
; CHECK-NEXT: EMIT vp<[[VP10:%[0-9]+]]> = shl ir<%l.ext>, ir<7>
+; CHECK-NEXT: WIDEN-CAST ir<%mul.ext> = sext vp<[[VP10]]> to i64
; CHECK-NEXT: EXPRESSION vp<[[VP11]]> = ir<true> + reduce.add (vp<[[VP10]]> sext to i64, vp<%evl>, ir<true>)
; CHECK-NEXT: EMIT-SCALAR vp<[[VP12:%[0-9]+]]> = zext vp<%evl> to i64
; CHECK-NEXT: EMIT vp<%current.iteration.next> = add vp<[[VP12]]>, vp<[[VP6]]>
@@ -1118,6 +1122,7 @@ define i64 @print_ext_mul_two_uses(i64 %n, ptr %a, i16 %b, i32 %c) {
; CHECK-NEXT: WIDEN-REDUCTION-PHI ir<%res2> = phi (add) vp<[[VP4]]>, vp<[[VP7:%[0-9]+]]>
; CHECK-NEXT: EMIT-SCALAR vp<%avl> = phi [ vp<[[VP3]]>, vector.ph ], [ vp<%avl.next>, vector.body ]
; CHECK-NEXT: EMIT-SCALAR vp<%evl> = EXPLICIT-VECTOR-LENGTH vp<%avl>
+; CHECK-NEXT: WIDEN-CAST ir<%mul.ext> = zext ir<%mul> to i64
; CHECK-NEXT: EXPRESSION vp<[[VP7]]> = ir<true> + reduce.add (ir<%mul> zext to i64, vp<%evl>, ir<true>)
; CHECK-NEXT: EMIT-SCALAR vp<[[VP8:%[0-9]+]]> = zext vp<%evl> to i64
; CHECK-NEXT: EMIT vp<%current.iteration.next> = add vp<[[VP8]]>, vp<[[VP6]]>
>From f61e32b93a778f1852b0626495d0c590d6ae59a4 Mon Sep 17 00:00:00 2001
From: Elvis Wang <elvis.wang at sifive.com>
Date: Mon, 29 Jun 2026 18:05:40 -0700
Subject: [PATCH 4/5] !fixup, returns expression recipes when decompose.
---
llvm/lib/Transforms/Vectorize/VPlan.h | 8 ++++----
.../lib/Transforms/Vectorize/VPlanRecipes.cpp | 4 +++-
.../Transforms/Vectorize/VPlanTransforms.cpp | 19 ++++++-------------
3 files changed, 13 insertions(+), 18 deletions(-)
diff --git a/llvm/lib/Transforms/Vectorize/VPlan.h b/llvm/lib/Transforms/Vectorize/VPlan.h
index d21cef716f657..71a5d9e135b9e 100644
--- a/llvm/lib/Transforms/Vectorize/VPlan.h
+++ b/llvm/lib/Transforms/Vectorize/VPlan.h
@@ -3657,10 +3657,10 @@ class VPExpressionRecipe : public VPSingleDefRecipe {
return getOperand(getNumOperands() - OpIdx);
}
- /// Insert the recipes of the expression back into the VPlan, directly before
- /// the current recipe. Leaves the expression recipe empty, which must be
- /// removed before codegen.
- void decompose();
+ /// Return and insert the recipes of the expression back into the VPlan,
+ /// directly before the current recipe. Leaves the expression recipe empty,
+ /// which must be removed before codegen.
+ ArrayRef<VPSingleDefRecipe *> decompose();
/// Returns the expression type of this recipe.
ExpressionTypes getExpressionType() const { return ExpressionType; }
diff --git a/llvm/lib/Transforms/Vectorize/VPlanRecipes.cpp b/llvm/lib/Transforms/Vectorize/VPlanRecipes.cpp
index af33a6d6eb49d..e201fac6f703f 100644
--- a/llvm/lib/Transforms/Vectorize/VPlanRecipes.cpp
+++ b/llvm/lib/Transforms/Vectorize/VPlanRecipes.cpp
@@ -3495,7 +3495,7 @@ VPExpressionRecipe::VPExpressionRecipe(
R->replaceUsesOfWith(LiveIn, Tmp);
}
-void VPExpressionRecipe::decompose() {
+ArrayRef<VPSingleDefRecipe *> VPExpressionRecipe::decompose() {
for (auto *R : ExpressionRecipes)
// Since the list could contain duplicates, make sure the recipe hasn't
// already been inserted.
@@ -3506,7 +3506,9 @@ void VPExpressionRecipe::decompose() {
LiveInPlaceholders[Idx]->replaceAllUsesWith(Op);
replaceAllUsesWith(ExpressionRecipes.back());
+ ArrayRef<VPSingleDefRecipe *> Expressions(ExpressionRecipes);
ExpressionRecipes.clear();
+ return Expressions;
}
InstructionCost VPExpressionRecipe::computeCost(ElementCount VF,
diff --git a/llvm/lib/Transforms/Vectorize/VPlanTransforms.cpp b/llvm/lib/Transforms/Vectorize/VPlanTransforms.cpp
index 6717e28409973..c5eebd1f247c8 100644
--- a/llvm/lib/Transforms/Vectorize/VPlanTransforms.cpp
+++ b/llvm/lib/Transforms/Vectorize/VPlanTransforms.cpp
@@ -3161,25 +3161,18 @@ static VPRecipeBase *optimizeMaskToEVL(VPValue *HeaderMask,
if (auto *Expr = dyn_cast<VPExpressionRecipe>(&CurRecipe))
if (match(Expr->getOperand(Expr->getNumOperands() - 1),
m_RemoveMask(HeaderMask, Mask))) {
- auto PrevR = std::prev(Expr->getIterator());
- Expr->decompose();
+ // Decompose first and construct with VPReductionEVLRecipe later.
+ SmallVector<VPSingleDefRecipe *> ExpressionRecipes(Expr->decompose());
VPReductionRecipe *Red =
- cast<VPReductionRecipe>(&*std::prev(Expr->getIterator()));
-
- // Collect the recipes contained by the ExpressionRecipe except the last
- // VPReductionRecipe.
- SmallVector<VPSingleDefRecipe *, 4> Expressions;
- for (auto &R :
- make_range(std::next(PrevR), std::prev(Expr->getIterator())))
- Expressions.push_back(cast<VPSingleDefRecipe>(&R));
+ cast<VPReductionRecipe>(ExpressionRecipes.pop_back_val());
// Convert to VPReductionEVLRecipe.
auto *NewRed = new VPReductionEVLRecipe(
*Red, EVL, Mask ? Mask : Plan->getTrue(), Red->getDebugLoc());
NewRed->insertBefore(Expr);
- Expressions.push_back(NewRed);
+ ExpressionRecipes.push_back(NewRed);
auto *NewExpr =
- new VPExpressionRecipe(Expr->getExpressionType(), Expressions);
+ new VPExpressionRecipe(Expr->getExpressionType(), ExpressionRecipes);
// Replace uses and remove the old non-EVL reduction.
Red->replaceAllUsesWith(NewExpr);
@@ -4221,7 +4214,7 @@ void VPlanTransforms::convertToConcreteRecipes(VPlan &Plan) {
}
if (auto *Expr = dyn_cast<VPExpressionRecipe>(&R)) {
- Expr->decompose();
+ (void)Expr->decompose();
Expr->eraseFromParent();
continue;
}
>From a7082ee62f1f6db6c85024addab68eef134c3d19 Mon Sep 17 00:00:00 2001
From: Elvis Wang <elvis.wang at sifive.com>
Date: Tue, 30 Jun 2026 16:25:24 -0700
Subject: [PATCH 5/5] Address comments.
---
llvm/lib/Transforms/Vectorize/VPlan.h | 15 +++++++--------
llvm/lib/Transforms/Vectorize/VPlanRecipes.cpp | 6 ++----
llvm/lib/Transforms/Vectorize/VPlanTransforms.cpp | 2 +-
3 files changed, 10 insertions(+), 13 deletions(-)
diff --git a/llvm/lib/Transforms/Vectorize/VPlan.h b/llvm/lib/Transforms/Vectorize/VPlan.h
index 71a5d9e135b9e..f0a91b5f36f7c 100644
--- a/llvm/lib/Transforms/Vectorize/VPlan.h
+++ b/llvm/lib/Transforms/Vectorize/VPlan.h
@@ -3325,9 +3325,6 @@ class LLVM_ABI_FOR_TEST VPReductionRecipe : public VPRecipeWithIRFlags {
return Partial ? Partial->VFScaleFactor : 1;
}
- /// The ReductionStyle of this recipe.
- ReductionStyle getReductionStyle() const { return Style; }
-
protected:
#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
/// Print the recipe.
@@ -3348,7 +3345,9 @@ class LLVM_ABI_FOR_TEST VPReductionEVLRecipe : public VPReductionRecipe {
R.getFastMathFlagsOrNone(),
cast_or_null<Instruction>(R.getUnderlyingValue()),
{R.getChainOp(), R.getVecOp(), &EVL}, CondOp,
- R.getReductionStyle(), DL) {}
+ getReductionStyle(R.isInLoop(), R.isOrdered(),
+ R.getVFScaleFactor()),
+ DL) {}
~VPReductionEVLRecipe() override = default;
@@ -3657,10 +3656,10 @@ class VPExpressionRecipe : public VPSingleDefRecipe {
return getOperand(getNumOperands() - OpIdx);
}
- /// Return and insert the recipes of the expression back into the VPlan,
- /// directly before the current recipe. Leaves the expression recipe empty,
- /// which must be removed before codegen.
- ArrayRef<VPSingleDefRecipe *> decompose();
+ /// Insert the recipes of the expression back into the VPlan,
+ /// directly before the current recipe, and return them. Leaves the expression
+ /// recipe empty, which must be removed before codegen.
+ SmallVector<VPSingleDefRecipe *> decompose();
/// Returns the expression type of this recipe.
ExpressionTypes getExpressionType() const { return ExpressionType; }
diff --git a/llvm/lib/Transforms/Vectorize/VPlanRecipes.cpp b/llvm/lib/Transforms/Vectorize/VPlanRecipes.cpp
index e201fac6f703f..d5b3408af910f 100644
--- a/llvm/lib/Transforms/Vectorize/VPlanRecipes.cpp
+++ b/llvm/lib/Transforms/Vectorize/VPlanRecipes.cpp
@@ -3495,7 +3495,7 @@ VPExpressionRecipe::VPExpressionRecipe(
R->replaceUsesOfWith(LiveIn, Tmp);
}
-ArrayRef<VPSingleDefRecipe *> VPExpressionRecipe::decompose() {
+SmallVector<VPSingleDefRecipe *> VPExpressionRecipe::decompose() {
for (auto *R : ExpressionRecipes)
// Since the list could contain duplicates, make sure the recipe hasn't
// already been inserted.
@@ -3506,9 +3506,7 @@ ArrayRef<VPSingleDefRecipe *> VPExpressionRecipe::decompose() {
LiveInPlaceholders[Idx]->replaceAllUsesWith(Op);
replaceAllUsesWith(ExpressionRecipes.back());
- ArrayRef<VPSingleDefRecipe *> Expressions(ExpressionRecipes);
- ExpressionRecipes.clear();
- return Expressions;
+ return std::move(ExpressionRecipes);
}
InstructionCost VPExpressionRecipe::computeCost(ElementCount VF,
diff --git a/llvm/lib/Transforms/Vectorize/VPlanTransforms.cpp b/llvm/lib/Transforms/Vectorize/VPlanTransforms.cpp
index c5eebd1f247c8..2f97e7a2137e3 100644
--- a/llvm/lib/Transforms/Vectorize/VPlanTransforms.cpp
+++ b/llvm/lib/Transforms/Vectorize/VPlanTransforms.cpp
@@ -3162,7 +3162,7 @@ static VPRecipeBase *optimizeMaskToEVL(VPValue *HeaderMask,
if (match(Expr->getOperand(Expr->getNumOperands() - 1),
m_RemoveMask(HeaderMask, Mask))) {
// Decompose first and construct with VPReductionEVLRecipe later.
- SmallVector<VPSingleDefRecipe *> ExpressionRecipes(Expr->decompose());
+ SmallVector<VPSingleDefRecipe *> ExpressionRecipes = Expr->decompose();
VPReductionRecipe *Red =
cast<VPReductionRecipe>(ExpressionRecipes.pop_back_val());
More information about the llvm-commits
mailing list