1//===-- reduce-chunk-list.cpp - Reduce a chunks list to its minimal size --===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// See the llvm-project/llvm/docs/ProgrammersManual.rst to see how to use this
10// tool
11//
12//===----------------------------------------------------------------------===//
13
14#include "llvm/Support/CommandLine.h"
15#include "llvm/Support/IntegerInclusiveInterval.h"
16#include "llvm/Support/Program.h"
17
18using namespace llvm;
19
20static cl::opt<std::string> ReproductionCmd(cl::Positional, cl::Required);
21
22static cl::opt<std::string> StartChunks(cl::Positional, cl::Required);
23
24static cl::opt<bool> Pessimist("pessimist", cl::init(Val: false));
25
26namespace {
27
28bool isStillInteresting(ArrayRef<IntegerInclusiveInterval> Chunks) {
29 IntegerInclusiveIntervalUtils::IntervalList SimpleChunks =
30 IntegerInclusiveIntervalUtils::mergeAdjacentIntervals(Intervals: Chunks);
31
32 std::string ChunkStr;
33 {
34 raw_string_ostream OS(ChunkStr);
35 IntegerInclusiveIntervalUtils::printIntervals(OS, Intervals: SimpleChunks);
36 }
37
38 errs() << "Checking with: " << ChunkStr << "\n";
39
40 std::vector<StringRef> Argv;
41 Argv.push_back(x: ReproductionCmd);
42 Argv.push_back(x: ChunkStr);
43
44 std::string ErrMsg;
45 bool ExecutionFailed;
46 int Result = sys::ExecuteAndWait(Program: Argv[0], Args: Argv, Env: std::nullopt, Redirects: {}, SecondsToWait: 0, MemoryLimit: 0,
47 ErrMsg: &ErrMsg, ExecutionFailed: &ExecutionFailed);
48 if (ExecutionFailed) {
49 errs() << "failed to execute : " << Argv[0] << " : " << ErrMsg << "\n";
50 exit(status: 1);
51 }
52
53 bool Res = Result != 0;
54 if (Res) {
55 errs() << "SUCCESS : Still Interesting\n";
56 } else {
57 errs() << "FAILURE : Not Interesting\n";
58 }
59 return Res;
60}
61
62bool increaseGranularity(IntegerInclusiveIntervalUtils::IntervalList &Chunks) {
63 errs() << "Increasing granularity\n";
64 IntegerInclusiveIntervalUtils::IntervalList NewChunks;
65 bool SplitOne = false;
66
67 for (auto &C : Chunks) {
68 if (C.getBegin() == C.getEnd()) {
69 NewChunks.push_back(Elt: C);
70 } else {
71 int64_t Half = (C.getBegin() + C.getEnd()) / 2;
72 NewChunks.push_back(Elt: IntegerInclusiveInterval(C.getBegin(), Half));
73 NewChunks.push_back(Elt: IntegerInclusiveInterval(Half + 1, C.getEnd()));
74 SplitOne = true;
75 }
76 }
77 if (SplitOne) {
78 Chunks = std::move(NewChunks);
79 }
80 return SplitOne;
81}
82
83} // namespace
84
85int main(int argc, char **argv) {
86 cl::ParseCommandLineOptions(argc, argv);
87
88 auto ExpectedChunks =
89 IntegerInclusiveIntervalUtils::parseIntervals(IntervalStr: StartChunks, Separator: ',');
90 if (!ExpectedChunks) {
91 handleAllErrors(E: ExpectedChunks.takeError(), Handlers: [](const StringError &E) {
92 errs() << "Error parsing chunks: " << E.getMessage() << "\n";
93 });
94 return 1;
95 }
96 IntegerInclusiveIntervalUtils::IntervalList CurrChunks =
97 std::move(*ExpectedChunks);
98
99 auto Program = sys::findProgramByName(Name: ReproductionCmd);
100 if (!Program) {
101 errs() << "failed to find command : " << ReproductionCmd << "\n";
102 return 1;
103 }
104 ReproductionCmd.setValue(V: Program.get());
105
106 errs() << "Input Checking:\n";
107 if (!isStillInteresting(Chunks: CurrChunks)) {
108 errs() << "starting chunks are not interesting\n";
109 return 1;
110 }
111 if (CurrChunks.size() == 1)
112 increaseGranularity(Chunks&: CurrChunks);
113 if (Pessimist)
114 while (increaseGranularity(Chunks&: CurrChunks))
115 /* empty body */;
116 while (1) {
117 for (int Idx = (CurrChunks.size() - 1); Idx >= 0; Idx--) {
118 if (CurrChunks.size() == 1)
119 break;
120
121 IntegerInclusiveInterval Testing = CurrChunks[Idx];
122 errs() << "Trying to remove : ";
123 Testing.print(OS&: errs());
124 errs() << "\n";
125
126 CurrChunks.erase(CI: CurrChunks.begin() + Idx);
127
128 if (!isStillInteresting(Chunks: CurrChunks))
129 CurrChunks.insert(I: CurrChunks.begin() + Idx, Elt: Testing);
130 }
131 bool HasSplit = increaseGranularity(Chunks&: CurrChunks);
132 if (!HasSplit)
133 break;
134 }
135
136 errs() << "Minimal Chunks = ";
137 IntegerInclusiveIntervalUtils::printIntervals(
138 OS&: llvm::errs(),
139 Intervals: IntegerInclusiveIntervalUtils::mergeAdjacentIntervals(Intervals: CurrChunks));
140 errs() << "\n";
141}
142