[llvm] [RISCV] Run EarlyMachineLICM before VLOptimizer to hoist constant splats (PR #210028)

Luke Lau via llvm-commits llvm-commits at lists.llvm.org
Thu Jul 16 04:49:58 PDT 2026


https://github.com/lukel97 updated https://github.com/llvm/llvm-project/pull/210028

>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/3] 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/3] [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

>From 13dc7ec5eb2b76f74b41fb682fc83f7f6b9cb11c Mon Sep 17 00:00:00 2001
From: Luke Lau <luke at igalia.com>
Date: Thu, 16 Jul 2026 19:49:33 +0800
Subject: [PATCH 3/3] Update O3-pipeline.ll

---
 llvm/test/CodeGen/RISCV/O3-pipeline.ll | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/llvm/test/CodeGen/RISCV/O3-pipeline.ll b/llvm/test/CodeGen/RISCV/O3-pipeline.ll
index efac5784df29d..c963236e5bb4c 100644
--- a/llvm/test/CodeGen/RISCV/O3-pipeline.ll
+++ b/llvm/test/CodeGen/RISCV/O3-pipeline.ll
@@ -106,7 +106,10 @@
 ; CHECK-NEXT:       RISC-V DAG->DAG Pattern Instruction Selection
 ; CHECK-NEXT:       Finalize ISel and expand pseudo-instructions
 ; CHECK-NEXT:       MachineDominator Tree Construction
+; CHECK-NEXT:	    Machine Natural Loop Construction
+; CHECK-NEXT:       Machine Block Frequency Analysis
 ; CHECK-NEXT:       Early Machine Loop Invariant Code Motion
+; CHECK-NEXT:       MachineDominator Tree Construction
 ; CHECK-NEXT:       RISC-V VL Optimizer
 ; CHECK-NEXT:       RISC-V Vector Peephole Optimization
 ; CHECK-NEXT:       RISC-V Fold Memory Offset



More information about the llvm-commits mailing list