@@ -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+
230332static bool mayAlias (MachineInstr &MIa,
231333 SmallVectorImpl<MachineInstr *> &MemInsns,
232334 AliasAnalysis *AA) {
0 commit comments