104#define DEBUG_TYPE "peephole-opt"
108 cl::desc(
"Aggressive extension optimization"));
112 cl::desc(
"Disable the peephole optimizer"));
119 cl::desc(
"Disable advanced copy optimization"));
123 cl::desc(
"Disable non-allocatable physical register copy optimization"));
129 cl::desc(
"Limit the length of PHI chains to lookup"));
135 cl::desc(
"Maximum length of recurrence chain when evaluating the benefit "
136 "of commuting operands"));
138STATISTIC(NumReuse,
"Number of extension results reused");
140STATISTIC(NumImmFold,
"Number of move immediate folded");
143STATISTIC(NumUncoalescableCopies,
"Number of uncoalescable copies optimized");
144STATISTIC(NumRewrittenCopies,
"Number of copies rewritten");
145STATISTIC(NumNAPhysCopies,
"Number of non-allocatable physical copies removed");
149class ValueTrackerResult;
150class RecurrenceInstr;
156 int CurrentSrcIdx = 0;
159 virtual ~Rewriter() =
default;
191 virtual bool RewriteCurrentSource(
Register NewReg,
unsigned NewSubReg) = 0;
195class CopyRewriter :
public Rewriter {
198 assert(
MI.isCopy() &&
"Expected copy instruction");
200 ~CopyRewriter()
override =
default;
204 if (++CurrentSrcIdx > 1)
208 const MachineOperand &MOSrc = CopyLike.getOperand(CurrentSrcIdx);
211 const MachineOperand &MODef = CopyLike.getOperand(0);
216 bool RewriteCurrentSource(
Register NewReg,
unsigned NewSubReg)
override {
217 MachineOperand &MOSrc = CopyLike.getOperand(CurrentSrcIdx);
226class UncoalescableRewriter :
public Rewriter {
230 UncoalescableRewriter(MachineInstr &
MI) :
Rewriter(
MI) {
231 NumDefs =
MI.getDesc().getNumDefs();
241 if (CurrentSrcIdx == NumDefs)
244 while (CopyLike.getOperand(CurrentSrcIdx).isDead()) {
246 if (CurrentSrcIdx == NumDefs)
252 const MachineOperand &MODef = CopyLike.getOperand(CurrentSrcIdx);
259 bool RewriteCurrentSource(
Register NewReg,
unsigned NewSubReg)
override {
265class InsertSubregRewriter :
public Rewriter {
268 assert(
MI.isInsertSubreg() &&
"Invalid instruction");
285 if (CurrentSrcIdx == 2)
289 const MachineOperand &MOInsertedReg = CopyLike.getOperand(2);
291 const MachineOperand &MODef = CopyLike.getOperand(0);
299 (
unsigned)CopyLike.getOperand(3).getImm());
303 bool RewriteCurrentSource(
Register NewReg,
unsigned NewSubReg)
override {
304 if (CurrentSrcIdx != 2)
307 MachineOperand &MO = CopyLike.getOperand(CurrentSrcIdx);
315class ExtractSubregRewriter :
public Rewriter {
316 const TargetInstrInfo &TII;
319 ExtractSubregRewriter(MachineInstr &
MI,
const TargetInstrInfo &TII)
321 assert(
MI.isExtractSubreg() &&
"Invalid instruction");
332 if (CurrentSrcIdx == 1)
336 const MachineOperand &MOExtractedReg = CopyLike.getOperand(1);
345 const MachineOperand &MODef = CopyLike.getOperand(0);
350 bool RewriteCurrentSource(
Register NewReg,
unsigned NewSubReg)
override {
352 if (CurrentSrcIdx != 1)
355 CopyLike.getOperand(CurrentSrcIdx).setReg(NewReg);
366 CopyLike.removeOperand(2);
368 CopyLike.setDesc(TII.get(TargetOpcode::COPY));
371 CopyLike.getOperand(CurrentSrcIdx + 1).setImm(NewSubReg);
377class RegSequenceRewriter :
public Rewriter {
380 assert(
MI.isRegSequence() &&
"Invalid instruction");
404 if (
static_cast<unsigned>(CurrentSrcIdx) >= CopyLike.getNumOperands())
407 const MachineOperand &MOInsertedReg = CopyLike.getOperand(CurrentSrcIdx);
408 Src.Reg = MOInsertedReg.
getReg();
413 Dst.SubReg = CopyLike.getOperand(CurrentSrcIdx + 1).getImm();
415 const MachineOperand &MODef = CopyLike.getOperand(0);
417 assert(MODef.
getSubReg() == 0 &&
"cannot have subregister def in SSA");
421 bool RewriteCurrentSource(
Register NewReg,
unsigned NewSubReg)
override {
422 MachineOperand &MO = CopyLike.getOperand(CurrentSrcIdx);
430 const TargetInstrInfo *TII =
nullptr;
431 const TargetRegisterInfo *TRI =
nullptr;
432 MachineRegisterInfo *MRI =
nullptr;
433 MachineDominatorTree *DT =
nullptr;
434 MachineLoopInfo *MLI =
nullptr;
437 PeepholeOptimizer(MachineDominatorTree *DT, MachineLoopInfo *MLI)
438 : DT(DT), MLI(MLI) {}
440 bool run(MachineFunction &MF);
442 using RewriteMapTy = SmallDenseMap<RegSubRegPair, ValueTrackerResult>;
445 using RecurrenceCycle = SmallVector<RecurrenceInstr, 4>;
448 bool optimizeCmpInstr(MachineInstr &
MI, MachineFunction &MF,
449 SmallPtrSet<MachineInstr *, 16> &LocalMIs);
450 bool optimizeExtInstr(MachineInstr &
MI, MachineBasicBlock &
MBB,
451 SmallPtrSetImpl<MachineInstr *> &LocalMIs);
452 bool optimizeSelect(MachineInstr &
MI,
453 SmallPtrSetImpl<MachineInstr *> &LocalMIs);
454 bool optimizeCondBranch(MachineInstr &
MI);
456 bool optimizeCoalescableCopyImpl(
Rewriter &&CpyRewriter);
457 bool optimizeCoalescableCopy(MachineInstr &
MI);
458 bool optimizeUncoalescableCopy(MachineInstr &
MI,
459 SmallPtrSetImpl<MachineInstr *> &LocalMIs);
460 bool optimizeRecurrence(MachineInstr &
PHI);
463 bool isMoveImmediate(MachineInstr &
MI, SmallSet<Register, 4> &ImmDefRegs,
464 DenseMap<Register, MachineInstr *> &ImmDefMIs);
465 bool foldImmediate(MachineInstr &
MI, SmallSet<Register, 4> &ImmDefRegs,
466 DenseMap<Register, MachineInstr *> &ImmDefMIs,
474 const SmallSet<Register, 2> &TargetReg,
475 RecurrenceCycle &RC);
482 bool foldRedundantCopy(MachineInstr &
MI);
493 foldRedundantNAPhysCopy(MachineInstr &
MI,
494 DenseMap<Register, MachineInstr *> &NAPhysToVirtMIs);
496 bool isLoadFoldable(MachineInstr &
MI,
497 SmallSet<Register, 16> &FoldAsLoadDefCandidates);
502 MachineInstr *foldLoadInto(MachineFunction &MF, MachineInstr &
MI,
504 SmallPtrSet<MachineInstr *, 16> &LocalMIs);
508 static bool isCoalescableCopy(
const MachineInstr &
MI) {
511 return MI.isCopy() ||
513 MI.isExtractSubreg()));
518 static bool isUncoalescableCopy(
const MachineInstr &
MI) {
520 MI.isInsertSubregLike() ||
521 MI.isExtractSubregLike()));
524 MachineInstr &rewriteSource(MachineInstr &CopyLike,
RegSubRegPair Def,
525 RewriteMapTy &RewriteMap);
529 DenseMap<RegSubRegPair, MachineInstr *> CopySrcMIs;
532 void MF_HandleInsertion(MachineInstr &
MI)
override {}
539 unsigned SrcSubReg =
MI.getOperand(1).getSubReg();
540 if (!SrcReg.
isVirtual() && !MRI->isConstantPhysReg(SrcReg))
549 void deleteChangedCopy(MachineInstr &
MI) {
551 if (!getCopySrc(
MI, SrcPair))
554 auto It = CopySrcMIs.find(SrcPair);
555 if (It != CopySrcMIs.end() && It->second == &
MI)
556 CopySrcMIs.erase(It);
559 void MF_HandleRemoval(MachineInstr &
MI)
override { deleteChangedCopy(
MI); }
561 void MF_HandleChangeDesc(MachineInstr &
MI,
const MCInstrDesc &TID)
override {
562 deleteChangedCopy(
MI);
570 PeepholeOptimizerLegacy() : MachineFunctionPass(ID) {}
572 bool runOnMachineFunction(MachineFunction &MF)
override;
574 void getAnalysisUsage(AnalysisUsage &AU)
const override {
586 MachineFunctionProperties getRequiredProperties()
const override {
587 return MachineFunctionProperties().setIsSSA();
597class RecurrenceInstr {
599 using IndexPair = std::pair<unsigned, unsigned>;
601 RecurrenceInstr(MachineInstr *MI) : MI(MI) {}
602 RecurrenceInstr(MachineInstr *MI,
unsigned Idx1,
unsigned Idx2)
603 : MI(MI), CommutePair(std::make_pair(Idx1, Idx2)) {}
605 MachineInstr *getMI()
const {
return MI; }
606 std::optional<IndexPair> getCommutePair()
const {
return CommutePair; }
610 std::optional<IndexPair> CommutePair;
616class ValueTrackerResult {
622 const MachineInstr *Inst =
nullptr;
625 ValueTrackerResult() =
default;
627 ValueTrackerResult(
Register Reg,
unsigned SubReg) { addSource(
Reg, SubReg); }
629 bool isValid()
const {
return getNumSources() > 0; }
631 void setInst(
const MachineInstr *
I) { Inst =
I; }
632 const MachineInstr *getInst()
const {
return Inst; }
639 void addSource(
Register SrcReg,
unsigned SrcSubReg) {
643 void setSource(
int Idx,
Register SrcReg,
unsigned SrcSubReg) {
644 assert(Idx < getNumSources() &&
"Reg pair source out of index");
648 int getNumSources()
const {
return RegSrcs.size(); }
653 assert(Idx < getNumSources() &&
"Reg source out of index");
654 return RegSrcs[Idx].Reg;
657 unsigned getSrcSubReg(
int Idx)
const {
658 assert(Idx < getNumSources() &&
"SubReg source out of index");
659 return RegSrcs[Idx].SubReg;
663 if (
Other.getInst() != getInst())
666 if (
Other.getNumSources() != getNumSources())
669 for (
int i = 0, e =
Other.getNumSources(); i != e; ++i)
670 if (
Other.getSrcReg(i) != getSrcReg(i) ||
671 Other.getSrcSubReg(i) != getSrcSubReg(i))
696 const MachineInstr *Def =
nullptr;
708 const MachineRegisterInfo &MRI;
711 const TargetInstrInfo *TII;
714 ValueTrackerResult getNextSourceImpl();
717 ValueTrackerResult getNextSourceFromCopy();
720 ValueTrackerResult getNextSourceFromBitcast();
723 ValueTrackerResult getNextSourceFromRegSequence();
726 ValueTrackerResult getNextSourceFromInsertSubreg();
729 ValueTrackerResult getNextSourceFromExtractSubreg();
732 ValueTrackerResult getNextSourceFromSubregToReg();
735 ValueTrackerResult getNextSourceFromPHI();
747 ValueTracker(
Register Reg,
unsigned DefSubReg,
const MachineRegisterInfo &MRI,
748 const TargetInstrInfo *TII =
nullptr)
749 : DefSubReg(DefSubReg), Reg(Reg), MRI(MRI), TII(TII) {
750 if (!Reg.isPhysical()) {
751 Def = MRI.getVRegDef(Reg);
752 DefIdx = MRI.def_begin(Reg).getOperandNo();
761 ValueTrackerResult getNextSource();
766char PeepholeOptimizerLegacy::ID = 0;
771 "Peephole Optimizations",
false,
false)
785bool PeepholeOptimizer::optimizeExtInstr(
790 if (!
TII->isCoalescableExtInstr(
MI, SrcReg, DstReg, SubIdx))
803 DstRC =
TRI->getSubClassWithSubReg(DstRC, SubIdx);
813 TRI->getSubClassWithSubReg(MRI->
getRegClass(SrcReg), SubIdx) !=
nullptr;
819 ReachedBBs.insert(UI.getParent());
827 bool ExtendLife =
true;
829 MachineInstr *UseMI = UseMO.getParent();
833 if (UseMI->isPHI()) {
839 if (UseSrcSubIdx && UseMO.getSubReg() != SubIdx)
859 if (
UseMI->getOpcode() == TargetOpcode::SUBREG_TO_REG)
863 if (UseMBB == &
MBB) {
865 if (!LocalMIs.count(
UseMI))
866 Uses.push_back(&UseMO);
867 }
else if (ReachedBBs.count(UseMBB)) {
870 Uses.push_back(&UseMO);
874 ExtendedUses.push_back(&UseMO);
883 if (ExtendLife && !ExtendedUses.empty())
885 Uses.append(ExtendedUses.begin(), ExtendedUses.end());
890 SmallPtrSet<MachineBasicBlock *, 4> PHIBBs;
895 for (MachineInstr &UI : MRI->use_nodbg_instructions(DstReg))
897 PHIBBs.insert(UI.getParent());
899 const TargetRegisterClass *RC = MRI->getRegClass(SrcReg);
900 for (MachineOperand *UseMO : Uses) {
901 MachineInstr *UseMI = UseMO->getParent();
902 MachineBasicBlock *UseMBB = UseMI->getParent();
903 if (PHIBBs.count(UseMBB))
908 MRI->clearKillFlags(DstReg);
909 MRI->constrainRegClass(DstReg, DstRC);
927 RC = MRI->getRegClass(UseMI->getOperand(0).getReg());
929 Register NewVR = MRI->createVirtualRegister(RC);
930 BuildMI(*UseMBB, UseMI, UseMI->getDebugLoc(),
931 TII->get(TargetOpcode::COPY), NewVR)
932 .addReg(DstReg, {}, SubIdx);
936 UseMO->setReg(NewVR);
949bool PeepholeOptimizer::optimizeCmpInstr(
955 int64_t CmpMask, CmpValue;
962 if (!
TII->optimizeCompareInstr(
MI, SrcReg, SrcReg2, CmpMask, CmpValue, MRI))
972 MachineInstr *LoadMI = MRI->
getVRegDef(SrcReg);
979 [](
const MachineInstr &
I) { return I.isLoadFoldBarrier(); }))
980 foldLoadInto(MF, *FlagProducer, SrcReg, LocalMIs);
987bool PeepholeOptimizer::optimizeSelect(
988 MachineInstr &
MI, SmallPtrSetImpl<MachineInstr *> &LocalMIs) {
989 assert(
MI.isSelect() &&
"Should only be called when MI->isSelect() is true");
990 if (!
TII->optimizeSelect(
MI, LocalMIs))
993 MI.eraseFromParent();
999bool PeepholeOptimizer::optimizeCondBranch(MachineInstr &
MI) {
1000 return TII->optimizeCondBranch(
MI);
1019 RewriteMapTy &RewriteMap) {
1028 unsigned PHICount = 0;
1035 ValueTracker ValTracker(CurSrcPair.
Reg, CurSrcPair.
SubReg, *MRI,
TII);
1040 ValueTrackerResult Res = ValTracker.getNextSource();
1046 auto [InsertPt, WasInserted] = RewriteMap.try_emplace(CurSrcPair, Res);
1049 const ValueTrackerResult &CurSrcRes = InsertPt->second;
1051 assert(CurSrcRes == Res &&
"ValueTrackerResult found must match");
1054 if (CurSrcRes.getNumSources() > 1) {
1056 <<
"findNextSource: found PHI cycle, aborting...\n");
1064 unsigned NumSrcs = Res.getNumSources();
1072 for (
unsigned i = 0; i < NumSrcs; ++i)
1077 CurSrcPair = Res.getSrc(0);
1087 if (!
TRI->shouldRewriteCopySrc(DefRC, DefSubReg, SrcRC,
1093 if (PHICount > 0 && CurSrcPair.
SubReg != 0)
1099 }
while (!SrcToLook.
empty());
1102 return CurSrcPair.
Reg !=
Reg;
1114 assert(!SrcRegs.
empty() &&
"No sources to create a PHI instruction?");
1119 assert(SrcRegs[0].SubReg == 0 &&
"should not have subreg operand");
1123 TII.get(TargetOpcode::PHI), NewVR);
1125 unsigned MBBOpIdx = 2;
1127 MIB.
addReg(RegPair.Reg, {}, RegPair.SubReg);
1148 const PeepholeOptimizer::RewriteMapTy &RewriteMap,
1149 bool HandleMultipleSources =
true) {
1152 ValueTrackerResult Res = RewriteMap.
lookup(LookupSrc);
1158 unsigned NumSrcs = Res.getNumSources();
1160 LookupSrc.
Reg = Res.getSrcReg(0);
1161 LookupSrc.
SubReg = Res.getSrcSubReg(0);
1166 if (!HandleMultipleSources)
1172 for (
unsigned i = 0; i < NumSrcs; ++i) {
1173 RegSubRegPair PHISrc(Res.getSrcReg(i), Res.getSrcSubReg(i));
1191bool PeepholeOptimizer::optimizeCoalescableCopyImpl(
Rewriter &&CpyRewriter) {
1197 while (CpyRewriter.getNextRewritableSource(TrackPair, Dst)) {
1198 if (Dst.Reg.isPhysical()) {
1209 RewriteMapTy RewriteMap;
1212 if (!findNextSource(DefRC, Dst.SubReg, TrackPair, RewriteMap))
1220 "should not rewrite source to original value");
1230 TRI->getSubClassWithSubReg(RC, NewSrc.
SubReg);
1237 if (CpyRewriter.RewriteCurrentSource(NewSrc.
Reg, NewSrc.
SubReg)) {
1249 NumRewrittenCopies +=
Changed;
1264bool PeepholeOptimizer::optimizeCoalescableCopy(MachineInstr &
MI) {
1265 assert(isCoalescableCopy(
MI) &&
"Invalid argument");
1266 assert(
MI.getDesc().getNumDefs() == 1 &&
1267 "Coalescer can understand multiple defs?!");
1268 const MachineOperand &MODef =
MI.getOperand(0);
1273 switch (
MI.getOpcode()) {
1274 case TargetOpcode::COPY:
1275 return optimizeCoalescableCopyImpl(CopyRewriter(
MI));
1276 case TargetOpcode::INSERT_SUBREG:
1277 return optimizeCoalescableCopyImpl(InsertSubregRewriter(
MI));
1278 case TargetOpcode::EXTRACT_SUBREG:
1279 return optimizeCoalescableCopyImpl(ExtractSubregRewriter(
MI, *
TII));
1280 case TargetOpcode::REG_SEQUENCE:
1281 return optimizeCoalescableCopyImpl(RegSequenceRewriter(
MI));
1284 if (
MI.isBitcast() ||
MI.isRegSequenceLike() ||
MI.isInsertSubregLike() ||
1285 MI.isExtractSubregLike())
1286 return optimizeCoalescableCopyImpl(UncoalescableRewriter(
MI));
1296MachineInstr &PeepholeOptimizer::rewriteSource(MachineInstr &CopyLike,
1298 RewriteMapTy &RewriteMap) {
1299 assert(!
Def.Reg.isPhysical() &&
"We do not rewrite physical registers");
1311 TRI->getSubClassWithSubReg(NewSrcRC, NewSrc.
SubReg);
1320 MachineInstr *NewCopy =
1322 TII->get(TargetOpcode::COPY), NewVReg)
1354bool PeepholeOptimizer::optimizeUncoalescableCopy(
1355 MachineInstr &
MI, SmallPtrSetImpl<MachineInstr *> &LocalMIs) {
1356 assert(isUncoalescableCopy(
MI) &&
"Invalid argument");
1357 UncoalescableRewriter CpyRewriter(
MI);
1362 RewriteMapTy RewriteMap;
1366 while (CpyRewriter.getNextRewritableSource(Src, Def)) {
1369 if (
Def.Reg.isPhysical())
1379 if (!findNextSource(DefRC,
Def.SubReg, Def, RewriteMap))
1388 MachineInstr &NewCopy = rewriteSource(
MI, Def, RewriteMap);
1389 LocalMIs.
insert(&NewCopy);
1394 MI.eraseFromParent();
1395 ++NumUncoalescableCopies;
1402bool PeepholeOptimizer::isLoadFoldable(
1403 MachineInstr &
MI, SmallSet<Register, 16> &FoldAsLoadDefCandidates) {
1404 if (!
MI.canFoldAsLoad() || !
MI.mayLoad())
1406 const MCInstrDesc &MCID =
MI.getDesc();
1423PeepholeOptimizer::foldLoadInto(MachineFunction &MF, MachineInstr &
MI,
1425 SmallPtrSet<MachineInstr *, 16> &LocalMIs) {
1427 MachineInstr *
DefMI =
nullptr;
1428 MachineInstr *CopyMI =
nullptr;
1429 MachineInstr *FoldMI =
TII->optimizeLoadInstr(
MI, MRI,
Reg,
DefMI, CopyMI);
1438 if (
MI.shouldUpdateAdditionalCallInfo())
1440 MI.eraseFromParent();
1447bool PeepholeOptimizer::isMoveImmediate(
1448 MachineInstr &
MI, SmallSet<Register, 4> &ImmDefRegs,
1449 DenseMap<Register, MachineInstr *> &ImmDefMIs) {
1450 const MCInstrDesc &MCID =
MI.getDesc();
1451 if (MCID.
getNumDefs() != 1 || !
MI.getOperand(0).isReg())
1458 if (!
MI.isMoveImmediate() && !
TII->getConstValDefinedInReg(
MI,
Reg, ImmVal))
1469bool PeepholeOptimizer::foldImmediate(
1470 MachineInstr &
MI, SmallSet<Register, 4> &ImmDefRegs,
1471 DenseMap<Register, MachineInstr *> &ImmDefMIs,
bool &
Deleted) {
1473 for (
unsigned i = 0, e =
MI.getDesc().getNumOperands(); i != e; ++i) {
1474 MachineOperand &MO =
MI.getOperand(i);
1483 assert(
II != ImmDefMIs.
end() &&
"couldn't find immediate definition");
1484 if (
TII->foldImmediate(
MI, *
II->second,
Reg, MRI)) {
1496 MI.eraseFromParent();
1520bool PeepholeOptimizer::foldRedundantCopy(MachineInstr &
MI) {
1521 assert(
MI.isCopy() &&
"expected a COPY machine instruction");
1524 if (!getCopySrc(
MI, SrcPair))
1531 if (CopySrcMIs.
insert(std::make_pair(SrcPair, &
MI)).second) {
1536 MachineInstr *PrevCopy = CopySrcMIs.
find(SrcPair)->second;
1539 "Unexpected mismatching subreg!");
1557bool PeepholeOptimizer::isNAPhysCopy(
Register Reg) {
1561bool PeepholeOptimizer::foldRedundantNAPhysCopy(
1562 MachineInstr &
MI, DenseMap<Register, MachineInstr *> &NAPhysToVirtMIs) {
1563 assert(
MI.isCopy() &&
"expected a COPY machine instruction");
1570 if (isNAPhysCopy(SrcReg) && DstReg.
isVirtual()) {
1574 NAPhysToVirtMIs.
insert({SrcReg, &
MI});
1578 if (!(SrcReg.
isVirtual() && isNAPhysCopy(DstReg)))
1582 auto PrevCopy = NAPhysToVirtMIs.
find(DstReg);
1583 if (PrevCopy == NAPhysToVirtMIs.
end()) {
1586 LLVM_DEBUG(
dbgs() <<
"NAPhysCopy: intervening clobber forbids erasing "
1592 if (PrevDstReg == SrcReg) {
1605 NAPhysToVirtMIs.
erase(PrevCopy);
1614bool PeepholeOptimizer::findTargetRecurrence(
1615 Register Reg,
const SmallSet<Register, 2> &TargetRegs,
1616 RecurrenceCycle &RC) {
1634 unsigned Idx =
MI.findRegisterUseOperandIdx(
Reg,
nullptr);
1638 if (
MI.getDesc().getNumDefs() != 1)
1641 MachineOperand &DefOp =
MI.getOperand(0);
1648 unsigned TiedUseIdx;
1649 if (!
MI.isRegTiedToUseOperand(0, &TiedUseIdx))
1652 if (Idx == TiedUseIdx) {
1653 RC.push_back(RecurrenceInstr(&
MI));
1654 return findTargetRecurrence(DefOp.
getReg(), TargetRegs, RC);
1658 if (
TII->findCommutedOpIndices(
MI, Idx, CommIdx) && CommIdx == TiedUseIdx) {
1659 RC.push_back(RecurrenceInstr(&
MI, Idx, CommIdx));
1660 return findTargetRecurrence(DefOp.
getReg(), TargetRegs, RC);
1685bool PeepholeOptimizer::optimizeRecurrence(MachineInstr &
PHI) {
1686 SmallSet<Register, 2> TargetRegs;
1687 for (
unsigned Idx = 1; Idx <
PHI.getNumOperands(); Idx += 2) {
1688 MachineOperand &MO =
PHI.getOperand(Idx);
1695 if (findTargetRecurrence(
PHI.getOperand(0).getReg(), TargetRegs, RC)) {
1699 for (
auto &RI : RC) {
1701 auto CP = RI.getCommutePair();
1704 TII->commuteInstruction(*(RI.getMI()),
false, (*CP).first,
1721 PeepholeOptimizer Impl(DT, MLI);
1733bool PeepholeOptimizerLegacy::runOnMachineFunction(
MachineFunction &MF) {
1737 ? &getAnalysis<MachineDominatorTreeWrapperPass>().getDomTree()
1739 auto *MLI = &getAnalysis<MachineLoopInfoWrapperPass>().getLI();
1740 PeepholeOptimizer Impl(DT, MLI);
1741 return Impl.run(MF);
1746 LLVM_DEBUG(
dbgs() <<
"********** PEEPHOLE OPTIMIZER **********\n");
1760 bool SeenMoveImm =
false;
1793 if (
MI->isDebugInstr())
1796 if (
MI->isPosition())
1799 if (IsLoopHeader &&
MI->isPHI()) {
1800 if (optimizeRecurrence(*
MI)) {
1806 if (!
MI->isCopy()) {
1807 for (
const MachineOperand &MO :
MI->operands()) {
1811 if (MO.
isDef() && isNAPhysCopy(
Reg)) {
1813 if (Def != NAPhysToVirtMIs.
end()) {
1817 <<
"NAPhysCopy: invalidating because of " << *
MI);
1818 NAPhysToVirtMIs.
erase(Def);
1823 NAPhysToVirtMIs.
remove_if([&](
const auto &RegMI) {
1827 <<
"NAPhysCopy: invalidating because of " << *
MI);
1834 if (
MI->isImplicitDef() ||
MI->isKill())
1837 if (
MI->isInlineAsm() ||
MI->hasUnmodeledSideEffects()) {
1844 NAPhysToVirtMIs.
clear();
1847 if (
MI->isCompare() && optimizeCmpInstr(*
MI, MF, LocalMIs)) {
1853 if ((isUncoalescableCopy(*
MI) &&
1854 optimizeUncoalescableCopy(*
MI, LocalMIs)) ||
1855 (
MI->isSelect() && optimizeSelect(*
MI, LocalMIs))) {
1862 if (
MI->isConditionalBranch() && optimizeCondBranch(*
MI)) {
1867 if (isCoalescableCopy(*
MI) && optimizeCoalescableCopy(*
MI)) {
1873 if (
MI->isCopy() && (foldRedundantCopy(*
MI) ||
1874 foldRedundantNAPhysCopy(*
MI, NAPhysToVirtMIs))) {
1877 MI->eraseFromParent();
1882 if (isMoveImmediate(*
MI, ImmDefRegs, ImmDefMIs)) {
1904 if (!isLoadFoldable(*
MI, FoldAsLoadDefCandidates) &&
1905 !FoldAsLoadDefCandidates.
empty()) {
1912 const MCInstrDesc &MIDesc =
MI->getDesc();
1913 for (
unsigned i = MIDesc.
getNumDefs(); i !=
MI->getNumOperands(); ++i) {
1914 const MachineOperand &MOp =
MI->getOperand(i);
1918 if (FoldAsLoadDefCandidates.
count(FoldAsLoadDefReg)) {
1921 Register FoldedReg = FoldAsLoadDefReg;
1922 if (MachineInstr *FoldMI =
1923 foldLoadInto(MF, *
MI, FoldAsLoadDefReg, LocalMIs)) {
1924 FoldAsLoadDefCandidates.
erase(FoldedReg);
1936 if (
MI->isLoadFoldBarrier()) {
1938 FoldAsLoadDefCandidates.
clear();
1943 MF.resetDelegate(
this);
1947ValueTrackerResult ValueTracker::getNextSourceFromCopy() {
1948 assert(
Def->isCopy() &&
"Invalid definition");
1953 assert(
Def->getNumOperands() -
Def->getNumImplicitOperands() == 2 &&
1954 "Invalid number of operands");
1955 assert(!
Def->hasImplicitDef() &&
"Only implicit uses are allowed");
1956 assert(!
Def->getOperand(DefIdx).getSubReg() &&
"no subregister defs in SSA");
1959 const MachineOperand &Src =
Def->getOperand(1);
1961 return ValueTrackerResult();
1964 unsigned SubReg = Src.getSubReg();
1967 SubReg =
TRI->composeSubRegIndices(SubReg, DefSubReg);
1972 if (!
TRI->isSubRegValidForRegClass(RegRC, SubReg))
1973 return ValueTrackerResult();
1975 if (!
TRI->getSubReg(SrcReg, SubReg))
1976 return ValueTrackerResult();
1980 return ValueTrackerResult(SrcReg, SubReg);
1983ValueTrackerResult ValueTracker::getNextSourceFromBitcast() {
1984 assert(
Def->isBitcast() &&
"Invalid definition");
1987 if (
Def->mayRaiseFPException() ||
Def->hasUnmodeledSideEffects())
1988 return ValueTrackerResult();
1991 if (
Def->getDesc().getNumDefs() != 1)
1992 return ValueTrackerResult();
1994 assert(!
Def->getOperand(DefIdx).getSubReg() &&
"no subregister defs in SSA");
1996 unsigned SrcIdx =
Def->getNumOperands();
1997 for (
unsigned OpIdx = DefIdx + 1, EndOpIdx = SrcIdx;
OpIdx != EndOpIdx;
1999 const MachineOperand &MO =
Def->getOperand(
OpIdx);
2005 assert(!MO.
isDef() &&
"We should have skipped all the definitions by now");
2006 if (SrcIdx != EndOpIdx)
2008 return ValueTrackerResult();
2014 if (SrcIdx >=
Def->getNumOperands())
2015 return ValueTrackerResult();
2017 const MachineOperand &DefOp =
Def->getOperand(DefIdx);
2022 if (
UseMI.isSubregToReg())
2023 return ValueTrackerResult();
2026 const MachineOperand &Src =
Def->getOperand(SrcIdx);
2028 return ValueTrackerResult();
2029 return ValueTrackerResult(Src.getReg(), Src.getSubReg());
2032ValueTrackerResult ValueTracker::getNextSourceFromRegSequence() {
2033 assert((
Def->isRegSequence() ||
Def->isRegSequenceLike()) &&
2034 "Invalid definition");
2036 assert(!
Def->getOperand(DefIdx).getSubReg() &&
"illegal subregister def");
2039 if (!
TII->getRegSequenceInputs(*Def, DefIdx, RegSeqInputRegs))
2040 return ValueTrackerResult();
2048 if (RegSeqInput.SubIdx == DefSubReg)
2049 return ValueTrackerResult(RegSeqInput.Reg, RegSeqInput.SubReg);
2057 LaneBitmask DefMask =
TRI->getSubRegIndexLaneMask(DefSubReg);
2058 LaneBitmask ThisOpRegMask =
TRI->getSubRegIndexLaneMask(RegSeqInput.SubIdx);
2064 if ((DefMask & ThisOpRegMask) != DefMask)
2067 unsigned ReverseDefCompose =
2068 TRI->reverseComposeSubRegIndices(RegSeqInput.SubIdx, DefSubReg);
2069 if (!ReverseDefCompose)
2072 unsigned ComposedDefInSrcReg1 =
2073 TRI->composeSubRegIndices(RegSeqInput.SubReg, ReverseDefCompose);
2080 if (!
TRI->isSubRegValidForRegClass(SrcRC, ComposedDefInSrcReg1))
2081 return ValueTrackerResult();
2083 return ValueTrackerResult(RegSeqInput.Reg, ComposedDefInSrcReg1);
2089 return ValueTrackerResult();
2092ValueTrackerResult ValueTracker::getNextSourceFromInsertSubreg() {
2093 assert((
Def->isInsertSubreg() ||
Def->isInsertSubregLike()) &&
2094 "Invalid definition");
2095 assert(!
Def->getOperand(DefIdx).getSubReg() &&
"no subreg defs in SSA");
2099 if (!
TII->getInsertSubregInputs(*Def, DefIdx, BaseReg, InsertedReg))
2100 return ValueTrackerResult();
2109 if (InsertedReg.
SubIdx == DefSubReg) {
2110 return ValueTrackerResult(InsertedReg.
Reg, InsertedReg.
SubReg);
2115 const MachineOperand &MODef =
Def->getOperand(DefIdx);
2121 return ValueTrackerResult();
2126 if ((
TRI->getSubRegIndexLaneMask(DefSubReg) &
2127 TRI->getSubRegIndexLaneMask(InsertedReg.
SubIdx))
2129 return ValueTrackerResult();
2132 return ValueTrackerResult(
BaseReg.Reg, DefSubReg);
2135ValueTrackerResult ValueTracker::getNextSourceFromExtractSubreg() {
2136 assert((
Def->isExtractSubreg() ||
Def->isExtractSubregLike()) &&
2137 "Invalid definition");
2144 return ValueTrackerResult();
2147 if (!
TII->getExtractSubregInputs(*Def, DefIdx, ExtractSubregInputReg))
2148 return ValueTrackerResult();
2152 if (ExtractSubregInputReg.
SubReg)
2153 return ValueTrackerResult();
2155 return ValueTrackerResult(ExtractSubregInputReg.
Reg,
2156 ExtractSubregInputReg.
SubIdx);
2159ValueTrackerResult ValueTracker::getNextSourceFromSubregToReg() {
2160 assert(
Def->isSubregToReg() &&
"Invalid definition");
2168 if (DefSubReg !=
Def->getOperand(2).getImm())
2169 return ValueTrackerResult();
2172 if (
Def->getOperand(1).getSubReg())
2173 return ValueTrackerResult();
2175 return ValueTrackerResult(
Def->getOperand(1).getReg(),
2176 Def->getOperand(2).getImm());
2180ValueTrackerResult ValueTracker::getNextSourceFromPHI() {
2181 assert(
Def->isPHI() &&
"Invalid definition");
2182 ValueTrackerResult Res;
2185 for (
unsigned i = 1, e =
Def->getNumOperands(); i < e; i += 2) {
2186 const MachineOperand &MO =
Def->getOperand(i);
2191 return ValueTrackerResult();
2198ValueTrackerResult ValueTracker::getNextSourceImpl() {
2199 assert(Def &&
"This method needs a valid definition");
2201 assert(((
Def->getOperand(DefIdx).isDef() &&
2202 (DefIdx < Def->
getDesc().getNumDefs() ||
2203 Def->getDesc().isVariadic())) ||
2204 Def->getOperand(DefIdx).isImplicit()) &&
2207 return getNextSourceFromCopy();
2208 if (
Def->isBitcast())
2209 return getNextSourceFromBitcast();
2213 return ValueTrackerResult();
2214 if (
Def->isRegSequence() ||
Def->isRegSequenceLike())
2215 return getNextSourceFromRegSequence();
2216 if (
Def->isInsertSubreg() ||
Def->isInsertSubregLike())
2217 return getNextSourceFromInsertSubreg();
2218 if (
Def->isExtractSubreg() ||
Def->isExtractSubregLike())
2219 return getNextSourceFromExtractSubreg();
2220 if (
Def->isSubregToReg())
2221 return getNextSourceFromSubregToReg();
2223 return getNextSourceFromPHI();
2224 return ValueTrackerResult();
2227ValueTrackerResult ValueTracker::getNextSource() {
2231 return ValueTrackerResult();
2233 ValueTrackerResult Res = getNextSourceImpl();
2234 if (Res.isValid()) {
2238 bool OneRegSrc = Res.getNumSources() == 1;
2240 Reg = Res.getSrcReg(0);
2252 DefSubReg = Res.getSrcSubReg(0);
for(const MachineOperand &MO :llvm::drop_begin(OldMI.operands(), Desc.getNumOperands()))
MachineInstrBuilder & UseMI
MachineInstrBuilder MachineInstrBuilder & DefMI
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
This file defines the DenseMap class.
const HexagonInstrInfo * TII
A common definition of LaneBitmask for use in TableGen and CodeGen.
TargetInstrInfo::RegSubRegPair RegSubRegPair
Register const TargetRegisterInfo * TRI
Promote Memory to Register
MachineInstr unsigned OpIdx
uint64_t IntrinsicInst * II
#define INITIALIZE_PASS_DEPENDENCY(depName)
#define INITIALIZE_PASS_END(passName, arg, name, cfg, analysis)
#define INITIALIZE_PASS_BEGIN(passName, arg, name, cfg, analysis)
static cl::opt< unsigned > RewritePHILimit("rewrite-phi-limit", cl::Hidden, cl::init(10), cl::desc("Limit the length of PHI chains to lookup"))
static cl::opt< bool > DisablePeephole("disable-peephole", cl::Hidden, cl::init(false), cl::desc("Disable the peephole optimizer"))
static cl::opt< unsigned > MaxRecurrenceChain("recurrence-chain-limit", cl::Hidden, cl::init(3), cl::desc("Maximum length of recurrence chain when evaluating the benefit " "of commuting operands"))
static cl::opt< bool > DisableNAPhysCopyOpt("disable-non-allocatable-phys-copy-opt", cl::Hidden, cl::init(false), cl::desc("Disable non-allocatable physical register copy optimization"))
static bool isVirtualRegisterOperand(MachineOperand &MO)
\bried Returns true if MO is a virtual register operand.
static MachineInstr & insertPHI(MachineRegisterInfo &MRI, const TargetInstrInfo &TII, const SmallVectorImpl< RegSubRegPair > &SrcRegs, MachineInstr &OrigPHI)
Insert a PHI instruction with incoming edges SrcRegs that are guaranteed to have the same register cl...
static cl::opt< bool > Aggressive("aggressive-ext-opt", cl::Hidden, cl::desc("Aggressive extension optimization"))
static cl::opt< bool > DisableAdvCopyOpt("disable-adv-copy-opt", cl::Hidden, cl::init(false), cl::desc("Disable advanced copy optimization"))
Specifiy whether or not the value tracking looks through complex instructions.
TargetInstrInfo::RegSubRegPairAndIdx RegSubRegPairAndIdx
static RegSubRegPair getNewSource(MachineRegisterInfo *MRI, const TargetInstrInfo *TII, RegSubRegPair Def, const PeepholeOptimizer::RewriteMapTy &RewriteMap, bool HandleMultipleSources=true)
Given a Def.Reg and Def.SubReg pair, use RewriteMap to find the new source to use for rewrite.
Remove Loads Into Fake Uses
static bool isValid(const char C)
Returns true if C is a valid mangled character: <0-9a-zA-Z_>.
This file defines the SmallPtrSet class.
This file defines the SmallSet class.
This file defines the SmallVector class.
This file defines the 'Statistic' class, which is designed to be an easy way to expose various metric...
#define STATISTIC(VARNAME, DESC)
Virtual Register Rewriter
PassT::Result & getResult(IRUnitT &IR, ExtraArgTs... ExtraArgs)
Get the result of an analysis pass for a given IR unit.
AnalysisUsage & addRequired()
AnalysisUsage & addPreserved()
Add the specified Pass class to the set of analyses preserved by this pass.
LLVM_ABI void setPreservesCFG()
This function should be called by the pass, iff they do not:
Represents analyses that only rely on functions' control flow.
ValueT lookup(const_arg_type_t< KeyT > Val) const
Return the entry for the specified key, or a default constructed value if no such entry exists.
iterator find(const_arg_type_t< KeyT > Val)
bool erase(const KeyT &Val)
bool remove_if(Predicate Pred)
Remove entries that match the given predicate.
std::pair< iterator, bool > insert(const std::pair< KeyT, ValueT > &KV)
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 isLoopHeader(const BlockT *BB) const
unsigned getNumDefs() const
Return the number of MachineOperands that are register definitions.
An RAII based helper class to modify MachineFunctionProperties when running pass.
MachineInstrBundleIterator< MachineInstr > iterator
Analysis pass which computes a MachineDominatorTree.
Analysis pass which computes a MachineDominatorTree.
bool dominates(const MachineInstr *A, const MachineInstr *B) 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.
void moveAdditionalCallInfo(const MachineInstr *Old, const MachineInstr *New)
Move the call site info from Old to \New call site info.
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.
MachineRegisterInfo & getRegInfo()
getRegInfo - Return information about the registers currently in use.
Function & getFunction()
Return the LLVM function that this machine code represents.
void setDelegate(Delegate *delegate)
Set the delegate.
const MachineInstrBuilder & addReg(Register RegNo, RegState Flags={}, unsigned SubReg=0) const
Add a new virtual register operand.
const MachineInstrBuilder & addMBB(MachineBasicBlock *MBB, unsigned TargetFlags=0) const
Representation of each machine instruction.
const MachineBasicBlock * getParent() const
bool mayLoad(QueryType Type=AnyInBundle) const
Return true if this instruction could possibly read memory.
const DebugLoc & getDebugLoc() const
Returns the debug location id of this MachineInstr.
const MachineOperand & getOperand(unsigned i) const
LLVM_ABI MachineInstrBundleIterator< MachineInstr > eraseFromParent()
Unlink 'this' from the containing basic block and delete it.
bool canFoldAsLoad(QueryType Type=IgnoreBundle) const
Return true for instructions that can be folded as memory operands in other instructions.
Analysis pass that exposes the MachineLoopInfo for a machine function.
MachineOperand class - Representation of each machine instruction operand.
void setSubReg(unsigned subReg)
unsigned getSubReg() const
bool isReg() const
isReg - Tests if this is a MO_Register operand.
bool isRegMask() const
isRegMask - Tests if this is a MO_RegisterMask operand.
MachineBasicBlock * getMBB() const
LLVM_ABI void setReg(Register Reg)
Change the register this operand corresponds to.
MachineInstr * getParent()
getParent - Return the instruction that this operand belongs to.
void setIsUndef(bool Val=true)
Register getReg() const
getReg - Returns the register number.
static bool clobbersPhysReg(const uint32_t *RegMask, MCRegister PhysReg)
clobbersPhysReg - Returns true if this RegMask clobbers PhysReg.
const uint32_t * getRegMask() const
getRegMask - Returns a bit mask of registers preserved by this RegMask operand.
unsigned getOperandNo() const
getOperandNo - Return the operand # of this MachineOperand in its MachineInstr.
MachineRegisterInfo - Keep track of information for virtual and physical registers,...
LLVM_ABI bool hasOneNonDBGUse(Register RegNo) const
hasOneNonDBGUse - Return true if there is exactly one non-Debug use of the specified register.
use_nodbg_iterator use_nodbg_begin(Register RegNo) const
LLVM_ABI void markUsesInDebugValueAsUndef(Register Reg) const
markUsesInDebugValueAsUndef - Mark every DBG_VALUE referencing the specified register as undefined wh...
const TargetRegisterClass * getRegClass(Register Reg) const
Return the register class of the specified virtual register.
LLVM_ABI void clearKillFlags(Register Reg) const
clearKillFlags - Iterate over all the uses of the given register and clear the kill flag from the Mac...
LLVM_ABI MachineInstr * getVRegDef(Register Reg) const
getVRegDef - Return the machine instr that defines the specified virtual register or null if none is ...
iterator_range< use_nodbg_iterator > use_nodbg_operands(Register Reg) const
def_iterator def_begin(Register RegNo) const
LLVM_ABI Register createVirtualRegister(const TargetRegisterClass *RegClass, StringRef Name="")
createVirtualRegister - Create and return a new virtual register in the function with the specified r...
use_instr_nodbg_iterator use_instr_nodbg_begin(Register RegNo) const
LLVM_ABI bool hasOneNonDBGUser(Register RegNo) const
hasOneNonDBGUse - Return true if there is exactly one non-Debug instruction using the specified regis...
bool isAllocatable(MCRegister PhysReg) const
isAllocatable - Returns true when PhysReg belongs to an allocatable register class and it hasn't been...
defusechain_iterator< false, true, false, true, false > def_iterator
def_iterator/def_begin/def_end - Walk all defs of the specified register.
iterator_range< use_instr_nodbg_iterator > use_nodbg_instructions(Register Reg) const
static def_iterator def_end()
const TargetRegisterInfo * getTargetRegisterInfo() const
LLVM_ABI const TargetRegisterClass * constrainRegClass(Register Reg, const TargetRegisterClass *RC, unsigned MinNumRegs=0)
constrainRegClass - Constrain the register class of the specified virtual register to be a common sub...
LLVM_ABI void replaceRegWith(Register FromReg, Register ToReg)
replaceRegWith - Replace all instances of FromReg with ToReg in the machine function.
LLVM_ABI PreservedAnalyses run(MachineFunction &MF, MachineFunctionAnalysisManager &MFAM)
static PreservedAnalyses all()
Construct a special preserved set that preserves all passes.
Wrapper class representing virtual and physical registers.
constexpr bool isVirtual() const
Return true if the specified register number is in the virtual register namespace.
constexpr bool isPhysical() const
Return true if the specified register number is in the physical register namespace.
A templated base class for SmallPtrSet which provides the typesafe interface that is common across al...
bool erase(PtrType Ptr)
Remove pointer from the set.
size_type count(ConstPtrType Ptr) const
count - Return 1 if the specified pointer is in the set, 0 otherwise.
std::pair< iterator, bool > insert(PtrType Ptr)
Inserts Ptr if and only if there is no element in the container equal to Ptr.
SmallPtrSet - This class implements a set which is optimized for holding SmallSize or less elements.
SmallSet - This maintains a set of unique values, optimizing for the case when the set is small (less...
size_type count(const T &V) const
count - Return 1 if the element is in the set, 0 otherwise.
std::pair< const_iterator, bool > insert(const T &V)
insert - Insert an element into the set if it isn't already there.
This class consists of common code factored out of the SmallVector class to reduce code duplication b...
void push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
TargetInstrInfo - Interface to description of machine instruction set.
static const unsigned CommuteAnyOperandIndex
virtual const TargetInstrInfo * getInstrInfo() const
virtual const TargetRegisterInfo * getRegisterInfo() const =0
Return the target's register information.
self_iterator getIterator()
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
MCInstrDesc const & getDesc(MCInstrInfo const &MCII, MCInst const &MCI)
initializer< Ty > init(const Ty &Val)
DXILDebugInfoMap run(Module &M)
NodeAddr< DefNode * > Def
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.
iterator_range< T > make_range(T x, T y)
Convenience function for iterating over sub-ranges.
AnalysisManager< MachineFunction > MachineFunctionAnalysisManager
bool operator==(const AddressRangeValuePair &LHS, const AddressRangeValuePair &RHS)
LLVM_ABI char & PeepholeOptimizerLegacyID
PeepholeOptimizer - This pass performs peephole optimizations - like extension and comparison elimina...
LLVM_ABI PreservedAnalyses getMachineFunctionPassPreservedAnalyses()
Returns the minimum set of Analyses that all machine function passes must preserve.
LLVM_ABI raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
bool none_of(R &&Range, UnaryPredicate P)
Provide wrappers to std::none_of which take ranges instead of having to pass begin/end explicitly.
class LLVM_GSL_OWNER SmallVector
Forward declaration of SmallVector so that calculateSmallVectorDefaultInlinedElements can reference s...
MCRegisterClass TargetRegisterClass
A pair composed of a pair of a register and a sub-register index, and another sub-register index.
A pair composed of a register and a sub-register index.