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();
220 Register StartReg = FirstOp0.getReg();
221 Register NextReg = SecondOp0.getReg();
224 unsigned StartRegState;
225 unsigned NextRegState = 0;
226 bool AddNextReg =
true;
228 if (
Opc == RISCV::LW) {
230 if (StartReg == RISCV::X0)
234 if (StartReg == Base1 || NextReg == Base1)
238 if (NextReg != StartReg + 1)
241 XqciOpc = RISCV::QC_LWMI;
245 assert(
Opc == RISCV::SW &&
"Expected a SW instruction");
246 if (StartReg == NextReg) {
247 XqciOpc = RISCV::QC_SETWMI;
248 StartRegState =
getKillRegState(FirstOp0.isKill() || SecondOp0.isKill());
250 }
else if (NextReg == StartReg + 1) {
251 XqciOpc = RISCV::QC_SWMI;
260 First->getDebugLoc() ?
First->getDebugLoc() : Second->getDebugLoc();
261 MachineInstrBuilder MIB =
BuildMI(*MF,
DL,
TII->get(XqciOpc));
262 MIB.
addReg(StartReg, StartRegState)
269 MIB.
addReg(NextReg, NextRegState);
272 First->removeFromParent();
273 Second->removeFromParent();
278bool RISCVLoadStoreOpt::tryConvertToMIPSLdStPair(
284 Align RequiredAlignment;
285 switch (
First->getOpcode()) {
289 PairOpc = RISCV::MIPS_SWP;
290 RequiredAlignment =
Align(8);
293 PairOpc = RISCV::MIPS_LWP;
294 RequiredAlignment =
Align(8);
297 PairOpc = RISCV::MIPS_SDP;
298 RequiredAlignment =
Align(16);
301 PairOpc = RISCV::MIPS_LDP;
302 RequiredAlignment =
Align(16);
306 const MachineMemOperand *MMO = *
First->memoperands_begin();
309 if (MMOAlign < RequiredAlignment)
316 MachineInstrBuilder MIB =
BuildMI(
317 *MF,
First->getDebugLoc() ?
First->getDebugLoc() : Second->getDebugLoc(),
320 .
add(Second->getOperand(0))
327 First->removeFromParent();
328 Second->removeFromParent();
338bool RISCVLoadStoreOpt::tryConvertToLdStPair(
340 MachineFunction *MF =
First->getMF();
341 const RISCVSubtarget &STI = MF->
getSubtarget<RISCVSubtarget>();
344 if (!STI.
is64Bit() && STI.hasVendorXqcilsm())
345 return tryConvertToXqcilsmLdStPair(MF,
First, Second);
348 return tryConvertToMIPSLdStPair(MF,
First, Second);
369 bool &MergeForward) {
372 MachineInstr &FirstMI = *
I;
381 MergeForward =
false;
385 ModifiedRegUnits.
clear();
386 UsedRegUnits.
clear();
389 SmallVector<MachineInstr *, 4> MemInsns;
397 if (!
MI.isTransient())
402 Register MIBaseReg =
MI.getOperand(1).getReg();
403 int64_t MIOffset =
MI.getOperand(2).getImm();
405 if (BaseReg == MIBaseReg) {
406 if ((
Offset != MIOffset + OffsetStride) &&
407 (
Offset + OffsetStride != MIOffset)) {
417 TRI->isSuperOrSubRegisterEq(
Reg,
MI.getOperand(0).getReg())) {
425 if (!ModifiedRegUnits.
available(BaseReg))
432 if (ModifiedRegUnits.
available(
MI.getOperand(0).getReg()) &&
434 !UsedRegUnits.
available(
MI.getOperand(0).getReg())) &&
437 MergeForward =
false;
469 if (!ModifiedRegUnits.
available(BaseReg))
473 if (
MI.mayLoadOrStore())
496 int Offset =
I->getOperand(2).getImm();
497 int PairedOffset = Paired->getOperand(2).getImm();
498 bool InsertAfter = (
Offset < PairedOffset) ^ MergeForward;
501 Paired->getOperand(1).setIsKill(
false);
504 if (
I->getOperand(0).isUse()) {
508 MachineOperand &PairedRegOp = Paired->getOperand(0);
509 if (PairedRegOp.
isKill()) {
510 for (
auto It = std::next(
I); It != Paired; ++It) {
511 if (It->readsRegister(PairedRegOp.
getReg(),
TRI)) {
521 for (MachineInstr &
MI :
make_range(std::next(
I), std::next(Paired)))
526 MachineInstr *ToInsert = DeletionPoint->removeFromParent();
527 MachineBasicBlock &
MBB = *InsertionPoint->getParent();
532 Second = InsertionPoint;
535 First = InsertionPoint;
538 if (tryConvertToLdStPair(
First, Second)) {
557 if (
First == RISCV::X0)
558 return Second == RISCV::X0;
561 unsigned FirstNum =
TRI->getEncodingValue(
First);
562 unsigned SecondNum =
TRI->getEncodingValue(Second);
565 return (FirstNum % 2 == 0) && (SecondNum == FirstNum + 1);
568void RISCVLoadStoreOpt::splitLdSdIntoTwo(MachineBasicBlock &
MBB,
571 MachineInstr *
MI = &*
MBBI;
574 const MachineOperand &FirstOp =
MI->getOperand(0);
575 const MachineOperand &SecondOp =
MI->getOperand(1);
576 const MachineOperand &BaseOp =
MI->getOperand(2);
582 const MachineOperand &
OffsetOp =
MI->getOperand(3);
590 unsigned Opc = IsLoad ? RISCV::LW : RISCV::SW;
591 MachineInstrBuilder MIB1, MIB2;
604 if (FirstReg == BaseReg) {
630 FirstReg != SecondReg &&
631 "First register and second register is impossible to be same register");
647 MIB2.
addImm(BaseOffset + 4);
668bool RISCVLoadStoreOpt::fixInvalidRegPairOp(MachineBasicBlock &
MBB,
670 MachineInstr *
MI = &*
MBBI;
671 unsigned Opcode =
MI->getOpcode();
674 if (Opcode != RISCV::PseudoLD_RV32_OPT && Opcode != RISCV::PseudoSD_RV32_OPT)
677 bool IsLoad = Opcode == RISCV::PseudoLD_RV32_OPT;
679 const MachineOperand &FirstOp =
MI->getOperand(0);
680 const MachineOperand &SecondOp =
MI->getOperand(1);
684 if (!isValidZilsdRegPair(FirstReg, SecondReg)) {
686 splitLdSdIntoTwo(
MBB,
MBBI, IsLoad);
691 const MachineOperand &BaseOp =
MI->getOperand(2);
695 const MachineOperand &
OffsetOp =
MI->getOperand(3);
697 unsigned RealOpc = IsLoad ? RISCV::LD_RV32 : RISCV::SD_RV32;
700 unsigned RegPair =
TRI->getMatchingSuperReg(FirstReg, RISCV::sub_gpr_even,
701 &RISCV::GPRPairRegClass);
718 LLVM_DEBUG(
dbgs() <<
"Converted pseudo to real instruction: " << *MIB
729 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.