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