38#define DEBUG_TYPE "riscv-load-store-opt"
39#define RISCV_LOAD_STORE_OPT_NAME "RISC-V Load / Store Optimizer"
45STATISTIC(NumLD2LW,
"Number of LD instructions split back to LW");
46STATISTIC(NumSD2SW,
"Number of SD instructions split back to SW");
56 MachineFunctionProperties getRequiredProperties()
const override {
57 return MachineFunctionProperties().setNoVRegs();
60 void getAnalysisUsage(AnalysisUsage &AU)
const override {
73 bool tryConvertToXqcilsmLdStPair(MachineFunction *MF,
76 bool tryConvertToMIPSLdStPair(MachineFunction *MF,
91 bool fixInvalidRegPairOp(MachineBasicBlock &
MBB,
94 void splitLdSdIntoTwo(MachineBasicBlock &
MBB,
99 MachineRegisterInfo *MRI;
100 const RISCVInstrInfo *TII;
101 const RISCVRegisterInfo *TRI;
102 LiveRegUnits ModifiedRegUnits, UsedRegUnits;
106char RISCVLoadStoreOpt::ID = 0;
111 if (skipFunction(Fn.getFunction()))
115 bool MadeChange =
false;
116 TII = Subtarget.getInstrInfo();
117 TRI = Subtarget.getRegisterInfo();
118 MRI = &Fn.getRegInfo();
119 AA = &getAnalysis<AAResultsWrapperPass>().getAAResults();
120 ModifiedRegUnits.init(*
TRI);
121 UsedRegUnits.init(*
TRI);
123 if (Subtarget.useMIPSLoadStorePairs() || Subtarget.hasVendorXqcilsm()) {
124 for (MachineBasicBlock &MBB : Fn) {
125 LLVM_DEBUG(dbgs() <<
"MBB: " << MBB.getName() <<
"\n");
127 for (MachineBasicBlock::iterator MBBI = MBB.begin(), E = MBB.end();
129 if (TII->isPairableLdStInstOpc(MBBI->getOpcode()) &&
130 tryToPairLdStInst(MBBI))
138 if (!Subtarget.is64Bit() && Subtarget.hasStdExtZilsd()) {
139 for (auto &MBB : Fn) {
140 for (auto MBBI = MBB.begin(), E = MBB.end(); MBBI != E;) {
141 if (fixInvalidRegPairOp(MBB, MBBI)) {
160 if (
MI.hasOrderedMemoryRef())
163 if (!
TII->isLdStSafeToPair(
MI,
TRI))
171 MBBI = mergePairedInsns(
MBBI, Paired, MergeForward);
177bool RISCVLoadStoreOpt::tryConvertToXqcilsmLdStPair(
181 if ((
Opc != RISCV::LW &&
Opc != RISCV::SW) || Second->getOpcode() !=
Opc)
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);
190 if (!FirstOp1.isReg() || !SecondOp1.isReg() || !FirstOp2.isImm() ||
195 Register Base2 = SecondOp1.getReg();
200 const MachineMemOperand *MMO = *
First->memoperands_begin();
203 if (MMOAlign <
Align(4))
206 auto &FirstOp0 =
First->getOperand(0);
207 auto &SecondOp0 = Second->getOperand(0);
209 int64_t Off1 = FirstOp2.getImm();
210 int64_t Off2 = SecondOp2.getImm();
217 Register StartReg = FirstOp0.getReg();
218 Register NextReg = SecondOp0.getReg();
220 if (StartReg == RISCV::X0 || NextReg == RISCV::X0)
224 if (
Opc == RISCV::LW && (StartReg == Base1 || NextReg == Base1))
230 if (NextReg != StartReg + 1)
233 unsigned XqciOpc = (
Opc == RISCV::LW) ? RISCV::QC_LWMI : RISCV::QC_SWMI;
243 First->getDebugLoc() ?
First->getDebugLoc() : Second->getDebugLoc();
244 MachineInstrBuilder MIB =
BuildMI(*MF,
DL,
TII->get(XqciOpc));
245 MIB.
addReg(StartReg, StartRegState)
250 .
addReg(NextReg, NextRegState);
253 First->removeFromParent();
254 Second->removeFromParent();
259bool RISCVLoadStoreOpt::tryConvertToMIPSLdStPair(
265 Align RequiredAlignment;
266 switch (
First->getOpcode()) {
270 PairOpc = RISCV::MIPS_SWP;
271 RequiredAlignment =
Align(8);
274 PairOpc = RISCV::MIPS_LWP;
275 RequiredAlignment =
Align(8);
278 PairOpc = RISCV::MIPS_SDP;
279 RequiredAlignment =
Align(16);
282 PairOpc = RISCV::MIPS_LDP;
283 RequiredAlignment =
Align(16);
287 const MachineMemOperand *MMO = *
First->memoperands_begin();
290 if (MMOAlign < RequiredAlignment)
297 MachineInstrBuilder MIB =
BuildMI(
298 *MF,
First->getDebugLoc() ?
First->getDebugLoc() : Second->getDebugLoc(),
301 .
add(Second->getOperand(0))
308 First->removeFromParent();
309 Second->removeFromParent();
319bool RISCVLoadStoreOpt::tryConvertToLdStPair(
321 MachineFunction *MF =
First->getMF();
322 const RISCVSubtarget &STI = MF->
getSubtarget<RISCVSubtarget>();
325 if (!STI.
is64Bit() && STI.hasVendorXqcilsm())
326 return tryConvertToXqcilsmLdStPair(MF,
First, Second);
329 return tryConvertToMIPSLdStPair(MF,
First, Second);
350 bool &MergeForward) {
353 MachineInstr &FirstMI = *
I;
362 MergeForward =
false;
366 ModifiedRegUnits.
clear();
367 UsedRegUnits.
clear();
370 SmallVector<MachineInstr *, 4> MemInsns;
378 if (!
MI.isTransient())
383 Register MIBaseReg =
MI.getOperand(1).getReg();
384 int64_t MIOffset =
MI.getOperand(2).getImm();
386 if (BaseReg == MIBaseReg) {
387 if ((
Offset != MIOffset + OffsetStride) &&
388 (
Offset + OffsetStride != MIOffset)) {
398 TRI->isSuperOrSubRegisterEq(
Reg,
MI.getOperand(0).getReg())) {
406 if (!ModifiedRegUnits.
available(BaseReg))
413 if (ModifiedRegUnits.
available(
MI.getOperand(0).getReg()) &&
415 !UsedRegUnits.
available(
MI.getOperand(0).getReg())) &&
418 MergeForward =
false;
450 if (!ModifiedRegUnits.
available(BaseReg))
454 if (
MI.mayLoadOrStore())
477 int Offset =
I->getOperand(2).getImm();
478 int PairedOffset = Paired->getOperand(2).getImm();
479 bool InsertAfter = (
Offset < PairedOffset) ^ MergeForward;
482 Paired->getOperand(1).setIsKill(
false);
485 if (
I->getOperand(0).isUse()) {
489 MachineOperand &PairedRegOp = Paired->getOperand(0);
490 if (PairedRegOp.
isKill()) {
491 for (
auto It = std::next(
I); It != Paired; ++It) {
492 if (It->readsRegister(PairedRegOp.
getReg(),
TRI)) {
502 for (MachineInstr &
MI :
make_range(std::next(
I), std::next(Paired)))
507 MachineInstr *ToInsert = DeletionPoint->removeFromParent();
508 MachineBasicBlock &
MBB = *InsertionPoint->getParent();
513 Second = InsertionPoint;
516 First = InsertionPoint;
519 if (tryConvertToLdStPair(
First, Second)) {
538 if (
First == RISCV::X0)
539 return Second == RISCV::X0;
542 unsigned FirstNum =
TRI->getEncodingValue(
First);
543 unsigned SecondNum =
TRI->getEncodingValue(Second);
546 return (FirstNum % 2 == 0) && (SecondNum == FirstNum + 1);
549void RISCVLoadStoreOpt::splitLdSdIntoTwo(MachineBasicBlock &
MBB,
552 MachineInstr *
MI = &*
MBBI;
555 const MachineOperand &FirstOp =
MI->getOperand(0);
556 const MachineOperand &SecondOp =
MI->getOperand(1);
557 const MachineOperand &BaseOp =
MI->getOperand(2);
563 const MachineOperand &
OffsetOp =
MI->getOperand(3);
571 unsigned Opc = IsLoad ? RISCV::LW : RISCV::SW;
572 MachineInstrBuilder MIB1, MIB2;
585 if (FirstReg == BaseReg) {
611 FirstReg != SecondReg &&
612 "First register and second register is impossible to be same register");
628 MIB2.
addImm(BaseOffset + 4);
649bool RISCVLoadStoreOpt::fixInvalidRegPairOp(MachineBasicBlock &
MBB,
651 MachineInstr *
MI = &*
MBBI;
652 unsigned Opcode =
MI->getOpcode();
655 if (Opcode != RISCV::PseudoLD_RV32_OPT && Opcode != RISCV::PseudoSD_RV32_OPT)
658 bool IsLoad = Opcode == RISCV::PseudoLD_RV32_OPT;
660 const MachineOperand &FirstOp =
MI->getOperand(0);
661 const MachineOperand &SecondOp =
MI->getOperand(1);
665 if (!isValidZilsdRegPair(FirstReg, SecondReg)) {
667 splitLdSdIntoTwo(
MBB,
MBBI, IsLoad);
672 const MachineOperand &BaseOp =
MI->getOperand(2);
676 const MachineOperand &
OffsetOp =
MI->getOperand(3);
678 unsigned RealOpc = IsLoad ? RISCV::LD_RV32 : RISCV::SD_RV32;
681 unsigned RegPair =
TRI->getMatchingSuperReg(FirstReg, RISCV::sub_gpr_even,
682 &RISCV::GPRPairRegClass);
699 LLVM_DEBUG(
dbgs() <<
"Converted pseudo to real instruction: " << *MIB
710 return new RISCVLoadStoreOpt();
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!")
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
MachineBasicBlock MachineBasicBlock::iterator MBBI
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
const HexagonInstrInfo * TII
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
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.
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 TargetSubtargetInfo & getSubtarget() const
getSubtarget - Return the subtarget for which this machine code is being compiled.
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.
@ Implicit
Not emitted register (e.g. carry, or temporary result).
@ 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()
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.
constexpr bool isShiftedUInt(uint64_t x)
Checks if a unsigned integer is an N bit number shifted left by S.
void swap(llvm::BitVector &LHS, llvm::BitVector &RHS)
Implement std::swap in terms of BitVector swap.