xref: /llvm-project/llvm/tools/llvm-reduce/llvm-reduce.cpp (revision 8128d4b1229203c2ab20d3136410c149ea3652cf)
1ddc64eb9SDiego Trevino Ferrer //===- llvm-reduce.cpp - The LLVM Delta Reduction utility -----------------===//
2ddc64eb9SDiego Trevino Ferrer //
3ddc64eb9SDiego Trevino Ferrer // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4ddc64eb9SDiego Trevino Ferrer // See https://llvm.org/LICENSE.txt for license information.
5ddc64eb9SDiego Trevino Ferrer // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6ddc64eb9SDiego Trevino Ferrer //
7ddc64eb9SDiego Trevino Ferrer //===----------------------------------------------------------------------===//
8ddc64eb9SDiego Trevino Ferrer //
9ddc64eb9SDiego Trevino Ferrer // This program tries to reduce an IR test case for a given interesting-ness
10ddc64eb9SDiego Trevino Ferrer // test. It runs multiple delta debugging passes in order to minimize the input
11ddc64eb9SDiego Trevino Ferrer // file. It's worth noting that this is a part of the bugpoint redesign
12ddc64eb9SDiego Trevino Ferrer // proposal, and thus a *temporary* tool that will eventually be integrated
13ddc64eb9SDiego Trevino Ferrer // into the bugpoint tool itself.
14ddc64eb9SDiego Trevino Ferrer //
15ddc64eb9SDiego Trevino Ferrer //===----------------------------------------------------------------------===//
16ddc64eb9SDiego Trevino Ferrer 
17ddc64eb9SDiego Trevino Ferrer #include "DeltaManager.h"
18fd41738eSMarkus Lavin #include "ReducerWorkItem.h"
19545a8177SArthur Eubanks #include "TestRunner.h"
20333ffafbSMatt Arsenault #include "llvm/Bitcode/BitcodeReader.h"
21fd41738eSMarkus Lavin #include "llvm/CodeGen/CommandFlags.h"
22ddc64eb9SDiego Trevino Ferrer #include "llvm/Support/CommandLine.h"
23ddc64eb9SDiego Trevino Ferrer #include "llvm/Support/InitLLVM.h"
24333ffafbSMatt Arsenault #include "llvm/Support/MemoryBufferRef.h"
2595abdebaSMatt Arsenault #include "llvm/Support/Process.h"
2675e164f6Sserge-sans-paille #include "llvm/Support/WithColor.h"
271747a93bSMatt Arsenault #include "llvm/Support/raw_ostream.h"
28ddc64eb9SDiego Trevino Ferrer #include <system_error>
29ddc64eb9SDiego Trevino Ferrer 
3095abdebaSMatt Arsenault #ifdef _WIN32
3195abdebaSMatt Arsenault #include <windows.h>
3295abdebaSMatt Arsenault #endif
3395abdebaSMatt Arsenault 
34ddc64eb9SDiego Trevino Ferrer using namespace llvm;
35ddc64eb9SDiego Trevino Ferrer 
360d36d84dSMarkus Lavin cl::OptionCategory LLVMReduceOptions("llvm-reduce options");
3734b9bbb7SRoman Lebedev 
3834b9bbb7SRoman Lebedev static cl::opt<bool> Help("h", cl::desc("Alias for -help"), cl::Hidden,
390d36d84dSMarkus Lavin                           cl::cat(LLVMReduceOptions));
4034b9bbb7SRoman Lebedev static cl::opt<bool> Version("v", cl::desc("Alias for -version"), cl::Hidden,
410d36d84dSMarkus Lavin                              cl::cat(LLVMReduceOptions));
42ddc64eb9SDiego Trevino Ferrer 
4395abdebaSMatt Arsenault static cl::opt<bool> PreserveDebugEnvironment(
4495abdebaSMatt Arsenault     "preserve-debug-environment",
4595abdebaSMatt Arsenault     cl::desc("Don't disable features used for crash "
4695abdebaSMatt Arsenault              "debugging (crash reports, llvm-symbolizer and core dumps)"),
4795abdebaSMatt Arsenault     cl::cat(LLVMReduceOptions));
4895abdebaSMatt Arsenault 
49545a8177SArthur Eubanks static cl::opt<bool>
50545a8177SArthur Eubanks     PrintDeltaPasses("print-delta-passes",
51545a8177SArthur Eubanks                      cl::desc("Print list of delta passes, passable to "
52fd41738eSMarkus Lavin                               "--delta-passes as a comma separated list"),
530d36d84dSMarkus Lavin                      cl::cat(LLVMReduceOptions));
54545a8177SArthur Eubanks 
559c8b89f5SMatt Arsenault static cl::opt<std::string> InputFilename(cl::Positional,
5634b9bbb7SRoman Lebedev                                           cl::desc("<input llvm ll/bc file>"),
570d36d84dSMarkus Lavin                                           cl::cat(LLVMReduceOptions));
58ddc64eb9SDiego Trevino Ferrer 
59ddc64eb9SDiego Trevino Ferrer static cl::opt<std::string>
609c8b89f5SMatt Arsenault     TestFilename("test",
6134b9bbb7SRoman Lebedev                  cl::desc("Name of the interesting-ness test to be run"),
620d36d84dSMarkus Lavin                  cl::cat(LLVMReduceOptions));
63ddc64eb9SDiego Trevino Ferrer 
64ddc64eb9SDiego Trevino Ferrer static cl::list<std::string>
65d0d1c416SFangrui Song     TestArguments("test-arg",
6634b9bbb7SRoman Lebedev                   cl::desc("Arguments passed onto the interesting-ness test"),
670d36d84dSMarkus Lavin                   cl::cat(LLVMReduceOptions));
68ddc64eb9SDiego Trevino Ferrer 
69fd41738eSMarkus Lavin static cl::opt<std::string> OutputFilename(
703c436ab0SMatt Arsenault     "output",
713c436ab0SMatt Arsenault     cl::desc("Specify the output file. default: reduced.ll|.bc|.mir"));
72ddc64eb9SDiego Trevino Ferrer static cl::alias OutputFileAlias("o", cl::desc("Alias for -output"),
7334b9bbb7SRoman Lebedev                                  cl::aliasopt(OutputFilename),
740d36d84dSMarkus Lavin                                  cl::cat(LLVMReduceOptions));
75ddc64eb9SDiego Trevino Ferrer 
76ddc64eb9SDiego Trevino Ferrer static cl::opt<bool>
77ddc64eb9SDiego Trevino Ferrer     ReplaceInput("in-place",
78ddc64eb9SDiego Trevino Ferrer                  cl::desc("WARNING: This option will replace your input file "
7934b9bbb7SRoman Lebedev                           "with the reduced version!"),
800d36d84dSMarkus Lavin                  cl::cat(LLVMReduceOptions));
81ddc64eb9SDiego Trevino Ferrer 
82fd41738eSMarkus Lavin enum class InputLanguages { None, IR, MIR };
83ddc64eb9SDiego Trevino Ferrer 
84fd41738eSMarkus Lavin static cl::opt<InputLanguages>
85fd41738eSMarkus Lavin     InputLanguage("x", cl::ValueOptional,
86fd41738eSMarkus Lavin                   cl::desc("Input language ('ir' or 'mir')"),
87fd41738eSMarkus Lavin                   cl::init(InputLanguages::None),
88fd41738eSMarkus Lavin                   cl::values(clEnumValN(InputLanguages::IR, "ir", ""),
89fd41738eSMarkus Lavin                              clEnumValN(InputLanguages::MIR, "mir", "")),
900d36d84dSMarkus Lavin                   cl::cat(LLVMReduceOptions));
91ddc64eb9SDiego Trevino Ferrer 
923c436ab0SMatt Arsenault static cl::opt<bool> ForceOutputBitcode(
933c436ab0SMatt Arsenault     "output-bitcode",
943c436ab0SMatt Arsenault     cl::desc("Emit final result as bitcode instead of text IR"), cl::Hidden,
953c436ab0SMatt Arsenault     cl::cat(LLVMReduceOptions));
963c436ab0SMatt Arsenault 
974eec1710SJohn Regehr static cl::opt<int>
984eec1710SJohn Regehr     MaxPassIterations("max-pass-iterations",
994eec1710SJohn Regehr                       cl::desc("Maximum number of times to run the full set "
10087710235SJohn Regehr                                "of delta passes (default=5)"),
10187710235SJohn Regehr                       cl::init(5), cl::cat(LLVMReduceOptions));
1024eec1710SJohn Regehr 
103*8128d4b1SStephen Tozer extern cl::opt<cl::boolOrDefault> PreserveInputDbgFormat;
10440bdfd39SJeremy Morse 
105fd41738eSMarkus Lavin static codegen::RegisterCodeGenFlags CGF;
106fd41738eSMarkus Lavin 
10795abdebaSMatt Arsenault /// Turn off crash debugging features
10895abdebaSMatt Arsenault ///
10995abdebaSMatt Arsenault /// Crash is expected, so disable crash reports and symbolization to reduce
11095abdebaSMatt Arsenault /// output clutter and avoid potentially slow symbolization.
disableEnvironmentDebugFeatures()11195abdebaSMatt Arsenault static void disableEnvironmentDebugFeatures() {
11295abdebaSMatt Arsenault   sys::Process::PreventCoreFiles();
11395abdebaSMatt Arsenault 
11495abdebaSMatt Arsenault   // TODO: Copied from not. Should have a wrapper around setenv.
11595abdebaSMatt Arsenault #ifdef _WIN32
11695abdebaSMatt Arsenault   SetEnvironmentVariableA("LLVM_DISABLE_CRASH_REPORT", "1");
11795abdebaSMatt Arsenault   SetEnvironmentVariableA("LLVM_DISABLE_SYMBOLIZATION", "1");
11895abdebaSMatt Arsenault #else
11995abdebaSMatt Arsenault   setenv("LLVM_DISABLE_CRASH_REPORT", "1", /*overwrite=*/1);
12095abdebaSMatt Arsenault   setenv("LLVM_DISABLE_SYMBOLIZATION", "1", /*overwrite=*/1);
12195abdebaSMatt Arsenault #endif
12295abdebaSMatt Arsenault }
12395abdebaSMatt Arsenault 
determineOutputType(bool IsMIR,bool InputIsBitcode)1243c436ab0SMatt Arsenault static std::pair<StringRef, bool> determineOutputType(bool IsMIR,
1253c436ab0SMatt Arsenault                                                       bool InputIsBitcode) {
1264e21bc0cSMatt Arsenault   bool OutputBitcode = ForceOutputBitcode || InputIsBitcode;
1277fef40d8STyker 
1283c436ab0SMatt Arsenault   if (ReplaceInput) { // In-place
1293c436ab0SMatt Arsenault     OutputFilename = InputFilename.c_str();
1304e21bc0cSMatt Arsenault   } else if (OutputFilename.empty()) {
1313c436ab0SMatt Arsenault     // Default to producing bitcode if the input was bitcode, if not explicitly
1323c436ab0SMatt Arsenault     // requested.
1333c436ab0SMatt Arsenault 
1343c436ab0SMatt Arsenault     OutputFilename =
1353c436ab0SMatt Arsenault         IsMIR ? "reduced.mir" : (OutputBitcode ? "reduced.bc" : "reduced.ll");
1364e21bc0cSMatt Arsenault   }
1373c436ab0SMatt Arsenault 
1383c436ab0SMatt Arsenault   return {OutputFilename, OutputBitcode};
1396b3956e1SMatthew Voss }
1406b3956e1SMatthew Voss 
main(int Argc,char ** Argv)14156fa1b4fSSamuel int main(int Argc, char **Argv) {
14256fa1b4fSSamuel   InitLLVM X(Argc, Argv);
1439c8b89f5SMatt Arsenault   const StringRef ToolName(Argv[0]);
144*8128d4b1SStephen Tozer   PreserveInputDbgFormat = cl::boolOrDefault::BOU_TRUE;
145ddc64eb9SDiego Trevino Ferrer 
1460d36d84dSMarkus Lavin   cl::HideUnrelatedOptions({&LLVMReduceOptions, &getColorCategory()});
14756fa1b4fSSamuel   cl::ParseCommandLineOptions(Argc, Argv, "LLVM automatic testcase reducer.\n");
148ddc64eb9SDiego Trevino Ferrer 
1499c8b89f5SMatt Arsenault   if (Argc == 1) {
1509c8b89f5SMatt Arsenault     cl::PrintHelpMessage();
1519c8b89f5SMatt Arsenault     return 0;
1529c8b89f5SMatt Arsenault   }
1539c8b89f5SMatt Arsenault 
1549c8b89f5SMatt Arsenault   if (PrintDeltaPasses) {
1559c8b89f5SMatt Arsenault     printDeltaPasses(outs());
1569c8b89f5SMatt Arsenault     return 0;
1579c8b89f5SMatt Arsenault   }
1589c8b89f5SMatt Arsenault 
159fd41738eSMarkus Lavin   bool ReduceModeMIR = false;
160fd41738eSMarkus Lavin   if (InputLanguage != InputLanguages::None) {
161fd41738eSMarkus Lavin     if (InputLanguage == InputLanguages::MIR)
162fd41738eSMarkus Lavin       ReduceModeMIR = true;
163586ecdf2SKazu Hirata   } else if (StringRef(InputFilename).ends_with(".mir")) {
164fd41738eSMarkus Lavin     ReduceModeMIR = true;
165fd41738eSMarkus Lavin   }
166fd41738eSMarkus Lavin 
1679c8b89f5SMatt Arsenault   if (InputFilename.empty()) {
1689c8b89f5SMatt Arsenault     WithColor::error(errs(), ToolName)
1699c8b89f5SMatt Arsenault         << "reduction testcase positional argument must be specified\n";
1709c8b89f5SMatt Arsenault     return 1;
1719c8b89f5SMatt Arsenault   }
1729c8b89f5SMatt Arsenault 
1739c8b89f5SMatt Arsenault   if (TestFilename.empty()) {
1749c8b89f5SMatt Arsenault     WithColor::error(errs(), ToolName) << "--test option must be specified\n";
1759c8b89f5SMatt Arsenault     return 1;
176545a8177SArthur Eubanks   }
177545a8177SArthur Eubanks 
17895abdebaSMatt Arsenault   if (!PreserveDebugEnvironment)
17995abdebaSMatt Arsenault     disableEnvironmentDebugFeatures();
18095abdebaSMatt Arsenault 
181ddc64eb9SDiego Trevino Ferrer   LLVMContext Context;
1821747a93bSMatt Arsenault   std::unique_ptr<TargetMachine> TM;
1831747a93bSMatt Arsenault 
1843c436ab0SMatt Arsenault   auto [OriginalProgram, InputIsBitcode] =
1859c8b89f5SMatt Arsenault       parseReducerWorkItem(ToolName, InputFilename, Context, TM, ReduceModeMIR);
186472c0091SLangston Barrett   if (!OriginalProgram) {
187472c0091SLangston Barrett     return 1;
188472c0091SLangston Barrett   }
189472c0091SLangston Barrett 
1903c436ab0SMatt Arsenault   StringRef OutputFilename;
1913c436ab0SMatt Arsenault   bool OutputBitcode;
1923c436ab0SMatt Arsenault   std::tie(OutputFilename, OutputBitcode) =
1933c436ab0SMatt Arsenault       determineOutputType(ReduceModeMIR, InputIsBitcode);
1943c436ab0SMatt Arsenault 
195ddc64eb9SDiego Trevino Ferrer   // Initialize test environment
1967c2db666SMatt Arsenault   TestRunner Tester(TestFilename, TestArguments, std::move(OriginalProgram),
1979c8b89f5SMatt Arsenault                     std::move(TM), ToolName, OutputFilename, InputIsBitcode,
198412c4a8bSMatt Arsenault                     OutputBitcode);
199ddc64eb9SDiego Trevino Ferrer 
200f041204eSMatt Arsenault   // This parses and writes out the testcase into a temporary file copy for the
201f041204eSMatt Arsenault   // test, rather than evaluating the source IR directly. This is for the
202f041204eSMatt Arsenault   // convenience of lit tests; the stripped out comments may have broken the
203f041204eSMatt Arsenault   // interestingness checks.
204592536a9SMatt Arsenault   if (!Tester.getProgram().isReduced(Tester)) {
205f041204eSMatt Arsenault     errs() << "\nInput isn't interesting! Verify interesting-ness test\n";
206f041204eSMatt Arsenault     return 1;
207f041204eSMatt Arsenault   }
208f041204eSMatt Arsenault 
209ddc64eb9SDiego Trevino Ferrer   // Try to reduce code
2104eec1710SJohn Regehr   runDeltaPasses(Tester, MaxPassIterations);
211ddc64eb9SDiego Trevino Ferrer 
212c2689253SDiego Trevino Ferrer   // Print reduced file to STDOUT
213c2689253SDiego Trevino Ferrer   if (OutputFilename == "-")
21477bc3ba3SArthur Eubanks     Tester.getProgram().print(outs(), nullptr);
2157fef40d8STyker   else
2163c436ab0SMatt Arsenault     Tester.writeOutput("Done reducing! Reduced testcase: ");
217ddc64eb9SDiego Trevino Ferrer 
218ddc64eb9SDiego Trevino Ferrer   return 0;
219ddc64eb9SDiego Trevino Ferrer }
220