Skip to content

Commit 8756043

Browse files
committed
[RISCV] Teach RISCVInsertVSETVLI to work without LiveIntervals
(Reapplying with corrected commit message) We recently moved RISCVInsertVSETVLI from before vector register allocation to after vector register allocation. When doing so, we added an unconditional dependency on LiveIntervals - even at O0 where LiveIntevals hadn't previously run. As reported in #93587, this was apparently not safe to do. This change makes LiveIntervals optional, and adjusts all the update code to only run wen live intervals is present. The only real tricky part of this change is the abstract state tracking in the dataflow. We need to represent a "register w/unknown definition" state - but only when we don't have LiveIntervals. This adjust the abstract state definition so that the AVLIsReg state can represent either a register + valno, or a register + unknown definition. With LiveIntervals, we have an exact definition for each AVL use. Without LiveIntervals, we treat the definition of a register AVL as being unknown. The key semantic change is that we now have a state in the lattice for which something is known about the AVL value, but for which two identical lattice elements do *not* neccessarily represent the same AVL value at runtime. Previously, the only case which could result in such an unknown AVL was the fully unknown state (where VTYPE is also fully unknown). This requires a small adjustment to hasSameAVL and lattice state equality to draw this important distinction. The net effect of this patch is that we remove the LiveIntervals dependency at O0, and O0 code quality will regress for cases involving register AVL values. In practice, this means we pessimize code written with intrinsics at O0. This patch is an alternative to #93796 and #94340. It is very directly inspired by review conversation around them, and thus should be considered coauthored by Luke.
1 parent 1d02815 commit 8756043

File tree

5 files changed

+155
-62
lines changed

5 files changed

+155
-62
lines changed

llvm/lib/Target/RISCV/RISCVInsertVSETVLI.cpp

Lines changed: 104 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -48,10 +48,13 @@ static cl::opt<bool> DisableInsertVSETVLPHIOpt(
4848
namespace {
4949

5050
/// Given a virtual register \p Reg, return the corresponding VNInfo for it.
51-
/// This will return nullptr if the virtual register is an implicit_def.
51+
/// This will return nullptr if the virtual register is an implicit_def or
52+
/// if LiveIntervals is not available.
5253
static VNInfo *getVNInfoFromReg(Register Reg, const MachineInstr &MI,
5354
const LiveIntervals *LIS) {
5455
assert(Reg.isVirtual());
56+
if (!LIS)
57+
return nullptr;
5558
auto &LI = LIS->getInterval(Reg);
5659
SlotIndex SI = LIS->getSlotIndexes()->getInstructionIndex(MI);
5760
return LI.getVNInfoBefore(SI);
@@ -512,7 +515,8 @@ DemandedFields getDemanded(const MachineInstr &MI, const RISCVSubtarget *ST) {
512515
/// values of the VL and VTYPE registers after insertion.
513516
class VSETVLIInfo {
514517
struct AVLDef {
515-
// Every AVLDef should have a VNInfo.
518+
// Every AVLDef should have a VNInfo, unless we're running without
519+
// LiveIntervals in which case this will be nullptr.
516520
const VNInfo *ValNo;
517521
Register DefReg;
518522
};
@@ -526,7 +530,7 @@ class VSETVLIInfo {
526530
AVLIsReg,
527531
AVLIsImm,
528532
AVLIsVLMAX,
529-
Unknown,
533+
Unknown, // AVL and VTYPE are fully unknown
530534
} State = Uninitialized;
531535

532536
// Fields from VTYPE.
@@ -552,7 +556,7 @@ class VSETVLIInfo {
552556
bool isUnknown() const { return State == Unknown; }
553557

554558
void setAVLRegDef(const VNInfo *VNInfo, Register AVLReg) {
555-
assert(VNInfo && AVLReg.isVirtual());
559+
assert(AVLReg.isVirtual());
556560
AVLRegDef.ValNo = VNInfo;
557561
AVLRegDef.DefReg = AVLReg;
558562
State = AVLIsReg;
@@ -582,9 +586,11 @@ class VSETVLIInfo {
582586
}
583587
// Most AVLIsReg infos will have a single defining MachineInstr, unless it was
584588
// a PHI node. In that case getAVLVNInfo()->def will point to the block
585-
// boundary slot.
589+
// boundary slot. If LiveIntervals isn't available, then nullptr is returned.
586590
const MachineInstr *getAVLDefMI(const LiveIntervals *LIS) const {
587591
assert(hasAVLReg());
592+
if (!LIS)
593+
return nullptr;
588594
auto *MI = LIS->getInstructionFromIndex(getAVLVNInfo()->def);
589595
assert(!(getAVLVNInfo()->isPHIDef() && MI));
590596
return MI;
@@ -628,10 +634,15 @@ class VSETVLIInfo {
628634
return (hasNonZeroAVL(LIS) && Other.hasNonZeroAVL(LIS));
629635
}
630636

631-
bool hasSameAVL(const VSETVLIInfo &Other) const {
632-
if (hasAVLReg() && Other.hasAVLReg())
637+
bool hasSameAVLLatticeValue(const VSETVLIInfo &Other) const {
638+
if (hasAVLReg() && Other.hasAVLReg()) {
639+
assert(!getAVLVNInfo() == !Other.getAVLVNInfo() &&
640+
"we either have intervals or we don't");
641+
if (!getAVLVNInfo())
642+
return getAVLReg() == Other.getAVLReg();
633643
return getAVLVNInfo()->id == Other.getAVLVNInfo()->id &&
634644
getAVLReg() == Other.getAVLReg();
645+
}
635646

636647
if (hasAVLImm() && Other.hasAVLImm())
637648
return getAVLImm() == Other.getAVLImm();
@@ -642,6 +653,21 @@ class VSETVLIInfo {
642653
return false;
643654
}
644655

656+
// Return true if the two lattice values are guaranteed to have
657+
// the same AVL value at runtime.
658+
bool hasSameAVL(const VSETVLIInfo &Other) const {
659+
// Without LiveIntervals, we don't know which instruction defines a
660+
// register. Since a register may be redefined, this means all AVLIsReg
661+
// states must be treated as possibly distinct.
662+
if (hasAVLReg() && Other.hasAVLReg()) {
663+
assert(!getAVLVNInfo() == !Other.getAVLVNInfo() &&
664+
"we either have intervals or we don't");
665+
if (!getAVLVNInfo())
666+
return false;
667+
}
668+
return hasSameAVLLatticeValue(Other);
669+
}
670+
645671
void setVTYPE(unsigned VType) {
646672
assert(isValid() && !isUnknown() &&
647673
"Can't set VTYPE for uninitialized or unknown");
@@ -741,7 +767,7 @@ class VSETVLIInfo {
741767
if (Other.isUnknown())
742768
return isUnknown();
743769

744-
if (!hasSameAVL(Other))
770+
if (!hasSameAVLLatticeValue(Other))
745771
return false;
746772

747773
// If the SEWLMULRatioOnly bits are different, then they aren't equal.
@@ -849,6 +875,7 @@ class RISCVInsertVSETVLI : public MachineFunctionPass {
849875
const RISCVSubtarget *ST;
850876
const TargetInstrInfo *TII;
851877
MachineRegisterInfo *MRI;
878+
// Possibly null!
852879
LiveIntervals *LIS;
853880

854881
std::vector<BlockData> BlockInfo;
@@ -863,9 +890,9 @@ class RISCVInsertVSETVLI : public MachineFunctionPass {
863890
void getAnalysisUsage(AnalysisUsage &AU) const override {
864891
AU.setPreservesCFG();
865892

866-
AU.addRequired<LiveIntervals>();
893+
AU.addUsedIfAvailable<LiveIntervals>();
867894
AU.addPreserved<LiveIntervals>();
868-
AU.addRequired<SlotIndexes>();
895+
AU.addUsedIfAvailable<SlotIndexes>();
869896
AU.addPreserved<SlotIndexes>();
870897
AU.addPreserved<LiveDebugVariables>();
871898
AU.addPreserved<LiveStacks>();
@@ -1061,7 +1088,8 @@ void RISCVInsertVSETVLI::insertVSETVLI(MachineBasicBlock &MBB,
10611088
.addReg(RISCV::X0, RegState::Kill)
10621089
.addImm(Info.encodeVTYPE())
10631090
.addReg(RISCV::VL, RegState::Implicit);
1064-
LIS->InsertMachineInstrInMaps(*MI);
1091+
if (LIS)
1092+
LIS->InsertMachineInstrInMaps(*MI);
10651093
return;
10661094
}
10671095

@@ -1078,7 +1106,8 @@ void RISCVInsertVSETVLI::insertVSETVLI(MachineBasicBlock &MBB,
10781106
.addReg(RISCV::X0, RegState::Kill)
10791107
.addImm(Info.encodeVTYPE())
10801108
.addReg(RISCV::VL, RegState::Implicit);
1081-
LIS->InsertMachineInstrInMaps(*MI);
1109+
if (LIS)
1110+
LIS->InsertMachineInstrInMaps(*MI);
10821111
return;
10831112
}
10841113
}
@@ -1090,7 +1119,8 @@ void RISCVInsertVSETVLI::insertVSETVLI(MachineBasicBlock &MBB,
10901119
.addReg(RISCV::X0, RegState::Define | RegState::Dead)
10911120
.addImm(Info.getAVLImm())
10921121
.addImm(Info.encodeVTYPE());
1093-
LIS->InsertMachineInstrInMaps(*MI);
1122+
if (LIS)
1123+
LIS->InsertMachineInstrInMaps(*MI);
10941124
return;
10951125
}
10961126

@@ -1100,8 +1130,10 @@ void RISCVInsertVSETVLI::insertVSETVLI(MachineBasicBlock &MBB,
11001130
.addReg(DestReg, RegState::Define | RegState::Dead)
11011131
.addReg(RISCV::X0, RegState::Kill)
11021132
.addImm(Info.encodeVTYPE());
1103-
LIS->InsertMachineInstrInMaps(*MI);
1104-
LIS->createAndComputeVirtRegInterval(DestReg);
1133+
if (LIS) {
1134+
LIS->InsertMachineInstrInMaps(*MI);
1135+
LIS->createAndComputeVirtRegInterval(DestReg);
1136+
}
11051137
return;
11061138
}
11071139

@@ -1111,12 +1143,14 @@ void RISCVInsertVSETVLI::insertVSETVLI(MachineBasicBlock &MBB,
11111143
.addReg(RISCV::X0, RegState::Define | RegState::Dead)
11121144
.addReg(AVLReg)
11131145
.addImm(Info.encodeVTYPE());
1114-
LIS->InsertMachineInstrInMaps(*MI);
1115-
// Normally the AVL's live range will already extend past the inserted vsetvli
1116-
// because the pseudos below will already use the AVL. But this isn't always
1117-
// the case, e.g. PseudoVMV_X_S doesn't have an AVL operand.
1118-
LIS->getInterval(AVLReg).extendInBlock(
1119-
LIS->getMBBStartIdx(&MBB), LIS->getInstructionIndex(*MI).getRegSlot());
1146+
if (LIS) {
1147+
LIS->InsertMachineInstrInMaps(*MI);
1148+
// Normally the AVL's live range will already extend past the inserted
1149+
// vsetvli because the pseudos below will already use the AVL. But this
1150+
// isn't always the case, e.g. PseudoVMV_X_S doesn't have an AVL operand.
1151+
LIS->getInterval(AVLReg).extendInBlock(
1152+
LIS->getMBBStartIdx(&MBB), LIS->getInstructionIndex(*MI).getRegSlot());
1153+
}
11201154
}
11211155

11221156
/// Return true if a VSETVLI is required to transition from CurInfo to Require
@@ -1230,10 +1264,14 @@ void RISCVInsertVSETVLI::transferAfter(VSETVLIInfo &Info,
12301264
if (RISCV::isFaultFirstLoad(MI)) {
12311265
// Update AVL to vl-output of the fault first load.
12321266
assert(MI.getOperand(1).getReg().isVirtual());
1233-
auto &LI = LIS->getInterval(MI.getOperand(1).getReg());
1234-
SlotIndex SI = LIS->getSlotIndexes()->getInstructionIndex(MI).getRegSlot();
1235-
VNInfo *VNI = LI.getVNInfoAt(SI);
1236-
Info.setAVLRegDef(VNI, MI.getOperand(1).getReg());
1267+
if (LIS) {
1268+
auto &LI = LIS->getInterval(MI.getOperand(1).getReg());
1269+
SlotIndex SI =
1270+
LIS->getSlotIndexes()->getInstructionIndex(MI).getRegSlot();
1271+
VNInfo *VNI = LI.getVNInfoAt(SI);
1272+
Info.setAVLRegDef(VNI, MI.getOperand(1).getReg());
1273+
} else
1274+
Info.setAVLRegDef(nullptr, MI.getOperand(1).getReg());
12371275
return;
12381276
}
12391277

@@ -1327,6 +1365,9 @@ bool RISCVInsertVSETVLI::needVSETVLIPHI(const VSETVLIInfo &Require,
13271365
if (!Require.hasAVLReg())
13281366
return true;
13291367

1368+
if (!LIS)
1369+
return true;
1370+
13301371
// We need the AVL to have been produced by a PHI node in this basic block.
13311372
const VNInfo *Valno = Require.getAVLVNInfo();
13321373
if (!Valno->isPHIDef() || LIS->getMBBFromIndex(Valno->def) != &MBB)
@@ -1402,27 +1443,29 @@ void RISCVInsertVSETVLI::emitVSETVLIs(MachineBasicBlock &MBB) {
14021443
MachineOperand &VLOp = MI.getOperand(getVLOpNum(MI));
14031444
if (VLOp.isReg()) {
14041445
Register Reg = VLOp.getReg();
1405-
LiveInterval &LI = LIS->getInterval(Reg);
14061446

14071447
// Erase the AVL operand from the instruction.
14081448
VLOp.setReg(RISCV::NoRegister);
14091449
VLOp.setIsKill(false);
1410-
SmallVector<MachineInstr *> DeadMIs;
1411-
LIS->shrinkToUses(&LI, &DeadMIs);
1412-
// We might have separate components that need split due to
1413-
// needVSETVLIPHI causing us to skip inserting a new VL def.
1414-
SmallVector<LiveInterval *> SplitLIs;
1415-
LIS->splitSeparateComponents(LI, SplitLIs);
1416-
1417-
// If the AVL was an immediate > 31, then it would have been emitted
1418-
// as an ADDI. However, the ADDI might not have been used in the
1419-
// vsetvli, or a vsetvli might not have been emitted, so it may be
1420-
// dead now.
1421-
for (MachineInstr *DeadMI : DeadMIs) {
1422-
if (!TII->isAddImmediate(*DeadMI, Reg))
1423-
continue;
1424-
LIS->RemoveMachineInstrFromMaps(*DeadMI);
1425-
DeadMI->eraseFromParent();
1450+
if (LIS) {
1451+
LiveInterval &LI = LIS->getInterval(Reg);
1452+
SmallVector<MachineInstr *> DeadMIs;
1453+
LIS->shrinkToUses(&LI, &DeadMIs);
1454+
// We might have separate components that need split due to
1455+
// needVSETVLIPHI causing us to skip inserting a new VL def.
1456+
SmallVector<LiveInterval *> SplitLIs;
1457+
LIS->splitSeparateComponents(LI, SplitLIs);
1458+
1459+
// If the AVL was an immediate > 31, then it would have been emitted
1460+
// as an ADDI. However, the ADDI might not have been used in the
1461+
// vsetvli, or a vsetvli might not have been emitted, so it may be
1462+
// dead now.
1463+
for (MachineInstr *DeadMI : DeadMIs) {
1464+
if (!TII->isAddImmediate(*DeadMI, Reg))
1465+
continue;
1466+
LIS->RemoveMachineInstrFromMaps(*DeadMI);
1467+
DeadMI->eraseFromParent();
1468+
}
14261469
}
14271470
}
14281471
MI.addOperand(MachineOperand::CreateReg(RISCV::VL, /*isDef*/ false,
@@ -1479,6 +1522,9 @@ void RISCVInsertVSETVLI::doPRE(MachineBasicBlock &MBB) {
14791522
if (!UnavailablePred || !AvailableInfo.isValid())
14801523
return;
14811524

1525+
if (!LIS)
1526+
return;
1527+
14821528
// If we don't know the exact VTYPE, we can't copy the vsetvli to the exit of
14831529
// the unavailable pred.
14841530
if (AvailableInfo.hasSEWLMULRatioOnly())
@@ -1625,7 +1671,7 @@ void RISCVInsertVSETVLI::coalesceVSETVLIs(MachineBasicBlock &MBB) const {
16251671

16261672
// The def of DefReg moved to MI, so extend the LiveInterval up to
16271673
// it.
1628-
if (DefReg.isVirtual()) {
1674+
if (DefReg.isVirtual() && LIS) {
16291675
LiveInterval &DefLI = LIS->getInterval(DefReg);
16301676
SlotIndex MISlot = LIS->getInstructionIndex(MI).getRegSlot();
16311677
VNInfo *DefVNI = DefLI.getVNInfoAt(DefLI.beginIndex());
@@ -1654,13 +1700,15 @@ void RISCVInsertVSETVLI::coalesceVSETVLIs(MachineBasicBlock &MBB) const {
16541700

16551701
if (OldVLReg && OldVLReg.isVirtual()) {
16561702
// NextMI no longer uses OldVLReg so shrink its LiveInterval.
1657-
LIS->shrinkToUses(&LIS->getInterval(OldVLReg));
1703+
if (LIS)
1704+
LIS->shrinkToUses(&LIS->getInterval(OldVLReg));
16581705

16591706
MachineInstr *VLOpDef = MRI->getUniqueVRegDef(OldVLReg);
16601707
if (VLOpDef && TII->isAddImmediate(*VLOpDef, OldVLReg) &&
16611708
MRI->use_nodbg_empty(OldVLReg)) {
16621709
VLOpDef->eraseFromParent();
1663-
LIS->removeInterval(OldVLReg);
1710+
if (LIS)
1711+
LIS->removeInterval(OldVLReg);
16641712
}
16651713
}
16661714
MI.setDesc(NextMI->getDesc());
@@ -1676,7 +1724,8 @@ void RISCVInsertVSETVLI::coalesceVSETVLIs(MachineBasicBlock &MBB) const {
16761724

16771725
NumCoalescedVSETVL += ToDelete.size();
16781726
for (auto *MI : ToDelete) {
1679-
LIS->RemoveMachineInstrFromMaps(*MI);
1727+
if (LIS)
1728+
LIS->RemoveMachineInstrFromMaps(*MI);
16801729
MI->eraseFromParent();
16811730
}
16821731
}
@@ -1691,12 +1740,14 @@ void RISCVInsertVSETVLI::insertReadVL(MachineBasicBlock &MBB) {
16911740
auto ReadVLMI = BuildMI(MBB, I, MI.getDebugLoc(),
16921741
TII->get(RISCV::PseudoReadVL), VLOutput);
16931742
// Move the LiveInterval's definition down to PseudoReadVL.
1694-
SlotIndex NewDefSI =
1695-
LIS->InsertMachineInstrInMaps(*ReadVLMI).getRegSlot();
1696-
LiveInterval &DefLI = LIS->getInterval(VLOutput);
1697-
VNInfo *DefVNI = DefLI.getVNInfoAt(DefLI.beginIndex());
1698-
DefLI.removeSegment(DefLI.beginIndex(), NewDefSI);
1699-
DefVNI->def = NewDefSI;
1743+
if (LIS) {
1744+
SlotIndex NewDefSI =
1745+
LIS->InsertMachineInstrInMaps(*ReadVLMI).getRegSlot();
1746+
LiveInterval &DefLI = LIS->getInterval(VLOutput);
1747+
VNInfo *DefVNI = DefLI.getVNInfoAt(DefLI.beginIndex());
1748+
DefLI.removeSegment(DefLI.beginIndex(), NewDefSI);
1749+
DefVNI->def = NewDefSI;
1750+
}
17001751
}
17011752
// We don't use the vl output of the VLEFF/VLSEGFF anymore.
17021753
MI.getOperand(1).setReg(RISCV::X0);
@@ -1714,7 +1765,7 @@ bool RISCVInsertVSETVLI::runOnMachineFunction(MachineFunction &MF) {
17141765

17151766
TII = ST->getInstrInfo();
17161767
MRI = &MF.getRegInfo();
1717-
LIS = &getAnalysis<LiveIntervals>();
1768+
LIS = getAnalysisIfAvailable<LiveIntervals>();
17181769

17191770
assert(BlockInfo.empty() && "Expect empty block infos");
17201771
BlockInfo.resize(MF.getNumBlockIDs());

llvm/test/CodeGen/RISCV/O0-pipeline.ll

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -47,9 +47,6 @@
4747
; CHECK-NEXT: Eliminate PHI nodes for register allocation
4848
; CHECK-NEXT: Two-Address instruction pass
4949
; CHECK-NEXT: Fast Register Allocator
50-
; CHECK-NEXT: MachineDominator Tree Construction
51-
; CHECK-NEXT: Slot index numbering
52-
; CHECK-NEXT: Live Interval Analysis
5350
; CHECK-NEXT: RISC-V Insert VSETVLI pass
5451
; CHECK-NEXT: Fast Register Allocator
5552
; CHECK-NEXT: Remove Redundant DEBUG_VALUE analysis
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 5
2+
; RUN: llc -mtriple=riscv64 -O0 < %s | FileCheck %s
3+
4+
; Make sure we don't run LiveIntervals at O0, otherwise it will crash when
5+
; running on this unreachable block.
6+
7+
define i16 @f() {
8+
; CHECK-LABEL: f:
9+
; CHECK: # %bb.0: # %BB
10+
; CHECK-NEXT: addi sp, sp, -16
11+
; CHECK-NEXT: .cfi_def_cfa_offset 16
12+
; CHECK-NEXT: j .LBB0_1
13+
; CHECK-NEXT: .LBB0_1: # %BB1
14+
; CHECK-NEXT: # =>This Inner Loop Header: Depth=1
15+
; CHECK-NEXT: li a0, 0
16+
; CHECK-NEXT: sd a0, 8(sp) # 8-byte Folded Spill
17+
; CHECK-NEXT: j .LBB0_1
18+
; CHECK-NEXT: # %bb.2: # %BB1
19+
; CHECK-NEXT: li a0, 0
20+
; CHECK-NEXT: bnez a0, .LBB0_1
21+
; CHECK-NEXT: j .LBB0_3
22+
; CHECK-NEXT: .LBB0_3: # %BB2
23+
; CHECK-NEXT: ld a0, 8(sp) # 8-byte Folded Reload
24+
; CHECK-NEXT: addi sp, sp, 16
25+
; CHECK-NEXT: ret
26+
BB:
27+
br label %BB1
28+
29+
BB1:
30+
%A = or i16 0, 0
31+
%B = fcmp true float 0.000000e+00, 0.000000e+00
32+
%C = or i1 %B, false
33+
br i1 %C, label %BB1, label %BB2
34+
35+
BB2:
36+
ret i16 %A
37+
}

0 commit comments

Comments
 (0)