Skip to content

Commit 27d71e4

Browse files
committed
[RISCV] Enable early if-conversion.
Implements the necessary target methods (insertSelect, canInsertSelect) and adds early if-conversion to the RISCV pipeline. Doing if-conversion increases the number of executed instructions, so it only makes sense if there is enough ILP.
1 parent 7273ad1 commit 27d71e4

File tree

6 files changed

+159
-1
lines changed

6 files changed

+159
-1
lines changed

llvm/lib/CodeGen/EarlyIfConversion.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -879,7 +879,7 @@ bool EarlyIfConverter::shouldConvertIf() {
879879
// from a loop-invariant address predictable; we were unable to prove that it
880880
// doesn't alias any of the memory-writes in the loop, but it is likely to
881881
// read to same value multiple times.
882-
if (CurrentLoop && any_of(IfConv.Cond, [&](MachineOperand &MO) {
882+
if (CurrentLoop && all_of(IfConv.Cond, [&](MachineOperand &MO) {
883883
if (!MO.isReg() || !MO.isUse())
884884
return false;
885885
Register Reg = MO.getReg();

llvm/lib/Target/RISCV/RISCVInstrInfo.cpp

Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1446,6 +1446,127 @@ RISCVInstrInfo::optimizeSelect(MachineInstr &MI,
14461446
return NewMI;
14471447
}
14481448

1449+
int RISCVInstrInfo::getICmpCost(unsigned CC,
1450+
const TargetSchedModel &SchedModel) const {
1451+
switch (CC) {
1452+
default:
1453+
llvm_unreachable("Unknown condition code!");
1454+
case RISCVCC::COND_LT:
1455+
return SchedModel.computeInstrLatency(RISCV::SLT);
1456+
case RISCVCC::COND_LTU:
1457+
return SchedModel.computeInstrLatency(RISCV::SLTU);
1458+
case RISCVCC::COND_EQ:
1459+
return SchedModel.computeInstrLatency(RISCV::XOR) +
1460+
SchedModel.computeInstrLatency(RISCV::SLTIU);
1461+
case RISCVCC::COND_NE:
1462+
return SchedModel.computeInstrLatency(RISCV::XOR) +
1463+
SchedModel.computeInstrLatency(RISCV::SLTU);
1464+
case RISCVCC::COND_GE:
1465+
return SchedModel.computeInstrLatency(RISCV::XORI) +
1466+
SchedModel.computeInstrLatency(RISCV::SLT);
1467+
case RISCVCC::COND_GEU:
1468+
return SchedModel.computeInstrLatency(RISCV::XORI) +
1469+
SchedModel.computeInstrLatency(RISCV::SLTU);
1470+
}
1471+
}
1472+
1473+
void RISCVInstrInfo::insertICmp(MachineBasicBlock &MBB,
1474+
MachineBasicBlock::iterator MI,
1475+
const DebugLoc &DL, Register DstReg,
1476+
ArrayRef<MachineOperand> Cond) const {
1477+
MachineRegisterInfo &MRI = MI->getParent()->getParent()->getRegInfo();
1478+
unsigned CC = Cond[0].getImm();
1479+
Register LHSReg = Cond[1].getReg();
1480+
Register RHSReg = Cond[2].getReg();
1481+
1482+
switch (CC) {
1483+
default:
1484+
llvm_unreachable("Unknown condition code!");
1485+
case RISCVCC::COND_LT:
1486+
case RISCVCC::COND_LTU: {
1487+
BuildMI(MBB, MI, DL, get(CC == RISCVCC::COND_LT ? RISCV::SLT : RISCV::SLTU),
1488+
DstReg)
1489+
.addReg(LHSReg)
1490+
.addReg(RHSReg);
1491+
return;
1492+
}
1493+
case RISCVCC::COND_EQ:
1494+
case RISCVCC::COND_NE: {
1495+
Register XorReg = MRI.createVirtualRegister(&RISCV::GPRRegClass);
1496+
BuildMI(MBB, MI, DL, get(RISCV::XOR), XorReg).addReg(LHSReg).addReg(RHSReg);
1497+
if (CC == RISCVCC::COND_EQ) {
1498+
BuildMI(MBB, MI, DL, get(RISCV::SLTIU), DstReg).addReg(XorReg).addImm(1);
1499+
return;
1500+
} else {
1501+
BuildMI(MBB, MI, DL, get(RISCV::SLTU), DstReg)
1502+
.addReg(RISCV::X0)
1503+
.addReg(XorReg);
1504+
return;
1505+
}
1506+
}
1507+
case RISCVCC::COND_GE:
1508+
case RISCVCC::COND_GEU: {
1509+
Register NotCCReg = MRI.createVirtualRegister(&RISCV::GPRRegClass);
1510+
BuildMI(MBB, MI, DL, get(CC == RISCVCC::COND_GE ? RISCV::SLT : RISCV::SLTU),
1511+
NotCCReg)
1512+
.addReg(LHSReg)
1513+
.addReg(RHSReg);
1514+
BuildMI(MBB, MI, DL, get(RISCV::XORI), DstReg).addReg(NotCCReg).addImm(1);
1515+
return;
1516+
}
1517+
}
1518+
}
1519+
1520+
void RISCVInstrInfo::insertSelect(MachineBasicBlock &MBB,
1521+
MachineBasicBlock::iterator MI,
1522+
const DebugLoc &DL, Register DstReg,
1523+
ArrayRef<MachineOperand> Cond,
1524+
Register TrueReg, Register FalseReg) const {
1525+
MachineFunction &MF = *MI->getParent()->getParent();
1526+
const RISCVSubtarget &ST = MF.getSubtarget<RISCVSubtarget>();
1527+
MachineRegisterInfo &MRI = MF.getRegInfo();
1528+
1529+
Register CCReg = MRI.createVirtualRegister(&RISCV::GPRRegClass);
1530+
insertICmp(MBB, MI, DL, CCReg, Cond);
1531+
unsigned CondZeroEqzOpc =
1532+
ST.hasVendorXVentanaCondOps() ? RISCV::VT_MASKC : RISCV::CZERO_EQZ;
1533+
unsigned CondZeroNezOpc =
1534+
ST.hasVendorXVentanaCondOps() ? RISCV::VT_MASKCN : RISCV::CZERO_NEZ;
1535+
Register TrueValOrZeroReg = MRI.createVirtualRegister(&RISCV::GPRRegClass);
1536+
Register FalseValOrZeroReg = MRI.createVirtualRegister(&RISCV::GPRRegClass);
1537+
BuildMI(MBB, MI, DL, get(CondZeroEqzOpc), TrueValOrZeroReg)
1538+
.addReg(TrueReg)
1539+
.addReg(CCReg);
1540+
BuildMI(MBB, MI, DL, get(CondZeroNezOpc), FalseValOrZeroReg)
1541+
.addReg(FalseReg)
1542+
.addReg(CCReg);
1543+
BuildMI(MBB, MI, DL, get(RISCV::OR), DstReg)
1544+
.addReg(TrueValOrZeroReg)
1545+
.addReg(FalseValOrZeroReg);
1546+
return;
1547+
}
1548+
1549+
bool RISCVInstrInfo::canInsertSelect(const MachineBasicBlock &MBB,
1550+
ArrayRef<MachineOperand> Cond,
1551+
Register DstReg, Register TrueReg,
1552+
Register FalseReg, int &CondCycles,
1553+
int &TrueCycles, int &FalseCycles) const {
1554+
TargetSchedModel SchedModel;
1555+
SchedModel.init(&STI);
1556+
1557+
CondCycles = getICmpCost(Cond[0].getImm(), SchedModel);
1558+
TrueCycles = SchedModel.computeInstrLatency(RISCV::OR) +
1559+
SchedModel.computeInstrLatency(STI.hasVendorXVentanaCondOps()
1560+
? RISCV::VT_MASKC
1561+
: RISCV::CZERO_EQZ);
1562+
FalseCycles = SchedModel.computeInstrLatency(RISCV::OR) +
1563+
SchedModel.computeInstrLatency(STI.hasVendorXVentanaCondOps()
1564+
? RISCV::VT_MASKCN
1565+
: RISCV::CZERO_NEZ);
1566+
1567+
return true;
1568+
}
1569+
14491570
unsigned RISCVInstrInfo::getInstSizeInBytes(const MachineInstr &MI) const {
14501571
if (MI.isMetaInstruction())
14511572
return 0;

llvm/lib/Target/RISCV/RISCVInstrInfo.h

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,20 @@ class RISCVInstrInfo : public RISCVGenInstrInfo {
149149
SmallPtrSetImpl<MachineInstr *> &SeenMIs,
150150
bool) const override;
151151

152+
int getICmpCost(unsigned CC, const TargetSchedModel &SchedModel) const;
153+
void insertICmp(MachineBasicBlock &MBB, MachineBasicBlock::iterator MI,
154+
const DebugLoc &DL, Register DstReg,
155+
ArrayRef<MachineOperand> Cond) const;
156+
157+
bool canInsertSelect(const MachineBasicBlock &, ArrayRef<MachineOperand> Cond,
158+
Register, Register, Register, int &, int &,
159+
int &) const override;
160+
161+
void insertSelect(MachineBasicBlock &MBB, MachineBasicBlock::iterator MI,
162+
const DebugLoc &DL, Register DstReg,
163+
ArrayRef<MachineOperand> Cond, Register TrueReg,
164+
Register FalseReg) const override;
165+
152166
bool isAsCheapAsAMove(const MachineInstr &MI) const override;
153167

154168
std::optional<DestSourcePair>

llvm/lib/Target/RISCV/RISCVSubtarget.cpp

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,11 @@ static cl::opt<unsigned> RISCVMinimumJumpTableEntries(
6565
"riscv-min-jump-table-entries", cl::Hidden,
6666
cl::desc("Set minimum number of entries to use a jump table on RISCV"));
6767

68+
static cl::opt<bool>
69+
RISCVDisableEarlyIfcvt("riscv-disable-early-ifcvt", cl::Hidden,
70+
cl::desc("Disable early if-conversion"),
71+
cl::init(true), cl::Hidden);
72+
6873
void RISCVSubtarget::anchor() {}
6974

7075
RISCVSubtarget &
@@ -203,3 +208,11 @@ unsigned RISCVSubtarget::getMinimumJumpTableEntries() const {
203208
? RISCVMinimumJumpTableEntries
204209
: TuneInfo->MinimumJumpTableEntries;
205210
}
211+
212+
bool RISCVSubtarget::enableEarlyIfConversion() const {
213+
TargetSchedModel SchedModel;
214+
SchedModel.init(this);
215+
return !RISCVDisableEarlyIfcvt &&
216+
(hasStdExtZicond() || hasVendorXVentanaCondOps()) &&
217+
SchedModel.hasInstrSchedModelOrItineraries();
218+
}

llvm/lib/Target/RISCV/RISCVSubtarget.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -303,6 +303,8 @@ class RISCVSubtarget : public RISCVGenSubtargetInfo {
303303
unsigned getMinimumJumpTableEntries() const;
304304

305305
bool supportsInitUndef() const override { return hasVInstructions(); }
306+
307+
bool enableEarlyIfConversion() const override;
306308
};
307309
} // End llvm namespace
308310

llvm/lib/Target/RISCV/RISCVTargetMachine.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -349,6 +349,7 @@ class RISCVPassConfig : public TargetPassConfig {
349349
bool addPreISel() override;
350350
void addCodeGenPrepare() override;
351351
bool addInstSelector() override;
352+
bool addILPOpts() override;
352353
bool addIRTranslator() override;
353354
void addPreLegalizeMachineIR() override;
354355
bool addLegalizeMachineIR() override;
@@ -450,6 +451,13 @@ bool RISCVPassConfig::addInstSelector() {
450451
return false;
451452
}
452453

454+
bool RISCVPassConfig::addILPOpts() {
455+
if (getOptLevel() != CodeGenOptLevel::None) {
456+
addPass(&EarlyIfConverterID);
457+
}
458+
return true;
459+
}
460+
453461
bool RISCVPassConfig::addIRTranslator() {
454462
addPass(new IRTranslator(getOptLevel()));
455463
return false;

0 commit comments

Comments
 (0)