27#include "llvm/Config/llvm-config.h"
44#define DEBUG_TYPE "hsdr"
49 cl::desc(
"Maximum number of split partitions"));
51 cl::desc(
"Do not split loads or stores"));
64 return "Hexagon Split Double Registers";
83 using USet = std::set<unsigned>;
84 using UUSetMap = std::map<unsigned, USet>;
85 using UUPair = std::pair<unsigned, unsigned>;
86 using UUPairMap = std::map<unsigned, UUPair>;
87 using LoopRegMap = std::map<const MachineLoop *, USet>;
89 bool isInduction(
unsigned Reg, LoopRegMap &IRM)
const;
92 void partitionRegisters(UUSetMap &P2Rs);
95 bool isProfitable(
const USet &Part, LoopRegMap &IRM)
const;
97 void collectIndRegsForLoop(
const MachineLoop *L, USet &Rs);
98 void collectIndRegs(LoopRegMap &IRM);
101 const UUPairMap &PairMap,
unsigned SubR);
109 void replaceSubregUses(
MachineInstr *
MI,
const UUPairMap &PairMap);
110 void collapseRegPairs(
MachineInstr *
MI,
const UUPairMap &PairMap);
111 bool splitPartition(
const USet &Part);
115 static void dump_partition(
raw_ostream&,
const USet&,
121char HexagonSplitDoubleRegs::ID;
122int HexagonSplitDoubleRegs::Counter = 0;
124 &Hexagon::DoubleRegsRegClass;
127 "Hexagon Split Double Registers",
false,
false)
129#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
139bool HexagonSplitDoubleRegs::isInduction(
unsigned Reg, LoopRegMap &IRM)
const {
141 const USet &Rs =
I.second;
142 if (Rs.find(Reg) != Rs.end())
148bool HexagonSplitDoubleRegs::isVolatileInstr(
const MachineInstr *
MI)
const {
149 for (
auto &MO :
MI->memoperands())
150 if (MO->isVolatile() || MO->isAtomic())
155bool HexagonSplitDoubleRegs::isFixedInstr(
const MachineInstr *
MI)
const {
156 if (
MI->mayLoadOrStore())
159 if (
MI->isDebugInstr())
162 unsigned Opc =
MI->getOpcode();
167 case TargetOpcode::PHI:
168 case TargetOpcode::COPY:
171 case Hexagon::L2_loadrd_io:
173 if (
MI->getOperand(1).isReg())
176 case Hexagon::S2_storerd_io:
178 if (
MI->getOperand(0).isReg())
181 case Hexagon::L2_loadrd_pi:
182 case Hexagon::S2_storerd_pi:
184 case Hexagon::A2_tfrpi:
185 case Hexagon::A2_combineii:
186 case Hexagon::A4_combineir:
187 case Hexagon::A4_combineii:
188 case Hexagon::A4_combineri:
189 case Hexagon::A2_combinew:
190 case Hexagon::CONST64:
192 case Hexagon::A2_sxtw:
194 case Hexagon::A2_andp:
195 case Hexagon::A2_orp:
196 case Hexagon::A2_xorp:
197 case Hexagon::S2_asl_i_p_or:
198 case Hexagon::S2_asl_i_p:
199 case Hexagon::S2_asr_i_p:
200 case Hexagon::S2_lsr_i_p:
204 for (
auto &
Op :
MI->operands()) {
214void HexagonSplitDoubleRegs::partitionRegisters(UUSetMap &P2Rs) {
215 using UUMap = std::map<unsigned, unsigned>;
216 using UVect = std::vector<unsigned>;
218 unsigned NumRegs =
MRI->getNumVirtRegs();
220 for (
unsigned i = 0; i < NumRegs; ++i) {
222 if (
MRI->getRegClass(R) == DoubleRC)
233 if (!DefI || isFixedInstr(DefI))
243 USet &Asc = AssocMap[
R];
244 for (
auto U =
MRI->use_nodbg_begin(R), Z =
MRI->use_nodbg_end();
248 if (isFixedInstr(UseI))
252 if (&MO == &
Op || !MO.isReg() || MO.getSubReg())
255 if (!
T.isVirtual()) {
259 if (
MRI->getRegClass(
T) != DoubleRC)
261 unsigned u =
T.virtRegIndex();
267 AssocMap[
T].insert(R);
278 if (Visited.count(R))
281 unsigned ThisP = FixedRegs[
x] ? 0 : NextP++;
284 for (
unsigned i = 0; i < WorkQ.size(); ++i) {
285 unsigned T = WorkQ[i];
286 if (Visited.count(
T))
291 USet &Asc = AssocMap[
T];
297 P2Rs[
I.second].insert(
I.first);
302 if (Imm == 0 || Imm == 0xFFFFFFFF)
307int32_t HexagonSplitDoubleRegs::profit(
const MachineInstr *
MI)
const {
309 unsigned Opc =
MI->getOpcode();
311 case TargetOpcode::PHI:
312 for (
const auto &
Op :
MI->operands())
316 case TargetOpcode::COPY:
317 if (
MI->getOperand(1).getSubReg() != 0)
321 case Hexagon::L2_loadrd_io:
322 case Hexagon::S2_storerd_io:
324 case Hexagon::L2_loadrd_pi:
325 case Hexagon::S2_storerd_pi:
328 case Hexagon::A2_tfrpi:
329 case Hexagon::CONST64: {
331 unsigned Lo =
D & 0xFFFFFFFFULL;
332 unsigned Hi =
D >> 32;
335 case Hexagon::A2_combineii:
336 case Hexagon::A4_combineii: {
341 return Prof1 + Prof2;
343 case Hexagon::A4_combineri:
347 case Hexagon::A4_combineir: {
352 if (V == 0 || V == -1)
358 case Hexagon::A2_combinew:
361 case Hexagon::A2_sxtw:
364 case Hexagon::A2_andp:
365 case Hexagon::A2_orp:
366 case Hexagon::A2_xorp: {
369 return profit(Rs) + profit(Rt);
372 case Hexagon::S2_asl_i_p_or: {
373 unsigned S =
MI->getOperand(3).getImm();
374 if (S == 0 || S == 32)
378 case Hexagon::S2_asl_i_p:
379 case Hexagon::S2_asr_i_p:
380 case Hexagon::S2_lsr_i_p:
381 unsigned S =
MI->getOperand(2).getImm();
382 if (S == 0 || S == 32)
394int32_t HexagonSplitDoubleRegs::profit(
Register Reg)
const {
399 case Hexagon::A2_tfrpi:
400 case Hexagon::CONST64:
401 case Hexagon::A2_combineii:
402 case Hexagon::A4_combineii:
403 case Hexagon::A4_combineri:
404 case Hexagon::A4_combineir:
405 case Hexagon::A2_combinew:
413bool HexagonSplitDoubleRegs::isProfitable(
const USet &Part, LoopRegMap &IRM)
415 unsigned FixedNum = 0, LoopPhiNum = 0;
418 for (
unsigned DR : Part) {
420 int32_t
P = profit(DefI);
421 if (
P == std::numeric_limits<int>::min())
425 if (isInduction(DR, IRM))
428 for (
auto U =
MRI->use_nodbg_begin(DR), W =
MRI->use_nodbg_end();
431 if (isFixedInstr(UseI)) {
435 if (
Op.isReg() && Part.count(
Op.getReg()))
448 if (L &&
L->getHeader() ==
PB)
452 int32_t
P = profit(UseI);
453 if (
P == std::numeric_limits<int>::min())
459 if (FixedNum > 0 && LoopPhiNum > 0)
460 TotalP -= 20*LoopPhiNum;
468void HexagonSplitDoubleRegs::collectIndRegsForLoop(
const MachineLoop *L,
484 if (BadLB ||
Cond.size() != 2)
490 if (TB != HB && FB != HB)
492 assert(
Cond[1].
isReg() &&
"Unexpected Cond vector from analyzeBranch");
495 assert(
MRI->getRegClass(PR) == &Hexagon::PredRegsRegClass);
501 while (CmpI->
getOpcode() == Hexagon::C2_not)
504 int64_t
Mask = 0, Val = 0;
509 if (CmpR1 &&
MRI->getRegClass(CmpR1) != DoubleRC)
511 if (CmpR2 &&
MRI->getRegClass(CmpR2) != DoubleRC)
513 if (!CmpR1 && !CmpR2)
523 using UVect = std::vector<unsigned>;
526 for (
auto &
MI : *HB) {
531 if (
MRI->getRegClass(R) == DoubleRC)
537 auto NoIndOp = [
this, CmpR1, CmpR2] (
unsigned R) ->
bool {
538 for (
auto I =
MRI->use_nodbg_begin(R), E =
MRI->use_nodbg_end();
541 if (UseI->
getOpcode() != Hexagon::A2_addp)
547 if (
T == CmpR1 ||
T == CmpR2)
553 Rs.insert(DP.begin(),
End);
559 dump_partition(
dbgs(), Rs, *
TRI);
564void HexagonSplitDoubleRegs::collectIndRegs(LoopRegMap &IRM) {
565 using LoopVector = std::vector<MachineLoop *>;
570 for (
unsigned i = 0; i < WorkQ.size(); ++i)
576 collectIndRegsForLoop(L, Rs);
578 IRM.insert(std::make_pair(L, Rs));
583 const UUPairMap &PairMap,
unsigned SubR) {
588 for (
auto &
Op :
MI->operands()) {
595 unsigned SR =
Op.getSubReg();
596 bool isVirtReg =
R.isVirtual();
597 bool isKill =
Op.isKill();
598 if (isVirtReg &&
MRI->getRegClass(R) == DoubleRC) {
600 UUPairMap::const_iterator
F = PairMap.find(R);
601 if (
F == PairMap.end()) {
604 const UUPair &
P =
F->second;
605 R = (SubR == Hexagon::isub_lo) ?
P.first :
P.second;
610 Op.isDead(),
Op.isUndef(),
Op.isEarlyClobber(), SR,
Op.isDebug(),
611 Op.isInternalRead());
617 const UUPairMap &PairMap) {
618 bool Load =
MI->mayLoad();
619 unsigned OrigOpc =
MI->getOpcode();
620 bool PostInc = (OrigOpc == Hexagon::L2_loadrd_pi ||
621 OrigOpc == Hexagon::S2_storerd_pi);
633 :
MI->getOperand(2));
634 UUPairMap::const_iterator
F = PairMap.find(ValOp.
getReg());
638 const UUPair &
P =
F->second;
647 const UUPair &
P =
F->second;
661 int64_t Inc =
Load ?
MI->getOperand(3).getImm()
662 :
MI->getOperand(2).getImm();
670 MRI->replaceRegWith(UpdOp.
getReg(), NewR);
676 for (
auto &MO :
MI->memoperands()) {
690 const UUPairMap &PairMap) {
698 UUPairMap::const_iterator
F = PairMap.find(Op0.
getReg());
700 const UUPair &
P =
F->second;
711 .
addImm(int32_t(V & 0xFFFFFFFFULL));
713 .
addImm(int32_t(V >> 32));
717 const UUPairMap &PairMap) {
725 UUPairMap::const_iterator
F = PairMap.find(Op0.
getReg());
727 const UUPair &
P =
F->second;
747 const UUPairMap &PairMap) {
754 UUPairMap::const_iterator
F = PairMap.find(Op0.
getReg());
756 const UUPair &
P =
F->second;
767 const UUPairMap &PairMap) {
768 using namespace Hexagon;
774 int64_t Sh64 = Op2.
getImm();
775 assert(Sh64 >= 0 && Sh64 < 64);
778 UUPairMap::const_iterator
F = PairMap.find(Op0.
getReg());
780 const UUPair &
P =
F->second;
784 unsigned Opc =
MI->getOpcode();
785 bool Right = (
Opc == S2_lsr_i_p ||
Opc == S2_asr_i_p);
793 : (
Signed ? S2_asr_i_r : S2_lsr_i_r);
794 unsigned LoSR = isub_lo;
795 unsigned HiSR = isub_hi;
826 else if (S == 16 &&
Signed)
857 }
else if (S == 32) {
872 else if (S == 16 &&
Signed)
891 const UUPairMap &PairMap) {
892 using namespace Hexagon;
899 int64_t Sh64 = Op3.
getImm();
900 assert(Sh64 >= 0 && Sh64 < 64);
903 UUPairMap::const_iterator
F = PairMap.find(Op0.
getReg());
905 const UUPair &
P =
F->second;
906 unsigned LoR =
P.first;
907 unsigned HiR =
P.second;
915 unsigned LoSR = isub_lo;
916 unsigned HiSR = isub_hi;
945 Register TmpR1 =
MRI->createVirtualRegister(IntRC);
950 Register TmpR2 =
MRI->createVirtualRegister(IntRC);
958 }
else if (S == 32) {
984 const UUPairMap &PairMap) {
985 using namespace Hexagon;
989 unsigned Opc =
MI->getOpcode();
992 case TargetOpcode::PHI:
993 case TargetOpcode::COPY: {
995 if (
MRI->getRegClass(DstR) == DoubleRC) {
996 createHalfInstr(
Opc,
MI, PairMap, isub_lo);
997 createHalfInstr(
Opc,
MI, PairMap, isub_hi);
1003 createHalfInstr(A2_and,
MI, PairMap, isub_lo);
1004 createHalfInstr(A2_and,
MI, PairMap, isub_hi);
1008 createHalfInstr(A2_or,
MI, PairMap, isub_lo);
1009 createHalfInstr(A2_or,
MI, PairMap, isub_hi);
1013 createHalfInstr(A2_xor,
MI, PairMap, isub_lo);
1014 createHalfInstr(A2_xor,
MI, PairMap, isub_hi);
1022 splitMemRef(
MI, PairMap);
1028 splitImmediate(
MI, PairMap);
1037 splitCombine(
MI, PairMap);
1042 splitExt(
MI, PairMap);
1049 splitShift(
MI, PairMap);
1054 splitAslOr(
MI, PairMap);
1067 const UUPairMap &PairMap) {
1068 for (
auto &
Op :
MI->operands()) {
1069 if (!
Op.isReg() || !
Op.isUse() || !
Op.getSubReg())
1072 UUPairMap::const_iterator
F = PairMap.find(R);
1073 if (
F == PairMap.end())
1075 const UUPair &
P =
F->second;
1076 switch (
Op.getSubReg()) {
1077 case Hexagon::isub_lo:
1080 case Hexagon::isub_hi:
1081 Op.setReg(
P.second);
1089 const UUPairMap &PairMap) {
1093 for (
auto &
Op :
MI->operands()) {
1094 if (!
Op.isReg() || !
Op.isUse())
1099 if (
MRI->getRegClass(R) != DoubleRC ||
Op.getSubReg())
1101 UUPairMap::const_iterator
F = PairMap.find(R);
1102 if (
F == PairMap.end())
1104 const UUPair &Pr =
F->second;
1105 Register NewDR =
MRI->createVirtualRegister(DoubleRC);
1108 .
addImm(Hexagon::isub_lo)
1110 .
addImm(Hexagon::isub_hi);
1115bool HexagonSplitDoubleRegs::splitPartition(
const USet &Part) {
1116 using MISet = std::set<MachineInstr *>;
1119 bool Changed =
false;
1122 dump_partition(
dbgs(), Part, *
TRI);
dbgs() <<
'\n');
1127 for (
unsigned DR : Part) {
1129 SplitIns.insert(DefI);
1133 for (
auto U =
MRI->use_nodbg_begin(DR),
W =
MRI->use_nodbg_end();
1135 SplitIns.insert(
U->getParent());
1142 PairMap.insert(std::make_pair(DR, UUPair(LoR, HiR)));
1146 for (
auto *
MI : SplitIns) {
1147 if (isFixedInstr(
MI)) {
1148 collapseRegPairs(
MI, PairMap);
1150 bool Done = splitInstr(
MI, PairMap);
1157 for (
unsigned DR : Part) {
1162 for (
auto U =
MRI->use_nodbg_begin(DR), W =
MRI->use_nodbg_end();
1164 Uses.insert(
U->getParent());
1165 for (
auto *M :
Uses)
1166 replaceSubregUses(M, PairMap);
1169 for (
auto *
MI : Erase) {
1177bool HexagonSplitDoubleRegs::runOnMachineFunction(
MachineFunction &MF) {
1185 TRI =
ST.getRegisterInfo();
1186 TII =
ST.getInstrInfo();
1188 MLI = &getAnalysis<MachineLoopInfoWrapperPass>().getLI();
1193 collectIndRegs(IRM);
1194 partitionRegisters(P2Rs);
1197 dbgs() <<
"Register partitioning: (partition #0 is fixed)\n";
1198 for (UUSetMap::iterator
I = P2Rs.begin(), E = P2Rs.end();
I != E; ++
I) {
1199 dbgs() <<
'#' <<
I->first <<
" -> ";
1200 dump_partition(
dbgs(),
I->second, *
TRI);
1205 bool Changed =
false;
1208 for (UUSetMap::iterator
I = P2Rs.begin(), E = P2Rs.end();
I != E; ++
I) {
1211 if (Limit >= 0 && Counter >= Limit)
1213 USet &Part =
I->second;
1219 Changed |= splitPartition(Part);
1226 return new HexagonSplitDoubleRegs();
unsigned const MachineRegisterInfo * MRI
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
This file implements the BitVector class.
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
static GCRegistry::Add< ErlangGC > A("erlang", "erlang-compatible garbage collector")
static GCRegistry::Add< StatepointGC > D("statepoint-example", "an example strategy for statepoint")
#define LLVM_DUMP_METHOD
Mark debug helper function definitions like dump() that should not be stripped from debug builds.
const HexagonInstrInfo * TII
static cl::opt< bool > MemRefsFixed("hsdr-no-mem", cl::Hidden, cl::init(true), cl::desc("Do not split loads or stores"))
static cl::opt< bool > SplitAll("hsdr-split-all", cl::Hidden, cl::init(false), cl::desc("Split all partitions"))
static cl::opt< int > MaxHSDR("max-hsdr", cl::Hidden, cl::init(-1), cl::desc("Maximum number of split partitions"))
static int32_t profitImm(unsigned Imm)
Register const TargetRegisterInfo * TRI
static bool isReg(const MCInst &MI, unsigned OpNo)
PassBuilder PB(Machine, PassOpts->PTO, std::nullopt, &PIC)
#define INITIALIZE_PASS(passName, arg, name, cfg, analysis)
const SmallVectorImpl< MachineOperand > & Cond
Remove Loads Into Fake Uses
This file defines the SmallVector class.
static const MCPhysReg DoubleRegs[32]
static bool isProfitable(const StableFunctionMap::StableFunctionEntries &SFS)
support::ulittle16_t & Lo
support::ulittle16_t & Hi
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.
FunctionPass class - This class is used to implement most global optimizations.
bool analyzeBranch(MachineBasicBlock &MBB, MachineBasicBlock *&TBB, MachineBasicBlock *&FBB, SmallVectorImpl< MachineOperand > &Cond, bool AllowModify) const override
Analyze the branching code at the end of MBB, returning true if it cannot be understood (e....
bool analyzeCompare(const MachineInstr &MI, Register &SrcReg, Register &SrcReg2, int64_t &Mask, int64_t &Value) const override
For a comparison instruction, return the source registers in SrcReg and SrcReg2 if having two registe...
bool PredOpcodeHasJMP_c(unsigned Opcode) const
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.
StringRef getName() const
getName - Return the name of the corresponding LLVM function.
MachineMemOperand * getMachineMemOperand(MachinePointerInfo PtrInfo, MachineMemOperand::Flags f, LLT MemTy, Align base_alignment, const AAMDNodes &AAInfo=AAMDNodes(), const MDNode *Ranges=nullptr, SyncScope::ID SSID=SyncScope::System, AtomicOrdering Ordering=AtomicOrdering::NotAtomic, AtomicOrdering FailureOrdering=AtomicOrdering::NotAtomic)
getMachineMemOperand - Allocate a new MachineMemOperand.
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.
Representation of each machine instruction.
unsigned getOpcode() const
Returns the opcode of this MachineInstr.
const MachineBasicBlock * getParent() const
LLVM_ABI void addOperand(MachineFunction &MF, const MachineOperand &Op)
Add the specified operand to the instruction.
const MachineOperand & getOperand(unsigned i) const
LLVM_ABI void addMemOperand(MachineFunction &MF, MachineMemOperand *MO)
Add a MachineMemOperand to the machine instruction.
Flags
Flags values. These may be or'd together.
MachineOperand class - Representation of each machine instruction operand.
unsigned getSubReg() const
bool isReg() const
isReg - Tests if this is a MO_Register operand.
bool isImm() const
isImm - Tests if this is a MO_Immediate operand.
Register getReg() const
getReg - Returns the register number.
static MachineOperand CreateReg(Register Reg, bool isDef, bool isImp=false, bool isKill=false, bool isDead=false, bool isUndef=false, bool isEarlyClobber=false, unsigned SubReg=0, bool isDebug=false, bool isInternalRead=false, bool isRenamable=false)
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.
static Register index2VirtReg(unsigned Index)
Convert a 0-based index to a virtual register number.
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.
TargetRegisterInfo base class - We assume that the target defines a static array of TargetRegisterDes...
This class implements an extremely fast bulk output stream that can only output to a stream.
#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.
@ Kill
The last use of a register.
Reg
All possible values of the reg field in the ModR/M byte.
@ TB
TB - TwoByte - Set if this instruction has a two byte opcode, which starts with a 0x0F byte before th...
initializer< Ty > init(const Ty &Val)
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.
void append_range(Container &C, Range &&R)
Wrapper function to append range R to container C.
LLVM_ABI raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
auto remove_if(R &&Range, UnaryPredicate P)
Provide wrappers to std::remove_if which take ranges instead of having to pass begin/end explicitly.
unsigned getRegState(const MachineOperand &RegOp)
Get all register state flags from machine operand RegOp.
FunctionPass * createHexagonSplitDoubleRegs()
LLVM_ABI 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.
LLVM_ABI Printable printMBBReference(const MachineBasicBlock &MBB)
Prints a machine basic block reference.
This struct is a compact representation of a valid (non-zero power of two) alignment.
This class contains a discriminated union of information about pointers in memory operands,...