LLVM 24.0.0git
RISCVLoadStoreOptimizer.cpp
Go to the documentation of this file.
1//===----- RISCVLoadStoreOptimizer.cpp ------------------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// Load/Store Pairing: It identifies pairs of load or store instructions
10// operating on consecutive memory locations and merges them into a single
11// paired instruction, leveraging hardware support for paired memory accesses.
12// Much of the pairing logic is adapted from the AArch64LoadStoreOpt pass.
13//
14// Post-allocation Zilsd decomposition: Fixes invalid LD/SD instructions if
15// register allocation didn't provide suitable consecutive registers.
16//
17// NOTE: The AArch64LoadStoreOpt pass performs additional optimizations such as
18// merging zero store instructions, promoting loads that read directly from a
19// preceding store, and merging base register updates with load/store
20// instructions (via pre-/post-indexed addressing). These advanced
21// transformations are not yet implemented in the RISC-V pass but represent
22// potential future enhancements for further optimizing RISC-V memory
23// operations.
24//
25//===----------------------------------------------------------------------===//
26
27#include "RISCV.h"
28#include "RISCVTargetMachine.h"
30#include "llvm/ADT/Statistic.h"
34#include "llvm/CodeGen/Passes.h"
35#include "llvm/IR/Analysis.h"
37#include "llvm/Support/Debug.h"
39
40using namespace llvm;
41
42#define DEBUG_TYPE "riscv-load-store-opt"
43#define RISCV_LOAD_STORE_OPT_NAME "RISC-V Load / Store Optimizer"
44
45STATISTIC(NumLD2LW, "Number of LD instructions split back to LW");
46STATISTIC(NumSD2SW, "Number of SD instructions split back to SW");
47
48namespace {
49
50class RISCVLoadStoreOptLegacy : public MachineFunctionPass {
51public:
52 static char ID;
53 bool runOnMachineFunction(MachineFunction &Fn) override;
54
55 RISCVLoadStoreOptLegacy() : MachineFunctionPass(ID) {}
56
57 MachineFunctionProperties getRequiredProperties() const override {
58 return MachineFunctionProperties().setNoVRegs();
59 }
60
61 void getAnalysisUsage(AnalysisUsage &AU) const override {
62 AU.setPreservesCFG();
63 AU.addRequired<AAResultsWrapperPass>();
64 AU.addPreserved<MachineRegisterClassInfoWrapperPass>();
66 }
67
68 StringRef getPassName() const override { return RISCV_LOAD_STORE_OPT_NAME; }
69};
70
71class RISCVLoadStoreOptImpl {
72 // Find and pair load/store instructions.
73 bool tryToPairLdStInst(MachineBasicBlock::iterator &MBBI);
74
75 // Convert load/store pairs to single instructions.
76 bool tryConvertToLdStPair(MachineBasicBlock::iterator First,
78 bool tryConvertToXqcilsmLdStPair(MachineFunction *MF,
81 bool tryConvertToXqcilsmMultiLdSt(MachineBasicBlock::iterator &First);
82 bool tryConvertToMIPSLdStPair(MachineFunction *MF,
85
86 // Scan the instructions looking for a load/store that can be combined
87 // with the current instruction into a load/store pair.
88 // Return the matching instruction if one is found, else MBB->end().
90 bool &MergeForward);
91
93 mergePairedInsns(MachineBasicBlock::iterator I,
94 MachineBasicBlock::iterator Paired, bool MergeForward);
95
96 // Post reg-alloc zilsd part
97 bool fixInvalidRegPairOp(MachineBasicBlock &MBB,
99 bool isValidZilsdRegPair(Register First, Register Second);
100 void splitLdSdIntoTwo(MachineBasicBlock &MBB,
101 MachineBasicBlock::iterator &MBBI, bool IsLoad);
102
103 AliasAnalysis *AA;
104 MachineRegisterInfo *MRI;
105 const RISCVInstrInfo *TII;
106 const RISCVRegisterInfo *TRI;
107 const RISCVSubtarget *STI = nullptr;
108 LiveRegUnits ModifiedRegUnits, UsedRegUnits;
109
110public:
111 bool runOnMachineFunction(MachineFunction &MF,
112 function_ref<AliasAnalysis *()> GetAA);
113};
114} // end anonymous namespace
115
116char RISCVLoadStoreOptLegacy::ID = 0;
118 false, false)
119
120bool RISCVLoadStoreOptImpl::runOnMachineFunction(
122
123 bool MadeChange = false;
124 STI = &MF.getSubtarget<RISCVSubtarget>();
125 TII = STI->getInstrInfo();
126 TRI = STI->getRegisterInfo();
127 MRI = &MF.getRegInfo();
128 AA = GetAA();
129 ModifiedRegUnits.init(*TRI);
130 UsedRegUnits.init(*TRI);
131
132 if (STI->useMIPSLoadStorePairs() || STI->hasVendorXqcilsm()) {
133 for (MachineBasicBlock &MBB : MF) {
134 LLVM_DEBUG(dbgs() << "MBB: " << MBB.getName() << "\n");
135
136 for (MachineBasicBlock::iterator MBBI = MBB.begin(), E = MBB.end();
137 MBBI != E;) {
138 if (TII->isPairableLdStInstOpc(MBBI->getOpcode()) &&
139 tryToPairLdStInst(MBBI))
140 MadeChange = true;
141 else
142 ++MBBI;
143 }
144 }
145 }
146
147 if (!STI->is64Bit() && STI->hasStdExtZilsd()) {
148 for (auto &MBB : MF) {
149 for (auto MBBI = MBB.begin(), E = MBB.end(); MBBI != E;) {
150 if (fixInvalidRegPairOp(MBB, MBBI)) {
151 MadeChange = true;
152 // Iterator was updated by fixInvalidRegPairOp
153 } else {
154 ++MBBI;
155 }
156 }
157 }
158 }
159
160 return MadeChange;
161}
162
163// Find loads and stores that can be merged into a single load or store pair
164// instruction.
165bool RISCVLoadStoreOptImpl::tryToPairLdStInst(
167 MachineInstr &MI = *MBBI;
168
169 // If this is volatile, it is not a candidate.
170 if (MI.hasOrderedMemoryRef())
171 return false;
172
173 if (!TII->isLdStSafeToPair(MI, TRI))
174 return false;
175
176 // If Xqcilsm is available, first try to form a multi-instruction group (>2).
177 if (!STI->is64Bit() && STI->hasVendorXqcilsm()) {
178 if (tryConvertToXqcilsmMultiLdSt(MBBI))
179 return true;
180 }
181
182 // Look ahead for a pairable instruction.
183 MachineBasicBlock::iterator E = MI.getParent()->end();
184 bool MergeForward;
185 MachineBasicBlock::iterator Paired = findMatchingInsn(MBBI, MergeForward);
186 if (Paired != E) {
187 MBBI = mergePairedInsns(MBBI, Paired, MergeForward);
188 return true;
189 }
190 return false;
191}
192
193static bool isMemOpAligned(MachineInstr &MI, Align RequiredAlignment) {
194 const MachineMemOperand *MMO = *MI.memoperands_begin();
195 Align MMOAlign = MMO->getAlign();
196 return MMOAlign >= RequiredAlignment;
197}
198
199// Convert set of 3 or more LW/SW instructions to QC_LWMI/QC_SWMI/QC_SETWMI.
200// For now this only handles consecutive loads and stores traversing the basic
201// block top-down.
202// TODO: Traverse the basic block bottom-up as well.
203bool RISCVLoadStoreOptImpl::tryConvertToXqcilsmMultiLdSt(
205 MachineInstr &FirstMI = *FirstIt;
206 MachineFunction *MF = FirstMI.getMF();
207
208 if (STI->is64Bit() || !STI->hasVendorXqcilsm())
209 return false;
210
211 unsigned Opc = FirstMI.getOpcode();
212 if (Opc != RISCV::LW && Opc != RISCV::SW)
213 return false;
214
215 if (!FirstMI.hasOneMemOperand())
216 return false;
217
218 if (!isMemOpAligned(FirstMI, Align(4)))
219 return false;
220
221 // Require simple reg+imm addressing.
222 const MachineOperand &BaseOp = FirstMI.getOperand(1);
223 const MachineOperand &OffOp = FirstMI.getOperand(2);
224 if (!BaseOp.isReg() || !OffOp.isImm())
225 return false;
226
227 Register Base = BaseOp.getReg();
228 int64_t BaseOff = OffOp.getImm();
229
230 if (!isShiftedUInt<5, 2>(BaseOff))
231 return false;
232
233 Register StartReg = FirstMI.getOperand(0).getReg();
234 bool IsLoad = (Opc == RISCV::LW);
235
236 // Load rd cannot be x0 and must not clobber the base register.
237 if (IsLoad) {
238 if (StartReg == RISCV::X0)
239 return false;
240 if (StartReg == Base)
241 return false;
242 }
243
244 // Collect a set of consecutive matching instructions.
245 SmallVector<MachineInstr *, 8> Group;
246 Group.push_back(&FirstMI);
247
248 MachineBasicBlock::iterator E = FirstIt->getParent()->end();
250 int64_t ExpectedOff = BaseOff + 4;
251 unsigned Index = 1;
252 enum class StoreMode { Unknown, Setwmi, Swmi };
253 StoreMode SMode = StoreMode::Unknown;
254
255 while (It != E) {
256 MachineInstr &MI = *It;
257
258 if (!TII->isPairableLdStInstOpc(MI.getOpcode()))
259 break;
260 if (MI.getOpcode() != Opc)
261 break;
262 if (!TII->isLdStSafeToPair(MI, TRI))
263 break;
264 if (!MI.hasOneMemOperand())
265 break;
266 if (!isMemOpAligned(MI, Align(4)))
267 break;
268
269 const MachineOperand &BaseMIOp = MI.getOperand(1);
270 const MachineOperand &OffsetMIOp = MI.getOperand(2);
271 if (!BaseMIOp.isReg() || !OffsetMIOp.isImm())
272 break;
273 if (BaseMIOp.getReg() != Base)
274 break;
275 int64_t Off = OffsetMIOp.getImm();
276 if (Off != ExpectedOff)
277 break;
278
279 Register Reg = MI.getOperand(0).getReg();
280 if (IsLoad) {
281 // For loads, require consecutive destination registers.
282 if (Reg != StartReg + Index)
283 break;
284 if (Reg == Base)
285 break;
286 } else {
287 // For stores, decide mode based on the second instruction and then
288 // enforce the same for the rest.
289 if (SMode == StoreMode::Unknown) {
290 if (Reg == StartReg)
291 SMode = StoreMode::Setwmi;
292 else if (Reg == StartReg + 1)
293 SMode = StoreMode::Swmi;
294 else
295 break;
296 } else if (SMode == StoreMode::Setwmi) {
297 if (Reg != StartReg)
298 break;
299 } else {
300 if (Reg != StartReg + Index)
301 break;
302 }
303 }
304
305 // Passed checks, extend the group.
306 Group.push_back(&MI);
307 ++Index;
308 ExpectedOff += 4;
309 It = next_nodbg(It, E);
310 }
311
312 // We only handle more than 2 here. Pairs are handled in
313 // tryConvertToXqcilsmLdStPair.
314 unsigned Len = Group.size();
315 if (Len < 3 || Len > 31)
316 return false;
317
318 unsigned NewOpc;
319 RegState StartRegState;
320 bool AddImplicitRegs = true;
321
322 if (IsLoad) {
323 NewOpc = RISCV::QC_LWMI;
324 StartRegState = RegState::Define;
325 } else {
326 assert(SMode != StoreMode::Unknown &&
327 "Group should be large enough to know the store mode");
328 if (SMode == StoreMode::Setwmi) {
329 NewOpc = RISCV::QC_SETWMI;
330 // Kill if any of the individual stores killed the reg.
331 bool StartKill = false;
332 for (MachineInstr *MI : Group)
333 StartKill |= MI->getOperand(0).isKill();
334 StartRegState = getKillRegState(StartKill);
335 AddImplicitRegs = false;
336 } else {
337 // SWMI requires consecutive source regs and rd != x0.
338 if (StartReg == RISCV::X0)
339 return false;
340 NewOpc = RISCV::QC_SWMI;
341 StartRegState = getKillRegState(Group.front()->getOperand(0).isKill());
342 }
343 }
344
345 // Aggregate kill on base.
346 bool BaseKill = false;
347 for (MachineInstr *MI : Group)
348 BaseKill |= MI->getOperand(1).isKill();
349
350 // Build the new instruction.
351 DebugLoc DL = FirstMI.getDebugLoc();
352 if (!DL)
353 DL = Group.back()->getDebugLoc();
354 MachineInstrBuilder MIB = BuildMI(*MF, DL, TII->get(NewOpc));
355 MIB.addReg(StartReg, StartRegState)
356 .addReg(Base, getKillRegState(BaseKill))
357 .addImm(Len)
358 .addImm(BaseOff);
359
360 // Merge memory references.
361 MIB.cloneMergedMemRefs(Group);
362
363 if (AddImplicitRegs) {
364 // Add implicit operands for the additional registers.
365 for (unsigned i = 1; i < Len; ++i) {
366 Register R = StartReg + i;
367 RegState State;
368 if (IsLoad)
369 State = RegState::ImplicitDefine;
370 else
371 State = RegState::Implicit |
372 getKillRegState(Group[i]->getOperand(0).isKill());
373 MIB.addReg(R, State);
374 }
375 }
376
377 // Insert before the first instruction and remove all in the group.
378 MachineBasicBlock *MBB = FirstIt->getParent();
379 MachineBasicBlock::iterator NewIt = MBB->insert(FirstIt, MIB);
380 for (MachineInstr *MI : Group)
381 MI->removeFromParent();
382
383 // Advance the cursor to the next non-debug instruction after the group.
384 FirstIt = next_nodbg(NewIt, MBB->end());
385 return true;
386}
387
388bool RISCVLoadStoreOptImpl::tryConvertToXqcilsmLdStPair(
391 unsigned Opc = First->getOpcode();
392 if ((Opc != RISCV::LW && Opc != RISCV::SW) || Second->getOpcode() != Opc)
393 return false;
394
395 const auto &FirstOp1 = First->getOperand(1);
396 const auto &SecondOp1 = Second->getOperand(1);
397 const auto &FirstOp2 = First->getOperand(2);
398 const auto &SecondOp2 = Second->getOperand(2);
399
400 // Require simple reg+imm addressing for both.
401 if (!FirstOp1.isReg() || !SecondOp1.isReg() || !FirstOp2.isImm() ||
402 !SecondOp2.isImm())
403 return false;
404
405 Register Base1 = FirstOp1.getReg();
406 Register Base2 = SecondOp1.getReg();
407
408 if (Base1 != Base2)
409 return false;
410
411 if (!First->hasOneMemOperand() || !Second->hasOneMemOperand())
412 return false;
413
414 if (!isMemOpAligned(*First, Align(4)) || !isMemOpAligned(*Second, Align(4)))
415 return false;
416
417 auto &FirstOp0 = First->getOperand(0);
418 auto &SecondOp0 = Second->getOperand(0);
419
420 int64_t Off1 = FirstOp2.getImm();
421 int64_t Off2 = SecondOp2.getImm();
422
423 if (Off2 < Off1) {
424 std::swap(FirstOp0, SecondOp0);
425 std::swap(Off1, Off2);
426 }
427
428 if (!isShiftedUInt<5, 2>(Off1) || (Off2 - Off1 != 4))
429 return false;
430
431 Register StartReg = FirstOp0.getReg();
432 Register NextReg = SecondOp0.getReg();
433
434 unsigned XqciOpc;
435 RegState StartRegState;
436 RegState NextRegState = {};
437 bool AddNextReg = true;
438
439 if (Opc == RISCV::LW) {
440
441 if (StartReg == RISCV::X0)
442 return false;
443
444 // If the base reg gets overwritten by one of the loads bail out.
445 if (StartReg == Base1 || NextReg == Base1)
446 return false;
447
448 // The registers need to be consecutive.
449 if (NextReg != StartReg + 1)
450 return false;
451
452 XqciOpc = RISCV::QC_LWMI;
453 StartRegState = RegState::Define;
454 NextRegState = RegState::ImplicitDefine;
455 } else {
456 assert(Opc == RISCV::SW && "Expected a SW instruction");
457 if (StartReg == NextReg) {
458 XqciOpc = RISCV::QC_SETWMI;
459 StartRegState = getKillRegState(FirstOp0.isKill() || SecondOp0.isKill());
460 AddNextReg = false;
461 } else if (NextReg == StartReg + 1 && StartReg != RISCV::X0) {
462 XqciOpc = RISCV::QC_SWMI;
463 StartRegState = getKillRegState(FirstOp0.isKill());
464 NextRegState = RegState::Implicit | getKillRegState(SecondOp0.isKill());
465 } else {
466 return false;
467 }
468 }
469
470 DebugLoc DL =
471 First->getDebugLoc() ? First->getDebugLoc() : Second->getDebugLoc();
472 MachineInstrBuilder MIB = BuildMI(*MF, DL, TII->get(XqciOpc));
473 MIB.addReg(StartReg, StartRegState)
474 .addReg(Base1, getKillRegState(FirstOp1.isKill() || SecondOp1.isKill()))
475 .addImm(2)
476 .addImm(Off1)
477 .cloneMergedMemRefs({&*First, &*Second});
478
479 if (AddNextReg)
480 MIB.addReg(NextReg, NextRegState);
481
482 First->getParent()->insert(First, MIB);
483 First->removeFromParent();
484 Second->removeFromParent();
485
486 return true;
487}
488
489bool RISCVLoadStoreOptImpl::tryConvertToMIPSLdStPair(
492 // Try converting to SWP/LWP/LDP/SDP.
493 // SWP/LWP requires 8-byte alignment whereas LDP/SDP needs 16-byte alignment.
494 unsigned PairOpc;
495 Align RequiredAlignment;
496 switch (First->getOpcode()) {
497 default:
498 llvm_unreachable("Unsupported load/store instruction for pairing");
499 case RISCV::SW:
500 PairOpc = RISCV::MIPS_SWP;
501 RequiredAlignment = Align(8);
502 break;
503 case RISCV::LW:
504 PairOpc = RISCV::MIPS_LWP;
505 RequiredAlignment = Align(8);
506 break;
507 case RISCV::SD:
508 PairOpc = RISCV::MIPS_SDP;
509 RequiredAlignment = Align(16);
510 break;
511 case RISCV::LD:
512 PairOpc = RISCV::MIPS_LDP;
513 RequiredAlignment = Align(16);
514 break;
515 }
516
517 if (!First->hasOneMemOperand())
518 return false;
519
520 if (!isMemOpAligned(*First, RequiredAlignment))
521 return false;
522
523 int64_t Offset = First->getOperand(2).getImm();
524 if (!isUInt<7>(Offset))
525 return false;
526
527 MachineInstrBuilder MIB = BuildMI(
528 *MF, First->getDebugLoc() ? First->getDebugLoc() : Second->getDebugLoc(),
529 TII->get(PairOpc));
530 MIB.add(First->getOperand(0))
531 .add(Second->getOperand(0))
532 .add(First->getOperand(1))
533 .add(First->getOperand(2))
534 .cloneMergedMemRefs({&*First, &*Second});
535
536 First->getParent()->insert(First, MIB);
537
538 First->removeFromParent();
539 Second->removeFromParent();
540
541 return true;
542}
543
544// Merge two adjacent load/store instructions into a paired instruction.
545// This function calls the vendor specific implementation that seelects the
546// appropriate paired opcode, verifies that the memory operand is properly
547// aligned, and checks that the offset is valid. If all conditions are met, it
548// builds and inserts the paired instruction.
549bool RISCVLoadStoreOptImpl::tryConvertToLdStPair(
551 MachineFunction *MF = First->getMF();
552
553 // Try converting to QC_LWMI/QC_SWMI if the XQCILSM extension is enabled.
554 if (!STI->is64Bit() && STI->hasVendorXqcilsm())
555 return tryConvertToXqcilsmLdStPair(MF, First, Second);
556
557 // Else try to convert them into MIPS Paired Loads/Stores.
558 return tryConvertToMIPSLdStPair(MF, First, Second);
559}
560
561static bool mayAlias(MachineInstr &MIa,
563 AliasAnalysis *AA) {
564 for (MachineInstr *MIb : MemInsns)
565 if (MIa.mayAlias(AA, *MIb, /*UseTBAA*/ false))
566 return true;
567
568 return false;
569}
570
571// Scan the instructions looking for a load/store that can be combined with the
572// current instruction into a wider equivalent or a load/store pair.
573// TODO: Extend pairing logic to consider reordering both instructions
574// to a safe "middle" position rather than only merging forward/backward.
575// This requires more sophisticated checks for aliasing, register
576// liveness, and potential scheduling hazards.
578RISCVLoadStoreOptImpl::findMatchingInsn(MachineBasicBlock::iterator I,
579 bool &MergeForward) {
580 MachineBasicBlock::iterator E = I->getParent()->end();
582 MachineInstr &FirstMI = *I;
583 MBBI = next_nodbg(MBBI, E);
584
585 bool MayLoad = FirstMI.mayLoad();
586 Register Reg = FirstMI.getOperand(0).getReg();
587 Register BaseReg = FirstMI.getOperand(1).getReg();
588 int64_t Offset = FirstMI.getOperand(2).getImm();
589 int64_t OffsetStride = (*FirstMI.memoperands_begin())->getSize().getValue();
590
591 MergeForward = false;
592
593 // Track which register units have been modified and used between the first
594 // insn (inclusive) and the second insn.
595 ModifiedRegUnits.clear();
596 UsedRegUnits.clear();
597
598 // Remember any instructions that read/write memory between FirstMI and MI.
599 SmallVector<MachineInstr *, 4> MemInsns;
600
601 for (unsigned Count = 0;
602 MBBI != E && Count < STI->getCLOpts().load_store_scan_limit;
603 MBBI = next_nodbg(MBBI, E)) {
604 MachineInstr &MI = *MBBI;
605
606 // Don't count transient instructions towards the search limit since there
607 // may be different numbers of them if e.g. debug information is present.
608 if (!MI.isTransient())
609 ++Count;
610
611 if (MI.getOpcode() == FirstMI.getOpcode() &&
612 TII->isLdStSafeToPair(MI, TRI)) {
613 Register MIBaseReg = MI.getOperand(1).getReg();
614 int64_t MIOffset = MI.getOperand(2).getImm();
615
616 if (BaseReg == MIBaseReg) {
617 if ((Offset != MIOffset + OffsetStride) &&
618 (Offset + OffsetStride != MIOffset)) {
619 LiveRegUnits::accumulateUsedDefed(MI, ModifiedRegUnits, UsedRegUnits,
620 TRI);
621 MemInsns.push_back(&MI);
622 continue;
623 }
624
625 // If the destination register of one load is the same register or a
626 // sub/super register of the other load, bail and keep looking.
627 if (MayLoad &&
628 TRI->isSuperOrSubRegisterEq(Reg, MI.getOperand(0).getReg())) {
629 LiveRegUnits::accumulateUsedDefed(MI, ModifiedRegUnits, UsedRegUnits,
630 TRI);
631 MemInsns.push_back(&MI);
632 continue;
633 }
634
635 // If the BaseReg has been modified, then we cannot do the optimization.
636 if (!ModifiedRegUnits.available(BaseReg))
637 return E;
638
639 // If the Rt of the second instruction was not modified or used between
640 // the two instructions and none of the instructions between the second
641 // and first alias with the second, we can combine the second into the
642 // first.
643 if (ModifiedRegUnits.available(MI.getOperand(0).getReg()) &&
644 !(MI.mayLoad() &&
645 !UsedRegUnits.available(MI.getOperand(0).getReg())) &&
646 !mayAlias(MI, MemInsns, AA)) {
647
648 MergeForward = false;
649 return MBBI;
650 }
651
652 // Likewise, if the Rt of the first instruction is not modified or used
653 // between the two instructions and none of the instructions between the
654 // first and the second alias with the first, we can combine the first
655 // into the second.
656 if (!(MayLoad &&
657 !UsedRegUnits.available(FirstMI.getOperand(0).getReg())) &&
658 !mayAlias(FirstMI, MemInsns, AA)) {
659
660 if (ModifiedRegUnits.available(FirstMI.getOperand(0).getReg())) {
661 MergeForward = true;
662 return MBBI;
663 }
664 }
665 // Unable to combine these instructions due to interference in between.
666 // Keep looking.
667 }
668 }
669
670 // If the instruction wasn't a matching load or store. Stop searching if we
671 // encounter a call instruction that might modify memory.
672 if (MI.isCall())
673 return E;
674
675 // Update modified / uses register units.
676 LiveRegUnits::accumulateUsedDefed(MI, ModifiedRegUnits, UsedRegUnits, TRI);
677
678 // Otherwise, if the base register is modified, we have no match, so
679 // return early.
680 if (!ModifiedRegUnits.available(BaseReg))
681 return E;
682
683 // Update list of instructions that read/write memory.
684 if (MI.mayLoadOrStore())
685 MemInsns.push_back(&MI);
686 }
687 return E;
688}
689
691RISCVLoadStoreOptImpl::mergePairedInsns(MachineBasicBlock::iterator I,
693 bool MergeForward) {
694 MachineBasicBlock::iterator E = I->getParent()->end();
696 // If NextI is the second of the two instructions to be merged, skip one
697 // further for now. For the MIPS load/store, the merge will invalidate the
698 // iterator, and we don't need to scan the new instruction, as it's a pairwise
699 // instruction, which we're not considering for further action anyway. For the
700 // Xqcilsm load/store, we may not want to do this as the second instruction
701 // could possibly be the first in another pair if we do not merge here. This
702 // is handled in the else block after the call to tryConvertToLdStPair below.
703 if (NextI == Paired)
704 NextI = next_nodbg(NextI, E);
705
706 // Insert our new paired instruction after whichever of the paired
707 // instructions MergeForward indicates.
708 MachineBasicBlock::iterator InsertionPoint = MergeForward ? Paired : I;
709 MachineBasicBlock::iterator DeletionPoint = MergeForward ? I : Paired;
710 int Offset = I->getOperand(2).getImm();
711 int PairedOffset = Paired->getOperand(2).getImm();
712 bool InsertAfter = (Offset < PairedOffset) ^ MergeForward;
713
714 if (!MergeForward)
715 Paired->getOperand(1).setIsKill(false);
716
717 // Kill flags may become invalid when moving stores for pairing.
718 if (I->getOperand(0).isUse()) {
719 if (!MergeForward) {
720 // Check if the Paired store's source register has a kill flag and clear
721 // it only if there are intermediate uses between I and Paired.
722 MachineOperand &PairedRegOp = Paired->getOperand(0);
723 if (PairedRegOp.isKill()) {
724 for (auto It = std::next(I); It != Paired; ++It) {
725 if (It->readsRegister(PairedRegOp.getReg(), TRI)) {
726 PairedRegOp.setIsKill(false);
727 break;
728 }
729 }
730 }
731 } else {
732 // Clear kill flags of the first store's register in the forward
733 // direction.
734 Register Reg = I->getOperand(0).getReg();
735 for (MachineInstr &MI : make_range(std::next(I), std::next(Paired)))
736 MI.clearRegisterKills(Reg, TRI);
737 }
738 }
739
740 // Remember the original position of the instruction we're moving so we can
741 // restore it if we fail to form a pair.
742 MachineBasicBlock::iterator OrigNext = std::next(DeletionPoint);
743
744 MachineInstr *ToInsert = DeletionPoint->removeFromParent();
745 MachineBasicBlock &MBB = *InsertionPoint->getParent();
746 MachineBasicBlock::iterator First, Second, Moved;
747
748 if (!InsertAfter) {
749 First = MBB.insert(InsertionPoint, ToInsert);
750 Second = InsertionPoint;
751 Moved = First;
752 } else {
753 Second = MBB.insertAfter(InsertionPoint, ToInsert);
754 First = InsertionPoint;
755 Moved = Second;
756 }
757
758 if (tryConvertToLdStPair(First, Second)) {
759 LLVM_DEBUG(dbgs() << "Pairing load/store:\n ");
760 LLVM_DEBUG(prev_nodbg(NextI, MBB.begin())->print(dbgs()));
761 } else if (!STI->is64Bit() && STI->hasVendorXqcilsm()) {
762 // We were unable to form the pair, so move the instruction back to it's
763 // original place. Point NextI to the next non-debug instruction after the
764 // first instruction we had wanted to merge.
765 MachineInstr *MovedMI = Moved->removeFromParent();
766 MBB.insert(OrigNext, MovedMI);
767 NextI = next_nodbg(I, E);
768 }
769
770 return NextI;
771}
772
773//===----------------------------------------------------------------------===//
774// Post reg-alloc zilsd pass implementation
775//===----------------------------------------------------------------------===//
776
777bool RISCVLoadStoreOptImpl::isValidZilsdRegPair(Register First,
778 Register Second) {
779 // Special case: First register can not be zero unless both registers are
780 // zeros.
781 // Spec says: LD instructions with destination x0 are processed as any other
782 // load, but the result is discarded entirely and x1 is not written. If using
783 // x0 as src of SD, the entire 64-bit operand is zero — i.e., register x1 is
784 // not accessed.
785 if (First == RISCV::X0)
786 return Second == RISCV::X0;
787
788 // Check if registers form a valid even/odd pair for Zilsd
789 unsigned FirstNum = TRI->getEncodingValue(First);
790 unsigned SecondNum = TRI->getEncodingValue(Second);
791
792 // Must be consecutive and first must be even
793 return (FirstNum % 2 == 0) && (SecondNum == FirstNum + 1);
794}
795
796void RISCVLoadStoreOptImpl::splitLdSdIntoTwo(MachineBasicBlock &MBB,
798 bool IsLoad) {
799 MachineInstr *MI = &*MBBI;
800 DebugLoc DL = MI->getDebugLoc();
801
802 const MachineOperand &FirstOp = MI->getOperand(0);
803 const MachineOperand &SecondOp = MI->getOperand(1);
804 const MachineOperand &BaseOp = MI->getOperand(2);
805 Register FirstReg = FirstOp.getReg();
806 Register SecondReg = SecondOp.getReg();
807 Register BaseReg = BaseOp.getReg();
808
809 // Handle both immediate and symbolic operands for offset
810 const MachineOperand &OffsetOp = MI->getOperand(3);
811 int BaseOffset;
812 if (OffsetOp.isImm())
813 BaseOffset = OffsetOp.getImm();
814 else
815 // For symbolic operands, extract the embedded offset
816 BaseOffset = OffsetOp.getOffset();
817
818 unsigned Opc = IsLoad ? RISCV::LW : RISCV::SW;
819 MachineInstrBuilder MIB1, MIB2;
820
821 // Create two separate instructions
822 if (IsLoad) {
823 // It's possible that first register is same as base register, when we split
824 // it becomes incorrect because base register is overwritten, e.g.
825 // X10, X13 = PseudoLD_RV32_OPT killed X10, 0
826 // =>
827 // X10 = LW X10, 0
828 // X13 = LW killed X10, 4
829 // we can just switch the order to resolve that:
830 // X13 = LW X10, 4
831 // X10 = LW killed X10, 0
832 if (FirstReg == BaseReg) {
833 MIB2 = BuildMI(MBB, MBBI, DL, TII->get(Opc))
834 .addDef(SecondReg, getDeadRegState(SecondOp.isDead()))
835 .addReg(BaseReg);
836 MIB1 = BuildMI(MBB, MBBI, DL, TII->get(Opc))
837 .addDef(FirstReg, getDeadRegState(FirstOp.isDead()))
838 .addReg(BaseReg, getKillRegState(BaseOp.isKill()));
839
840 } else {
841 MIB1 = BuildMI(MBB, MBBI, DL, TII->get(Opc))
842 .addDef(FirstReg, getDeadRegState(FirstOp.isDead()))
843 .addReg(BaseReg);
844
845 MIB2 = BuildMI(MBB, MBBI, DL, TII->get(Opc))
846 .addDef(SecondReg, getDeadRegState(SecondOp.isDead()))
847 .addReg(BaseReg, getKillRegState(BaseOp.isKill()));
848 }
849
850 ++NumLD2LW;
851 LLVM_DEBUG(dbgs() << "Split LD back to two LW instructions\n");
852 } else {
853 assert(
854 FirstReg != SecondReg &&
855 "First register and second register is impossible to be same register");
856 MIB1 = BuildMI(MBB, MBBI, DL, TII->get(Opc))
857 .addReg(FirstReg, getKillRegState(FirstOp.isKill()))
858 .addReg(BaseReg);
859
860 MIB2 = BuildMI(MBB, MBBI, DL, TII->get(Opc))
861 .addReg(SecondReg, getKillRegState(SecondOp.isKill()))
862 .addReg(BaseReg, getKillRegState(BaseOp.isKill()));
863
864 ++NumSD2SW;
865 LLVM_DEBUG(dbgs() << "Split SD back to two SW instructions\n");
866 }
867
868 // Add offset operands - preserve symbolic references
869 MIB1.add(OffsetOp);
870 if (OffsetOp.isImm())
871 MIB2.addImm(BaseOffset + 4);
872 else if (OffsetOp.isGlobal())
873 MIB2.addGlobalAddress(OffsetOp.getGlobal(), BaseOffset + 4,
874 OffsetOp.getTargetFlags());
875 else if (OffsetOp.isCPI())
876 MIB2.addConstantPoolIndex(OffsetOp.getIndex(), BaseOffset + 4,
877 OffsetOp.getTargetFlags());
878 else if (OffsetOp.isBlockAddress())
879 MIB2.addBlockAddress(OffsetOp.getBlockAddress(), BaseOffset + 4,
880 OffsetOp.getTargetFlags());
881
882 // Copy memory operands if the original instruction had them
883 // FIXME: This is overly conservative; the new instruction accesses 4 bytes,
884 // not 8.
885 MIB1.cloneMemRefs(*MI);
886 MIB2.cloneMemRefs(*MI);
887
888 // Remove the original paired instruction and update iterator
889 MBBI = MBB.erase(MBBI);
890}
891
892bool RISCVLoadStoreOptImpl::fixInvalidRegPairOp(
893 MachineBasicBlock &MBB, MachineBasicBlock::iterator &MBBI) {
894 MachineInstr *MI = &*MBBI;
895 unsigned Opcode = MI->getOpcode();
896
897 // Check if this is a Zilsd pseudo that needs fixing
898 if (Opcode != RISCV::PseudoLD_RV32_OPT && Opcode != RISCV::PseudoSD_RV32_OPT)
899 return false;
900
901 bool IsLoad = Opcode == RISCV::PseudoLD_RV32_OPT;
902
903 const MachineOperand &FirstOp = MI->getOperand(0);
904 const MachineOperand &SecondOp = MI->getOperand(1);
905 Register FirstReg = FirstOp.getReg();
906 Register SecondReg = SecondOp.getReg();
907
908 if (!isValidZilsdRegPair(FirstReg, SecondReg)) {
909 // Need to split back into two instructions
910 splitLdSdIntoTwo(MBB, MBBI, IsLoad);
911 return true;
912 }
913
914 // Registers are valid, convert to real LD/SD instruction
915 const MachineOperand &BaseOp = MI->getOperand(2);
916 Register BaseReg = BaseOp.getReg();
917 DebugLoc DL = MI->getDebugLoc();
918 // Handle both immediate and symbolic operands for offset
919 const MachineOperand &OffsetOp = MI->getOperand(3);
920
921 unsigned RealOpc = IsLoad ? RISCV::LD_RV32 : RISCV::SD_RV32;
922
923 // Create register pair from the two individual registers
924 MCRegister RegPair = TRI->getMatchingSuperReg(FirstReg, RISCV::sub_gpr_even,
925 &RISCV::GPRPairRegClass);
926 // Create the real LD/SD instruction with register pair
927 MachineInstrBuilder MIB = BuildMI(MBB, MBBI, DL, TII->get(RealOpc));
928
929 if (IsLoad) {
930 // For LD, the register pair is the destination
931 MIB.addDef(RegPair, getDeadRegState(FirstOp.isDead() && SecondOp.isDead()));
932 } else {
933 // For SD, the register pair is the source
934 MIB.addReg(RegPair, getKillRegState(FirstOp.isKill() && SecondOp.isKill()));
935 }
936
937 MIB.addReg(BaseReg, getKillRegState(BaseOp.isKill()))
938 .add(OffsetOp)
939 .cloneMemRefs(*MI);
940
941 LLVM_DEBUG(dbgs() << "Converted pseudo to real instruction: " << *MIB
942 << "\n");
943
944 // Remove the pseudo instruction and update iterator
945 MBBI = MBB.erase(MBBI);
946
947 return true;
948}
949
950// Returns an instance of the Load / Store Optimization pass.
952 return new RISCVLoadStoreOptLegacy();
953}
954
955bool RISCVLoadStoreOptLegacy::runOnMachineFunction(MachineFunction &MF) {
956 if (skipFunction(MF.getFunction()))
957 return false;
958 RISCVLoadStoreOptImpl Impl;
959 return Impl.runOnMachineFunction(MF, [&]() {
960 return &getAnalysis<AAResultsWrapperPass>().getAAResults();
961 });
962}
963
964PreservedAnalyses
967 RISCVLoadStoreOptImpl Impl;
968 bool Changed = Impl.runOnMachineFunction(MF, [&]() {
970 .getManager()
971 .getResult<AAManager>(MF.getFunction());
972 });
976}
static bool mayAlias(MachineInstr &MIa, SmallVectorImpl< MachineInstr * > &MemInsns, AliasAnalysis *AA)
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
MachineBasicBlock & MBB
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
MachineBasicBlock MachineBasicBlock::iterator MBBI
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
#define DEBUG_TYPE
const HexagonInstrInfo * TII
IRTranslator LLVM IR MI
std::pair< Instruction::BinaryOps, Value * > OffsetOp
Find all possible pairs (BinOp, RHS) that BinOp V, RHS can be simplified.
#define I(x, y, z)
Definition MD5.cpp:57
Register Reg
Register const TargetRegisterInfo * TRI
Promote Memory to Register
Definition Mem2Reg.cpp:110
#define INITIALIZE_PASS(passName, arg, name, cfg, analysis)
Definition PassSupport.h:56
MachineRegisterInfo & MRI
#define RISCV_LOAD_STORE_OPT_NAME
static bool isMemOpAligned(MachineInstr &MI, Align RequiredAlignment)
This file defines the SmallVector class.
This file defines the 'Statistic' class, which is designed to be an easy way to expose various metric...
#define STATISTIC(VARNAME, DESC)
Definition Statistic.h:171
#define LLVM_DEBUG(...)
Definition Debug.h:119
A manager for alias analyses.
PassT::Result & getResult(IRUnitT &IR, ExtraArgTs... ExtraArgs)
Get the result of an analysis pass for a given IR unit.
AnalysisUsage & addRequired()
AnalysisUsage & addPreserved()
Add the specified Pass class to the set of analyses preserved by this pass.
LLVM_ABI void setPreservesCFG()
This function should be called by the pass, iff they do not:
Definition Pass.cpp:280
Represents analyses that only rely on functions' control flow.
Definition Analysis.h:73
FunctionPass class - This class is used to implement most global optimizations.
Definition Pass.h:312
static void accumulateUsedDefed(const MachineInstr &MI, LiveRegUnits &ModifiedRegUnits, LiveRegUnits &UsedRegUnits, const TargetRegisterInfo *TRI)
For a machine instruction MI, adds all register units used in UsedRegUnits and defined or clobbered i...
bool available(MCRegister Reg) const
Returns true if no part of physical register Reg is live.
void clear()
Clears the set.
LLVM_ABI instr_iterator insert(instr_iterator I, MachineInstr *M)
Insert MI into the instruction list before I, possibly inside a bundle.
LLVM_ABI instr_iterator erase(instr_iterator I)
Remove an instruction from the instruction list and delete it.
iterator insertAfter(iterator I, MachineInstr *MI)
Insert MI into the instruction list after I.
MachineInstrBundleIterator< MachineInstr > iterator
MachineFunctionPass - This class adapts the FunctionPass interface to allow convenient creation of pa...
void getAnalysisUsage(AnalysisUsage &AU) const override
getAnalysisUsage - Subclasses that override getAnalysisUsage must call this.
Function & getFunction()
Return the LLVM function that this machine code represents.
const MachineInstrBuilder & cloneMergedMemRefs(ArrayRef< const MachineInstr * > OtherMIs) const
const MachineInstrBuilder & addReg(Register RegNo, RegState Flags={}, unsigned SubReg=0) const
Add a new virtual register operand.
const MachineInstrBuilder & addImm(int64_t Val) const
Add a new immediate operand.
const MachineInstrBuilder & addBlockAddress(const BlockAddress *BA, int64_t Offset=0, unsigned TargetFlags=0) const
const MachineInstrBuilder & add(const MachineOperand &MO) const
const MachineInstrBuilder & addConstantPoolIndex(unsigned Idx, int Offset=0, unsigned TargetFlags=0) const
const MachineInstrBuilder & addGlobalAddress(const GlobalValue *GV, int64_t Offset=0, unsigned TargetFlags=0) const
const MachineInstrBuilder & addDef(Register RegNo, RegState Flags={}, unsigned SubReg=0) const
Add a virtual register definition operand.
const MachineInstrBuilder & cloneMemRefs(const MachineInstr &OtherMI) const
Representation of each machine instruction.
unsigned getOpcode() const
Returns the opcode of this MachineInstr.
const MachineBasicBlock * getParent() const
LLVM_ABI bool mayAlias(BatchAAResults *AA, const MachineInstr &Other, bool UseTBAA) const
Returns true if this instruction's memory access aliases the memory access of Other.
bool mayLoad(QueryType Type=AnyInBundle) const
Return true if this instruction could possibly read memory.
bool hasOneMemOperand() const
Return true if this instruction has exactly one MachineMemOperand.
mmo_iterator memoperands_begin() const
Access to memory operands of the instruction.
LLVM_ABI const MachineFunction * getMF() const
Return the function that contains the basic block that this instruction belongs to.
const DebugLoc & getDebugLoc() const
Returns the debug location id of this MachineInstr.
const MachineOperand & getOperand(unsigned i) const
A description of a memory reference used in the backend.
LLVM_ABI Align getAlign() const
Return the minimum known alignment in bytes of the actual memory reference.
int64_t getImm() const
bool isReg() const
isReg - Tests if this is a MO_Register operand.
bool isImm() const
isImm - Tests if this is a MO_Immediate operand.
void setIsKill(bool Val=true)
Register getReg() const
getReg - Returns the register number.
static PreservedAnalyses all()
Construct a special preserved set that preserves all passes.
Definition Analysis.h:118
PreservedAnalyses & preserveSet()
Mark an analysis set as preserved.
Definition Analysis.h:151
PreservedAnalyses run(MachineFunction &MF, MachineFunctionAnalysisManager &MFAM)
const RISCVOptions & getCLOpts() const
This class consists of common code factored out of the SmallVector class to reduce code duplication b...
void push_back(const T &Elt)
An efficient, type-erasing, non-owning reference to a callable.
Pass manager infrastructure for declaring and invalidating analyses.
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
Abstract Attribute helper functions.
Definition Attributor.h:164
constexpr char Align[]
Key for Kernel::Arg::Metadata::mAlign.
BaseReg
Stack frame base register. Bit 0 of FREInfo.Info.
Definition SFrame.h:77
This is an optimization pass for GlobalISel generic memory operations.
IterT next_nodbg(IterT It, IterT End, bool SkipPseudoOp=true)
Increment It, then continue incrementing it while it points to a debug instruction.
@ Offset
Definition DWP.cpp:577
MachineInstrBuilder BuildMI(MachineFunction &MF, const MIMetadata &MIMD, const MCInstrDesc &MCID)
Builder interface. Specify how to create the initial instruction itself.
@ Unknown
Not known to have no common set bits.
RegState
Flags to represent properties of register accesses.
constexpr RegState getKillRegState(bool B)
iterator_range< T > make_range(T x, T y)
Convenience function for iterating over sub-ranges.
AnalysisManager< MachineFunction > MachineFunctionAnalysisManager
constexpr RegState getDeadRegState(bool B)
LLVM_ABI PreservedAnalyses getMachineFunctionPassPreservedAnalyses()
Returns the minimum set of Analyses that all machine function passes must preserve.
LLVM_ABI raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
Definition Debug.cpp:209
FunctionPass * createRISCVLoadStoreOptLegacyPass()
constexpr bool isUInt(uint64_t x)
Checks if an unsigned integer fits into the given bit width.
Definition MathExtras.h:190
@ First
Helpers to iterate all locations in the MemoryEffectsBase class.
Definition ModRef.h:74
RelativeUniformCounterPtr ValuesPtrExpr VTableAddr Count
Definition InstrProf.h:145
AAResults AliasAnalysis
Temporary typedef for legacy code that uses a generic AliasAnalysis pointer or reference.
IterT prev_nodbg(IterT It, IterT Begin, bool SkipPseudoOp=true)
Decrement It, then continue decrementing it while it points to a debug instruction.
constexpr bool isShiftedUInt(uint64_t x)
Checks if a unsigned integer is an N bit number shifted left by S.
Definition MathExtras.h:199
void swap(llvm::BitVector &LHS, llvm::BitVector &RHS)
Implement std::swap in terms of BitVector swap.
Definition BitVector.h:880
This struct is a compact representation of a valid (non-zero power of two) alignment.
Definition Alignment.h:39