[llvm] [RISCV] Run MachineLICM before VLOptimizer to hoist constant splats (PR #210028)
Luke Lau via llvm-commits
llvm-commits at lists.llvm.org
Thu Jul 16 03:48:40 PDT 2026
https://github.com/lukel97 created https://github.com/llvm/llvm-project/pull/210028
In #179377 we moved RISCVVLOptimizer before the machine SSA optimization passes. This includes EarlyMachineLICM, which caused previously loop invariant PseudoVMV_V_I splats to use a loop variant VL defined by a PseudoVSETVLI. This prevents it from being hosited out: https://godbolt.org/z/Wf49roo7s
This fixes it by adding another pass of EarlyMachineLICM before RISCVVLOptimizer. I considered using MachineLoopInfo in RISCVVLOptimizer to avoid changing the VL of any loop invariant pseudos. But that still involves running the same analysis that EarlyMachineLICM depends on anyway, so I figured we might as well just do the hoisting.
>From 68aa4b3fb17f6e81a786c99919933511e22cd3fe Mon Sep 17 00:00:00 2001
From: Luke Lau <luke at igalia.com>
Date: Thu, 16 Jul 2026 18:31:27 +0800
Subject: [PATCH 1/2] Precommit test
---
llvm/test/CodeGen/RISCV/rvv/vl-opt-licm.ll | 39 ++++++++++++++++++++++
1 file changed, 39 insertions(+)
create mode 100644 llvm/test/CodeGen/RISCV/rvv/vl-opt-licm.ll
diff --git a/llvm/test/CodeGen/RISCV/rvv/vl-opt-licm.ll b/llvm/test/CodeGen/RISCV/rvv/vl-opt-licm.ll
new file mode 100644
index 0000000000000..0975c5f79a87e
--- /dev/null
+++ b/llvm/test/CodeGen/RISCV/rvv/vl-opt-licm.ll
@@ -0,0 +1,39 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 6
+; RUN: llc < %s -mtriple riscv64 -mattr=+v | FileCheck %s
+
+define void @hoist_const_splats(ptr %p, i32 zeroext %n) {
+; CHECK-LABEL: hoist_const_splats:
+; CHECK: # %bb.0: # %entry
+; CHECK-NEXT: li a2, 0
+; CHECK-NEXT: .LBB0_1: # %loop
+; CHECK-NEXT: # =>This Inner Loop Header: Depth=1
+; CHECK-NEXT: vsetvli a3, a1, e32, m2, ta, ma
+; CHECK-NEXT: vmv.v.i v8, 1
+; CHECK-NEXT: slli a4, a2, 2
+; CHECK-NEXT: add a4, a0, a4
+; CHECK-NEXT: sub a1, a1, a3
+; CHECK-NEXT: vse32.v v8, (a4)
+; CHECK-NEXT: addw a2, a2, a3
+; CHECK-NEXT: bnez a1, .LBB0_1
+; CHECK-NEXT: # %bb.2: # %exit
+; CHECK-NEXT: ret
+entry:
+ %n.zext = zext i32 %n to i64
+ br label %loop
+
+loop:
+ %iv = phi i32 [0, %entry], [%iv.next, %loop]
+ %avl = phi i64 [%n.zext, %entry], [%avl.next, %loop]
+ %evl = call i32 @llvm.experimental.get.vector.length(i64 %avl, i32 4, i1 true)
+ %gep = getelementptr i32, ptr %p, i32 %iv
+ call void @llvm.vp.store(<vscale x 4 x i32> splat (i32 1), ptr %gep, <vscale x 4 x i1> splat (i1 true), i32 %evl)
+ %iv.next = add i32 %iv, %evl
+ %evl.zext = zext i32 %evl to i64
+ %avl.next = sub i64 %avl, %evl.zext
+ %ec = icmp eq i64
+ %avl.next, 0
+ br i1 %ec, label %exit, label %loop
+
+exit:
+ ret void
+}
>From 6b4340f060d5d067e4a7efefa0c184457ab87742 Mon Sep 17 00:00:00 2001
From: Luke Lau <luke at igalia.com>
Date: Thu, 16 Jul 2026 18:11:54 +0800
Subject: [PATCH 2/2] [RISCV] Run MachineLICM before VLOptimizer to hoist
constant splats
In #179377 we moved RISCVVLOptimizer before the machine SSA optimization passes. This includes EarlyMachineLICM, which caused previously loop invariant PseudoVMV_V_I splats to use a loop variant VL defined by a PseudoVSETVLI. This prevents it from being hosited out: https://godbolt.org/z/Wf49roo7s
This fixes it by adding another pass of EarlyMachineLICM before RISCVVLOptimizer. I considered using MachineLoopInfo in RISCVVLOptimizer to avoid changing the VL of any loop invariant pseudos. But that still involves running the same analysis that EarlyMachineLICM depends on anyway, so I figured we might as well just do the hoisting.
---
llvm/lib/Target/RISCV/RISCVTargetMachine.cpp | 4 ++-
llvm/test/CodeGen/RISCV/O3-pipeline.ll | 1 +
llvm/test/CodeGen/RISCV/rvv/vl-opt-licm.ll | 7 ++--
llvm/test/CodeGen/RISCV/rvv/vsetvli-insert.ll | 9 +++---
.../RISCV/rvv/vxrm-insert-out-of-loop.ll | 32 +++++++++----------
5 files changed, 29 insertions(+), 24 deletions(-)
diff --git a/llvm/lib/Target/RISCV/RISCVTargetMachine.cpp b/llvm/lib/Target/RISCV/RISCVTargetMachine.cpp
index 88bc7ae9c1994..5d56048c8f5b2 100644
--- a/llvm/lib/Target/RISCV/RISCVTargetMachine.cpp
+++ b/llvm/lib/Target/RISCV/RISCVTargetMachine.cpp
@@ -623,8 +623,10 @@ void RISCVPassConfig::addPreEmitPass2() {
void RISCVPassConfig::addMachineSSAOptimization() {
// It's beneficial to reduce the VL to enable more
// Machine SSA optimizations.
- if (TM->getOptLevel() != CodeGenOptLevel::None)
+ if (TM->getOptLevel() != CodeGenOptLevel::None) {
+ addPass(&EarlyMachineLICMID);
addPass(createRISCVVLOptimizerPass());
+ }
addPass(createRISCVVectorPeepholePass());
addPass(createRISCVFoldMemOffsetPass());
diff --git a/llvm/test/CodeGen/RISCV/O3-pipeline.ll b/llvm/test/CodeGen/RISCV/O3-pipeline.ll
index 12b0895e0f158..efac5784df29d 100644
--- a/llvm/test/CodeGen/RISCV/O3-pipeline.ll
+++ b/llvm/test/CodeGen/RISCV/O3-pipeline.ll
@@ -106,6 +106,7 @@
; CHECK-NEXT: RISC-V DAG->DAG Pattern Instruction Selection
; CHECK-NEXT: Finalize ISel and expand pseudo-instructions
; CHECK-NEXT: MachineDominator Tree Construction
+; CHECK-NEXT: Early Machine Loop Invariant Code Motion
; CHECK-NEXT: RISC-V VL Optimizer
; CHECK-NEXT: RISC-V Vector Peephole Optimization
; CHECK-NEXT: RISC-V Fold Memory Offset
diff --git a/llvm/test/CodeGen/RISCV/rvv/vl-opt-licm.ll b/llvm/test/CodeGen/RISCV/rvv/vl-opt-licm.ll
index 0975c5f79a87e..95dad4f7393c3 100644
--- a/llvm/test/CodeGen/RISCV/rvv/vl-opt-licm.ll
+++ b/llvm/test/CodeGen/RISCV/rvv/vl-opt-licm.ll
@@ -4,16 +4,17 @@
define void @hoist_const_splats(ptr %p, i32 zeroext %n) {
; CHECK-LABEL: hoist_const_splats:
; CHECK: # %bb.0: # %entry
+; CHECK-NEXT: vsetvli a2, zero, e32, m2, ta, ma
+; CHECK-NEXT: vmv.v.i v8, 1
; CHECK-NEXT: li a2, 0
; CHECK-NEXT: .LBB0_1: # %loop
; CHECK-NEXT: # =>This Inner Loop Header: Depth=1
-; CHECK-NEXT: vsetvli a3, a1, e32, m2, ta, ma
-; CHECK-NEXT: vmv.v.i v8, 1
+; CHECK-NEXT: vsetvli a3, a1, e8, mf2, ta, ma
; CHECK-NEXT: slli a4, a2, 2
; CHECK-NEXT: add a4, a0, a4
; CHECK-NEXT: sub a1, a1, a3
-; CHECK-NEXT: vse32.v v8, (a4)
; CHECK-NEXT: addw a2, a2, a3
+; CHECK-NEXT: vse32.v v8, (a4)
; CHECK-NEXT: bnez a1, .LBB0_1
; CHECK-NEXT: # %bb.2: # %exit
; CHECK-NEXT: ret
diff --git a/llvm/test/CodeGen/RISCV/rvv/vsetvli-insert.ll b/llvm/test/CodeGen/RISCV/rvv/vsetvli-insert.ll
index 0e767cff76fe9..c1a7435849221 100644
--- a/llvm/test/CodeGen/RISCV/rvv/vsetvli-insert.ll
+++ b/llvm/test/CodeGen/RISCV/rvv/vsetvli-insert.ll
@@ -821,20 +821,21 @@ define void @coalesce_vl_clobber(ptr %p) {
; CHECK-NEXT: vmv.v.i v9, 0
; CHECK-NEXT: vmv1r.v v0, v8
; CHECK-NEXT: vmerge.vim v9, v9, 1, v0
+; CHECK-NEXT: vsetvli a2, zero, e32, m2, ta, ma
+; CHECK-NEXT: vmv.v.i v10, 0
; CHECK-NEXT: li a2, 0
; CHECK-NEXT: .LBB43_1: # %vector.body
; CHECK-NEXT: # =>This Inner Loop Header: Depth=1
; CHECK-NEXT: vsetivli zero, 0, e8, mf2, ta, mu
; CHECK-NEXT: vmv1r.v v0, v8
-; CHECK-NEXT: vmv1r.v v10, v9
+; CHECK-NEXT: vmv1r.v v12, v9
; CHECK-NEXT: slli a2, a2, 32
; CHECK-NEXT: srli a2, a2, 32
-; CHECK-NEXT: vslideup.vx v10, v9, a2, v0.t
+; CHECK-NEXT: vslideup.vx v12, v9, a2, v0.t
; CHECK-NEXT: vsetvli zero, zero, e8, mf2, ta, ma
-; CHECK-NEXT: vmsne.vi v0, v10, 0, v0.t
+; CHECK-NEXT: vmsne.vi v0, v12, 0, v0.t
; CHECK-NEXT: vsetvli a2, a1, e8, mf8, ta, ma
; CHECK-NEXT: vsetvli zero, a2, e32, m2, ta, ma
-; CHECK-NEXT: vmv.v.i v10, 0
; CHECK-NEXT: vse32.v v10, (a0), v0.t
; CHECK-NEXT: li a1, 1
; CHECK-NEXT: j .LBB43_1
diff --git a/llvm/test/CodeGen/RISCV/rvv/vxrm-insert-out-of-loop.ll b/llvm/test/CodeGen/RISCV/rvv/vxrm-insert-out-of-loop.ll
index d164861aa3e0d..cba670e62a79a 100644
--- a/llvm/test/CodeGen/RISCV/rvv/vxrm-insert-out-of-loop.ll
+++ b/llvm/test/CodeGen/RISCV/rvv/vxrm-insert-out-of-loop.ll
@@ -196,11 +196,11 @@ define void @test1(ptr nocapture noundef writeonly %dst, i32 noundef signext %i_
; RV64P670-NEXT: or t4, t4, t5
; RV64P670-NEXT: li t5, 32
; RV64P670-NEXT: maxu t5, t3, t5
-; RV64P670-NEXT: or t6, t6, t4
-; RV64P670-NEXT: add t4, a0, a6
+; RV64P670-NEXT: or t4, t6, t4
; RV64P670-NEXT: sltu t5, a6, t5
-; RV64P670-NEXT: or t5, t5, t6
-; RV64P670-NEXT: andi t5, t5, 1
+; RV64P670-NEXT: or t4, t5, t4
+; RV64P670-NEXT: add t5, a0, a6
+; RV64P670-NEXT: andi t4, t4, 1
; RV64P670-NEXT: j .LBB0_4
; RV64P670-NEXT: .LBB0_3: # %for.cond1.for.cond.cleanup3_crit_edge.us
; RV64P670-NEXT: # in Loop: Header=BB0_4 Depth=1
@@ -214,7 +214,7 @@ define void @test1(ptr nocapture noundef writeonly %dst, i32 noundef signext %i_
; RV64P670-NEXT: # =>This Loop Header: Depth=1
; RV64P670-NEXT: # Child Loop BB0_7 Depth 2
; RV64P670-NEXT: # Child Loop BB0_10 Depth 2
-; RV64P670-NEXT: beqz t5, .LBB0_6
+; RV64P670-NEXT: beqz t4, .LBB0_6
; RV64P670-NEXT: # %bb.5: # in Loop: Header=BB0_4 Depth=1
; RV64P670-NEXT: li t6, 0
; RV64P670-NEXT: j .LBB0_9
@@ -249,7 +249,7 @@ define void @test1(ptr nocapture noundef writeonly %dst, i32 noundef signext %i_
; RV64P670-NEXT: add s1, a0, t6
; RV64P670-NEXT: add s2, a4, t6
; RV64P670-NEXT: add t6, t6, a2
-; RV64P670-NEXT: add s0, s0, t4
+; RV64P670-NEXT: add s0, s0, t5
; RV64P670-NEXT: .LBB0_10: # %for.body4.us
; RV64P670-NEXT: # Parent Loop BB0_4 Depth=1
; RV64P670-NEXT: # => This Inner Loop Header: Depth=2
@@ -330,9 +330,9 @@ define void @test1(ptr nocapture noundef writeonly %dst, i32 noundef signext %i_
; RV64X60-NEXT: maxu t6, t3, s0
; RV64X60-NEXT: or t4, t4, t5
; RV64X60-NEXT: sltu t5, a6, t6
-; RV64X60-NEXT: or t5, t5, t4
-; RV64X60-NEXT: add t4, a0, a6
-; RV64X60-NEXT: andi t5, t5, 1
+; RV64X60-NEXT: or t4, t5, t4
+; RV64X60-NEXT: andi t4, t4, 1
+; RV64X60-NEXT: add t5, a0, a6
; RV64X60-NEXT: j .LBB0_4
; RV64X60-NEXT: .LBB0_3: # %for.cond1.for.cond.cleanup3_crit_edge.us
; RV64X60-NEXT: # in Loop: Header=BB0_4 Depth=1
@@ -346,7 +346,7 @@ define void @test1(ptr nocapture noundef writeonly %dst, i32 noundef signext %i_
; RV64X60-NEXT: # =>This Loop Header: Depth=1
; RV64X60-NEXT: # Child Loop BB0_7 Depth 2
; RV64X60-NEXT: # Child Loop BB0_10 Depth 2
-; RV64X60-NEXT: beqz t5, .LBB0_6
+; RV64X60-NEXT: beqz t4, .LBB0_6
; RV64X60-NEXT: # %bb.5: # in Loop: Header=BB0_4 Depth=1
; RV64X60-NEXT: li t6, 0
; RV64X60-NEXT: j .LBB0_9
@@ -379,7 +379,7 @@ define void @test1(ptr nocapture noundef writeonly %dst, i32 noundef signext %i_
; RV64X60-NEXT: # in Loop: Header=BB0_4 Depth=1
; RV64X60-NEXT: mul s1, a1, t0
; RV64X60-NEXT: add s0, a0, t6
-; RV64X60-NEXT: add s1, s1, t4
+; RV64X60-NEXT: add s1, s1, t5
; RV64X60-NEXT: add s2, a4, t6
; RV64X60-NEXT: add t6, t6, a2
; RV64X60-NEXT: .LBB0_10: # %for.body4.us
@@ -466,9 +466,9 @@ define void @test1(ptr nocapture noundef writeonly %dst, i32 noundef signext %i_
; RV64-NEXT: or t5, t5, t6
; RV64-NEXT: or t5, s0, t5
; RV64-NEXT: sltu t4, a6, t4
-; RV64-NEXT: or t5, t4, t5
-; RV64-NEXT: add t4, a0, a6
-; RV64-NEXT: andi t5, t5, 1
+; RV64-NEXT: or t4, t4, t5
+; RV64-NEXT: andi t4, t4, 1
+; RV64-NEXT: add t5, a0, a6
; RV64-NEXT: csrwi vxrm, 0
; RV64-NEXT: j .LBB0_6
; RV64-NEXT: .LBB0_5: # %for.cond1.for.cond.cleanup3_crit_edge.us
@@ -483,7 +483,7 @@ define void @test1(ptr nocapture noundef writeonly %dst, i32 noundef signext %i_
; RV64-NEXT: # =>This Loop Header: Depth=1
; RV64-NEXT: # Child Loop BB0_9 Depth 2
; RV64-NEXT: # Child Loop BB0_12 Depth 2
-; RV64-NEXT: beqz t5, .LBB0_8
+; RV64-NEXT: beqz t4, .LBB0_8
; RV64-NEXT: # %bb.7: # in Loop: Header=BB0_6 Depth=1
; RV64-NEXT: li t6, 0
; RV64-NEXT: j .LBB0_11
@@ -516,7 +516,7 @@ define void @test1(ptr nocapture noundef writeonly %dst, i32 noundef signext %i_
; RV64-NEXT: # in Loop: Header=BB0_6 Depth=1
; RV64-NEXT: mul s1, a1, t2
; RV64-NEXT: add s0, a0, t6
-; RV64-NEXT: add s1, t4, s1
+; RV64-NEXT: add s1, t5, s1
; RV64-NEXT: add s2, a4, t6
; RV64-NEXT: add t6, a2, t6
; RV64-NEXT: .LBB0_12: # %for.body4.us
More information about the llvm-commits
mailing list