Skip to content

Commit b0ee183

Browse files
committed
[RISCV] Don't forward AVL in VSETVLIInfo if it would clobber other definitions
This fixes a crash found when compiling OpenBLAS with -mllvm -verify-machineinstrs. When we "forward" the AVL from the output of a vsetvli, we might have to extend the LiveInterval of the AVL down to where insert the new vsetvli. Most of the time we are able to extend the LiveInterval because there's only one val num (definition) for the register. But PHI elimination can assign multiple values to the same register, in which case we end up clobbering a different val num when extending: %x = PseudoVSETVLI %avl, ... %avl = ADDI ... %v = PseudoVADD ..., avl=%x ; %avl is forwarded to PseudoVADD: %x = PseudoVSETVLI %avl, ... %avl = ADDI ... %v = PseudoVADD ..., avl=%avl Here there's no way to extend the %avl from the vsetvli since %avl is redefined, i.e. we have two val nums. This fixes it by only forwarding it when we have exactly one val num, where it should be safe to extend it.
1 parent f76ea31 commit b0ee183

File tree

3 files changed

+96
-3
lines changed

3 files changed

+96
-3
lines changed

llvm/lib/Target/RISCV/RISCVInsertVSETVLI.cpp

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -955,6 +955,12 @@ void RISCVInsertVSETVLI::forwardVSETVLIAVL(VSETVLIInfo &Info) const {
955955
VSETVLIInfo DefInstrInfo = getInfoForVSETVLI(*DefMI);
956956
if (!DefInstrInfo.hasSameVLMAX(Info))
957957
return;
958+
// If the AVL is a register with multiple definitions, don't forward it. We
959+
// might not be able to extend its LiveInterval without clobbering other val
960+
// nums.
961+
if (DefInstrInfo.hasAVLReg() &&
962+
!LIS->getInterval(DefInstrInfo.getAVLReg()).containsOneValue())
963+
return;
958964
Info.setAVL(DefInstrInfo);
959965
}
960966

@@ -1155,15 +1161,22 @@ void RISCVInsertVSETVLI::insertVSETVLI(MachineBasicBlock &MBB,
11551161
.addImm(Info.encodeVTYPE());
11561162
if (LIS) {
11571163
LIS->InsertMachineInstrInMaps(*MI);
1158-
// Normally the AVL's live range will already extend past the inserted
1164+
// Normally the AVL's LiveInterval will already extend past the inserted
11591165
// vsetvli because the pseudos below will already use the AVL. But this
11601166
// isn't always the case, e.g. PseudoVMV_X_S doesn't have an AVL operand or
11611167
// we've taken the AVL from the VL output of another vsetvli.
11621168
LiveInterval &LI = LIS->getInterval(AVLReg);
11631169
// Need to get non-const VNInfo
11641170
VNInfo *VNI = LI.getValNumInfo(Info.getAVLVNInfo()->id);
1165-
LI.addSegment(LiveInterval::Segment(
1166-
VNI->def, LIS->getInstructionIndex(*MI).getRegSlot(), VNI));
1171+
1172+
LiveInterval::Segment Segment(
1173+
VNI->def, LIS->getInstructionIndex(*MI).getRegSlot(), VNI);
1174+
// We should never end up extending the interval over a different value.
1175+
assert(all_of(LI.segments, [&Segment](LiveInterval::Segment S) {
1176+
return !S.containsInterval(Segment.start, Segment.end) ||
1177+
S.valno == S.valno;
1178+
}));
1179+
LI.addSegment(Segment);
11671180
}
11681181
}
11691182

llvm/test/CodeGen/RISCV/rvv/vsetvli-insert-crossbb.ll

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1062,3 +1062,39 @@ exit:
10621062
%c = call <vscale x 2 x i32> @llvm.riscv.vadd.nxv2i32(<vscale x 2 x i32> undef, <vscale x 2 x i32> %a, <vscale x 2 x i32> %d, i64 %vl)
10631063
ret <vscale x 2 x i32> %c
10641064
}
1065+
1066+
; Check that we don't forward an AVL if we wouldn't be able to extend its
1067+
; LiveInterval without clobbering other val nos.
1068+
define <vscale x 4 x i32> @unforwardable_avl(i64 %n, <vscale x 4 x i32> %v, i1 %cmp) {
1069+
; CHECK-LABEL: unforwardable_avl:
1070+
; CHECK: # %bb.0: # %entry
1071+
; CHECK-NEXT: vsetvli a2, a0, e32, m2, ta, ma
1072+
; CHECK-NEXT: andi a1, a1, 1
1073+
; CHECK-NEXT: .LBB25_1: # %for.body
1074+
; CHECK-NEXT: # =>This Inner Loop Header: Depth=1
1075+
; CHECK-NEXT: addi a0, a0, 1
1076+
; CHECK-NEXT: bnez a1, .LBB25_1
1077+
; CHECK-NEXT: # %bb.2: # %for.cond.cleanup
1078+
; CHECK-NEXT: vsetvli a0, zero, e32, m2, ta, ma
1079+
; CHECK-NEXT: vadd.vv v10, v8, v8
1080+
; CHECK-NEXT: vsetvli zero, a2, e32, m2, ta, ma
1081+
; CHECK-NEXT: vadd.vv v8, v10, v8
1082+
; CHECK-NEXT: ret
1083+
entry:
1084+
%0 = tail call i64 @llvm.riscv.vsetvli.i64(i64 %n, i64 2, i64 1)
1085+
br label %for.body
1086+
1087+
for.body:
1088+
; Use %n in a PHI here so its virtual register is assigned to a second time here.
1089+
%1 = phi i64 [ %3, %for.body ], [ %n, %entry ]
1090+
%2 = tail call i64 @llvm.riscv.vsetvli.i64(i64 %1, i64 0, i64 0)
1091+
%3 = add i64 %1, 1
1092+
br i1 %cmp, label %for.body, label %for.cond.cleanup
1093+
1094+
for.cond.cleanup:
1095+
%4 = tail call <vscale x 4 x i32> @llvm.riscv.vadd.nxv2f32.nxv2f32.i64(<vscale x 4 x i32> undef, <vscale x 4 x i32> %v, <vscale x 4 x i32> %v, i64 -1)
1096+
; VL toggle needed here: If the %n AVL was forwarded here we wouldn't be able
1097+
; to extend it's LiveInterval because it would clobber the assignment at %1.
1098+
%5 = tail call <vscale x 4 x i32> @llvm.riscv.vadd.nxv2f32.nxv2f32.i64(<vscale x 4 x i32> undef, <vscale x 4 x i32> %4, <vscale x 4 x i32> %v, i64 %0)
1099+
ret <vscale x 4 x i32> %5
1100+
}

llvm/test/CodeGen/RISCV/rvv/vsetvli-insert-crossbb.mir

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,10 @@
134134
ret void
135135
}
136136

137+
define void @unforwardable_avl() {
138+
ret void
139+
}
140+
137141
declare i32 @llvm.vector.reduce.add.v4i32(<4 x i32>)
138142

139143
declare <vscale x 1 x i64> @llvm.riscv.vadd.nxv1i64.nxv1i64.i64(<vscale x 1 x i64>, <vscale x 1 x i64>, <vscale x 1 x i64>, i64) #1
@@ -990,3 +994,43 @@ body: |
990994
%x:gpr = PseudoVMV_X_S undef $noreg, 6
991995
PseudoBR %bb.1
992996
...
997+
---
998+
name: unforwardable_avl
999+
tracksRegLiveness: true
1000+
body: |
1001+
; CHECK-LABEL: name: unforwardable_avl
1002+
; CHECK: bb.0:
1003+
; CHECK-NEXT: successors: %bb.1(0x80000000)
1004+
; CHECK-NEXT: liveins: $x10, $v8m2
1005+
; CHECK-NEXT: {{ $}}
1006+
; CHECK-NEXT: %avl:gprnox0 = COPY $x10
1007+
; CHECK-NEXT: %outvl:gprnox0 = PseudoVSETVLI %avl, 209 /* e32, m2, ta, ma */, implicit-def $vl, implicit-def $vtype
1008+
; CHECK-NEXT: {{ $}}
1009+
; CHECK-NEXT: bb.1:
1010+
; CHECK-NEXT: successors: %bb.2(0x80000000)
1011+
; CHECK-NEXT: liveins: $v8m2
1012+
; CHECK-NEXT: {{ $}}
1013+
; CHECK-NEXT: dead %avl:gprnox0 = ADDI %avl, 1
1014+
; CHECK-NEXT: {{ $}}
1015+
; CHECK-NEXT: bb.2:
1016+
; CHECK-NEXT: liveins: $v8m2
1017+
; CHECK-NEXT: {{ $}}
1018+
; CHECK-NEXT: dead [[PseudoVSETVLIX0_:%[0-9]+]]:gpr = PseudoVSETVLIX0 killed $x0, 209 /* e32, m2, ta, ma */, implicit-def $vl, implicit-def $vtype
1019+
; CHECK-NEXT: renamable $v10m2 = PseudoVADD_VV_M2 undef renamable $v10m2, renamable $v8m2, renamable $v8m2, -1, 5 /* e32 */, 0 /* tu, mu */, implicit $vl, implicit $vtype
1020+
; CHECK-NEXT: dead $x0 = PseudoVSETVLI %outvl, 209 /* e32, m2, ta, ma */, implicit-def $vl, implicit-def $vtype
1021+
; CHECK-NEXT: renamable $v8m2 = PseudoVADD_VV_M2 undef renamable $v8m2, killed renamable $v10m2, renamable $v8m2, $noreg, 5 /* e32 */, 0 /* tu, mu */, implicit $vl, implicit $vtype
1022+
; CHECK-NEXT: PseudoRET implicit $v8m2
1023+
bb.0:
1024+
liveins: $x10, $v8m2
1025+
%avl:gprnox0 = COPY $x10
1026+
%outvl:gprnox0 = PseudoVSETVLI %avl:gprnox0, 209, implicit-def dead $vl, implicit-def dead $vtype
1027+
1028+
bb.1:
1029+
liveins: $v8m2
1030+
%avl:gprnox0 = ADDI %avl:gprnox0, 1
1031+
1032+
bb.2:
1033+
liveins: $v8m2
1034+
renamable $v10m2 = PseudoVADD_VV_M2 undef renamable $v10m2, renamable $v8m2, renamable $v8m2, -1, 5, 0
1035+
renamable $v8m2 = PseudoVADD_VV_M2 undef renamable $v8m2, killed renamable $v10m2, killed renamable $v8m2, %outvl:gprnox0, 5, 0
1036+
PseudoRET implicit $v8m2

0 commit comments

Comments
 (0)