Skip to content

Commit 4f9d5a8

Browse files
authored
[RISCV] Generate Xqcilsm LWMI/SWMI load/store multiple instructions (#171079)
This patch adds support for generating the Xqcilsm load/store multiple instructions as a part of the RISCVLoadStoreOptimizer pass. For now we only combine two load/store instructions into a load/store multiple. Support for converting more loads/stores will be added in follow-up patches. These instructions are only applicable for 32-bit loads/stores with an alignment of 4-bytes.
1 parent 426cedc commit 4f9d5a8

File tree

2 files changed

+427
-10
lines changed

2 files changed

+427
-10
lines changed

llvm/lib/Target/RISCV/RISCVLoadStoreOptimizer.cpp

Lines changed: 112 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,12 @@ struct RISCVLoadStoreOpt : public MachineFunctionPass {
7070
// Convert load/store pairs to single instructions.
7171
bool tryConvertToLdStPair(MachineBasicBlock::iterator First,
7272
MachineBasicBlock::iterator Second);
73+
bool tryConvertToXqcilsmLdStPair(MachineFunction *MF,
74+
MachineBasicBlock::iterator First,
75+
MachineBasicBlock::iterator Second);
76+
bool tryConvertToMIPSLdStPair(MachineFunction *MF,
77+
MachineBasicBlock::iterator First,
78+
MachineBasicBlock::iterator Second);
7379

7480
// Scan the instructions looking for a load/store that can be combined
7581
// with the current instruction into a load/store pair.
@@ -114,7 +120,7 @@ bool RISCVLoadStoreOpt::runOnMachineFunction(MachineFunction &Fn) {
114120
ModifiedRegUnits.init(*TRI);
115121
UsedRegUnits.init(*TRI);
116122

117-
if (Subtarget.useMIPSLoadStorePairs()) {
123+
if (Subtarget.useMIPSLoadStorePairs() || Subtarget.hasVendorXqcilsm()) {
118124
for (MachineBasicBlock &MBB : Fn) {
119125
LLVM_DEBUG(dbgs() << "MBB: " << MBB.getName() << "\n");
120126

@@ -168,14 +174,93 @@ bool RISCVLoadStoreOpt::tryToPairLdStInst(MachineBasicBlock::iterator &MBBI) {
168174
return false;
169175
}
170176

171-
// Merge two adjacent load/store instructions into a paired instruction
172-
// (LDP/SDP/SWP/LWP) if the effective address is 8-byte aligned in case of
173-
// SWP/LWP 16-byte aligned in case of LDP/SDP. This function selects the
174-
// appropriate paired opcode, verifies that the memory operand is properly
175-
// aligned, and checks that the offset is valid. If all conditions are met, it
176-
// builds and inserts the paired instruction.
177-
bool RISCVLoadStoreOpt::tryConvertToLdStPair(
178-
MachineBasicBlock::iterator First, MachineBasicBlock::iterator Second) {
177+
bool RISCVLoadStoreOpt::tryConvertToXqcilsmLdStPair(
178+
MachineFunction *MF, MachineBasicBlock::iterator First,
179+
MachineBasicBlock::iterator Second) {
180+
unsigned Opc = First->getOpcode();
181+
if ((Opc != RISCV::LW && Opc != RISCV::SW) || Second->getOpcode() != Opc)
182+
return false;
183+
184+
const auto &FirstOp1 = First->getOperand(1);
185+
const auto &SecondOp1 = Second->getOperand(1);
186+
const auto &FirstOp2 = First->getOperand(2);
187+
const auto &SecondOp2 = Second->getOperand(2);
188+
189+
// Require simple reg+imm addressing for both.
190+
if (!FirstOp1.isReg() || !SecondOp1.isReg() || !FirstOp2.isImm() ||
191+
!SecondOp2.isImm())
192+
return false;
193+
194+
Register Base1 = FirstOp1.getReg();
195+
Register Base2 = SecondOp1.getReg();
196+
197+
if (Base1 != Base2)
198+
return false;
199+
200+
const MachineMemOperand *MMO = *First->memoperands_begin();
201+
Align MMOAlign = MMO->getAlign();
202+
203+
if (MMOAlign < Align(4))
204+
return false;
205+
206+
auto &FirstOp0 = First->getOperand(0);
207+
auto &SecondOp0 = Second->getOperand(0);
208+
209+
int64_t Off1 = FirstOp2.getImm();
210+
int64_t Off2 = SecondOp2.getImm();
211+
212+
if (Off2 < Off1) {
213+
std::swap(FirstOp0, SecondOp0);
214+
std::swap(Off1, Off2);
215+
}
216+
217+
Register StartReg = FirstOp0.getReg();
218+
Register NextReg = SecondOp0.getReg();
219+
220+
if (StartReg == RISCV::X0 || NextReg == RISCV::X0)
221+
return false;
222+
223+
// If the base reg gets overwritten by one of the loads then bail out.
224+
if (Opc == RISCV::LW && (StartReg == Base1 || NextReg == Base1))
225+
return false;
226+
227+
if (!isShiftedUInt<5, 2>(Off1) || (Off2 - Off1 != 4))
228+
return false;
229+
230+
if (NextReg != StartReg + 1)
231+
return false;
232+
233+
unsigned XqciOpc = (Opc == RISCV::LW) ? RISCV::QC_LWMI : RISCV::QC_SWMI;
234+
235+
auto StartRegState = (Opc == RISCV::LW) ? RegState::Define
236+
: getKillRegState(FirstOp0.isKill());
237+
auto NextRegState =
238+
(Opc == RISCV::LW)
239+
? RegState::ImplicitDefine
240+
: (RegState::Implicit | getKillRegState(SecondOp0.isKill()));
241+
242+
DebugLoc DL =
243+
First->getDebugLoc() ? First->getDebugLoc() : Second->getDebugLoc();
244+
MachineInstrBuilder MIB = BuildMI(*MF, DL, TII->get(XqciOpc));
245+
MIB.addReg(StartReg, StartRegState)
246+
.addReg(Base1, getKillRegState(FirstOp1.isKill() || SecondOp1.isKill()))
247+
.addImm(2)
248+
.addImm(Off1)
249+
.cloneMergedMemRefs({&*First, &*Second})
250+
.addReg(NextReg, NextRegState);
251+
252+
First->getParent()->insert(First, MIB);
253+
First->removeFromParent();
254+
Second->removeFromParent();
255+
256+
return true;
257+
}
258+
259+
bool RISCVLoadStoreOpt::tryConvertToMIPSLdStPair(
260+
MachineFunction *MF, MachineBasicBlock::iterator First,
261+
MachineBasicBlock::iterator Second) {
262+
// Try converting to SWP/LWP/LDP/SDP.
263+
// SWP/LWP requires 8-byte alignment whereas LDP/SDP needs 16-byte alignment.
179264
unsigned PairOpc;
180265
Align RequiredAlignment;
181266
switch (First->getOpcode()) {
@@ -199,7 +284,6 @@ bool RISCVLoadStoreOpt::tryConvertToLdStPair(
199284
break;
200285
}
201286

202-
MachineFunction *MF = First->getMF();
203287
const MachineMemOperand *MMO = *First->memoperands_begin();
204288
Align MMOAlign = MMO->getAlign();
205289

@@ -227,6 +311,24 @@ bool RISCVLoadStoreOpt::tryConvertToLdStPair(
227311
return true;
228312
}
229313

314+
// Merge two adjacent load/store instructions into a paired instruction.
315+
// This function calls the vendor specific implementation that seelects the
316+
// appropriate paired opcode, verifies that the memory operand is properly
317+
// aligned, and checks that the offset is valid. If all conditions are met, it
318+
// builds and inserts the paired instruction.
319+
bool RISCVLoadStoreOpt::tryConvertToLdStPair(
320+
MachineBasicBlock::iterator First, MachineBasicBlock::iterator Second) {
321+
MachineFunction *MF = First->getMF();
322+
const RISCVSubtarget &STI = MF->getSubtarget<RISCVSubtarget>();
323+
324+
// Try converting to QC_LWMI/QC_SWMI if the XQCILSM extension is enabled.
325+
if (!STI.is64Bit() && STI.hasVendorXqcilsm())
326+
return tryConvertToXqcilsmLdStPair(MF, First, Second);
327+
328+
// Else try to convert them into MIPS Paired Loads/Stores.
329+
return tryConvertToMIPSLdStPair(MF, First, Second);
330+
}
331+
230332
static bool mayAlias(MachineInstr &MIa,
231333
SmallVectorImpl<MachineInstr *> &MemInsns,
232334
AliasAnalysis *AA) {

0 commit comments

Comments
 (0)