diff options
author | Jessica Paquette <jpaquette@apple.com> | 2022-02-16 12:50:31 -0800 |
---|---|---|
committer | Jessica Paquette <jpaquette@apple.com> | 2023-02-03 15:33:37 -0800 |
commit | 4de8521bc528436abc47a250b2495f8b8fbc7798 (patch) | |
tree | 634581c9be0da062ee1b86bfca750d1717e50c59 /llvm/lib/CodeGen/MachineOutliner.cpp | |
parent | f2eb551801d504b43be06c0c70ed377c3445bbc5 (diff) | |
download | llvm-4de8521bc528436abc47a250b2495f8b8fbc7798.zip llvm-4de8521bc528436abc47a250b2495f8b8fbc7798.tar.gz llvm-4de8521bc528436abc47a250b2495f8b8fbc7798.tar.bz2 |
[MachineOutliner][AArch64] NFC: Split MBBs into "outlinable ranges"
Recommit with bug fixes + added testcases to the outliner. Also adds some
debug output.
We found a case in the Swift benchmarks where the MachineOutliner introduces
about a 20% compile time overhead in comparison to building without the
MachineOutliner.
The origin of this slowdown is that the benchmark has long blocks which incur
lots of LRU checks for lots of candidates.
Imagine a case like this:
```
bb:
i1
i2
i3
...
i123456
```
Now imagine that all of the outlining candidates appear early in the block, and
that something like, say, NZCV is defined at the end of the block.
The outliner has to check liveness for certain registers across all candidates,
because outlining from areas where those registers are used is unsafe at call
boundaries.
This is fairly wasteful because in the previously-described case, the outlining
candidates will never appear in an area where those registers are live.
To avoid this, precalculate areas where we will consider outlining from.
Anything outside of these areas is mapped to illegal and not included in the
outlining search space. This allows us to reduce the size of the outliner's
suffix tree as well, giving us a potential memory win.
By precalculating areas, we can also optimize other checks too, like whether
or not LR is live across an outlining candidate.
Doing all of this is about a 16% compile time improvement on the case.
This is likely useful for other targets (e.g. ARM + RISCV) as well, but for now,
this only implements the AArch64 path. The original "is the MBB safe" method
still works as before.
Diffstat (limited to 'llvm/lib/CodeGen/MachineOutliner.cpp')
-rw-r--r-- | llvm/lib/CodeGen/MachineOutliner.cpp | 89 |
1 files changed, 64 insertions, 25 deletions
diff --git a/llvm/lib/CodeGen/MachineOutliner.cpp b/llvm/lib/CodeGen/MachineOutliner.cpp index c7ba66b..a7422f6 100644 --- a/llvm/lib/CodeGen/MachineOutliner.cpp +++ b/llvm/lib/CodeGen/MachineOutliner.cpp @@ -254,12 +254,20 @@ struct InstructionMapper { /// \param TII \p TargetInstrInfo for the function. void convertToUnsignedVec(MachineBasicBlock &MBB, const TargetInstrInfo &TII) { + LLVM_DEBUG(dbgs() << "*** Converting MBB '" << MBB.getName() + << "' to unsigned vector ***\n"); unsigned Flags = 0; // Don't even map in this case. if (!TII.isMBBSafeToOutlineFrom(MBB, Flags)) return; + auto OutlinableRanges = TII.getOutlinableRanges(MBB, Flags); + LLVM_DEBUG(dbgs() << MBB.getName() << ": " << OutlinableRanges.size() + << " outlinable range(s)\n"); + if (OutlinableRanges.empty()) + return; + // Store info for the MBB for later outlining. MBBFlagsMap[&MBB] = Flags; @@ -282,37 +290,68 @@ struct InstructionMapper { std::vector<unsigned> UnsignedVecForMBB; std::vector<MachineBasicBlock::iterator> InstrListForMBB; - for (MachineBasicBlock::iterator Et = MBB.end(); It != Et; ++It) { - // Keep track of where this instruction is in the module. - switch (TII.getOutliningType(It, Flags)) { - case InstrType::Illegal: + LLVM_DEBUG(dbgs() << "*** Mapping outlinable ranges ***\n"); + for (auto &OutlinableRange : OutlinableRanges) { + auto OutlinableRangeBegin = OutlinableRange.first; + auto OutlinableRangeEnd = OutlinableRange.second; +#ifndef NDEBUG + LLVM_DEBUG( + dbgs() << "Mapping " + << std::distance(OutlinableRangeBegin, OutlinableRangeEnd) + << " instruction range\n"); + // Everything outside of an outlinable range is illegal. + unsigned NumSkippedInRange = 0; +#endif + for (; It != OutlinableRangeBegin; ++It) { +#ifndef NDEBUG + ++NumSkippedInRange; +#endif mapToIllegalUnsigned(It, CanOutlineWithPrevInstr, UnsignedVecForMBB, InstrListForMBB); - break; - - case InstrType::Legal: - mapToLegalUnsigned(It, CanOutlineWithPrevInstr, HaveLegalRange, - NumLegalInBlock, UnsignedVecForMBB, InstrListForMBB); - break; - - case InstrType::LegalTerminator: - mapToLegalUnsigned(It, CanOutlineWithPrevInstr, HaveLegalRange, - NumLegalInBlock, UnsignedVecForMBB, InstrListForMBB); - // The instruction also acts as a terminator, so we have to record that - // in the string. - mapToIllegalUnsigned(It, CanOutlineWithPrevInstr, UnsignedVecForMBB, + } +#ifndef NDEBUG + LLVM_DEBUG(dbgs() << "Skipped " << NumSkippedInRange + << " instructions outside outlinable range\n"); +#endif + assert(It != MBB.end() && "Should still have instructions?"); + // `It` is now positioned at the beginning of a range of instructions + // which may be outlinable. Check if each instruction is known to be safe. + for (; It != OutlinableRangeEnd; ++It) { + // Keep track of where this instruction is in the module. + switch (TII.getOutliningType(It, Flags)) { + case InstrType::Illegal: + mapToIllegalUnsigned(It, CanOutlineWithPrevInstr, UnsignedVecForMBB, + InstrListForMBB); + break; + + case InstrType::Legal: + mapToLegalUnsigned(It, CanOutlineWithPrevInstr, HaveLegalRange, + NumLegalInBlock, UnsignedVecForMBB, InstrListForMBB); - break; - - case InstrType::Invisible: - // Normally this is set by mapTo(Blah)Unsigned, but we just want to - // skip this instruction. So, unset the flag here. - ++NumInvisible; - AddedIllegalLastTime = false; - break; + break; + + case InstrType::LegalTerminator: + mapToLegalUnsigned(It, CanOutlineWithPrevInstr, HaveLegalRange, + NumLegalInBlock, UnsignedVecForMBB, + InstrListForMBB); + // The instruction also acts as a terminator, so we have to record + // that in the string. + mapToIllegalUnsigned(It, CanOutlineWithPrevInstr, UnsignedVecForMBB, + InstrListForMBB); + break; + + case InstrType::Invisible: + // Normally this is set by mapTo(Blah)Unsigned, but we just want to + // skip this instruction. So, unset the flag here. + ++NumInvisible; + AddedIllegalLastTime = false; + break; + } } } + LLVM_DEBUG(dbgs() << "HaveLegalRange = " << HaveLegalRange << "\n"); + // Are there enough legal instructions in the block for outlining to be // possible? if (HaveLegalRange) { |