69#define DEBUG_TYPE "hexagon-load-store-widening"
73 cl::desc(
"Limit block size to analyze in load/store widening pass"));
77struct HexagonLoadStoreWidening {
78 enum WideningMode { Store, Load };
98 const unsigned MaxWideSize = 8;
105 InstrSet ProcessedInsts;
112 void createGroup(
MachineInstr *BaseInst, InstrGroup &Group);
115 bool processGroup(InstrGroup &Group);
117 InstrGroup &OG,
unsigned &TotalSize,
unsigned MaxSize);
118 bool createWideInsts(InstrGroup &OG, InstrGroup &NG,
unsigned TotalSize);
119 bool createWideStores(InstrGroup &OG, InstrGroup &NG,
unsigned TotalSize);
120 bool createWideLoads(InstrGroup &OG, InstrGroup &NG,
unsigned TotalSize);
121 bool replaceInsts(InstrGroup &OG, InstrGroup &NG);
147 AliasAnalysis *AA = &getAnalysis<AAResultsWrapperPass>().getAAResults();
149 return HexagonLoadStoreWidening(
TII,
TRI,
MRI, AA, &MFn,
true).run();
174 AliasAnalysis *AA = &getAnalysis<AAResultsWrapperPass>().getAAResults();
175 return HexagonLoadStoreWidening(
TII,
TRI,
MRI, AA, &MFn,
false).run();
179char HexagonStoreWidening::ID = 0;
180char HexagonLoadWidening::ID = 0;
185 "Hexagon Store Widening",
false,
false)
197 assert(!
MI->memoperands_empty() &&
"Expecting memory operands");
198 return **
MI->memoperands_begin();
202HexagonLoadStoreWidening::getBaseAddressRegister(
const MachineInstr *
MI) {
203 assert(HexagonLoadStoreWidening::handledInstType(
MI) &&
"Unhandled opcode");
207 assert(MO.
isReg() &&
"Expecting register operand");
211int64_t HexagonLoadStoreWidening::getOffset(
const MachineInstr *
MI) {
212 assert(HexagonLoadStoreWidening::handledInstType(
MI) &&
"Unhandled opcode");
216 if (HII->isPostIncrement(*
MI))
235HexagonLoadStoreWidening::getPostIncrementValue(
const MachineInstr *
MI) {
236 unsigned Base, PostIncIdx;
237 HII->getBaseAndOffsetPosition(*
MI,
Base, PostIncIdx);
244inline bool HexagonLoadStoreWidening::handledInstType(
const MachineInstr *
MI) {
245 unsigned Opc =
MI->getOpcode();
246 if (Mode == WideningMode::Store) {
248 case Hexagon::S4_storeirb_io:
249 case Hexagon::S4_storeirh_io:
250 case Hexagon::S4_storeiri_io:
251 case Hexagon::S2_storeri_io:
253 return MI->getOperand(0).isReg();
254 case Hexagon::S2_storeri_pi:
255 return MI->getOperand(1).isReg();
262 case Hexagon::L2_loadri_io:
264 return !
MI->memoperands_empty() &&
MI->getOperand(1).isReg() &&
265 MI->getOperand(2).isImm();
266 case Hexagon::L2_loadri_pi:
267 return !
MI->memoperands_empty() &&
MI->getOperand(2).isReg();
276 for (
const auto &
Op :
MI->operands()) {
286bool HexagonLoadStoreWidening::canSwapInstructions(
const MachineInstr *
A,
291 if (
A->mayLoadOrStore() &&
B->mayLoadOrStore() &&
292 (
A->mayStore() ||
B->mayStore()) &&
A->mayAlias(AA, *
B,
true))
294 for (
const auto &BOp :
B->operands()) {
297 if ((BOp.isDef() || BOp.readsReg()) && ARegDefs.
contains(BOp.getReg()))
299 if (BOp.isDef() && ARegUses.
contains(BOp.getReg()))
315 InstrGroupList &StoreGroups) {
321 if (!handledInstType(
MI))
323 if (ProcessedInsts.count(
MI))
330 StoreGroups.push_back(
G);
337void HexagonLoadStoreWidening::createGroup(
MachineInstr *BaseInst,
339 assert(handledInstType(BaseInst) &&
"Unexpected instruction");
340 unsigned BaseReg = getBaseAddressRegister(BaseInst);
343 Group.push_back(BaseInst);
355 if (
MI->isCall() ||
MI->hasUnmodeledSideEffects() ||
356 MI->hasOrderedMemoryRef())
359 if (!handledInstType(
MI)) {
360 if (
MI->mayLoadOrStore())
368 for (
auto GI : Group)
369 if (GI->mayAlias(AA, *
MI,
true))
371 if (Mode == WideningMode::Load) {
375 for (
auto MemI :
Other)
376 if (!canSwapInstructions(
MI, MemI))
382 for (
auto MemI :
Other) {
383 if (std::distance(Group.back()->getIterator(), MemI->getIterator()) <=
386 for (
auto GI : Group)
387 if (!canSwapInstructions(MemI, GI))
392 unsigned BR = getBaseAddressRegister(
MI);
396 ProcessedInsts.insert(
MI);
405 if (!handledInstType(
S1) || !handledInstType(S2))
415 : int(Off1 + S1MO.
getSize().getValue()) == Off2;
424bool HexagonLoadStoreWidening::selectInsts(InstrGroup::iterator Begin,
425 InstrGroup::iterator
End,
426 InstrGroup &OG,
unsigned &TotalSize,
428 assert(Begin !=
End &&
"No instructions to analyze");
429 assert(OG.empty() &&
"Old group not empty on entry");
431 if (std::distance(Begin,
End) <= 1)
442 unsigned FirstOffset =
getOffset(FirstMI);
448 if (SizeAccum >= MaxSize)
453 if (SizeAccum >= Alignment) {
455 dbgs() <<
"Size of load/store greater than equal to its alignment\n");
465 unsigned OffsetOrIncVal = 0;
466 if (HII->isPostIncrement(*FirstMI))
467 OffsetOrIncVal = getPostIncrementValue(FirstMI);
469 OffsetOrIncVal = FirstOffset;
470 if ((2 * SizeAccum - 1) & OffsetOrIncVal) {
471 LLVM_DEBUG(
dbgs() <<
"Instruction cannot be widened as the offset/postinc"
472 <<
" value: " << getPostIncrementValue(FirstMI)
473 <<
" is invalid in the widened version\n");
477 OG.push_back(FirstMI);
482 unsigned Pow2Num = 1;
483 unsigned Pow2Size = SizeAccum;
484 bool HavePostInc = HII->isPostIncrement(*
S1);
491 for (InstrGroup::iterator
I = Begin + 1;
I !=
End; ++
I) {
495 if (!areAdjacent(
S1, S2))
500 if (HavePostInc && HII->isPostIncrement(*S2))
504 if (SizeAccum + S2Size > std::min(MaxSize, Alignment))
511 Pow2Size = SizeAccum;
513 if ((2 * Pow2Size - 1) & FirstOffset)
527 TotalSize = Pow2Size;
533bool HexagonLoadStoreWidening::createWideInsts(InstrGroup &OG, InstrGroup &NG,
534 unsigned TotalSize) {
535 if (Mode == WideningMode::Store) {
536 return createWideStores(OG, NG, TotalSize);
538 return createWideLoads(OG, NG, TotalSize);
544bool HexagonLoadStoreWidening::createWideStores(InstrGroup &OG, InstrGroup &NG,
545 unsigned TotalSize) {
550 if (TotalSize > MaxWideSize)
555 bool HaveImm =
false;
556 bool HaveReg =
false;
573 Mask = (0xFFFFFFFFFFFFFFFFU >> (64 - NBits));
587 if (HaveImm && HaveReg) {
588 LLVM_DEBUG(
dbgs() <<
"Cannot merge store register and store imm\n");
600 (HII->isPostIncrement(*FirstSt) ? FirstSt->
getOperand(1)
602 auto SecondSt = OG.back();
605 (HII->isPostIncrement(*FirstSt) ? FirstSt->
getOperand(3)
609 assert(!HII->isPostIncrement(*SecondSt) &&
"Unexpected PostInc");
612 "Cannot merge store register and store imm");
615 MF->getRegInfo().createVirtualRegister(&Hexagon::DoubleRegsRegClass);
619 if (FirstSt->
getOpcode() == Hexagon::S2_storeri_pi) {
637 assert(!HII->isPostIncrement(*FirstSt) &&
"Unexpected PostInc");
639 if (TotalSize == 8) {
642 int LowerAcc = int(Mask & Acc);
643 int UpperAcc = Acc >> 32;
645 MF->getRegInfo().createVirtualRegister(&Hexagon::DoubleRegsRegClass);
650 Register VReg = MF->getRegInfo().createVirtualRegister(RC);
667 }
else if (Acc < 0x10000) {
669 unsigned WOpc = (TotalSize == 2) ? Hexagon::S4_storeirh_io
670 : (TotalSize == 4) ? Hexagon::S4_storeiri_io
672 assert(WOpc &&
"Unexpected size");
674 int Val = (TotalSize == 2) ? int16_t(Acc) : int(Acc);
681 Register VReg = MF->getRegInfo().createVirtualRegister(RC);
685 unsigned WOpc = (TotalSize == 2) ? Hexagon::S2_storerh_io
686 : (TotalSize == 4) ? Hexagon::S2_storeri_io
688 assert(WOpc &&
"Unexpected size");
703bool HexagonLoadStoreWidening::createWideLoads(InstrGroup &OG, InstrGroup &NG,
704 unsigned TotalSize) {
709 if (TotalSize > MaxWideSize)
711 assert(OG.size() == 2 &&
"Expecting two elements in Instruction Group.");
721 (HII->isPostIncrement(*FirstLd) ? FirstLd->
getOperand(2)
726 Register NewMR =
MRI->createVirtualRegister(&Hexagon::DoubleRegsRegClass);
730 if (FirstLd->
getOpcode() == Hexagon::L2_loadri_pi) {
751 Register DestReg = DstReg->getOperand(0).getReg();
752 return BuildMI(*MF,
DL,
TII->get(Hexagon::COPY), DestReg)
756 MachineInstr *LdI_lo = getHalfReg(LdI, Hexagon::isub_lo, FirstLd);
757 MachineInstr *LdI_hi = getHalfReg(LdI, Hexagon::isub_hi, OG.back());
758 NG.push_back(LdI_lo);
759 NG.push_back(LdI_hi);
769bool HexagonLoadStoreWidening::replaceInsts(InstrGroup &OG, InstrGroup &NG) {
771 dbgs() <<
"Replacing:\n";
793 if (Mode == WideningMode::Load) {
795 for (
auto &
I : *
MBB) {
796 if (OldMemInsts.count(&
I)) {
802 assert((InsertAt !=
MBB->
end()) &&
"Cannot locate any load from the group");
810 if (OldMemInsts.count(&(*
I))) {
811 InsertAt = (*I).getIterator();
816 assert((
I !=
MBB->
rend()) &&
"Cannot locate any store from the group");
818 for (
auto I = NG.rbegin();
I != NG.rend(); ++
I)
823 I->eraseFromParent();
831bool HexagonLoadStoreWidening::processGroup(InstrGroup &Group) {
832 bool Changed =
false;
833 InstrGroup::iterator
I = Group.begin(), E = Group.end();
835 unsigned CollectedSize;
841 bool Succ = selectInsts(
I++, E, OG, CollectedSize, MaxWideSize) &&
842 createWideInsts(OG, NG, CollectedSize) && replaceInsts(OG, NG);
846 assert(OG.size() > 1 &&
"Created invalid group");
847 assert(std::distance(
I, E) + 1 >=
int(OG.size()) &&
"Too many elements");
864 bool Changed =
false;
870 createGroups(
MBB, SGs);
875 for (
auto &
G : SGs) {
876 assert(
G.size() > 1 &&
"Group with fewer than 2 elements");
879 Changed |= processGroup(
G);
885bool HexagonLoadStoreWidening::run() {
886 bool Changed =
false;
889 Changed |= processBasicBlock(
B);
895 return new HexagonStoreWidening();
899 return new HexagonLoadWidening();
unsigned const MachineRegisterInfo * MRI
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
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)
Register 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)
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.
A private abstract base class describing the concept of an individual alias analysis implementation.
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.
LLVM_ABI 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.
LLVM_ABI void dump() const
const MachineOperand & getOperand(unsigned i) const
LLVM_ABI 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,.
LLVM_ABI 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,...
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.
BaseReg
Stack frame base register. Bit 0 of FREInfo.Info.
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.
constexpr from_range_t from_range
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)
LLVM_ABI raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
FunctionPass * createHexagonLoadWidening()
unsigned getKillRegState(bool B)
FunctionPass * createHexagonStoreWidening()
uint64_t value() const
This is a hole in the type system and should not be abused.