xref: /llvm-project/llvm/tools/llvm-reduce/TestRunner.cpp (revision e748db0f7f0971dc258c6631ae1fb0a38cfdf9dd)
1 //===-- TestRunner.cpp ----------------------------------------------------===//
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 #include "TestRunner.h"
10 #include "ReducerWorkItem.h"
11 #include "deltas/Utils.h"
12 #include "llvm/Analysis/ModuleSummaryAnalysis.h"
13 #include "llvm/Analysis/ProfileSummaryInfo.h"
14 #include "llvm/Bitcode/BitcodeReader.h"
15 #include "llvm/Bitcode/BitcodeWriter.h"
16 #include "llvm/Passes/PassBuilder.h"
17 #include "llvm/Transforms/IPO/ThinLTOBitcodeWriter.h"
18 
19 using namespace llvm;
20 
21 TestRunner::TestRunner(StringRef TestName,
22                        const std::vector<std::string> &TestArgs,
23                        std::unique_ptr<ReducerWorkItem> Program,
24                        std::unique_ptr<TargetMachine> TM, const char *ToolName,
25                        StringRef OutputName, bool InputIsBitcode,
26                        bool OutputBitcode)
27     : TestName(TestName), ToolName(ToolName), TestArgs(TestArgs),
28       Program(std::move(Program)), TM(std::move(TM)),
29       OutputFilename(OutputName), InputIsBitcode(InputIsBitcode),
30       EmitBitcode(OutputBitcode) {
31   assert(this->Program && "Initialized with null program?");
32 }
33 
34 /// Runs the interestingness test, passes file to be tested as first argument
35 /// and other specified test arguments after that.
36 int TestRunner::run(StringRef Filename) const {
37   std::vector<StringRef> ProgramArgs;
38   ProgramArgs.push_back(TestName);
39 
40   for (const auto &Arg : TestArgs)
41     ProgramArgs.push_back(Arg);
42 
43   ProgramArgs.push_back(Filename);
44 
45   std::string ErrMsg;
46   SmallVector<std::optional<StringRef>, 3> Redirects;
47   std::optional<StringRef> Empty = StringRef();
48   if (!Verbose) {
49     for (int i = 0; i < 3; ++i)
50       Redirects.push_back(Empty);
51   }
52   int Result =
53       sys::ExecuteAndWait(TestName, ProgramArgs, /*Env=*/None, Redirects,
54                           /*SecondsToWait=*/0, /*MemoryLimit=*/0, &ErrMsg);
55 
56   if (Result < 0) {
57     Error E = make_error<StringError>("Error running interesting-ness test: " +
58                                           ErrMsg,
59                                       inconvertibleErrorCode());
60     errs() << toString(std::move(E));
61     exit(1);
62   }
63 
64   return !Result;
65 }
66 
67 void TestRunner::setProgram(std::unique_ptr<ReducerWorkItem> P) {
68   assert(P && "Setting null program?");
69   Program = std::move(P);
70 }
71 
72 void writeBitcode(ReducerWorkItem &M, raw_ostream &OutStream) {
73   if (M.LTOInfo && M.LTOInfo->IsThinLTO && M.LTOInfo->EnableSplitLTOUnit) {
74     PassBuilder PB;
75     LoopAnalysisManager LAM;
76     FunctionAnalysisManager FAM;
77     CGSCCAnalysisManager CGAM;
78     ModuleAnalysisManager MAM;
79     PB.registerModuleAnalyses(MAM);
80     PB.registerCGSCCAnalyses(CGAM);
81     PB.registerFunctionAnalyses(FAM);
82     PB.registerLoopAnalyses(LAM);
83     PB.crossRegisterProxies(LAM, FAM, CGAM, MAM);
84     ModulePassManager MPM;
85     MPM.addPass(ThinLTOBitcodeWriterPass(OutStream, nullptr));
86     MPM.run(*M.M, MAM);
87   } else {
88     std::unique_ptr<ModuleSummaryIndex> Index;
89     if (M.LTOInfo && M.LTOInfo->HasSummary) {
90       ProfileSummaryInfo PSI(M);
91       Index = std::make_unique<ModuleSummaryIndex>(
92           buildModuleSummaryIndex(M, nullptr, &PSI));
93     }
94     WriteBitcodeToFile(M, OutStream, Index.get());
95   }
96 }
97 
98 void TestRunner::writeOutput(StringRef Message) {
99   std::error_code EC;
100   raw_fd_ostream Out(OutputFilename, EC,
101                      EmitBitcode && !Program->isMIR() ? sys::fs::OF_None
102                                                       : sys::fs::OF_Text);
103   if (EC) {
104     errs() << "Error opening output file: " << EC.message() << "!\n";
105     exit(1);
106   }
107 
108   // Requesting bitcode emission with mir is nonsense, so just ignore it.
109   if (EmitBitcode && !Program->isMIR())
110     writeBitcode(*Program, Out);
111   else
112     Program->print(Out, /*AnnotationWriter=*/nullptr);
113 
114   errs() << Message << OutputFilename << '\n';
115 }
116