42#define DEBUG_TYPE "opt-addr-mode"
69 return "Optimize addressing mode of load/store";
101 bool findFirstReachedInst(
111 bool analyzeUses(
unsigned DefR,
const NodeList &UNodeList,
112 InstrEvalMap &InstrEvalResult,
short &SizeInc);
117 unsigned LRExtReg,
const NodeList &UNodeList);
133char HexagonOptAddrMode::ID = 0;
136 "Optimize addressing mode",
false,
false)
142bool HexagonOptAddrMode::hasRepForm(
MachineInstr &
MI,
unsigned TfrDefR) {
156 return (HII->changeAddrMode_rr_ur(
MI) >= 0);
159 return (HII->changeAddrMode_io_abs(
MI) >= 0);
182 Register OffsetReg =
MI.getOperand(2).getReg();
187 if (OffsetReg == RR.
Reg) {
189 OffsetRegRD = UA.Addr->getReachingDef();
193 for (
auto I = UNodeList.rbegin(), E = UNodeList.rend();
I != E; ++
I) {
199 if ((DFG->IsDef(AA) && AA.
Id != OffsetRegRD) ||
200 AA.
Addr->getReachingDef() != OffsetRegRD)
207 MI.getParent() !=
UseMI.getParent())
213 getBaseWithLongOffset(
UseMI) < 0)
221 for (
auto &Mo :
UseMI.operands())
226 if (!
UseMI.getParent()->isLiveIn(OffsetReg) &&
227 MI.getParent() !=
UseMI.getParent()) {
229 <<
" is NOT live in to MBB "
230 <<
UseMI.getParent()->getName() <<
"\n");
239 for (
auto I = UNodeList.rbegin(), E = UNodeList.rend();
I != E; ++
I) {
243 const auto &
P = LV->getAllReachingDefsRec(UR, UN, Visited, Defs);
246 dbgs() <<
"*** Unable to collect all reaching defs for use ***\n"
248 <<
"The program's complexity may exceed the limits.\n";
252 const auto &ReachingDefs =
P.first;
253 if (ReachingDefs.size() > 1) {
255 dbgs() <<
"*** Multiple Reaching Defs found!!! ***\n";
256 for (
auto DI : ReachingDefs) {
259 dbgs() <<
"\t\t[Reaching Def]: "
276 auto UseSet = LV->getAllReachedUses(DR, DA);
278 for (
auto UI : UseSet) {
282 dbgs() <<
"\t\t\t[Reached Use]: "
292 if (!phiUse.empty()) {
293 for (
auto I : phiUse) {
296 auto phiUseSet =
I.second;
297 for (
auto phiUI : phiUseSet) {
299 UNodeList.push_back(phiUA);
304 UNodeList.push_back(UA);
318 if (LRExtReg == RR.
Reg) {
320 LRExtRegRD = UA.
Addr->getReachingDef();
324 for (
auto I = UNodeList.rbegin(), E = UNodeList.rend();
I != E; ++
I) {
332 if ((DFG->IsDef(AA) && AA.
Id != LRExtRegRD) ||
333 AA.
Addr->getReachingDef() != LRExtRegRD) {
335 dbgs() <<
"isSafeToExtLR: Returning false; another reaching def\n");
355 <<
" is NOT live in to MBB "
364 if (HII->isHVXVec(*
MI)) {
367 switch (
MI->getOpcode()) {
368 case Hexagon::V6_vgathermh_pseudo:
369 case Hexagon::V6_vgathermw_pseudo:
370 case Hexagon::V6_vgathermhw_pseudo:
371 case Hexagon::V6_vgathermhq_pseudo:
372 case Hexagon::V6_vgathermwq_pseudo:
373 case Hexagon::V6_vgathermhwq_pseudo:
374 return HII->isValidOffset(
MI->getOpcode(),
Offset, HRI,
false);
378 unsigned AlignMask = HII->getMemAccessSize(*
MI) - 1;
379 if ((AlignMask &
Offset) == 0)
380 return HII->isValidOffset(
MI->getOpcode(),
Offset, HRI,
false);
389 unsigned AlignMask = 0;
390 switch (HII->getMemAccessSize(*
MI)) {
391 case HexagonII::MemAccessSize::DoubleWordAccess:
394 case HexagonII::MemAccessSize::WordAccess:
397 case HexagonII::MemAccessSize::HalfWordAccess:
400 case HexagonII::MemAccessSize::ByteAccess:
407 if ((AlignMask &
Offset) != 0)
409 return HII->isValidOffset(
MI->getOpcode(),
Offset, HRI,
false);
414 switch (
MI->getOpcode()) {
418 case Hexagon::V6_vgathermh_pseudo:
419 case Hexagon::V6_vgathermw_pseudo:
420 case Hexagon::V6_vgathermhw_pseudo:
421 case Hexagon::V6_vgathermhq_pseudo:
422 case Hexagon::V6_vgathermwq_pseudo:
423 case Hexagon::V6_vgathermhwq_pseudo:
430unsigned HexagonOptAddrMode::getOffsetOpPosition(
MachineInstr *
MI) {
433 "Looking for an offset in non-BaseImmOffset addressing mode instruction");
436 switch (
MI->getOpcode()) {
440 case Hexagon::V6_vgathermh_pseudo:
441 case Hexagon::V6_vgathermw_pseudo:
442 case Hexagon::V6_vgathermhw_pseudo:
443 case Hexagon::V6_vgathermhq_pseudo:
444 case Hexagon::V6_vgathermwq_pseudo:
445 case Hexagon::V6_vgathermhwq_pseudo:
456 getAllRealUses(CurrentInstSN, LoadStoreUseList);
457 bool FoundLoadStoreUse =
false;
458 for (
auto I = LoadStoreUseList.begin(), E = LoadStoreUseList.end();
I != E;
465 isValidOffset(LoadStoreMI, NewOffset)) {
466 FoundLoadStoreUse =
true;
470 return FoundLoadStoreUse;
473bool HexagonOptAddrMode::findFirstReachedInst(
490 for (
auto &InstIter : *CurrentMBB) {
492 if (InstIter.getOpcode() == Hexagon::A2_addi) {
493 auto Iter = std::find_if(
494 AddiList.begin(), AddiList.end(), [&InstIter](
const auto &SUPair) {
495 return SUPair.first.Addr->getCode() == &InstIter;
497 if (Iter != AddiList.end()) {
534 bool Changed =
false;
536 LLVM_DEBUG(
dbgs() <<
"\n\t\t[Processing Addi]: " << *AddMI <<
"\n");
542 if (ProcessedAddiInsts.find(
MI) != ProcessedAddiInsts.end()) {
543 LLVM_DEBUG(
dbgs() <<
"\t\t\tAddi already found in ProcessedAddiInsts: "
544 << *
MI <<
"\n\t\t\tSkipping...");
550 if (Processed(AddMI, ProcessedAddiInsts))
552 ProcessedAddiInsts.insert(AddMI);
565 if (BaseReg != URR.
Reg)
568 UAReachingDefID = UA.
Addr->getReachingDef();
571 LLVM_DEBUG(
dbgs() <<
"\t\t\t Could not find reachingDef. Skipping...\n");
581 MachineInstr *ReachingDefInstr = ReachingDefStmt.Addr->getCode();
582 if (HII->isPredicated(*ReachingDefInstr))
589 getAllRealUses(ReachingDefStmt, AddiUseList);
590 for (
auto I = AddiUseList.begin(), E = AddiUseList.end();
I != E; ++
I) {
596 if (
MI->getOpcode() == Hexagon::A2_addi &&
597 !(
MI != AddMI && Processed(
MI, ProcessedAddiInsts))) {
598 AddiList.push_back({SN, UN});
601 ProcessedAddiInsts.insert(
MI);
606 if (AddiList.size() <= 1)
611 if (!findFirstReachedInst(AddMI, AddiList, FirstReachedUseSN))
618 FirstReachedUseSN.
Addr->members_if(DFG->IsDef, *DFG).front();
622 if (!FirstReachedMIImmOp.
isImm())
625 for (
auto &
I : AddiList) {
636 if (!CurrentMIImmOp.
isImm())
639 NewOffset = CurrentMIImmOp.
getImm() - FirstReachedMIImmOp.
getImm();
642 if (CurrentMI == FirstReachedMI) {
656 if (!usedInLoadStore(CurrentInstSN, NewOffset)) {
662 RegisterRef FirstReachedDefRR = FirstReachedUseDN.
Addr->getRegRef(*DFG);
665 LV->getNearestAliasedRef(FirstReachedDefRR, CurrentAddiIN);
666 if ((DFG->IsDef(NearestAA) && NearestAA.
Id != FirstReachedUseDN.
Id) ||
667 (!DFG->IsDef(NearestAA) &&
668 NearestAA.
Addr->getReachingDef() != FirstReachedUseDN.
Id)) {
670 LLVM_DEBUG(
dbgs() <<
"\t\t\tCould not modify below Addi since the first "
671 "defined Addi register was redefined\n");
682 Changed |= updateAddBases(CurrentMI, FirstReachedMI, NewOffset);
685 CurrentInstUN.
Addr->linkToDef(CurrentInstUN.
Id, FirstReachedUseDN);
691bool HexagonOptAddrMode::updateAddBases(
MachineInstr *CurrentMI,
694 LLVM_DEBUG(
dbgs() <<
"[About to modify the Addi]: " << *CurrentMI <<
"\n");
701 CurrentMIBaseOp.
setReg(FirstDefRegister);
704 CurrentMIImmOp.
setImm(NewOffset);
705 ProcessedAddiInsts.insert(CurrentMI);
706 MRI->clearKillFlags(FirstDefRegister);
716 for (
auto I = UNodeList.rbegin(), E = UNodeList.rend();
I != E; ++
I) {
731 if (!OffsetOp.
isImm())
735 if (!isValidOffset(
MI, newOffset))
745 if (!isSafeToExtLR(AddSN, AddMI, BaseReg, UNodeList))
754 if (BaseReg == RR.
Reg)
755 LRExtRegRD = UA.
Addr->getReachingDef();
760 bool Changed =
false;
761 for (
auto I = UNodeList.rbegin(), E = UNodeList.rend();
I != E; ++
I) {
764 "Found a PhiRef node as a real reached use!!");
769 <<
">]: " << *
UseMI <<
"\n");
770 Changed |= updateAddUses(AddMI,
UseMI);
776 UseN.
Addr->linkToDef(UseN.
Id, LRExtRegDN);
785bool HexagonOptAddrMode::updateAddUses(
MachineInstr *AddMI,
797 MRI->clearKillFlags(NewReg);
802bool HexagonOptAddrMode::analyzeUses(
unsigned tfrDefR,
804 InstrEvalMap &InstrEvalResult,
806 bool KeepTfr =
false;
807 bool HasRepInstr =
false;
808 InstrEvalResult.clear();
810 for (
auto I = UNodeList.rbegin(), E = UNodeList.rend();
I != E; ++
I) {
811 bool CanBeReplaced =
false;
817 if (!hasRepForm(
MI, tfrDefR)) {
822 CanBeReplaced =
true;
823 }
else if (
MI.getOpcode() == Hexagon::S2_addasl_rrri) {
827 getAllRealUses(SN, AddaslUseList);
829 if (allValidCandidates(SN, AddaslUseList) &&
830 canRemoveAddasl(SN,
MI, AddaslUseList)) {
831 SizeInc += AddaslUseList.size();
833 CanBeReplaced =
true;
843 InstrEvalResult[&
MI] = CanBeReplaced;
844 HasRepInstr |= CanBeReplaced;
856 bool Changed =
false;
867 short NewOpCode = HII->changeAddrMode_rr_ur(*OldMI);
868 assert(NewOpCode >= 0 &&
"Invalid New opcode\n");
878 short NewOpCode = HII->changeAddrMode_io_abs(*OldMI);
879 assert(NewOpCode >= 0 &&
"Invalid New opcode\n");
893 }
else if (ImmOpNum == 2) {
895 short NewOpCode = HII->changeAddrMode_rr_io(*OldMI);
896 assert(NewOpCode >= 0 &&
"Invalid New opcode\n");
909 for (
unsigned i = OpStart; i < OpEnd; ++i)
917 bool Changed =
false;
918 unsigned OpStart = 0;
927 short NewOpCode = HII->changeAddrMode_rr_ur(*OldMI);
928 assert(NewOpCode >= 0 &&
"Invalid New opcode\n");
937 short NewOpCode = HII->changeAddrMode_io_abs(*OldMI);
938 assert(NewOpCode >= 0 &&
"Invalid New opcode\n");
948 short NewOpCode = HII->changeAddrMode_rr_io(*OldMI);
949 assert(NewOpCode >= 0 &&
"Invalid New opcode\n");
960 for (
unsigned i = OpStart; i < OpEnd; ++i)
967short HexagonOptAddrMode::getBaseWithLongOffset(
const MachineInstr &
MI)
const {
969 short TempOpCode = HII->changeAddrMode_io_rr(
MI);
970 return HII->changeAddrMode_rr_ur(TempOpCode);
972 return HII->changeAddrMode_rr_ur(
MI);
984 getAllRealUses(SA, UNodeList);
986 for (
auto I = UNodeList.rbegin(), E = UNodeList.rend();
I != E; ++
I) {
989 "Can't transform this 'AddAsl' instruction!");
996 <<
">]: " << *
UseMI <<
"\n");
1002 short NewOpCode = getBaseWithLongOffset(*
UseMI);
1003 assert(NewOpCode >= 0 &&
"Invalid New opcode\n");
1031 for (
unsigned i = OpStart; i < OpEnd; ++i)
1041 unsigned UseMOnum) {
1044 unsigned Changed =
false;
1046 Changed = changeLoad(
UseMI, ImmOp, UseMOnum);
1048 Changed = changeStore(
UseMI, ImmOp, UseMOnum);
1050 Changed = changeAddAsl(UseN,
UseMI, ImmOp, UseMOnum);
1059 bool Changed =
false;
1061 for (
auto IA : BA.
Addr->members(*DFG)) {
1067 if ((
MI->getOpcode() != Hexagon::A2_tfrsi ||
1068 !
MI->getOperand(1).isGlobal()) &&
1069 (
MI->getOpcode() != Hexagon::A2_addi ||
1070 !
MI->getOperand(2).isImm() || HII->isConstExtended(*
MI)))
1074 <<
"]: " << *
MI <<
"\n\t[InstrNode]: "
1077 if (
MI->getOpcode() == Hexagon::A2_addi)
1078 Changed |= processAddBases(SA,
MI);
1080 getAllRealUses(SA, UNodeList);
1082 if (!allValidCandidates(SA, UNodeList))
1095 if (
MI->getOpcode() == Hexagon::A2_addi) {
1096 Changed |= processAddUses(SA,
MI, UNodeList);
1102 InstrEvalMap InstrEvalResult;
1106 if (!analyzeUses(DefR, UNodeList, InstrEvalResult, SizeInc))
1111 bool KeepTfr =
false;
1113 LLVM_DEBUG(
dbgs() <<
"\t[Total reached uses] : " << UNodeList.size()
1116 for (
auto I = UNodeList.rbegin(), E = UNodeList.rend();
I != E; ++
I) {
1119 "Found a PhiRef node as a real reached use!!");
1124 <<
">]: " << *
UseMI <<
"\n");
1128 for (
unsigned j = 0;
j < NumOperands - 1; ++
j) {
1130 if (
op.isReg() &&
op.isUse() && DefR ==
op.getReg())
1139 bool Xformed =
false;
1140 if (UseMOnum >= 0 && InstrEvalResult[
UseMI])
1141 Xformed = xformUseMI(
MI,
UseMI, UseN, UseMOnum);
1143 KeepTfr |= !Xformed;
1159 <<
": too many basic blocks\n");
1163 bool Changed =
false;
1167 HII = HST.getInstrInfo();
1168 HRI = HST.getRegisterInfo();
1169 const auto &MDF = getAnalysis<MachineDominanceFrontier>();
1170 MDT = &getAnalysis<MachineDominatorTreeWrapperPass>().getDomTree();
1183 ProcessedAddiInsts.clear();
1189 Changed |= processBlock(BA);
1192 MI->eraseFromParent();
1209 return new HexagonOptAddrMode();
unsigned const MachineRegisterInfo * MRI
MachineInstrBuilder & UseMI
This file defines the DenseMap class.
This file defines the DenseSet and SmallDenseSet classes.
static cl::opt< int > CodeGrowthLimit("hexagon-amode-growth-limit", cl::Hidden, cl::init(0), cl::desc("Code growth limit for address mode " "optimization"))
amode Optimize addressing mode
cl::opt< unsigned > RDFFuncBlockLimit
unsigned const TargetRegisterInfo * TRI
#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())
Represent the analysis usage information of a pass.
AnalysisUsage & addRequired()
void setPreservesAll()
Set by analyses that do not transform their input at all.
Implements a dense probed hash-table based set.
FunctionPass class - This class is used to implement most global optimizations.
Describe properties that are true of each instruction in the target description file.
bool mayStore() const
Return true if this instruction could possibly modify memory.
bool mayLoad() const
Return true if this instruction could possibly read memory.
static MDTuple * get(LLVMContext &Context, ArrayRef< Metadata * > MDs)
int getNumber() const
MachineBasicBlocks are uniquely numbered at the function level, unless they're not in a MachineFuncti...
Instructions::iterator instr_iterator
MachineInstrBundleIterator< MachineInstr > iterator
StringRef getName() const
Return the name of the corresponding LLVM basic block, or an empty string.
bool isLiveIn(MCRegister Reg, LaneBitmask LaneMask=LaneBitmask::getAll()) const
Return true if the specified register is in the live in set.
Analysis pass which computes a MachineDominatorTree.
DominatorTree Class - Concrete subclass of DominatorTreeBase that is used to compute a normal dominat...
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.
Register getReg(unsigned Idx) const
Get the register for the operand index.
const MachineInstrBuilder & add(const MachineOperand &MO) const
const MachineInstrBuilder & addGlobalAddress(const GlobalValue *GV, int64_t Offset=0, unsigned TargetFlags=0) const
Representation of each machine instruction.
unsigned getOpcode() const
Returns the opcode of this MachineInstr.
const MachineBasicBlock * getParent() const
unsigned getNumOperands() const
Retuns the total number of operands.
const MCInstrDesc & getDesc() const
Returns the target instruction descriptor of this MachineInstr.
const DebugLoc & getDebugLoc() const
Returns the debug location id of this MachineInstr.
const MachineOperand & getOperand(unsigned i) const
MachineOperand class - Representation of each machine instruction operand.
const GlobalValue * getGlobal() const
void setImplicit(bool Val=true)
void setImm(int64_t immVal)
bool isReg() const
isReg - Tests if this is a MO_Register operand.
void setReg(Register Reg)
Change the register this operand corresponds to.
bool isImm() const
isImm - Tests if this is a MO_Immediate operand.
unsigned getTargetFlags() const
void setIsUndef(bool Val=true)
Register getReg() const
getReg - Returns the register number.
int64_t getOffset() const
Return the offset from the symbol in this operand.
MachineRegisterInfo - Keep track of information for virtual and physical registers,...
A NodeSet contains a set of SUnit DAG nodes with additional information that assigns a priority to th...
PassRegistry - This class manages the registration and intitialization of the pass subsystem as appli...
virtual StringRef getPassName() const
getPassName - Return a nice clean name for a pass.
Wrapper class representing virtual and physical registers.
StringRef - Represent a constant reference to a string, i.e.
TargetRegisterInfo base class - We assume that the target defines a static array of TargetRegisterDes...
virtual const TargetRegisterInfo * getRegisterInfo() const
getRegisterInfo - If register information is available, return it.
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
unsigned ID
LLVM IR allows to use arbitrary numbers as calling convention identifiers.
initializer< Ty > init(const Ty &Val)
This is an optimization pass for GlobalISel generic memory operations.
void initializeHexagonOptAddrModePass(PassRegistry &)
MachineInstrBuilder BuildMI(MachineFunction &MF, const MIMetadata &MIMD, const MCInstrDesc &MCID)
Builder interface. Specify how to create the initial instruction itself.
raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
FunctionPass * createHexagonOptAddrMode()
Printable printReg(Register Reg, const TargetRegisterInfo *TRI=nullptr, unsigned SubIdx=0, const MachineRegisterInfo *MRI=nullptr)
Prints virtual and physical registers with or without a TRI instance.
Printable printMBBReference(const MachineBasicBlock &MBB)
Prints a machine basic block reference.
std::unordered_map< RegisterId, DefStack > DefStackMap
std::unordered_map< RegisterId, NodeRefSet > RefMap