From 3e4fd3777da07667b5b4d9330633aec5110c5c12 Mon Sep 17 00:00:00 2001 From: Luke Lau Date: Thu, 13 Nov 2025 00:05:41 +0800 Subject: [PATCH 1/2] [RISCV] Fix RISCVInsertVSETVLI coalescing clobbering VL def segment This fixes an assert when compiling llvm-test-suite with -march=rva23u64 -O3 that started appearing sometime this week. We get "Cannot overlap two segments with differing ValID's" because we try to coalescse these two vsetvlis: %x:gprnox0 = COPY $x8 dead $x0 = PseudoVSETIVLI 1, 208, implicit-def $vl, implicit-def $vtype %y:gprnox0 = COPY %x %v:vr = COPY $v8, implicit $vtype %x = PseudoVSETVLI %x, 208, implicit-def $vl, implicit-def $vtype --> %x:gprnox0 = COPY $x8 %x = PseudoVSETVLI %x, 208, implicit-def $vl, implicit-def $vtype %y:gprnox0 = COPY %x %v:vr = COPY $v8, implicit $vtype However to do so would cause us to extend the segment of the new value of %x up past the first segment, which overlaps. This fixes it by checking that its safe to extend the segment, by simply making sure the interval isn't live at the first vsetvli. This unfortunately causes a regression in the existing coalesce_vl_avl_same_reg test because even though we could coalesce the vsetvlis there, we now bail. I couldn't think of an easy way to handle this safely, but I don't think this is an important case to handle: After testing this patch on SPEC CPU 2017 there are no codegen changes. --- llvm/lib/Target/RISCV/RISCVInsertVSETVLI.cpp | 8 ++++ llvm/test/CodeGen/RISCV/rvv/vsetvli-insert.ll | 43 +++++++++++++++++++ .../test/CodeGen/RISCV/rvv/vsetvli-insert.mir | 27 ++++++++++++ 3 files changed, 78 insertions(+) diff --git a/llvm/lib/Target/RISCV/RISCVInsertVSETVLI.cpp b/llvm/lib/Target/RISCV/RISCVInsertVSETVLI.cpp index bf9de0a4b5604..06268b947ab31 100644 --- a/llvm/lib/Target/RISCV/RISCVInsertVSETVLI.cpp +++ b/llvm/lib/Target/RISCV/RISCVInsertVSETVLI.cpp @@ -1755,6 +1755,14 @@ bool RISCVInsertVSETVLI::canMutatePriorConfig( if (!VNI || !PrevVNI || VNI != PrevVNI) return false; } + + // If we define VL and need to move the definition up, check we can extend + // the live interval upwards from PrevMI to MI. + Register VL = MI.getOperand(0).getReg(); + if (VL.isVirtual() && LIS && + LIS->getInterval(VL).overlaps(LIS->getInstructionIndex(PrevMI), + LIS->getInstructionIndex(MI))) + return false; } assert(PrevMI.getOperand(2).isImm() && MI.getOperand(2).isImm()); diff --git a/llvm/test/CodeGen/RISCV/rvv/vsetvli-insert.ll b/llvm/test/CodeGen/RISCV/rvv/vsetvli-insert.ll index b6e29cf76cd48..e8d89d4066e43 100644 --- a/llvm/test/CodeGen/RISCV/rvv/vsetvli-insert.ll +++ b/llvm/test/CodeGen/RISCV/rvv/vsetvli-insert.ll @@ -879,3 +879,46 @@ entry: %3 = tail call { , i64 } @llvm.riscv.vleff( poison, ptr %p, i64 %2) ret void } + +; This will create a live interval in such a way we can't coalesce two vsetvlis, +; see the corresponding .mir test for more details. Make sure we check for this +; and don't crash. +define void @coalesce_vl_clobber(ptr %p) { +; CHECK-LABEL: coalesce_vl_clobber: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: li a2, 0 +; CHECK-NEXT: li a1, 0 +; CHECK-NEXT: vsetivli zero, 0, e8, mf2, ta, ma +; CHECK-NEXT: vmclr.m v8 +; CHECK-NEXT: vmv.v.i v9, 0 +; CHECK-NEXT: vmv1r.v v0, v8 +; CHECK-NEXT: vmerge.vim v9, v9, 1, v0 +; CHECK-NEXT: .LBB43_1: # %vector.body +; CHECK-NEXT: # =>This Inner Loop Header: Depth=1 +; CHECK-NEXT: vsetivli zero, 1, e8, m1, ta, ma +; CHECK-NEXT: vmv1r.v v0, v8 +; CHECK-NEXT: slli a3, a1, 32 +; CHECK-NEXT: vsetvli a1, a2, e8, mf8, ta, ma +; CHECK-NEXT: vsetivli zero, 0, e8, mf2, ta, mu +; CHECK-NEXT: vmv.v.i v10, 0 +; CHECK-NEXT: srli a3, a3, 32 +; CHECK-NEXT: vmerge.vim v10, v10, 1, v0 +; CHECK-NEXT: vslideup.vx v10, v9, a3, v0.t +; CHECK-NEXT: vsetvli zero, zero, e8, mf2, ta, ma +; CHECK-NEXT: vmsne.vi v0, v10, 0, v0.t +; CHECK-NEXT: vsetvli zero, a1, e32, m2, ta, ma +; CHECK-NEXT: vmv.v.i v10, 0 +; CHECK-NEXT: vse32.v v10, (a0), v0.t +; CHECK-NEXT: li a2, 1 +; CHECK-NEXT: j .LBB43_1 +entry: + br label %vector.body + +vector.body: + %avl = phi i64 [ 0, %entry ], [ 1, %vector.body ] + %prev.evl = phi i32 [ 0, %entry ], [ %0, %vector.body ] + %0 = tail call i32 @llvm.experimental.get.vector.length(i64 %avl, i32 1, i1 true) + %1 = tail call @llvm.experimental.vp.splice( zeroinitializer, zeroinitializer, i32 0, zeroinitializer, i32 %prev.evl, i32 0) + tail call void @llvm.vp.store( zeroinitializer, ptr %p, %1, i32 %0) + br label %vector.body +} diff --git a/llvm/test/CodeGen/RISCV/rvv/vsetvli-insert.mir b/llvm/test/CodeGen/RISCV/rvv/vsetvli-insert.mir index f9929c9caf712..396ca517e4017 100644 --- a/llvm/test/CodeGen/RISCV/rvv/vsetvli-insert.mir +++ b/llvm/test/CodeGen/RISCV/rvv/vsetvli-insert.mir @@ -100,6 +100,10 @@ ret void } + define void @coalesce_vl_clobber() { + ret void + } + define void @vsetvli_vleff() { ret void } @@ -624,10 +628,33 @@ body: | ; CHECK: liveins: $x8, $v8 ; CHECK-NEXT: {{ $}} ; CHECK-NEXT: %x:gprnox0 = COPY $x8 + ; CHECK-NEXT: dead $x0 = PseudoVSETIVLI 1, 208 /* e32, m1, ta, ma */, implicit-def $vl, implicit-def $vtype + ; CHECK-NEXT: dead %v:vr = COPY $v8, implicit $vtype ; CHECK-NEXT: dead %x:gprnox0 = PseudoVSETVLI %x, 208 /* e32, m1, ta, ma */, implicit-def $vl, implicit-def $vtype + %x:gprnox0 = COPY $x8 + dead $x0 = PseudoVSETIVLI 1, 208, implicit-def $vl, implicit-def $vtype + %v:vr = COPY $v8, implicit $vtype + %x = PseudoVSETVLI %x, 208, implicit-def $vl, implicit-def $vtype +... +--- +# Because of the %y:gprnox0 = COPY %x, we can't extend the live range of %x from +# the second vsetvli to the first vsetvli when coalescing. +name: coalesce_vl_clobber +tracksRegLiveness: true +body: | + bb.0: + liveins: $x8, $v8 + ; CHECK-LABEL: name: coalesce_vl_clobber + ; CHECK: liveins: $x8, $v8 + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: %x:gprnox0 = COPY $x8 + ; CHECK-NEXT: dead $x0 = PseudoVSETIVLI 1, 208 /* e32, m1, ta, ma */, implicit-def $vl, implicit-def $vtype + ; CHECK-NEXT: dead %y:gprnox0 = COPY %x ; CHECK-NEXT: dead %v:vr = COPY $v8, implicit $vtype + ; CHECK-NEXT: dead %x:gprnox0 = PseudoVSETVLI %x, 208 /* e32, m1, ta, ma */, implicit-def $vl, implicit-def $vtype %x:gprnox0 = COPY $x8 dead $x0 = PseudoVSETIVLI 1, 208, implicit-def $vl, implicit-def $vtype + %y:gprnox0 = COPY %x %v:vr = COPY $v8, implicit $vtype %x = PseudoVSETVLI %x, 208, implicit-def $vl, implicit-def $vtype ... From 488edca984e1ba7adfe7e006ebb5fa03e076116a Mon Sep 17 00:00:00 2001 From: Luke Lau Date: Thu, 13 Nov 2025 16:30:33 +0800 Subject: [PATCH 2/2] Fix comment --- llvm/lib/Target/RISCV/RISCVInsertVSETVLI.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/llvm/lib/Target/RISCV/RISCVInsertVSETVLI.cpp b/llvm/lib/Target/RISCV/RISCVInsertVSETVLI.cpp index 06268b947ab31..e5819d90526d9 100644 --- a/llvm/lib/Target/RISCV/RISCVInsertVSETVLI.cpp +++ b/llvm/lib/Target/RISCV/RISCVInsertVSETVLI.cpp @@ -1757,7 +1757,7 @@ bool RISCVInsertVSETVLI::canMutatePriorConfig( } // If we define VL and need to move the definition up, check we can extend - // the live interval upwards from PrevMI to MI. + // the live interval upwards from MI to PrevMI. Register VL = MI.getOperand(0).getReg(); if (VL.isVirtual() && LIS && LIS->getInterval(VL).overlaps(LIS->getInstructionIndex(PrevMI),