Skip to content

Commit e93a813

Browse files
committed
[RISCVRVVInitUndef] Remove implicit single use assumption for IMPLICIT_DEF (try 2)
Reapplying after revert due to sanitizer failure. Includes fix to avoid querying dead lanes for vreg introduced by previous transform. The code was written with the implicit assumption that each IMPLICIT_DEF either a) the tied operand, or b) an untied source, but not both. This is true right now, but an upcoming change may allow CSE of IMPLICIT_DEFs in some cases, so let's rewrite the code to handle that possibility. I added an MIR case which demonstrates the multiple use IMPLICIT_DEF. To my knowledge, this is not a reachable configuration from IR right now. As an aside, this makes the structure a much closer match with the sub-reg liveness case, and we can probably just merge these routines. (Future work.) Differential Revision: https://reviews.llvm.org/D156477
1 parent 2d1e46f commit e93a813

File tree

3 files changed

+141
-39
lines changed

3 files changed

+141
-39
lines changed

llvm/lib/Target/RISCV/RISCVRVVInitUndef.cpp

Lines changed: 33 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,8 @@ class RISCVInitUndef : public MachineFunctionPass {
4949
const RISCVSubtarget *ST;
5050
const TargetRegisterInfo *TRI;
5151

52+
// Newly added vregs, assumed to be fully rewritten
53+
SmallSet<Register, 8> NewRegs;
5254
public:
5355
static char ID;
5456

@@ -118,65 +120,61 @@ static unsigned getUndefInitOpcode(unsigned RegClassID) {
118120
}
119121
}
120122

123+
static bool isEarlyClobberMI(MachineInstr &MI) {
124+
return llvm::any_of(MI.defs(), [](const MachineOperand &DefMO) {
125+
return DefMO.isReg() && DefMO.isEarlyClobber();
126+
});
127+
}
128+
121129
bool RISCVInitUndef::handleImplicitDef(MachineBasicBlock &MBB,
122130
MachineBasicBlock::iterator &Inst) {
123-
const TargetRegisterInfo &TRI =
124-
*MBB.getParent()->getSubtarget().getRegisterInfo();
125-
126131
assert(Inst->getOpcode() == TargetOpcode::IMPLICIT_DEF);
127132

128133
Register Reg = Inst->getOperand(0).getReg();
129134
if (!Reg.isVirtual())
130135
return false;
131136

132-
bool NeedPseudoInit = false;
137+
bool HasOtherUse = false;
133138
SmallVector<MachineOperand *, 1> UseMOs;
134139
for (MachineOperand &MO : MRI->use_nodbg_operands(Reg)) {
135-
MachineInstr *UserMI = MO.getParent();
136-
137-
bool HasEarlyClobber = false;
138-
bool TiedToDef = false;
139-
for (MachineOperand &UserMO : UserMI->operands()) {
140-
if (!UserMO.isReg())
141-
continue;
142-
if (UserMO.isEarlyClobber())
143-
HasEarlyClobber = true;
144-
if (UserMO.isUse() && UserMO.isTied() &&
145-
TRI.regsOverlap(UserMO.getReg(), Reg))
146-
TiedToDef = true;
147-
}
148-
if (HasEarlyClobber && !TiedToDef) {
149-
NeedPseudoInit = true;
150-
UseMOs.push_back(&MO);
140+
if (isEarlyClobberMI(*MO.getParent())) {
141+
if (MO.isUse() && !MO.isTied())
142+
UseMOs.push_back(&MO);
143+
else
144+
HasOtherUse = true;
151145
}
152146
}
153147

154-
if (!NeedPseudoInit)
148+
if (UseMOs.empty())
155149
return false;
156150

157151
LLVM_DEBUG(
158152
dbgs() << "Emitting PseudoRVVInitUndef for implicit vector register "
159153
<< Reg << '\n');
160154

161-
unsigned RegClassID = getVRLargestSuperClass(MRI->getRegClass(Reg))->getID();
162-
unsigned Opcode = getUndefInitOpcode(RegClassID);
155+
const TargetRegisterClass *TargetRegClass =
156+
getVRLargestSuperClass(MRI->getRegClass(Reg));
157+
unsigned Opcode = getUndefInitOpcode(TargetRegClass->getID());
163158

164-
BuildMI(MBB, Inst, Inst->getDebugLoc(), TII->get(Opcode), Reg);
159+
Register NewDest = Reg;
160+
if (HasOtherUse) {
161+
NewDest = MRI->createVirtualRegister(TargetRegClass);
162+
// We don't have a way to update dead lanes, so keep track of the
163+
// new register so that we avoid querying it later.
164+
NewRegs.insert(NewDest);
165+
}
166+
BuildMI(MBB, Inst, Inst->getDebugLoc(), TII->get(Opcode), NewDest);
165167

166-
Inst = MBB.erase(Inst);
168+
if (!HasOtherUse)
169+
Inst = MBB.erase(Inst);
167170

168-
for (auto MO : UseMOs)
171+
for (auto MO : UseMOs) {
172+
MO->setReg(NewDest);
169173
MO->setIsUndef(false);
170-
174+
}
171175
return true;
172176
}
173177

174-
static bool isEarlyClobberMI(MachineInstr &MI) {
175-
return llvm::any_of(MI.defs(), [](const MachineOperand &DefMO) {
176-
return DefMO.isReg() && DefMO.isEarlyClobber();
177-
});
178-
}
179-
180178
bool RISCVInitUndef::handleSubReg(MachineFunction &MF, MachineInstr &MI,
181179
const DeadLaneDetector &DLD) {
182180
bool Changed = false;
@@ -188,6 +186,8 @@ bool RISCVInitUndef::handleSubReg(MachineFunction &MF, MachineInstr &MI,
188186
continue;
189187

190188
Register Reg = UseMO.getReg();
189+
if (NewRegs.count(Reg))
190+
continue;
191191
DeadLaneDetector::VRegInfo Info =
192192
DLD.getVRegInfo(Register::virtReg2Index(Reg));
193193

llvm/test/CodeGen/RISCV/rvv/undef-earlyclobber-chain.ll

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,17 @@
11
; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
22
; RUN: llc -mtriple riscv64 -mattr=+v -riscv-enable-subreg-liveness < %s | FileCheck %s
33

4+
define <vscale x 2 x float> @vrgather_all_undef(ptr %p) {
5+
; CHECK-LABEL: vrgather_all_undef:
6+
; CHECK: # %bb.0: # %entry
7+
; CHECK-NEXT: vsetivli zero, 0, e32, m1, ta, ma
8+
; CHECK-NEXT: vrgather.vi v8, v9, 0
9+
; CHECK-NEXT: ret
10+
entry:
11+
%0 = tail call <vscale x 2 x float> @llvm.riscv.vrgather.vx.nxv2f32.i64(<vscale x 2 x float> undef, <vscale x 2 x float> undef, i64 0, i64 0)
12+
ret <vscale x 2 x float> %0
13+
}
14+
415
define dso_local signext i32 @undef_early_clobber_chain() {
516
; CHECK-LABEL: undef_early_clobber_chain:
617
; CHECK: # %bb.0: # %entry
@@ -25,14 +36,14 @@ entry:
2536
define internal void @SubRegLivenessUndefInPhi(i64 %cond) {
2637
; CHECK-LABEL: SubRegLivenessUndefInPhi:
2738
; CHECK: # %bb.0: # %start
28-
; CHECK-NEXT: blez a0, .LBB1_2
39+
; CHECK-NEXT: blez a0, .LBB2_2
2940
; CHECK-NEXT: # %bb.1: # %Cond1
3041
; CHECK-NEXT: vsetvli a0, zero, e16, mf4, ta, ma
3142
; CHECK-NEXT: vid.v v8
3243
; CHECK-NEXT: vadd.vi v10, v8, 1
3344
; CHECK-NEXT: vadd.vi v12, v8, 3
34-
; CHECK-NEXT: j .LBB1_3
35-
; CHECK-NEXT: .LBB1_2: # %Cond2
45+
; CHECK-NEXT: j .LBB2_3
46+
; CHECK-NEXT: .LBB2_2: # %Cond2
3647
; CHECK-NEXT: vsetvli a0, zero, e16, mf4, ta, ma
3748
; CHECK-NEXT: vid.v v9
3849
; CHECK-NEXT: csrr a0, vlenb
@@ -48,7 +59,7 @@ define internal void @SubRegLivenessUndefInPhi(i64 %cond) {
4859
; CHECK-NEXT: vadd.vi v9, v9, 3
4960
; CHECK-NEXT: vsetvli zero, a1, e16, m1, ta, ma
5061
; CHECK-NEXT: vslideup.vx v12, v9, a0
51-
; CHECK-NEXT: .LBB1_3: # %UseSR
62+
; CHECK-NEXT: .LBB2_3: # %UseSR
5263
; CHECK-NEXT: vl1r.v v14, (zero)
5364
; CHECK-NEXT: vsetivli zero, 4, e8, m1, ta, ma
5465
; CHECK-NEXT: vrgatherei16.vv v13, v14, v8
@@ -104,7 +115,7 @@ define internal void @SubRegLivenessUndef() {
104115
; CHECK-NEXT: vid.v v8
105116
; CHECK-NEXT: vadd.vi v10, v8, 1
106117
; CHECK-NEXT: vadd.vi v12, v8, 3
107-
; CHECK-NEXT: .LBB2_1: # %loopIR3.i.i
118+
; CHECK-NEXT: .LBB3_1: # %loopIR3.i.i
108119
; CHECK-NEXT: # =>This Inner Loop Header: Depth=1
109120
; CHECK-NEXT: vl1r.v v14, (zero)
110121
; CHECK-NEXT: vsetivli zero, 4, e8, m1, ta, ma
@@ -117,7 +128,7 @@ define internal void @SubRegLivenessUndef() {
117128
; CHECK-NEXT: vsetvli a0, zero, e8, m1, ta, ma
118129
; CHECK-NEXT: vand.vv v9, v9, v11
119130
; CHECK-NEXT: vs1r.v v9, (zero)
120-
; CHECK-NEXT: j .LBB2_1
131+
; CHECK-NEXT: j .LBB3_1
121132
loopIR.preheader.i.i:
122133
%v15 = tail call <vscale x 1 x i16> @llvm.experimental.stepvector.nxv1i16()
123134
%v17 = tail call <vscale x 8 x i16> @llvm.vector.insert.nxv8i16.nxv1i16(<vscale x 8 x i16> poison, <vscale x 1 x i16> %v15, i64 0)
Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
# NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py
2+
# RUN: llc -mtriple=riscv32 -mattr=+v -riscv-enable-subreg-liveness -run-pass riscv-init-undef -run-pass machineverifier %s -o - | FileCheck %s
3+
4+
--- |
5+
source_filename = "<stdin>"
6+
target datalayout = "e-m:e-p:64:64-i64:64-i128:128-n32:64-S128"
7+
target triple = "riscv64"
8+
9+
define <vscale x 2 x float> @undef_early_clobber_chain(ptr %p) #0 {
10+
entry:
11+
%0 = tail call <vscale x 2 x float> @llvm.riscv.vrgather.vx.nxv2f32.i64(<vscale x 2 x float> undef, <vscale x 2 x float> undef, i64 0, i64 0)
12+
ret <vscale x 2 x float> %0
13+
}
14+
15+
declare <vscale x 2 x float> @llvm.riscv.vrgather.vx.nxv2f32.i64(<vscale x 2 x float>, <vscale x 2 x float>, i64, i64) #1
16+
17+
attributes #0 = { "target-features"="+v" }
18+
attributes #1 = { nocallback nofree nosync nounwind willreturn memory(none) "target-features"="+v" }
19+
20+
...
21+
---
22+
name: undef_early_clobber_chain
23+
alignment: 4
24+
exposesReturnsTwice: false
25+
legalized: false
26+
regBankSelected: false
27+
selected: false
28+
failedISel: false
29+
tracksRegLiveness: true
30+
hasWinCFI: false
31+
callsEHReturn: false
32+
callsUnwindInit: false
33+
hasEHCatchret: false
34+
hasEHScopes: false
35+
hasEHFunclets: false
36+
isOutlined: false
37+
debugInstrRef: false
38+
failsVerification: false
39+
tracksDebugUserValues: false
40+
registers:
41+
- { id: 0, class: gpr, preferred-register: '' }
42+
- { id: 1, class: vr, preferred-register: '' }
43+
- { id: 2, class: vr, preferred-register: '' }
44+
- { id: 3, class: vr, preferred-register: '' }
45+
liveins: []
46+
frameInfo:
47+
isFrameAddressTaken: false
48+
isReturnAddressTaken: false
49+
hasStackMap: false
50+
hasPatchPoint: false
51+
stackSize: 0
52+
offsetAdjustment: 0
53+
maxAlignment: 1
54+
adjustsStack: false
55+
hasCalls: false
56+
stackProtector: ''
57+
functionContext: ''
58+
maxCallFrameSize: 4294967295
59+
cvBytesOfCalleeSavedRegisters: 0
60+
hasOpaqueSPAdjustment: false
61+
hasVAStart: false
62+
hasMustTailInVarArgFunc: false
63+
hasTailCall: false
64+
localFrameSize: 0
65+
savePoint: ''
66+
restorePoint: ''
67+
fixedStack: []
68+
stack: []
69+
entry_values: []
70+
callSites: []
71+
debugValueSubstitutions: []
72+
constants: []
73+
machineFunctionInfo:
74+
varArgsFrameIndex: 0
75+
varArgsSaveSize: 0
76+
body: |
77+
bb.0.entry:
78+
; CHECK-LABEL: name: undef_early_clobber_chain
79+
; CHECK: [[PseudoRVVInitUndefM1_:%[0-9]+]]:vr = PseudoRVVInitUndefM1
80+
; CHECK-NEXT: [[DEF:%[0-9]+]]:vr = IMPLICIT_DEF
81+
; CHECK-NEXT: dead $x0 = PseudoVSETIVLI 0, 208 /* e32, m1, ta, ma */, implicit-def $vl, implicit-def $vtype
82+
; CHECK-NEXT: early-clobber %1:vr = PseudoVRGATHER_VI_M1 undef [[DEF]], [[PseudoRVVInitUndefM1_]], 0, 0, 5 /* e32 */, 0 /* tu, mu */, implicit $vl, implicit $vtype
83+
; CHECK-NEXT: $v8 = COPY %1
84+
; CHECK-NEXT: PseudoRET implicit $v8
85+
%2:vr = IMPLICIT_DEF
86+
dead $x0 = PseudoVSETIVLI 0, 208 /* e32, m1, ta, ma */, implicit-def $vl, implicit-def $vtype
87+
early-clobber %1:vr = PseudoVRGATHER_VI_M1 undef %2, undef %2, 0, 0, 5 /* e32 */, 0 /* tu, mu */, implicit $vl, implicit $vtype
88+
$v8 = COPY %1
89+
PseudoRET implicit $v8
90+
91+
...

0 commit comments

Comments
 (0)