diff --git a/llvm/test/tools/llvm-reduce/Inputs/llvm-dis-and-filecheck.py b/llvm/test/tools/llvm-reduce/Inputs/llvm-dis-and-filecheck.py --- a/llvm/test/tools/llvm-reduce/Inputs/llvm-dis-and-filecheck.py +++ b/llvm/test/tools/llvm-reduce/Inputs/llvm-dis-and-filecheck.py @@ -13,6 +13,7 @@ import sys +import os import subprocess llvm_dis = sys.argv[1] @@ -20,10 +21,23 @@ filecheck_args = [filecheck, ] filecheck_args.extend(sys.argv[3:-1]) bitcode_file = sys.argv[-1] +ir_file = bitcode_file + ".ll" -disassemble = subprocess.Popen([llvm_dis, "-o", "-", bitcode_file], - stdout=subprocess.PIPE) -check = subprocess.Popen(filecheck_args, stdin=disassemble.stdout) -disassemble.stdout.close() +disassemble = subprocess.Popen([llvm_dis, "-o", ir_file, bitcode_file]) +if os.path.exists(ir_file + ".0"): + ir_file = ir_file + ".0" + +disassemble.communicate() + +if disassemble.returncode != 0: + print("stderr:") + print(disassemble.stderr) + print("stdout:") + print(disassemble.stdout) + sys.exit(1) + +check=None +with open(ir_file, "r") as ir: + check = subprocess.Popen(filecheck_args, stdin=ir, stdout=sys.stdout) check.communicate() sys.exit(check.returncode) diff --git a/llvm/test/tools/llvm-reduce/fail-file-open.test b/llvm/test/tools/llvm-reduce/fail-file-open.test --- a/llvm/test/tools/llvm-reduce/fail-file-open.test +++ b/llvm/test/tools/llvm-reduce/fail-file-open.test @@ -2,4 +2,4 @@ This file will not be read. An invalid file path is fed to llvm-reduce. -# CHECK: llvm-reduce{{.*}}: {{.*}}.NotAFileInTestingDir: error: \ No newline at end of file +# CHECK: llvm-reduce{{.*}}: error: {{.*}}.NotAFileInTestingDir: diff --git a/llvm/test/tools/llvm-reduce/invalid-bitcode-error.ll b/llvm/test/tools/llvm-reduce/invalid-bitcode-error.ll new file mode 100644 --- /dev/null +++ b/llvm/test/tools/llvm-reduce/invalid-bitcode-error.ll @@ -0,0 +1,3 @@ +; RUN: not %python %p/Inputs/llvm-dis-and-filecheck.py llvm-dis FileCheck %s %s 2>&1 | FileCheck %s +; CHECK: stderr +; CHECK: stdout diff --git a/llvm/test/tools/llvm-reduce/temporary-files-as-bitcode-split.ll b/llvm/test/tools/llvm-reduce/temporary-files-as-bitcode-split.ll new file mode 100644 --- /dev/null +++ b/llvm/test/tools/llvm-reduce/temporary-files-as-bitcode-split.ll @@ -0,0 +1,27 @@ +; RUN: opt --thinlto-bc --thinlto-split-lto-unit %s -o %t0 +; RUN: llvm-reduce -write-tmp-files-as-bitcode --delta-passes=basic-blocks %t0 -o %t1 \ +; RUN: --test %python --test-arg %p/Inputs/llvm-dis-and-filecheck.py --test-arg llvm-dis --test-arg FileCheck --test-arg --check-prefixes=CHECK-ALL,CHECK-INTERESTINGNESS --test-arg %s +; RUN: cat %t1* | FileCheck --check-prefixes=CHECK-ALL,CHECK-FINAL %s + +@g = internal global i8 42, !type !0 + +; CHECK-INTERESTINGNESS: @callee( +; CHECK-FINAL: declare void @callee() +define void @callee() { + ret void +} + +; CHECK-ALL: define void @caller() +define void @caller() { +entry: +; CHECK-ALL: call void @callee() +; CHECK-ALL: ret void + call void @callee() + ret void +} +define i8* @f() { + ; CHECK-ALL: ret i8* @g.{{([0-9a-f]{32})}} + ret i8* @g +} + +!0 = !{i32 0, !"typeid"} diff --git a/llvm/tools/llvm-reduce/CMakeLists.txt b/llvm/tools/llvm-reduce/CMakeLists.txt --- a/llvm/tools/llvm-reduce/CMakeLists.txt +++ b/llvm/tools/llvm-reduce/CMakeLists.txt @@ -14,6 +14,7 @@ Support Target TransformUtils + IPO ) add_llvm_tool(llvm-reduce diff --git a/llvm/tools/llvm-reduce/ReducerWorkItem.h b/llvm/tools/llvm-reduce/ReducerWorkItem.h --- a/llvm/tools/llvm-reduce/ReducerWorkItem.h +++ b/llvm/tools/llvm-reduce/ReducerWorkItem.h @@ -9,9 +9,11 @@ #ifndef LLVM_TOOLS_LLVM_REDUCE_REDUCERWORKITEM_H #define LLVM_TOOLS_LLVM_REDUCE_REDUCERWORKITEM_H +#include "llvm/Bitcode/BitcodeReader.h" #include "llvm/CodeGen/MachineFunction.h" #include "llvm/CodeGen/MachineModuleInfo.h" #include "llvm/IR/Module.h" +#include "llvm/IR/ModuleSummaryIndex.h" #include "llvm/Target/TargetMachine.h" using namespace llvm; @@ -19,6 +21,7 @@ class ReducerWorkItem { public: std::shared_ptr M; + std::unique_ptr LTOInfo; std::unique_ptr MMI; bool isMIR() const { return MMI != nullptr; } diff --git a/llvm/tools/llvm-reduce/ReducerWorkItem.cpp b/llvm/tools/llvm-reduce/ReducerWorkItem.cpp --- a/llvm/tools/llvm-reduce/ReducerWorkItem.cpp +++ b/llvm/tools/llvm-reduce/ReducerWorkItem.cpp @@ -7,6 +7,7 @@ //===----------------------------------------------------------------------===// #include "ReducerWorkItem.h" +#include "llvm/Bitcode/BitcodeReader.h" #include "llvm/CodeGen/CommandFlags.h" #include "llvm/CodeGen/MIRParser/MIRParser.h" #include "llvm/CodeGen/MIRPrinter.h" @@ -17,11 +18,14 @@ #include "llvm/CodeGen/MachineModuleInfo.h" #include "llvm/CodeGen/MachineRegisterInfo.h" #include "llvm/CodeGen/TargetInstrInfo.h" +#include "llvm/IR/ModuleSummaryIndex.h" #include "llvm/IR/Verifier.h" #include "llvm/IRReader/IRReader.h" #include "llvm/MC/TargetRegistry.h" #include "llvm/Support/Host.h" +#include "llvm/Support/MemoryBufferRef.h" #include "llvm/Support/SourceMgr.h" +#include "llvm/Support/TargetSelect.h" #include "llvm/Support/WithColor.h" #include "llvm/Target/TargetMachine.h" #include "llvm/Transforms/Utils/Cloning.h" @@ -31,6 +35,8 @@ cl::desc("Set the target triple"), cl::cat(LLVMReduceOptions)); +void readBitcode(ReducerWorkItem &M, MemoryBufferRef Data, LLVMContext &Ctx, const char *ToolName); + static void cloneFrameInfo( MachineFrameInfo &DstMFI, const MachineFrameInfo &SrcMFI, const DenseMap &Src2DstMBB) { @@ -352,6 +358,13 @@ return DstMF; } +static void initializeTargetInfo() { + InitializeAllTargets(); + InitializeAllTargetMCs(); + InitializeAllAsmPrinters(); + InitializeAllAsmParsers(); +} + std::unique_ptr parseReducerWorkItem(const char *ToolName, StringRef Filename, LLVMContext &Ctxt, std::unique_ptr &TM, @@ -361,6 +374,8 @@ auto MMM = std::make_unique(); if (IsMIR) { + initializeTargetInfo(); + auto FileOrErr = MemoryBuffer::getFileOrSTDIN(Filename, /*IsText=*/true); if (std::error_code EC = FileOrErr.getError()) { WithColor::error(errs(), ToolName) << EC.message() << '\n'; @@ -409,17 +424,31 @@ MMM->M = std::move(M); } else { SMDiagnostic Err; - std::unique_ptr Result = parseIRFile(Filename, Err, Ctxt); - if (!Result) { - Err.print(ToolName, errs()); - return std::unique_ptr(); + ErrorOr> MB = MemoryBuffer::getFileOrSTDIN(Filename); + if (std::error_code EC = MB.getError()) { + WithColor::error(errs(), ToolName) << Filename << ": " << EC.message() << "\n"; + return nullptr; + } + + if (!isBitcode((const unsigned char *)(*MB)->getBufferStart(), + (const unsigned char *)(*MB)->getBufferEnd())) { + std::unique_ptr Result = parseIRFile(Filename, Err, Ctxt); + if (!Result) { + Err.print(ToolName, errs()); + return nullptr; + } + MMM->M = std::move(Result); + } else { + readBitcode(*MMM, MemoryBufferRef(**MB), Ctxt, ToolName); + + if (MMM->LTOInfo->IsThinLTO && MMM->LTOInfo->EnableSplitLTOUnit) + initializeTargetInfo(); } - MMM->M = std::move(Result); } if (verifyReducerWorkItem(*MMM, &errs())) { WithColor::error(errs(), ToolName) << Filename << " - input module is broken!\n"; - return std::unique_ptr(); + return nullptr; } return MMM; } diff --git a/llvm/tools/llvm-reduce/TestRunner.h b/llvm/tools/llvm-reduce/TestRunner.h --- a/llvm/tools/llvm-reduce/TestRunner.h +++ b/llvm/tools/llvm-reduce/TestRunner.h @@ -28,7 +28,7 @@ public: TestRunner(StringRef TestName, const std::vector &TestArgs, std::unique_ptr Program, - std::unique_ptr TM); + std::unique_ptr TM, const char *ToolName); /// Runs the interesting-ness test for the specified file /// @returns 0 if test was successful, 1 if otherwise @@ -41,8 +41,11 @@ const TargetMachine *getTargetMachine() const { return TM.get(); } + const char *getToolName() const { return ToolName; } + private: StringRef TestName; + const char *ToolName; const std::vector &TestArgs; std::unique_ptr Program; std::unique_ptr TM; diff --git a/llvm/tools/llvm-reduce/TestRunner.cpp b/llvm/tools/llvm-reduce/TestRunner.cpp --- a/llvm/tools/llvm-reduce/TestRunner.cpp +++ b/llvm/tools/llvm-reduce/TestRunner.cpp @@ -15,9 +15,9 @@ TestRunner::TestRunner(StringRef TestName, const std::vector &TestArgs, std::unique_ptr Program, - std::unique_ptr TM) + std::unique_ptr TM, const char *ToolName) : TestName(TestName), TestArgs(TestArgs), Program(std::move(Program)), - TM(std::move(TM)) { + TM(std::move(TM)), ToolName(ToolName) { assert(this->Program && "Initialized with null program?"); } diff --git a/llvm/tools/llvm-reduce/deltas/Delta.cpp b/llvm/tools/llvm-reduce/deltas/Delta.cpp --- a/llvm/tools/llvm-reduce/deltas/Delta.cpp +++ b/llvm/tools/llvm-reduce/deltas/Delta.cpp @@ -15,11 +15,16 @@ #include "Delta.h" #include "ReducerWorkItem.h" #include "llvm/ADT/STLExtras.h" +#include "llvm/Analysis/ProfileSummaryInfo.h" +#include "llvm/Analysis/ModuleSummaryAnalysis.h" #include "llvm/Bitcode/BitcodeReader.h" #include "llvm/Bitcode/BitcodeWriter.h" #include "llvm/CodeGen/MachineFunction.h" +#include "llvm/IR/Module.h" #include "llvm/IR/Verifier.h" +#include "llvm/MC/TargetRegistry.h" #include "llvm/Support/CommandLine.h" +#include "llvm/Support/MemoryBufferRef.h" #include "llvm/Support/ThreadPool.h" #include "llvm/Support/ToolOutputFile.h" #include @@ -56,6 +61,11 @@ void writeOutput(ReducerWorkItem &M, llvm::StringRef Message); +void writeBitcode(ReducerWorkItem &M, raw_ostream &OutStream); + +void readBitcode(ReducerWorkItem &M, MemoryBufferRef Data, LLVMContext &Ctx, + const char *ToolName); + bool isReduced(ReducerWorkItem &M, TestRunner &Test, SmallString<128> &CurrentFilepath) { // Write ReducerWorkItem to tmp file @@ -70,7 +80,7 @@ if (TmpFilesAsBitcode) { llvm::raw_fd_ostream OutStream(FD, true); - WriteBitcodeToFile(M, OutStream); + writeBitcode(M, OutStream); OutStream.close(); if (OutStream.has_error()) { errs() << "Error emitting bitcode to file '" << CurrentFilepath << "'!\n"; @@ -192,14 +202,10 @@ std::vector &ChunksStillConsideredInteresting, SmallString<0> &OriginalBC, std::atomic &AnyReduced) { LLVMContext Ctx; - Expected> MOrErr = parseBitcodeFile( - MemoryBufferRef(StringRef(OriginalBC.data(), OriginalBC.size()), - ""), - Ctx); - if (!MOrErr) - report_fatal_error("Failed to read bitcode"); auto CloneMMM = std::make_unique(); - CloneMMM->M = std::move(MOrErr.get()); + auto Data = MemoryBufferRef(StringRef(OriginalBC.data(), OriginalBC.size()), + ""); + readBitcode(*CloneMMM, Data, Ctx, Test.getToolName()); SmallString<0> Result; if (std::unique_ptr ChunkResult = @@ -207,7 +213,7 @@ Test, ExtractChunksFromModule, UninterestingChunks, ChunksStillConsideredInteresting)) { raw_svector_ostream BCOS(Result); - WriteBitcodeToFile(*ChunkResult->M, BCOS); + writeBitcode(*ChunkResult, BCOS); // Communicate that the task reduced a chunk. AnyReduced = true; } @@ -284,7 +290,7 @@ SmallString<0> OriginalBC; if (NumJobs > 1) { raw_svector_ostream BCOS(OriginalBC); - WriteBitcodeToFile(*Test.getProgram().M, BCOS); + writeBitcode(Test.getProgram(), BCOS); } std::deque>> TaskQueue; @@ -351,14 +357,11 @@ continue; } - Expected> MOrErr = parseBitcodeFile( - MemoryBufferRef(StringRef(Res.data(), Res.size()), - ""), - Test.getProgram().M->getContext()); - if (!MOrErr) - report_fatal_error("Failed to read bitcode"); Result = std::make_unique(); - Result->M = std::move(MOrErr.get()); + auto Data = MemoryBufferRef(StringRef(Res.data(), Res.size()), + ""); + readBitcode(*Result, Data, Test.getProgram().M->getContext(), + Test.getToolName()); break; } // Forward I to the last chunk processed in parallel. diff --git a/llvm/tools/llvm-reduce/llvm-reduce.cpp b/llvm/tools/llvm-reduce/llvm-reduce.cpp --- a/llvm/tools/llvm-reduce/llvm-reduce.cpp +++ b/llvm/tools/llvm-reduce/llvm-reduce.cpp @@ -17,10 +17,15 @@ #include "DeltaManager.h" #include "ReducerWorkItem.h" #include "TestRunner.h" +#include "llvm/Analysis/ProfileSummaryInfo.h" +#include "llvm/Analysis/ModuleSummaryAnalysis.h" #include "llvm/ADT/SmallString.h" +#include "llvm/Bitcode/BitcodeReader.h" +#include "llvm/Bitcode/BitcodeWriter.h" #include "llvm/CodeGen/CommandFlags.h" #include "llvm/CodeGen/MachineFunction.h" #include "llvm/CodeGen/MachineModuleInfo.h" +#include "llvm/IR/LegacyPassManager.h" #include "llvm/IR/LLVMContext.h" #include "llvm/IR/Verifier.h" #include "llvm/IRReader/IRReader.h" @@ -32,6 +37,7 @@ #include "llvm/Support/TargetSelect.h" #include "llvm/Support/WithColor.h" #include "llvm/Support/raw_ostream.h" +#include "llvm/Transforms/IPO.h" #include #include @@ -94,13 +100,6 @@ static codegen::RegisterCodeGenFlags CGF; -static void initializeTargetInfo() { - InitializeAllTargets(); - InitializeAllTargetMCs(); - InitializeAllAsmPrinters(); - InitializeAllAsmParsers(); -} - void writeOutput(ReducerWorkItem &M, StringRef Message) { if (ReplaceInput) // In-place OutputFilename = InputFilename.c_str(); @@ -116,6 +115,39 @@ errs() << Message << OutputFilename << "\n"; } +void writeBitcode(ReducerWorkItem &M, llvm::raw_ostream &OutStream) { + if (M.LTOInfo && M.LTOInfo->IsThinLTO && M.LTOInfo->EnableSplitLTOUnit) { + legacy::PassManager PM; + PM.add(llvm::createWriteThinLTOBitcodePass(OutStream)); + PM.run(*(M.M)); + } else { + std::unique_ptr Index; + if (M.LTOInfo && M.LTOInfo->HasSummary) { + ProfileSummaryInfo PSI(M); + Index = std::make_unique( + buildModuleSummaryIndex(M, nullptr, &PSI)); + } + WriteBitcodeToFile(M, OutStream, Index.get()); + } +} + +void readBitcode(ReducerWorkItem &M, MemoryBufferRef Data, LLVMContext &Ctx, const char *ToolName) { + Expected IF = llvm::getBitcodeFileContents(Data); + if (!IF) { + WithColor::error(errs(), ToolName) << IF.takeError(); + exit(1); + } + BitcodeModule BM = IF->Mods[0]; + Expected LI = BM.getLTOInfo(); + Expected> MOrErr = BM.parseModule(Ctx); + if (!LI || !MOrErr) { + WithColor::error(errs(), ToolName) << IF.takeError(); + exit(1); + } + M.LTOInfo = std::make_unique(*LI); + M.M = std::move(MOrErr.get()); +} + int main(int Argc, char **Argv) { InitLLVM X(Argc, Argv); @@ -135,9 +167,6 @@ return 0; } - if (ReduceModeMIR) - initializeTargetInfo(); - LLVMContext Context; std::unique_ptr TM; @@ -149,7 +178,7 @@ // Initialize test environment TestRunner Tester(TestFilename, TestArguments, std::move(OriginalProgram), - std::move(TM)); + std::move(TM), Argv[0]); // Try to reduce code runDeltaPasses(Tester, MaxPassIterations);