[StringExtras] Add a helper class for comma-separated lists

This patch introduces a helper class SubsequentDelim to simplify loops
that generate a comma-separated lists.

For example, consider the following loop, taken from
llvm/lib/CodeGen/MachineBasicBlock.cpp:

    for (auto I = pred_begin(), E = pred_end(); I != E; ++I) {
      if (I != pred_begin())
        OS << ", ";
      OS << printMBBReference(**I);
    }

The new class allows us to rewrite the loop as:

    SubsequentDelim SD;
    for (auto I = pred_begin(), E = pred_end(); I != E; ++I)
      OS << SD << printMBBReference(**I);

where SD evaluates to the empty string for the first time and ", " for
subsequent iterations.

Unlike interleaveComma, defined in llvm/include/llvm/ADT/STLExtras.h,
SubsequentDelim can accommodate a wider variety of loops, including:

- those that conditionally skip certain items,
- those that need iterators to call getSuccProbability(I), and
- those that iterate over integer ranges.

As an example, this patch cleans up MachineBasicBlock::print.

Differential Revision: https://reviews.llvm.org/D94377
This commit is contained in:
Kazu Hirata 2021-01-10 14:32:02 -08:00
parent 7be3285248
commit 407b1e65a4
3 changed files with 47 additions and 16 deletions

View File

@ -462,6 +462,30 @@ inline std::string join_items(Sep Separator, Args &&... Items) {
return Result;
}
/// A helper class to return the specified delimiter string after the first
/// invocation of operator StringRef(). Used to generate a comma-separated
/// list from a loop like so:
///
/// \code
/// SubsequentDelim SD;
/// for (auto &I : C)
/// OS << SD << I.getName();
/// \end
class SubsequentDelim {
bool First = true;
StringRef Delim;
public:
SubsequentDelim(StringRef Delim = ", ") : Delim(Delim) {}
operator StringRef() {
if (First) {
First = false;
return {};
}
return Delim;
}
};
} // end namespace llvm
#endif // LLVM_ADT_STRINGEXTRAS_H

View File

@ -353,11 +353,9 @@ void MachineBasicBlock::print(raw_ostream &OS, ModuleSlotTracker &MST,
if (Indexes) OS << '\t';
// Don't indent(2), align with previous line attributes.
OS << "; predecessors: ";
for (auto I = pred_begin(), E = pred_end(); I != E; ++I) {
if (I != pred_begin())
OS << ", ";
OS << printMBBReference(**I);
}
SubsequentDelim SD;
for (auto *Pred : predecessors())
OS << SD << printMBBReference(*Pred);
OS << '\n';
HasLineAttributes = true;
}
@ -366,10 +364,9 @@ void MachineBasicBlock::print(raw_ostream &OS, ModuleSlotTracker &MST,
if (Indexes) OS << '\t';
// Print the successors
OS.indent(2) << "successors: ";
SubsequentDelim SD;
for (auto I = succ_begin(), E = succ_end(); I != E; ++I) {
if (I != succ_begin())
OS << ", ";
OS << printMBBReference(**I);
OS << SD << printMBBReference(**I);
if (!Probs.empty())
OS << '('
<< format("0x%08" PRIx32, getSuccProbability(I).getNumerator())
@ -378,11 +375,10 @@ void MachineBasicBlock::print(raw_ostream &OS, ModuleSlotTracker &MST,
if (!Probs.empty() && IsStandalone) {
// Print human readable probabilities as comments.
OS << "; ";
SubsequentDelim SD;
for (auto I = succ_begin(), E = succ_end(); I != E; ++I) {
const BranchProbability &BP = getSuccProbability(I);
if (I != succ_begin())
OS << ", ";
OS << printMBBReference(**I) << '('
OS << SD << printMBBReference(**I) << '('
<< format("%.2f%%",
rint(((double)BP.getNumerator() / BP.getDenominator()) *
100.0 * 100.0) /
@ -399,12 +395,9 @@ void MachineBasicBlock::print(raw_ostream &OS, ModuleSlotTracker &MST,
if (Indexes) OS << '\t';
OS.indent(2) << "liveins: ";
bool First = true;
SubsequentDelim SD;
for (const auto &LI : liveins()) {
if (!First)
OS << ", ";
First = false;
OS << printReg(LI.PhysReg, TRI);
OS << SD << printReg(LI.PhysReg, TRI);
if (!LI.LaneMask.all())
OS << ":0x" << PrintLaneMask(LI.LaneMask);
}

View File

@ -215,3 +215,17 @@ TEST(StringExtras, IToStr) {
EXPECT_EQ(std::to_string(MinInt64), itostr(MinInt64));
EXPECT_EQ(std::to_string(MaxInt64), itostr(MaxInt64));
}
TEST(StringExtras, SubsequentDelim) {
SubsequentDelim SD;
StringRef S = SD;
EXPECT_EQ(S, "");
S = SD;
EXPECT_EQ(S, ", ");
SubsequentDelim SD2(" ");
S = SD2;
EXPECT_EQ(S, "");
S = SD2;
EXPECT_EQ(S, " ");
}