[MachineOutliner] Refactor iterating over Candidate's instructions (#78972)

Make Candidate's front() and back() functions return references to
MachineInstr and introduce begin() and end() returning iterators, the
same way it is usually done in other container-like classes.

This makes possible to iterate over the instructions contained in
Candidate the same way one can iterate over MachineBasicBlock (note that
begin() and end() return bundled iterators, just like MachineBasicBlock
does, but no instr_begin() and instr_end() are defined yet).
This commit is contained in:
Anatoly Trosinenko 2024-01-23 17:21:40 +03:00 committed by GitHub
parent 654131fab2
commit 10bd69a4f7
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 69 additions and 80 deletions

View File

@ -87,7 +87,7 @@ private:
// Compute liveness from the end of the block up to the beginning of the
// outlining candidate.
for (auto &MI : make_range(MBB->rbegin(),
(MachineBasicBlock::reverse_iterator)front()))
(MachineBasicBlock::reverse_iterator)begin()))
FromEndOfBlockToStartOfSeq.stepBackward(MI);
}
@ -100,7 +100,7 @@ private:
return;
InSeqWasSet = true;
InSeq.init(TRI);
for (auto &MI : make_range(front(), std::next(back())))
for (auto &MI : *this)
InSeq.accumulate(MI);
}
@ -135,8 +135,11 @@ public:
/// Returns the call overhead of this candidate if it is in the list.
unsigned getCallOverhead() const { return CallOverhead; }
MachineBasicBlock::iterator &front() { return FirstInst; }
MachineBasicBlock::iterator &back() { return LastInst; }
MachineBasicBlock::iterator begin() { return FirstInst; }
MachineBasicBlock::iterator end() { return std::next(LastInst); }
MachineInstr &front() { return *FirstInst; }
MachineInstr &back() { return *LastInst; }
MachineFunction *getMF() const { return MBB->getParent(); }
MachineBasicBlock *getMBB() const { return MBB; }

View File

@ -525,7 +525,7 @@ void MachineOutliner::emitNotOutliningCheaperRemark(
MachineOptimizationRemarkEmitter MORE(*(C.getMF()), nullptr);
MORE.emit([&]() {
MachineOptimizationRemarkMissed R(DEBUG_TYPE, "NotOutliningCheaper",
C.front()->getDebugLoc(), C.getMBB());
C.front().getDebugLoc(), C.getMBB());
R << "Did not outline " << NV("Length", StringLen) << " instructions"
<< " from " << NV("NumOccurrences", CandidatesForRepeatedSeq.size())
<< " locations."
@ -538,7 +538,7 @@ void MachineOutliner::emitNotOutliningCheaperRemark(
// Tell the user the other places the candidate was found.
for (unsigned i = 1, e = CandidatesForRepeatedSeq.size(); i < e; i++) {
R << NV((Twine("OtherStartLoc") + Twine(i)).str(),
CandidatesForRepeatedSeq[i].front()->getDebugLoc());
CandidatesForRepeatedSeq[i].front().getDebugLoc());
if (i != e - 1)
R << ", ";
}
@ -563,7 +563,7 @@ void MachineOutliner::emitOutlinedFunctionRemark(OutlinedFunction &OF) {
for (size_t i = 0, e = OF.Candidates.size(); i < e; i++) {
R << NV((Twine("StartLoc") + Twine(i)).str(),
OF.Candidates[i].front()->getDebugLoc());
OF.Candidates[i].front().getDebugLoc());
if (i != e - 1)
R << ", ";
}
@ -732,23 +732,22 @@ MachineFunction *MachineOutliner::createOutlinedFunction(
// Insert the new function into the module.
MF.insert(MF.begin(), &MBB);
MachineFunction *OriginalMF = FirstCand.front()->getMF();
MachineFunction *OriginalMF = FirstCand.front().getMF();
const std::vector<MCCFIInstruction> &Instrs =
OriginalMF->getFrameInstructions();
for (auto I = FirstCand.front(), E = std::next(FirstCand.back()); I != E;
++I) {
if (I->isDebugInstr())
for (auto &MI : FirstCand) {
if (MI.isDebugInstr())
continue;
// Don't keep debug information for outlined instructions.
auto DL = DebugLoc();
if (I->isCFIInstruction()) {
unsigned CFIIndex = I->getOperand(0).getCFIIndex();
if (MI.isCFIInstruction()) {
unsigned CFIIndex = MI.getOperand(0).getCFIIndex();
MCCFIInstruction CFI = Instrs[CFIIndex];
BuildMI(MBB, MBB.end(), DL, TII.get(TargetOpcode::CFI_INSTRUCTION))
.addCFIIndex(MF.addFrameInst(CFI));
} else {
MachineInstr *NewMI = MF.CloneMachineInstr(&*I);
MachineInstr *NewMI = MF.CloneMachineInstr(&MI);
NewMI->dropMemRefs(MF);
NewMI->setDebugLoc(DL);
MBB.insert(MBB.end(), NewMI);
@ -768,11 +767,11 @@ MachineFunction *MachineOutliner::createOutlinedFunction(
LivePhysRegs LiveIns(TRI);
for (auto &Cand : OF.Candidates) {
// Figure out live-ins at the first instruction.
MachineBasicBlock &OutlineBB = *Cand.front()->getParent();
MachineBasicBlock &OutlineBB = *Cand.front().getParent();
LivePhysRegs CandLiveIns(TRI);
CandLiveIns.addLiveOuts(OutlineBB);
for (const MachineInstr &MI :
reverse(make_range(Cand.front(), OutlineBB.end())))
reverse(make_range(Cand.begin(), OutlineBB.end())))
CandLiveIns.stepBackward(MI);
// The live-in set for the outlined function is the union of the live-ins
@ -884,8 +883,8 @@ bool MachineOutliner::outline(Module &M,
LLVM_DEBUG(dbgs() << "CREATE OUTLINED CALLS\n");
for (Candidate &C : OF.Candidates) {
MachineBasicBlock &MBB = *C.getMBB();
MachineBasicBlock::iterator StartIt = C.front();
MachineBasicBlock::iterator EndIt = C.back();
MachineBasicBlock::iterator StartIt = C.begin();
MachineBasicBlock::iterator EndIt = std::prev(C.end());
// Insert the call.
auto CallInst = TII.insertOutlinedCall(M, MBB, StartIt, *MF, C);

View File

@ -8230,11 +8230,11 @@ std::optional<outliner::OutlinedFunction>
AArch64InstrInfo::getOutliningCandidateInfo(
std::vector<outliner::Candidate> &RepeatedSequenceLocs) const {
outliner::Candidate &FirstCand = RepeatedSequenceLocs[0];
unsigned SequenceSize =
std::accumulate(FirstCand.front(), std::next(FirstCand.back()), 0,
[this](unsigned Sum, const MachineInstr &MI) {
return Sum + getInstSizeInBytes(MI);
});
unsigned SequenceSize = 0;
for (auto &MI : FirstCand)
SequenceSize += getInstSizeInBytes(MI);
unsigned NumBytesToCreateFrame = 0;
// We only allow outlining for functions having exactly matching return
@ -8287,7 +8287,7 @@ AArch64InstrInfo::getOutliningCandidateInfo(
AArch64PAuth::getCheckerSizeInBytes(LRCheckMethod);
// Checking the authenticated LR value may significantly impact
// SequenceSize, so account for it for more precise results.
if (isTailCallReturnInst(*RepeatedSequenceLocs[0].back()))
if (isTailCallReturnInst(RepeatedSequenceLocs[0].back()))
SequenceSize += NumBytesToCheckLRInTCEpilogue;
// We have to check if sp modifying instructions would get outlined.
@ -8296,37 +8296,36 @@ AArch64InstrInfo::getOutliningCandidateInfo(
// are not
auto hasIllegalSPModification = [&TRI](outliner::Candidate &C) {
int SPValue = 0;
MachineBasicBlock::iterator MBBI = C.front();
for (;;) {
if (MBBI->modifiesRegister(AArch64::SP, &TRI)) {
switch (MBBI->getOpcode()) {
for (auto &MI : C) {
if (MI.modifiesRegister(AArch64::SP, &TRI)) {
switch (MI.getOpcode()) {
case AArch64::ADDXri:
case AArch64::ADDWri:
assert(MBBI->getNumOperands() == 4 && "Wrong number of operands");
assert(MBBI->getOperand(2).isImm() &&
assert(MI.getNumOperands() == 4 && "Wrong number of operands");
assert(MI.getOperand(2).isImm() &&
"Expected operand to be immediate");
assert(MBBI->getOperand(1).isReg() &&
assert(MI.getOperand(1).isReg() &&
"Expected operand to be a register");
// Check if the add just increments sp. If so, we search for
// matching sub instructions that decrement sp. If not, the
// modification is illegal
if (MBBI->getOperand(1).getReg() == AArch64::SP)
SPValue += MBBI->getOperand(2).getImm();
if (MI.getOperand(1).getReg() == AArch64::SP)
SPValue += MI.getOperand(2).getImm();
else
return true;
break;
case AArch64::SUBXri:
case AArch64::SUBWri:
assert(MBBI->getNumOperands() == 4 && "Wrong number of operands");
assert(MBBI->getOperand(2).isImm() &&
assert(MI.getNumOperands() == 4 && "Wrong number of operands");
assert(MI.getOperand(2).isImm() &&
"Expected operand to be immediate");
assert(MBBI->getOperand(1).isReg() &&
assert(MI.getOperand(1).isReg() &&
"Expected operand to be a register");
// Check if the sub just decrements sp. If so, we search for
// matching add instructions that increment sp. If not, the
// modification is illegal
if (MBBI->getOperand(1).getReg() == AArch64::SP)
SPValue -= MBBI->getOperand(2).getImm();
if (MI.getOperand(1).getReg() == AArch64::SP)
SPValue -= MI.getOperand(2).getImm();
else
return true;
break;
@ -8334,9 +8333,6 @@ AArch64InstrInfo::getOutliningCandidateInfo(
return true;
}
}
if (MBBI == C.back())
break;
++MBBI;
}
if (SPValue)
return true;
@ -8357,7 +8353,7 @@ AArch64InstrInfo::getOutliningCandidateInfo(
for (outliner::Candidate &C : RepeatedSequenceLocs)
FlagsSetInAll &= C.Flags;
unsigned LastInstrOpcode = RepeatedSequenceLocs[0].back()->getOpcode();
unsigned LastInstrOpcode = RepeatedSequenceLocs[0].back().getOpcode();
// Helper lambda which sets call information for every candidate.
auto SetCandidateCallInfo =
@ -8376,8 +8372,7 @@ AArch64InstrInfo::getOutliningCandidateInfo(
// We check to see if CFI Instructions are present, and if they are
// we find the number of CFI Instructions in the candidates.
unsigned CFICount = 0;
for (auto &I : make_range(RepeatedSequenceLocs[0].front(),
std::next(RepeatedSequenceLocs[0].back()))) {
for (auto &I : RepeatedSequenceLocs[0]) {
if (I.isCFIInstruction())
CFICount++;
}
@ -8452,12 +8447,11 @@ AArch64InstrInfo::getOutliningCandidateInfo(
// True if it's possible to fix up each stack instruction in this sequence.
// Important for frames/call variants that modify the stack.
bool AllStackInstrsSafe = std::all_of(
FirstCand.front(), std::next(FirstCand.back()), IsSafeToFixup);
bool AllStackInstrsSafe = llvm::all_of(FirstCand, IsSafeToFixup);
// If the last instruction in any candidate is a terminator, then we should
// tail call all of the candidates.
if (RepeatedSequenceLocs[0].back()->isTerminator()) {
if (RepeatedSequenceLocs[0].back().isTerminator()) {
FrameID = MachineOutlinerTailCall;
NumBytesToCreateFrame = 0;
unsigned NumBytesForCall = 4 + NumBytesToCheckLRInTCEpilogue;
@ -8583,9 +8577,8 @@ AArch64InstrInfo::getOutliningCandidateInfo(
//
if (FlagsSetInAll & MachineOutlinerMBBFlags::HasCalls) {
erase_if(RepeatedSequenceLocs, [this, &TRI](outliner::Candidate &C) {
return (std::any_of(
C.front(), std::next(C.back()),
[](const MachineInstr &MI) { return MI.isCall(); })) &&
auto IsCall = [](const MachineInstr &MI) { return MI.isCall(); };
return (llvm::any_of(C, IsCall)) &&
(!C.isAvailableAcrossAndOutOfSeq(AArch64::LR, TRI) ||
!findRegisterToSaveLRTo(C));
});
@ -8605,7 +8598,7 @@ AArch64InstrInfo::getOutliningCandidateInfo(
// Check if the range contains a call. These require a save + restore of the
// link register.
bool ModStackToSaveLR = false;
if (std::any_of(FirstCand.front(), FirstCand.back(),
if (std::any_of(FirstCand.begin(), std::prev(FirstCand.end()),
[](const MachineInstr &MI) { return MI.isCall(); }))
ModStackToSaveLR = true;
@ -8615,7 +8608,7 @@ AArch64InstrInfo::getOutliningCandidateInfo(
// it being valid to tail call this sequence. We should consider this as
// well.
else if (FrameID != MachineOutlinerThunk &&
FrameID != MachineOutlinerTailCall && FirstCand.back()->isCall())
FrameID != MachineOutlinerTailCall && FirstCand.back().isCall())
ModStackToSaveLR = true;
if (ModStackToSaveLR) {

View File

@ -5874,11 +5874,10 @@ std::optional<outliner::OutlinedFunction>
ARMBaseInstrInfo::getOutliningCandidateInfo(
std::vector<outliner::Candidate> &RepeatedSequenceLocs) const {
outliner::Candidate &FirstCand = RepeatedSequenceLocs[0];
unsigned SequenceSize =
std::accumulate(FirstCand.front(), std::next(FirstCand.back()), 0,
[this](unsigned Sum, const MachineInstr &MI) {
return Sum + getInstSizeInBytes(MI);
});
unsigned SequenceSize = 0;
for (auto &MI : FirstCand)
SequenceSize += getInstSizeInBytes(MI);
// Properties about candidate MBBs that hold for all of them.
unsigned FlagsSetInAll = 0xF;
@ -5965,7 +5964,7 @@ ARMBaseInstrInfo::getOutliningCandidateInfo(
// At this point, we have only "safe" candidates to outline. Figure out
// frame + call instruction information.
unsigned LastInstrOpcode = RepeatedSequenceLocs[0].back()->getOpcode();
unsigned LastInstrOpcode = RepeatedSequenceLocs[0].back().getOpcode();
// Helper lambda which sets call information for every candidate.
auto SetCandidateCallInfo =
@ -5998,7 +5997,7 @@ ARMBaseInstrInfo::getOutliningCandidateInfo(
// If the last instruction in any candidate is a terminator, then we should
// tail call all of the candidates.
if (RepeatedSequenceLocs[0].back()->isTerminator()) {
if (RepeatedSequenceLocs[0].back().isTerminator()) {
FrameID = MachineOutlinerTailCall;
NumBytesToCreateFrame = Costs.FrameTailCall;
SetCandidateCallInfo(MachineOutlinerTailCall, Costs.CallTailCall);
@ -6024,7 +6023,7 @@ ARMBaseInstrInfo::getOutliningCandidateInfo(
const bool LRIsAvailable =
C.getMBB()->isReturnBlock() && !Last->isCall()
? isLRAvailable(TRI, Last,
(MachineBasicBlock::reverse_iterator)C.front())
(MachineBasicBlock::reverse_iterator)C.begin())
: C.isAvailableAcrossAndOutOfSeq(ARM::LR, TRI);
if (LRIsAvailable) {
FrameID = MachineOutlinerNoLRSave;
@ -6072,7 +6071,7 @@ ARMBaseInstrInfo::getOutliningCandidateInfo(
if (FlagsSetInAll & MachineOutlinerMBBFlags::HasCalls) {
// check if the range contains a call. These require a save + restore of
// the link register.
if (std::any_of(FirstCand.front(), FirstCand.back(),
if (std::any_of(FirstCand.begin(), std::prev(FirstCand.end()),
[](const MachineInstr &MI) { return MI.isCall(); }))
NumBytesToCreateFrame += Costs.SaveRestoreLROnStack;
@ -6082,7 +6081,7 @@ ARMBaseInstrInfo::getOutliningCandidateInfo(
// call without it being valid to tail call this sequence. We should
// consider this as well.
else if (FrameID != MachineOutlinerThunk &&
FrameID != MachineOutlinerTailCall && FirstCand.back()->isCall())
FrameID != MachineOutlinerTailCall && FirstCand.back().isCall())
NumBytesToCreateFrame += Costs.SaveRestoreLROnStack;
}

View File

@ -2434,10 +2434,8 @@ RISCVInstrInfo::getOutliningCandidateInfo(
unsigned SequenceSize = 0;
auto I = RepeatedSequenceLocs[0].front();
auto E = std::next(RepeatedSequenceLocs[0].back());
for (; I != E; ++I)
SequenceSize += getInstSizeInBytes(*I);
for (auto &MI : RepeatedSequenceLocs[0])
SequenceSize += getInstSizeInBytes(MI);
// call t0, function = 8 bytes.
unsigned CallOverhead = 8;

View File

@ -10387,23 +10387,20 @@ enum MachineOutlinerClass { MachineOutlinerDefault, MachineOutlinerTailCall };
std::optional<outliner::OutlinedFunction>
X86InstrInfo::getOutliningCandidateInfo(
std::vector<outliner::Candidate> &RepeatedSequenceLocs) const {
unsigned SequenceSize =
std::accumulate(RepeatedSequenceLocs[0].front(),
std::next(RepeatedSequenceLocs[0].back()), 0,
[](unsigned Sum, const MachineInstr &MI) {
// FIXME: x86 doesn't implement getInstSizeInBytes, so
// we can't tell the cost. Just assume each instruction
// is one byte.
if (MI.isDebugInstr() || MI.isKill())
return Sum;
return Sum + 1;
});
unsigned SequenceSize = 0;
for (auto &MI : RepeatedSequenceLocs[0]) {
// FIXME: x86 doesn't implement getInstSizeInBytes, so
// we can't tell the cost. Just assume each instruction
// is one byte.
if (MI.isDebugInstr() || MI.isKill())
continue;
SequenceSize += 1;
}
// We check to see if CFI Instructions are present, and if they are
// we find the number of CFI Instructions in the candidates.
unsigned CFICount = 0;
for (auto &I : make_range(RepeatedSequenceLocs[0].front(),
std::next(RepeatedSequenceLocs[0].back()))) {
for (auto &I : RepeatedSequenceLocs[0]) {
if (I.isCFIInstruction())
CFICount++;
}
@ -10422,7 +10419,7 @@ X86InstrInfo::getOutliningCandidateInfo(
}
// FIXME: Use real size in bytes for call and ret instructions.
if (RepeatedSequenceLocs[0].back()->isTerminator()) {
if (RepeatedSequenceLocs[0].back().isTerminator()) {
for (outliner::Candidate &C : RepeatedSequenceLocs)
C.setCallInfo(MachineOutlinerTailCall, 1);