69#define DEBUG_TYPE "hexagon-load-store-widening"
73 cl::desc(
"Limit block size to analyze in load/store widening pass"));
86struct HexagonLoadStoreWidening {
87 enum WideningMode { Store, Load };
107 const unsigned MaxWideSize = 8;
114 InstrSet ProcessedInsts;
121 void createGroup(
MachineInstr *BaseInst, InstrGroup &Group);
124 bool processGroup(InstrGroup &Group);
126 InstrGroup &OG,
unsigned &TotalSize,
unsigned MaxSize);
127 bool createWideInsts(InstrGroup &OG, InstrGroup &NG,
unsigned TotalSize);
128 bool createWideStores(InstrGroup &OG, InstrGroup &NG,
unsigned TotalSize);
129 bool createWideLoads(InstrGroup &OG, InstrGroup &NG,
unsigned TotalSize);
130 bool replaceInsts(InstrGroup &OG, InstrGroup &NG);
158 AliasAnalysis *AA = &getAnalysis<AAResultsWrapperPass>().getAAResults();
160 return HexagonLoadStoreWidening(
TII,
TRI,
MRI, AA, &MFn,
true).run();
187 AliasAnalysis *AA = &getAnalysis<AAResultsWrapperPass>().getAAResults();
188 return HexagonLoadStoreWidening(
TII,
TRI,
MRI, AA, &MFn,
false).run();
192char HexagonStoreWidening::ID = 0;
193char HexagonLoadWidening::ID = 0;
198 "Hexagon Store Widening",
false,
false)
210 assert(!
MI->memoperands_empty() &&
"Expecting memory operands");
211 return **
MI->memoperands_begin();
215HexagonLoadStoreWidening::getBaseAddressRegister(
const MachineInstr *
MI) {
216 assert(HexagonLoadStoreWidening::handledInstType(
MI) &&
"Unhandled opcode");
220 assert(MO.
isReg() &&
"Expecting register operand");
224int64_t HexagonLoadStoreWidening::getOffset(
const MachineInstr *
MI) {
225 assert(HexagonLoadStoreWidening::handledInstType(
MI) &&
"Unhandled opcode");
229 if (HII->isPostIncrement(*
MI))
248HexagonLoadStoreWidening::getPostIncrementValue(
const MachineInstr *
MI) {
249 unsigned Base, PostIncIdx;
250 HII->getBaseAndOffsetPosition(*
MI,
Base, PostIncIdx);
257inline bool HexagonLoadStoreWidening::handledInstType(
const MachineInstr *
MI) {
258 unsigned Opc =
MI->getOpcode();
259 if (Mode == WideningMode::Store) {
261 case Hexagon::S4_storeirb_io:
262 case Hexagon::S4_storeirh_io:
263 case Hexagon::S4_storeiri_io:
264 case Hexagon::S2_storeri_io:
266 return MI->getOperand(0).isReg();
267 case Hexagon::S2_storeri_pi:
268 return MI->getOperand(1).isReg();
275 case Hexagon::L2_loadri_io:
277 return !
MI->memoperands_empty() &&
MI->getOperand(1).isReg() &&
278 MI->getOperand(2).isImm();
279 case Hexagon::L2_loadri_pi:
280 return !
MI->memoperands_empty() &&
MI->getOperand(2).isReg();
289 for (
const auto &
Op :
MI->operands()) {
299bool HexagonLoadStoreWidening::canSwapInstructions(
const MachineInstr *
A,
304 if (
A->mayLoadOrStore() &&
B->mayLoadOrStore() &&
305 (
A->mayStore() ||
B->mayStore()) &&
A->mayAlias(AA, *
B,
true))
307 for (
const auto &BOp :
B->operands()) {
310 if ((BOp.isDef() || BOp.readsReg()) && ARegDefs.
contains(BOp.getReg()))
312 if (BOp.isDef() && ARegUses.
contains(BOp.getReg()))
328 InstrGroupList &StoreGroups) {
334 if (!handledInstType(
MI))
336 if (ProcessedInsts.count(
MI))
343 StoreGroups.push_back(
G);
350void HexagonLoadStoreWidening::createGroup(
MachineInstr *BaseInst,
352 assert(handledInstType(BaseInst) &&
"Unexpected instruction");
353 unsigned BaseReg = getBaseAddressRegister(BaseInst);
356 Group.push_back(BaseInst);
368 if (
MI->isCall() ||
MI->hasUnmodeledSideEffects() ||
369 MI->hasOrderedMemoryRef())
372 if (!handledInstType(
MI)) {
373 if (
MI->mayLoadOrStore())
381 for (
auto GI : Group)
382 if (GI->mayAlias(AA, *
MI,
true))
384 if (Mode == WideningMode::Load) {
388 for (
auto MemI :
Other)
389 if (!canSwapInstructions(
MI, MemI))
395 for (
auto MemI :
Other) {
396 if (std::distance(Group.back()->getIterator(), MemI->getIterator()) <=
399 for (
auto GI : Group)
400 if (!canSwapInstructions(MemI, GI))
405 unsigned BR = getBaseAddressRegister(
MI);
409 ProcessedInsts.insert(
MI);
418 if (!handledInstType(
S1) || !handledInstType(S2))
428 : int(Off1 + S1MO.
getSize().getValue()) == Off2;
437bool HexagonLoadStoreWidening::selectInsts(InstrGroup::iterator Begin,
438 InstrGroup::iterator
End,
439 InstrGroup &OG,
unsigned &TotalSize,
441 assert(Begin !=
End &&
"No instructions to analyze");
442 assert(OG.empty() &&
"Old group not empty on entry");
444 if (std::distance(Begin,
End) <= 1)
455 unsigned FirstOffset =
getOffset(FirstMI);
461 if (SizeAccum >= MaxSize)
466 if (SizeAccum >= Alignment) {
468 dbgs() <<
"Size of load/store greater than equal to its alignment\n");
478 unsigned OffsetOrIncVal = 0;
479 if (HII->isPostIncrement(*FirstMI))
480 OffsetOrIncVal = getPostIncrementValue(FirstMI);
482 OffsetOrIncVal = FirstOffset;
483 if ((2 * SizeAccum - 1) & OffsetOrIncVal) {
484 LLVM_DEBUG(
dbgs() <<
"Instruction cannot be widened as the offset/postinc"
485 <<
" value: " << getPostIncrementValue(FirstMI)
486 <<
" is invalid in the widened version\n");
490 OG.push_back(FirstMI);
495 unsigned Pow2Num = 1;
496 unsigned Pow2Size = SizeAccum;
497 bool HavePostInc = HII->isPostIncrement(*
S1);
504 for (InstrGroup::iterator
I = Begin + 1;
I !=
End; ++
I) {
508 if (!areAdjacent(
S1, S2))
513 if (HavePostInc && HII->isPostIncrement(*S2))
517 if (SizeAccum + S2Size > std::min(MaxSize, Alignment))
524 Pow2Size = SizeAccum;
526 if ((2 * Pow2Size - 1) & FirstOffset)
540 TotalSize = Pow2Size;
546bool HexagonLoadStoreWidening::createWideInsts(InstrGroup &OG, InstrGroup &NG,
547 unsigned TotalSize) {
548 if (Mode == WideningMode::Store) {
549 return createWideStores(OG, NG, TotalSize);
551 return createWideLoads(OG, NG, TotalSize);
557bool HexagonLoadStoreWidening::createWideStores(InstrGroup &OG, InstrGroup &NG,
558 unsigned TotalSize) {
563 if (TotalSize > MaxWideSize)
568 bool HaveImm =
false;
569 bool HaveReg =
false;
586 Mask = (0xFFFFFFFFFFFFFFFFU >> (64 - NBits));
600 if (HaveImm && HaveReg) {
601 LLVM_DEBUG(
dbgs() <<
"Cannot merge store register and store imm\n");
613 (HII->isPostIncrement(*FirstSt) ? FirstSt->
getOperand(1)
615 auto SecondSt = OG.back();
618 (HII->isPostIncrement(*FirstSt) ? FirstSt->
getOperand(3)
622 assert(!HII->isPostIncrement(*SecondSt) &&
"Unexpected PostInc");
625 "Cannot merge store register and store imm");
628 MF->getRegInfo().createVirtualRegister(&Hexagon::DoubleRegsRegClass);
632 if (FirstSt->
getOpcode() == Hexagon::S2_storeri_pi) {
650 assert(!HII->isPostIncrement(*FirstSt) &&
"Unexpected PostInc");
652 if (TotalSize == 8) {
655 int LowerAcc = int(Mask & Acc);
656 int UpperAcc = Acc >> 32;
658 MF->getRegInfo().createVirtualRegister(&Hexagon::DoubleRegsRegClass);
663 Register VReg = MF->getRegInfo().createVirtualRegister(RC);
680 }
else if (Acc < 0x10000) {
682 unsigned WOpc = (TotalSize == 2) ? Hexagon::S4_storeirh_io
683 : (TotalSize == 4) ? Hexagon::S4_storeiri_io
685 assert(WOpc &&
"Unexpected size");
687 int Val = (TotalSize == 2) ? int16_t(Acc) : int(Acc);
694 Register VReg = MF->getRegInfo().createVirtualRegister(RC);
698 unsigned WOpc = (TotalSize == 2) ? Hexagon::S2_storerh_io
699 : (TotalSize == 4) ? Hexagon::S2_storeri_io
701 assert(WOpc &&
"Unexpected size");
716bool HexagonLoadStoreWidening::createWideLoads(InstrGroup &OG, InstrGroup &NG,
717 unsigned TotalSize) {
722 if (TotalSize > MaxWideSize)
724 assert(OG.size() == 2 &&
"Expecting two elements in Instruction Group.");
734 (HII->isPostIncrement(*FirstLd) ? FirstLd->
getOperand(2)
739 Register NewMR =
MRI->createVirtualRegister(&Hexagon::DoubleRegsRegClass);
743 if (FirstLd->
getOpcode() == Hexagon::L2_loadri_pi) {
764 Register DestReg = DstReg->getOperand(0).getReg();
765 return BuildMI(*MF,
DL,
TII->get(Hexagon::COPY), DestReg)
769 MachineInstr *LdI_lo = getHalfReg(LdI, Hexagon::isub_lo, FirstLd);
770 MachineInstr *LdI_hi = getHalfReg(LdI, Hexagon::isub_hi, OG.back());
771 NG.push_back(LdI_lo);
772 NG.push_back(LdI_hi);
782bool HexagonLoadStoreWidening::replaceInsts(InstrGroup &OG, InstrGroup &NG) {
784 dbgs() <<
"Replacing:\n";
804 InstrSet OldMemInsts;
806 OldMemInsts.insert(
I);
808 if (Mode == WideningMode::Load) {
810 for (
auto &
I : *
MBB) {
811 if (OldMemInsts.count(&
I)) {
817 assert((InsertAt !=
MBB->
end()) &&
"Cannot locate any load from the group");
825 if (OldMemInsts.count(&(*
I))) {
826 InsertAt = (*I).getIterator();
831 assert((
I !=
MBB->
rend()) &&
"Cannot locate any store from the group");
833 for (
auto I = NG.rbegin();
I != NG.rend(); ++
I)
838 I->eraseFromParent();
846bool HexagonLoadStoreWidening::processGroup(InstrGroup &Group) {
847 bool Changed =
false;
848 InstrGroup::iterator
I = Group.begin(), E = Group.end();
850 unsigned CollectedSize;
856 bool Succ = selectInsts(
I++, E, OG, CollectedSize, MaxWideSize) &&
857 createWideInsts(OG, NG, CollectedSize) && replaceInsts(OG, NG);
861 assert(OG.size() > 1 &&
"Created invalid group");
862 assert(std::distance(
I, E) + 1 >=
int(OG.size()) &&
"Too many elements");
879 bool Changed =
false;
885 createGroups(
MBB, SGs);
890 for (
auto &
G : SGs) {
891 assert(
G.size() > 1 &&
"Group with fewer than 2 elements");
894 Changed |= processGroup(
G);
900bool HexagonLoadStoreWidening::run() {
901 bool Changed =
false;
904 Changed |= processBasicBlock(
B);
910 return new HexagonStoreWidening();
914 return new HexagonLoadWidening();
unsigned const MachineRegisterInfo * MRI
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
static GCRegistry::Add< ErlangGC > A("erlang", "erlang-compatible garbage collector")
std::optional< std::vector< StOtherPiece > > Other
const HexagonInstrInfo * TII
hexagon widen Hexagon Store Widening
static cl::opt< unsigned > MaxMBBSizeForLoadStoreWidening("max-bb-size-for-load-store-widening", cl::Hidden, cl::init(1000), cl::desc("Limit block size to analyze in load/store widening pass"))
hexagon widen Hexagon Store false hexagon widen loads
static void addDefsUsesToList(const MachineInstr *MI, DenseSet< Register > &RegDefs, DenseSet< Register > &RegUses)
hexagon widen Hexagon Store false hexagon widen Hexagon Load static false const MachineMemOperand & getMemTarget(const MachineInstr *MI)
unsigned const TargetRegisterInfo * TRI
This file provides utility analysis objects describing memory locations.
#define INITIALIZE_PASS_DEPENDENCY(depName)
#define INITIALIZE_PASS_END(passName, arg, name, cfg, analysis)
#define INITIALIZE_PASS_BEGIN(passName, arg, name, cfg, analysis)
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
This file defines the SmallPtrSet class.
static unsigned getSize(unsigned Kind)
A wrapper pass to provide the legacy pass manager access to a suitably prepared AAResults object.
Represent the analysis usage information of a pass.
AnalysisUsage & addRequired()
AnalysisUsage & addPreserved()
Add the specified Pass class to the set of analyses preserved by this pass.
This class represents an Operation in the Expression.
Implements a dense probed hash-table based set.
FunctionPass class - This class is used to implement most global optimizations.
bool skipFunction(const Function &F) const
Optional passes call this function to check whether the pass should be skipped.
constexpr bool isValid() const
TypeSize getValue() const
Describe properties that are true of each instruction in the target description file.
instr_iterator insert(instr_iterator I, MachineInstr *M)
Insert MI into the instruction list before I, possibly inside a bundle.
reverse_iterator rbegin()
iterator insertAfter(iterator I, MachineInstr *MI)
Insert MI into the instruction list after I.
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.
virtual bool runOnMachineFunction(MachineFunction &MF)=0
runOnMachineFunction - This method must be overloaded to perform the desired machine code transformat...
const TargetSubtargetInfo & getSubtarget() const
getSubtarget - Return the subtarget for which this machine code is being compiled.
MachineRegisterInfo & getRegInfo()
getRegInfo - Return information about the registers currently in use.
Function & getFunction()
Return the LLVM function that this machine code represents.
const MachineInstrBuilder & addImm(int64_t Val) const
Add a new immediate operand.
const MachineInstrBuilder & add(const MachineOperand &MO) const
const MachineInstrBuilder & addReg(Register RegNo, unsigned flags=0, unsigned SubReg=0) const
Add a new virtual register operand.
const MachineInstrBuilder & addDef(Register RegNo, unsigned Flags=0, unsigned SubReg=0) const
Add a virtual register definition operand.
Representation of each machine instruction.
unsigned getOpcode() const
Returns the opcode of this MachineInstr.
const MachineBasicBlock * getParent() const
bool memoperands_empty() const
Return true if we don't have any memory operands which described the memory access done by this instr...
const DebugLoc & getDebugLoc() const
Returns the debug location id of this MachineInstr.
const MachineOperand & getOperand(unsigned i) const
void addMemOperand(MachineFunction &MF, MachineMemOperand *MO)
Add a MachineMemOperand to the machine instruction.
A description of a memory reference used in the backend.
LocationSize getSize() const
Return the size in bytes of the memory reference.
const MachinePointerInfo & getPointerInfo() const
Flags getFlags() const
Return the raw flags of the source value,.
Align getAlign() const
Return the minimum known alignment in bytes of the actual memory reference.
LocationSize getSizeInBits() const
Return the size in bits of the memory reference.
AAMDNodes getAAInfo() const
Return the AA tags for the memory reference.
MachineOperand class - Representation of each machine instruction operand.
unsigned getSubReg() const
bool isReg() const
isReg - Tests if this is a MO_Register operand.
MachineOperandType getType() const
getType - Returns the MachineOperandType for this operand.
Register getReg() const
getReg - Returns the register number.
@ MO_Immediate
Immediate operand.
@ MO_GlobalAddress
Address of a global value.
@ MO_Register
Register operand.
int64_t getOffset() const
Return the offset from the symbol in this operand.
MachineRegisterInfo - Keep track of information for virtual and physical registers,...
PassRegistry - This class manages the registration and intitialization of the pass subsystem as appli...
static PassRegistry * getPassRegistry()
getPassRegistry - Access the global registry object, which is automatically initialized at applicatio...
virtual StringRef getPassName() const
getPassName - Return a nice clean name for a pass.
Wrapper class representing virtual and physical registers.
SmallPtrSet - This class implements a set which is optimized for holding SmallSize or less elements.
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
StringRef - Represent a constant reference to a string, i.e.
std::pair< iterator, bool > insert(const ValueT &V)
bool contains(const_arg_type_t< ValueT > V) const
Check if the set contains the given element.
self_iterator getIterator()
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
constexpr std::underlying_type_t< E > Mask()
Get a bitmask with 1s in all places up to the high-order bit of E's largest value.
unsigned ID
LLVM IR allows to use arbitrary numbers as calling convention identifiers.
@ BR
Control flow instructions. These all have token chains.
@ Kill
The last use of a register.
initializer< Ty > init(const Ty &Val)
PointerTypeMap run(const Module &M)
Compute the PointerTypeMap for the module M.
This is an optimization pass for GlobalISel generic memory operations.
MachineInstrBuilder BuildMI(MachineFunction &MF, const MIMetadata &MIMD, const MCInstrDesc &MCID)
Builder interface. Specify how to create the initial instruction itself.
static Error getOffset(const SymbolRef &Sym, SectionRef Sec, uint64_t &Result)
constexpr bool isPowerOf2_32(uint32_t Value)
Return true if the argument is a power of two > 0.
void sort(IteratorTy Start, IteratorTy End)
raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
FunctionPass * createHexagonLoadWidening()
void initializeHexagonStoreWideningPass(PassRegistry &)
unsigned getKillRegState(bool B)
void initializeHexagonLoadWideningPass(PassRegistry &)
FunctionPass * createHexagonStoreWidening()
uint64_t value() const
This is a hole in the type system and should not be abused.