1 //===- llvm-reduce.cpp - The LLVM Delta Reduction utility -----------------===//
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
7 //===----------------------------------------------------------------------===//
9 // This program tries to reduce an IR test case for a given interesting-ness
10 // test. It runs multiple delta debugging passes in order to minimize the input
11 // file. It's worth noting that this is a part of the bugpoint redesign
12 // proposal, and thus a *temporary* tool that will eventually be integrated
13 // into the bugpoint tool itself.
15 //===----------------------------------------------------------------------===//
17 #include "DeltaManager.h"
18 #include "ReducerWorkItem.h"
19 #include "TestRunner.h"
20 #include "llvm/ADT/SmallString.h"
21 #include "llvm/CodeGen/CommandFlags.h"
22 #include "llvm/IR/LLVMContext.h"
23 #include "llvm/IR/Verifier.h"
24 #include "llvm/IRReader/IRReader.h"
25 #include "llvm/MC/TargetRegistry.h"
26 #include "llvm/Support/CommandLine.h"
27 #include "llvm/Support/Host.h"
28 #include "llvm/Support/InitLLVM.h"
29 #include "llvm/Support/SourceMgr.h"
30 #include "llvm/Support/TargetSelect.h"
31 #include "llvm/Support/raw_ostream.h"
32 #include "llvm/Target/TargetMachine.h"
33 #include <system_error>
38 static cl::OptionCategory
Options("llvm-reduce options");
40 static cl::opt
<bool> Help("h", cl::desc("Alias for -help"), cl::Hidden
,
42 static cl::opt
<bool> Version("v", cl::desc("Alias for -version"), cl::Hidden
,
46 PrintDeltaPasses("print-delta-passes",
47 cl::desc("Print list of delta passes, passable to "
48 "--delta-passes as a comma separated list"),
51 static cl::opt
<std::string
> InputFilename(cl::Positional
, cl::Required
,
52 cl::desc("<input llvm ll/bc file>"),
55 static cl::opt
<std::string
>
56 TestFilename("test", cl::Required
,
57 cl::desc("Name of the interesting-ness test to be run"),
60 static cl::list
<std::string
>
61 TestArguments("test-arg", cl::ZeroOrMore
,
62 cl::desc("Arguments passed onto the interesting-ness test"),
65 static cl::opt
<std::string
> OutputFilename(
66 "output", cl::desc("Specify the output file. default: reduced.ll|mir"));
67 static cl::alias
OutputFileAlias("o", cl::desc("Alias for -output"),
68 cl::aliasopt(OutputFilename
),
72 ReplaceInput("in-place",
73 cl::desc("WARNING: This option will replace your input file "
74 "with the reduced version!"),
77 enum class InputLanguages
{ None
, IR
, MIR
};
79 static cl::opt
<InputLanguages
>
80 InputLanguage("x", cl::ValueOptional
,
81 cl::desc("Input language ('ir' or 'mir')"),
82 cl::init(InputLanguages::None
),
83 cl::values(clEnumValN(InputLanguages::IR
, "ir", ""),
84 clEnumValN(InputLanguages::MIR
, "mir", "")),
87 static cl::opt
<std::string
> TargetTriple("mtriple",
88 cl::desc("Set the target triple"),
92 MaxPassIterations("max-pass-iterations",
93 cl::desc("Maximum number of times to run the full set "
94 "of delta passes (default=1)"),
95 cl::init(1), cl::cat(Options
));
97 static codegen::RegisterCodeGenFlags CGF
;
99 void writeOutput(ReducerWorkItem
&M
, StringRef Message
) {
100 if (ReplaceInput
) // In-place
101 OutputFilename
= InputFilename
.c_str();
102 else if (OutputFilename
.empty() || OutputFilename
== "-")
103 OutputFilename
= M
.isMIR() ? "reduced.mir" : "reduced.ll";
105 raw_fd_ostream
Out(OutputFilename
, EC
);
107 errs() << "Error opening output file: " << EC
.message() << "!\n";
110 M
.print(Out
, /*AnnotationWriter=*/nullptr);
111 errs() << Message
<< OutputFilename
<< "\n";
114 static std::unique_ptr
<LLVMTargetMachine
> createTargetMachine() {
115 InitializeAllTargets();
116 InitializeAllTargetMCs();
117 InitializeAllAsmPrinters();
118 InitializeAllAsmParsers();
120 if (TargetTriple
== "")
121 TargetTriple
= sys::getDefaultTargetTriple();
122 auto TT(Triple::normalize(TargetTriple
));
123 std::string
CPU(codegen::getCPUStr());
124 std::string
FS(codegen::getFeaturesStr());
127 const Target
*TheTarget
= TargetRegistry::lookupTarget(TT
, Error
);
129 return std::unique_ptr
<LLVMTargetMachine
>(
130 static_cast<LLVMTargetMachine
*>(TheTarget
->createTargetMachine(
131 TT
, CPU
, FS
, TargetOptions(), None
, None
, CodeGenOpt::Default
)));
134 int main(int Argc
, char **Argv
) {
135 InitLLVM
X(Argc
, Argv
);
137 cl::HideUnrelatedOptions({&Options
, &getColorCategory()});
138 cl::ParseCommandLineOptions(Argc
, Argv
, "LLVM automatic testcase reducer.\n");
140 bool ReduceModeMIR
= false;
141 if (InputLanguage
!= InputLanguages::None
) {
142 if (InputLanguage
== InputLanguages::MIR
)
143 ReduceModeMIR
= true;
144 } else if (StringRef(InputFilename
).endswith(".mir")) {
145 ReduceModeMIR
= true;
148 if (PrintDeltaPasses
) {
149 printDeltaPasses(errs());
154 std::unique_ptr
<LLVMTargetMachine
> TM
;
155 std::unique_ptr
<MachineModuleInfo
> MMI
;
156 std::unique_ptr
<ReducerWorkItem
> OriginalProgram
;
158 TM
= createTargetMachine();
159 MMI
= std::make_unique
<MachineModuleInfo
>(TM
.get());
161 OriginalProgram
= parseReducerWorkItem(InputFilename
, Context
, MMI
.get());
162 if (!OriginalProgram
) {
166 // Initialize test environment
167 TestRunner
Tester(TestFilename
, TestArguments
, std::move(OriginalProgram
));
169 // Try to reduce code
170 runDeltaPasses(Tester
, MaxPassIterations
);
172 // Print reduced file to STDOUT
173 if (OutputFilename
== "-")
174 Tester
.getProgram().print(outs(), nullptr);
176 writeOutput(Tester
.getProgram(), "\nDone reducing! Reduced testcase: ");