LLVM: lib/Target/RISCV/RISCVLoadStoreOptimizer.cpp Source File (original) (raw)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
35
36using namespace llvm;
37
38#define DEBUG_TYPE "riscv-load-store-opt"
39#define RISCV_LOAD_STORE_OPT_NAME "RISC-V Load / Store Optimizer"
40
41
42
45STATISTIC(NumLD2LW, "Number of LD instructions split back to LW");
46STATISTIC(NumSD2SW, "Number of SD instructions split back to SW");
47
48namespace {
49
51 static char ID;
53
55
56 MachineFunctionProperties getRequiredProperties() const override {
57 return MachineFunctionProperties().setNoVRegs();
58 }
59
60 void getAnalysisUsage(AnalysisUsage &AU) const override {
63 }
64
66
67
69
70
73
74
75
76
78 bool &MergeForward);
79
83
84
85 bool fixInvalidRegPairOp(MachineBasicBlock &MBB,
88 void splitLdSdIntoTwo(MachineBasicBlock &MBB,
90
91private:
93 MachineRegisterInfo *MRI;
94 const RISCVInstrInfo *TII;
95 const RISCVRegisterInfo *TRI;
96 LiveRegUnits ModifiedRegUnits, UsedRegUnits;
97};
98}
99
100char RISCVLoadStoreOpt::ID = 0;
102 false)
103
105 if (skipFunction(Fn.getFunction()))
106 return false;
108
109 bool MadeChange = false;
110 TII = Subtarget.getInstrInfo();
111 TRI = Subtarget.getRegisterInfo();
112 MRI = &Fn.getRegInfo();
113 AA = &getAnalysis().getAAResults();
114 ModifiedRegUnits.init(*TRI);
115 UsedRegUnits.init(*TRI);
116
117 if (Subtarget.useMIPSLoadStorePairs()) {
118 for (MachineBasicBlock &MBB : Fn) {
119 LLVM_DEBUG(dbgs() << "MBB: " << MBB.getName() << "\n");
120
121 for (MachineBasicBlock::iterator MBBI = MBB.begin(), E = MBB.end();
122 MBBI != E;) {
123 if (TII->isPairableLdStInstOpc(MBBI->getOpcode()) &&
124 tryToPairLdStInst(MBBI))
125 MadeChange = true;
126 else
127 ++MBBI;
128 }
129 }
130 }
131
132 if (!Subtarget.is64Bit() && Subtarget.hasStdExtZilsd()) {
133 for (auto &MBB : Fn) {
134 for (auto MBBI = MBB.begin(), E = MBB.end(); MBBI != E;) {
135 if (fixInvalidRegPairOp(MBB, MBBI)) {
136 MadeChange = true;
137
138 } else {
139 ++MBBI;
140 }
141 }
142 }
143 }
144
145 return MadeChange;
146}
147
148
149
152
153
154 if (MI.hasOrderedMemoryRef())
155 return false;
156
157 if (->isLdStSafeToPair(MI, TRI))
158 return false;
159
160
162 bool MergeForward;
164 if (Paired != E) {
165 MBBI = mergePairedInsns(MBBI, Paired, MergeForward);
166 return true;
167 }
168 return false;
169}
170
171
172
173
174
175
176
177bool RISCVLoadStoreOpt::tryConvertToLdStPair(
179 unsigned PairOpc;
180 Align RequiredAlignment;
181 switch (First->getOpcode()) {
182 default:
183 llvm_unreachable("Unsupported load/store instruction for pairing");
184 case RISCV::SW:
185 PairOpc = RISCV::MIPS_SWP;
186 RequiredAlignment = Align(8);
187 break;
188 case RISCV::LW:
189 PairOpc = RISCV::MIPS_LWP;
190 RequiredAlignment = Align(8);
191 break;
192 case RISCV::SD:
193 PairOpc = RISCV::MIPS_SDP;
194 RequiredAlignment = Align(16);
195 break;
196 case RISCV::LD:
197 PairOpc = RISCV::MIPS_LDP;
198 RequiredAlignment = Align(16);
199 break;
200 }
201
202 MachineFunction *MF = First->getMF();
203 const MachineMemOperand *MMO = *First->memoperands_begin();
205
206 if (MMOAlign < RequiredAlignment)
207 return false;
208
209 int64_t Offset = First->getOperand(2).getImm();
211 return false;
212
213 MachineInstrBuilder MIB = BuildMI(
214 *MF, First->getDebugLoc() ? First->getDebugLoc() : Second->getDebugLoc(),
216 MIB.add(First->getOperand(0))
217 .add(Second->getOperand(0))
221
223
224 First->removeFromParent();
225 Second->removeFromParent();
226
227 return true;
228}
229
234 if (MIa.mayAlias(AA, *MIb, false))
235 return true;
236
237 return false;
238}
239
240
241
242
243
244
245
248 bool &MergeForward) {
251 MachineInstr &FirstMI = *I;
253
258 int64_t OffsetStride = (*FirstMI.memoperands_begin())->getSize().getValue();
259
260 MergeForward = false;
261
262
263
264 ModifiedRegUnits.clear();
265 UsedRegUnits.clear();
266
267
268 SmallVector<MachineInstr *, 4> MemInsns;
269
273
274
275
276 if (.isTransient())
278
279 if (MI.getOpcode() == FirstMI.getOpcode() &&
280 TII->isLdStSafeToPair(MI, TRI)) {
281 Register MIBaseReg = MI.getOperand(1).getReg();
282 int64_t MIOffset = MI.getOperand(2).getImm();
283
284 if (BaseReg == MIBaseReg) {
285 if ((Offset != MIOffset + OffsetStride) &&
286 (Offset + OffsetStride != MIOffset)) {
290 continue;
291 }
292
293
294
295 if (MayLoad &&
296 TRI->isSuperOrSubRegisterEq(Reg, MI.getOperand(0).getReg())) {
300 continue;
301 }
302
303
304 if (!ModifiedRegUnits.available(BaseReg))
305 return E;
306
307
308
309
310
311 if (ModifiedRegUnits.available(MI.getOperand(0).getReg()) &&
312 !(MI.mayLoad() &&
313 !UsedRegUnits.available(MI.getOperand(0).getReg())) &&
315
316 MergeForward = false;
318 }
319
320
321
322
323
324 if (!(MayLoad &&
326 (FirstMI, MemInsns, AA)) {
327
329 MergeForward = true;
331 }
332 }
333
334
335 }
336 }
337
338
339
340 if (MI.isCall())
341 return E;
342
343
345
346
347
348 if (!ModifiedRegUnits.available(BaseReg))
349 return E;
350
351
352 if (MI.mayLoadOrStore())
354 }
355 return E;
356}
357
361 bool MergeForward) {
364
365
366
367
368 if (NextI == Paired)
370
371
372
375 int Offset = I->getOperand(2).getImm();
376 int PairedOffset = Paired->getOperand(2).getImm();
377 bool InsertAfter = (Offset < PairedOffset) ^ MergeForward;
378
379 if (!MergeForward)
380 Paired->getOperand(1).setIsKill(false);
381
382
383 if (I->getOperand(0).isUse()) {
384 if (!MergeForward) {
385
386
387 MachineOperand &PairedRegOp = Paired->getOperand(0);
388 if (PairedRegOp.isKill()) {
389 for (auto It = std::next(I); It != Paired; ++It) {
390 if (It->readsRegister(PairedRegOp.getReg(), TRI)) {
392 break;
393 }
394 }
395 }
396 } else {
397
398
400 for (MachineInstr &MI : make_range(std::next(I), std::next(Paired)))
401 MI.clearRegisterKills(Reg, TRI);
402 }
403 }
404
405 MachineInstr *ToInsert = DeletionPoint->removeFromParent();
406 MachineBasicBlock &MBB = *InsertionPoint->getParent();
408
409 if (!InsertAfter) {
411 Second = InsertionPoint;
412 } else {
414 First = InsertionPoint;
415 }
416
417 if (tryConvertToLdStPair(First, Second)) {
420 }
421
422 return NextI;
423}
424
425
426
427
428
430
431
432
433
434
435
436 if (First == RISCV::X0)
437 return Second == RISCV::X0;
438
439
440 unsigned FirstNum = TRI->getEncodingValue(First);
441 unsigned SecondNum = TRI->getEncodingValue(Second);
442
443
444 return (FirstNum % 2 == 0) && (SecondNum == FirstNum + 1);
445}
446
447void RISCVLoadStoreOpt::splitLdSdIntoTwo(MachineBasicBlock &MBB,
449 bool IsLoad) {
450 MachineInstr *MI = &*MBBI;
452
453 const MachineOperand &FirstOp = MI->getOperand(0);
454 const MachineOperand &SecondOp = MI->getOperand(1);
455 const MachineOperand &BaseOp = MI->getOperand(2);
459
460
461 const MachineOperand &OffsetOp = MI->getOperand(3);
462 int BaseOffset;
464 BaseOffset = OffsetOp.getImm();
465 else
466
467 BaseOffset = OffsetOp.getOffset();
468
469 unsigned Opc = IsLoad ? RISCV::LW : RISCV::SW;
470 MachineInstrBuilder MIB1, MIB2;
471
472
473 if (IsLoad) {
474
475
476
477
478
479
480
481
482
483 if (FirstReg == BaseReg) {
492
493 } else {
498
503 }
504
505 ++NumLD2LW;
506 LLVM_DEBUG(dbgs() << "Split LD back to two LW instructions\n");
507 } else {
509 FirstReg != SecondReg &&
510 "First register and second register is impossible to be same register");
514
518
519 ++NumSD2SW;
520 LLVM_DEBUG(dbgs() << "Split SD back to two SW instructions\n");
521 }
522
523
526 MIB2.addImm(BaseOffset + 4);
527 else if (OffsetOp.isGlobal())
533 else if (OffsetOp.isBlockAddress())
536
537
538
539
542
543
545}
546
547bool RISCVLoadStoreOpt::fixInvalidRegPairOp(MachineBasicBlock &MBB,
549 MachineInstr *MI = &*MBBI;
550 unsigned Opcode = MI->getOpcode();
551
552
553 if (Opcode != RISCV::PseudoLD_RV32_OPT && Opcode != RISCV::PseudoSD_RV32_OPT)
554 return false;
555
556 bool IsLoad = Opcode == RISCV::PseudoLD_RV32_OPT;
557
558 const MachineOperand &FirstOp = MI->getOperand(0);
559 const MachineOperand &SecondOp = MI->getOperand(1);
562
563 if (!isValidZilsdRegPair(FirstReg, SecondReg)) {
564
565 splitLdSdIntoTwo(MBB, MBBI, IsLoad);
566 return true;
567 }
568
569
570 const MachineOperand &BaseOp = MI->getOperand(2);
573
574 const MachineOperand &OffsetOp = MI->getOperand(3);
575
576 unsigned RealOpc = IsLoad ? RISCV::LD_RV32 : RISCV::SD_RV32;
577
578
579 unsigned RegPair = TRI->getMatchingSuperReg(FirstReg, RISCV::sub_gpr_even,
580 &RISCV::GPRPairRegClass);
581
583
584 if (IsLoad) {
585
588 } else {
589
591 }
592
596
597 LLVM_DEBUG(dbgs() << "Converted pseudo to real instruction: " << *MIB
598 << "\n");
599
600
602
603 return true;
604}
605
606
608 return new RISCVLoadStoreOpt();
609}
unsigned const MachineRegisterInfo * MRI
static bool mayAlias(MachineInstr &MIa, SmallVectorImpl< MachineInstr * > &MemInsns, AliasAnalysis *AA)
static cl::opt< unsigned > LdStLimit("aarch64-load-store-scan-limit", cl::init(20), cl::Hidden)
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
const TargetInstrInfo & TII
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
MachineBasicBlock MachineBasicBlock::iterator MBBI
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
std::pair< Instruction::BinaryOps, Value * > OffsetOp
Find all possible pairs (BinOp, RHS) that BinOp V, RHS can be simplified.
Register const TargetRegisterInfo * TRI
Promote Memory to Register
#define INITIALIZE_PASS(passName, arg, name, cfg, analysis)
#define RISCV_LOAD_STORE_OPT_NAME
Definition RISCVLoadStoreOptimizer.cpp:39
static cl::opt< unsigned > LdStLimit("riscv-load-store-scan-limit", cl::init(128), cl::Hidden)
This file defines the 'Statistic' class, which is designed to be an easy way to expose various metric...
#define STATISTIC(VARNAME, DESC)
AnalysisUsage & addRequired()
FunctionPass class - This class is used to implement most global optimizations.
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.
const MCInstrDesc & get(unsigned Opcode) const
Return the machine instruction descriptor that corresponds to the specified instruction opcode.
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.
const MachineInstrBuilder & cloneMergedMemRefs(ArrayRef< const MachineInstr * > OtherMIs) const
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 & addReg(Register RegNo, unsigned flags=0, unsigned SubReg=0) const
Add a new virtual register 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.
mmo_iterator memoperands_begin() const
Access to memory operands of the instruction.
const MachineOperand & getOperand(unsigned i) const
LLVM_ABI Align getAlign() const
Return the minimum known alignment in bytes of the actual memory reference.
void setIsKill(bool Val=true)
Register getReg() const
getReg - Returns the register number.
This class consists of common code factored out of the SmallVector class to reduce code duplication b...
void push_back(const T &Elt)
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
Abstract Attribute helper functions.
constexpr char Align[]
Key for Kernel::Arg::Metadata::mAlign.
unsigned ID
LLVM IR allows to use arbitrary numbers as calling convention identifiers.
@ Define
Register definition.
initializer< Ty > init(const Ty &Val)
BaseReg
Stack frame base register. Bit 0 of FREInfo.Info.
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.
FunctionPass * createRISCVLoadStoreOptPass()
Definition RISCVLoadStoreOptimizer.cpp:607
MachineInstrBuilder BuildMI(MachineFunction &MF, const MIMetadata &MIMD, const MCInstrDesc &MCID)
Builder interface. Specify how to create the initial instruction itself.
iterator_range< T > make_range(T x, T y)
Convenience function for iterating over sub-ranges.
unsigned getDeadRegState(bool B)
LLVM_ABI raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
FunctionAddr VTableAddr Count
constexpr bool isUInt(uint64_t x)
Checks if an unsigned integer fits into the given bit width.
@ First
Helpers to iterate all locations in the MemoryEffectsBase class.
unsigned getKillRegState(bool B)
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.