319 changes: 207 additions & 112 deletions llvm/tools/llvm-reduce/ReducerWorkItem.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,11 @@
//===----------------------------------------------------------------------===//

#include "ReducerWorkItem.h"
#include "TestRunner.h"
#include "llvm/Analysis/ModuleSummaryAnalysis.h"
#include "llvm/Analysis/ProfileSummaryInfo.h"
#include "llvm/Bitcode/BitcodeReader.h"
#include "llvm/Bitcode/BitcodeWriter.h"
#include "llvm/CodeGen/CommandFlags.h"
#include "llvm/CodeGen/MIRParser/MIRParser.h"
#include "llvm/CodeGen/MIRPrinter.h"
Expand All @@ -25,12 +29,15 @@
#include "llvm/IR/Verifier.h"
#include "llvm/IRReader/IRReader.h"
#include "llvm/MC/TargetRegistry.h"
#include "llvm/Passes/PassBuilder.h"
#include "llvm/Support/Host.h"
#include "llvm/Support/MemoryBufferRef.h"
#include "llvm/Support/SourceMgr.h"
#include "llvm/Support/TargetSelect.h"
#include "llvm/Support/ToolOutputFile.h"
#include "llvm/Support/WithColor.h"
#include "llvm/Target/TargetMachine.h"
#include "llvm/Transforms/IPO/ThinLTOBitcodeWriter.h"
#include "llvm/Transforms/Utils/Cloning.h"
#include <optional>

Expand All @@ -44,8 +51,10 @@ static cl::opt<std::string> TargetTriple("mtriple",
cl::desc("Set the target triple"),
cl::cat(LLVMReduceOptions));

void readBitcode(ReducerWorkItem &M, MemoryBufferRef Data, LLVMContext &Ctx,
StringRef ToolName);
static cl::opt<bool> TmpFilesAsBitcode(
"write-tmp-files-as-bitcode",
cl::desc("Always write temporary files as bitcode instead of textual IR"),
cl::init(false), cl::cat(LLVMReduceOptions));

static void cloneFrameInfo(
MachineFrameInfo &DstMFI, const MachineFrameInfo &SrcMFI,
Expand Down Expand Up @@ -392,102 +401,74 @@ static void initializeTargetInfo() {
InitializeAllAsmParsers();
}

std::pair<std::unique_ptr<ReducerWorkItem>, bool>
parseReducerWorkItem(StringRef ToolName, StringRef Filename, LLVMContext &Ctxt,
std::unique_ptr<TargetMachine> &TM, bool IsMIR) {
bool IsBitcode = false;
Triple TheTriple;
void ReducerWorkItem::print(raw_ostream &ROS, void *p) const {
if (MMI) {
printMIR(ROS, *M);
for (Function &F : *M) {
if (auto *MF = MMI->getMachineFunction(F))
printMIR(ROS, *MF);
}
} else {
M->print(ROS, /*AssemblyAnnotationWriter=*/nullptr,
/*ShouldPreserveUseListOrder=*/true);
}
}

auto MMM = std::make_unique<ReducerWorkItem>();
bool ReducerWorkItem::verify(raw_fd_ostream *OS) const {
if (verifyModule(*M, OS))
return true;

if (IsMIR) {
initializeTargetInfo();
if (!MMI)
return false;

auto FileOrErr = MemoryBuffer::getFileOrSTDIN(Filename, /*IsText=*/true);
if (std::error_code EC = FileOrErr.getError()) {
WithColor::error(errs(), ToolName) << EC.message() << '\n';
return {nullptr, false};
for (const Function &F : getModule()) {
if (const MachineFunction *MF = MMI->getMachineFunction(F)) {
if (!MF->verify(nullptr, "", /*AbortOnError=*/false))
return true;
}
}

std::unique_ptr<MIRParser> MParser =
createMIRParser(std::move(FileOrErr.get()), Ctxt);

auto SetDataLayout = [&](StringRef DataLayoutTargetTriple,
StringRef OldDLStr) -> std::optional<std::string> {
// If we are supposed to override the target triple, do so now.
std::string IRTargetTriple = DataLayoutTargetTriple.str();
if (!TargetTriple.empty())
IRTargetTriple = Triple::normalize(TargetTriple);
TheTriple = Triple(IRTargetTriple);
if (TheTriple.getTriple().empty())
TheTriple.setTriple(sys::getDefaultTargetTriple());

std::string Error;
const Target *TheTarget =
TargetRegistry::lookupTarget(codegen::getMArch(), TheTriple, Error);
if (!TheTarget) {
WithColor::error(errs(), ToolName) << Error;
exit(1);
}
return false;
}

// Hopefully the MIR parsing doesn't depend on any options.
TargetOptions Options;
std::optional<Reloc::Model> RM = codegen::getExplicitRelocModel();
std::string CPUStr = codegen::getCPUStr();
std::string FeaturesStr = codegen::getFeaturesStr();
TM = std::unique_ptr<TargetMachine>(TheTarget->createTargetMachine(
TheTriple.getTriple(), CPUStr, FeaturesStr, Options, RM,
codegen::getExplicitCodeModel(), CodeGenOpt::Default));
assert(TM && "Could not allocate target machine!");
bool ReducerWorkItem::isReduced(const TestRunner &Test) const {
const bool UseBitcode = Test.inputIsBitcode() || TmpFilesAsBitcode;

return TM->createDataLayout().getStringRepresentation();
};
SmallString<128> CurrentFilepath;

std::unique_ptr<Module> M = MParser->parseIRModule(SetDataLayout);
LLVMTargetMachine *LLVMTM = static_cast<LLVMTargetMachine *>(TM.get());
// Write ReducerWorkItem to tmp file
int FD;
std::error_code EC = sys::fs::createTemporaryFile(
"llvm-reduce", isMIR() ? "mir" : (UseBitcode ? "bc" : "ll"), FD,
CurrentFilepath,
UseBitcode && !isMIR() ? sys::fs::OF_None : sys::fs::OF_Text);
if (EC) {
errs() << "Error making unique filename: " << EC.message() << "!\n";
exit(1);
}

MMM->MMI = std::make_unique<MachineModuleInfo>(LLVMTM);
MParser->parseMachineFunctions(*M, *MMM->MMI);
MMM->M = std::move(M);
} else {
SMDiagnostic Err;
ErrorOr<std::unique_ptr<MemoryBuffer>> MB = MemoryBuffer::getFileOrSTDIN(Filename);
if (std::error_code EC = MB.getError()) {
WithColor::error(errs(), ToolName) << Filename << ": " << EC.message() << "\n";
return {nullptr, false};
}
ToolOutputFile Out(CurrentFilepath, FD);

if (!isBitcode((const unsigned char *)(*MB)->getBufferStart(),
(const unsigned char *)(*MB)->getBufferEnd())) {
std::unique_ptr<Module> Result = parseIRFile(Filename, Err, Ctxt);
if (!Result) {
Err.print(ToolName.data(), errs());
return {nullptr, false};
}
MMM->M = std::move(Result);
} else {
IsBitcode = true;
readBitcode(*MMM, MemoryBufferRef(**MB), Ctxt, ToolName);
writeOutput(Out.os(), UseBitcode);

if (MMM->LTOInfo->IsThinLTO && MMM->LTOInfo->EnableSplitLTOUnit)
initializeTargetInfo();
}
Out.os().close();
if (Out.os().has_error()) {
errs() << "Error emitting bitcode to file '" << CurrentFilepath
<< "': " << Out.os().error().message();
exit(1);
}
if (verifyReducerWorkItem(*MMM, &errs())) {
WithColor::error(errs(), ToolName)
<< Filename << " - input module is broken!\n";
return {nullptr, false};
}
return {std::move(MMM), IsBitcode};

// Current Chunks aren't interesting
return Test.run(CurrentFilepath);
}

std::unique_ptr<ReducerWorkItem>
cloneReducerWorkItem(const ReducerWorkItem &MMM, const TargetMachine *TM) {
ReducerWorkItem::clone(const TargetMachine *TM) const {
auto CloneMMM = std::make_unique<ReducerWorkItem>();
if (TM) {
// We're assuming the Module IR contents are always unchanged by MIR
// reductions, and can share it as a constant.
CloneMMM->M = MMM.M;
CloneMMM->M = M;

// MachineModuleInfo contains a lot of other state used during codegen which
// we won't be using here, but we should be able to ignore it (although this
Expand All @@ -496,46 +477,16 @@ cloneReducerWorkItem(const ReducerWorkItem &MMM, const TargetMachine *TM) {
static_cast<const LLVMTargetMachine *>(TM);
CloneMMM->MMI = std::make_unique<MachineModuleInfo>(LLVMTM);

for (const Function &F : MMM.getModule()) {
if (auto *MF = MMM.MMI->getMachineFunction(F))
for (const Function &F : getModule()) {
if (auto *MF = MMI->getMachineFunction(F))
CloneMMM->MMI->insertFunction(F, cloneMF(MF, *CloneMMM->MMI));
}
} else {
CloneMMM->M = CloneModule(*MMM.M);
CloneMMM->M = CloneModule(*M);
}
return CloneMMM;
}

bool verifyReducerWorkItem(const ReducerWorkItem &MMM, raw_fd_ostream *OS) {
if (verifyModule(*MMM.M, OS))
return true;

if (!MMM.MMI)
return false;

for (const Function &F : MMM.getModule()) {
if (const MachineFunction *MF = MMM.MMI->getMachineFunction(F)) {
if (!MF->verify(nullptr, "", /*AbortOnError=*/false))
return true;
}
}

return false;
}

void ReducerWorkItem::print(raw_ostream &ROS, void *p) const {
if (MMI) {
printMIR(ROS, *M);
for (Function &F : *M) {
if (auto *MF = MMI->getMachineFunction(F))
printMIR(ROS, *MF);
}
} else {
M->print(ROS, /*AssemblyAnnotationWriter=*/nullptr,
/*ShouldPreserveUseListOrder=*/true);
}
}

/// Try to produce some number that indicates a function is getting smaller /
/// simpler.
static uint64_t computeMIRComplexityScoreImpl(const MachineFunction &MF) {
Expand Down Expand Up @@ -731,3 +682,147 @@ uint64_t ReducerWorkItem::computeIRComplexityScore() const {

return Score;
}

void ReducerWorkItem::writeOutput(raw_ostream &OS, bool EmitBitcode) const {
// Requesting bitcode emission with mir is nonsense, so just ignore it.
if (EmitBitcode && !isMIR())
writeBitcode(OS);
else
print(OS, /*AnnotationWriter=*/nullptr);
}

void ReducerWorkItem::readBitcode(MemoryBufferRef Data, LLVMContext &Ctx,
StringRef ToolName) {
Expected<BitcodeFileContents> IF = llvm::getBitcodeFileContents(Data);
if (!IF) {
WithColor::error(errs(), ToolName) << IF.takeError();
exit(1);
}
BitcodeModule BM = IF->Mods[0];
Expected<BitcodeLTOInfo> LI = BM.getLTOInfo();
Expected<std::unique_ptr<Module>> MOrErr = BM.parseModule(Ctx);
if (!LI || !MOrErr) {
WithColor::error(errs(), ToolName) << IF.takeError();
exit(1);
}
LTOInfo = std::make_unique<BitcodeLTOInfo>(*LI);
M = std::move(MOrErr.get());
}

void ReducerWorkItem::writeBitcode(raw_ostream &OutStream) const {
if (LTOInfo && LTOInfo->IsThinLTO && LTOInfo->EnableSplitLTOUnit) {
PassBuilder PB;
LoopAnalysisManager LAM;
FunctionAnalysisManager FAM;
CGSCCAnalysisManager CGAM;
ModuleAnalysisManager MAM;
PB.registerModuleAnalyses(MAM);
PB.registerCGSCCAnalyses(CGAM);
PB.registerFunctionAnalyses(FAM);
PB.registerLoopAnalyses(LAM);
PB.crossRegisterProxies(LAM, FAM, CGAM, MAM);
ModulePassManager MPM;
MPM.addPass(ThinLTOBitcodeWriterPass(OutStream, nullptr));
MPM.run(*M, MAM);
} else {
std::unique_ptr<ModuleSummaryIndex> Index;
if (LTOInfo && LTOInfo->HasSummary) {
ProfileSummaryInfo PSI(*M);
Index = std::make_unique<ModuleSummaryIndex>(
buildModuleSummaryIndex(*M, nullptr, &PSI));
}
WriteBitcodeToFile(getModule(), OutStream, Index.get());
}
}

std::pair<std::unique_ptr<ReducerWorkItem>, bool>
llvm::parseReducerWorkItem(StringRef ToolName, StringRef Filename,
LLVMContext &Ctxt,
std::unique_ptr<TargetMachine> &TM, bool IsMIR) {
bool IsBitcode = false;
Triple TheTriple;

auto MMM = std::make_unique<ReducerWorkItem>();

if (IsMIR) {
initializeTargetInfo();

auto FileOrErr = MemoryBuffer::getFileOrSTDIN(Filename, /*IsText=*/true);
if (std::error_code EC = FileOrErr.getError()) {
WithColor::error(errs(), ToolName) << EC.message() << '\n';
return {nullptr, false};
}

std::unique_ptr<MIRParser> MParser =
createMIRParser(std::move(FileOrErr.get()), Ctxt);

auto SetDataLayout = [&](StringRef DataLayoutTargetTriple,
StringRef OldDLStr) -> std::optional<std::string> {
// If we are supposed to override the target triple, do so now.
std::string IRTargetTriple = DataLayoutTargetTriple.str();
if (!TargetTriple.empty())
IRTargetTriple = Triple::normalize(TargetTriple);
TheTriple = Triple(IRTargetTriple);
if (TheTriple.getTriple().empty())
TheTriple.setTriple(sys::getDefaultTargetTriple());

std::string Error;
const Target *TheTarget =
TargetRegistry::lookupTarget(codegen::getMArch(), TheTriple, Error);
if (!TheTarget) {
WithColor::error(errs(), ToolName) << Error;
exit(1);
}

// Hopefully the MIR parsing doesn't depend on any options.
TargetOptions Options;
std::optional<Reloc::Model> RM = codegen::getExplicitRelocModel();
std::string CPUStr = codegen::getCPUStr();
std::string FeaturesStr = codegen::getFeaturesStr();
TM = std::unique_ptr<TargetMachine>(TheTarget->createTargetMachine(
TheTriple.getTriple(), CPUStr, FeaturesStr, Options, RM,
codegen::getExplicitCodeModel(), CodeGenOpt::Default));
assert(TM && "Could not allocate target machine!");

return TM->createDataLayout().getStringRepresentation();
};

std::unique_ptr<Module> M = MParser->parseIRModule(SetDataLayout);
LLVMTargetMachine *LLVMTM = static_cast<LLVMTargetMachine *>(TM.get());

MMM->MMI = std::make_unique<MachineModuleInfo>(LLVMTM);
MParser->parseMachineFunctions(*M, *MMM->MMI);
MMM->M = std::move(M);
} else {
SMDiagnostic Err;
ErrorOr<std::unique_ptr<MemoryBuffer>> MB =
MemoryBuffer::getFileOrSTDIN(Filename);
if (std::error_code EC = MB.getError()) {
WithColor::error(errs(), ToolName)
<< Filename << ": " << EC.message() << "\n";
return {nullptr, false};
}

if (!isBitcode((const unsigned char *)(*MB)->getBufferStart(),
(const unsigned char *)(*MB)->getBufferEnd())) {
std::unique_ptr<Module> Result = parseIRFile(Filename, Err, Ctxt);
if (!Result) {
Err.print(ToolName.data(), errs());
return {nullptr, false};
}
MMM->M = std::move(Result);
} else {
IsBitcode = true;
MMM->readBitcode(MemoryBufferRef(**MB), Ctxt, ToolName);

if (MMM->LTOInfo->IsThinLTO && MMM->LTOInfo->EnableSplitLTOUnit)
initializeTargetInfo();
}
}
if (MMM->verify(&errs())) {
WithColor::error(errs(), ToolName)
<< Filename << " - input module is broken!\n";
return {nullptr, false};
}
return {std::move(MMM), IsBitcode};
}
35 changes: 18 additions & 17 deletions llvm/tools/llvm-reduce/ReducerWorkItem.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
namespace llvm {
class LLVMContext;
class MachineModuleInfo;
class MemoryBufferRef;
class raw_ostream;
class TargetMachine;
class TestRunner;
Expand All @@ -26,6 +27,11 @@ class ReducerWorkItem {
std::unique_ptr<BitcodeLTOInfo> LTOInfo;
std::unique_ptr<MachineModuleInfo> MMI;

ReducerWorkItem();
~ReducerWorkItem();
ReducerWorkItem(ReducerWorkItem &) = delete;
ReducerWorkItem(ReducerWorkItem &&) = default;

bool isMIR() const { return MMI != nullptr; }

LLVMContext &getContext() {
Expand All @@ -34,36 +40,31 @@ class ReducerWorkItem {

Module &getModule() { return *M; }
const Module &getModule() const { return *M; }
operator Module &() const { return *M; }

void print(raw_ostream &ROS, void *p = nullptr) const;
operator Module &() const { return *M; }
bool verify(raw_fd_ostream *OS) const;
std::unique_ptr<ReducerWorkItem> clone(const TargetMachine *TM) const;

/// Return a number to indicate whether there was any reduction progress.
uint64_t getComplexityScore() const {
return isMIR() ? computeMIRComplexityScore() : computeIRComplexityScore();
}

ReducerWorkItem();
~ReducerWorkItem();
ReducerWorkItem(ReducerWorkItem &) = delete;
ReducerWorkItem(ReducerWorkItem &&) = default;
void writeOutput(raw_ostream &OS, bool EmitBitcode) const;
void readBitcode(MemoryBufferRef Data, LLVMContext &Ctx, StringRef ToolName);
void writeBitcode(raw_ostream &OutStream) const;

bool isReduced(const TestRunner &Test) const;

private:
uint64_t computeIRComplexityScore() const;
uint64_t computeMIRComplexityScore() const;
};
} // namespace llvm

std::pair<std::unique_ptr<llvm::ReducerWorkItem>, bool>
parseReducerWorkItem(llvm::StringRef ToolName, llvm::StringRef Filename,
llvm::LLVMContext &Ctxt,
std::unique_ptr<llvm::TargetMachine> &TM, bool IsMIR);

std::unique_ptr<llvm::ReducerWorkItem>
cloneReducerWorkItem(const llvm::ReducerWorkItem &MMM,
const llvm::TargetMachine *TM);

bool verifyReducerWorkItem(const llvm::ReducerWorkItem &MMM,
llvm::raw_fd_ostream *OS);
std::pair<std::unique_ptr<ReducerWorkItem>, bool>
parseReducerWorkItem(StringRef ToolName, StringRef Filename, LLVMContext &Ctxt,
std::unique_ptr<TargetMachine> &TM, bool IsMIR);
} // namespace llvm

#endif
44 changes: 1 addition & 43 deletions llvm/tools/llvm-reduce/TestRunner.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,7 @@
#include "TestRunner.h"
#include "ReducerWorkItem.h"
#include "deltas/Utils.h"
#include "llvm/Analysis/ModuleSummaryAnalysis.h"
#include "llvm/Analysis/ProfileSummaryInfo.h"
#include "llvm/Bitcode/BitcodeReader.h"
#include "llvm/Bitcode/BitcodeWriter.h"
#include "llvm/Passes/PassBuilder.h"
#include "llvm/Support/WithColor.h"
#include "llvm/Transforms/IPO/ThinLTOBitcodeWriter.h"

using namespace llvm;

Expand Down Expand Up @@ -65,37 +59,6 @@ int TestRunner::run(StringRef Filename) const {
return !Result;
}

void TestRunner::setProgram(std::unique_ptr<ReducerWorkItem> P) {
assert(P && "Setting null program?");
Program = std::move(P);
}

void writeBitcode(const ReducerWorkItem &M, raw_ostream &OutStream) {
if (M.LTOInfo && M.LTOInfo->IsThinLTO && M.LTOInfo->EnableSplitLTOUnit) {
PassBuilder PB;
LoopAnalysisManager LAM;
FunctionAnalysisManager FAM;
CGSCCAnalysisManager CGAM;
ModuleAnalysisManager MAM;
PB.registerModuleAnalyses(MAM);
PB.registerCGSCCAnalyses(CGAM);
PB.registerFunctionAnalyses(FAM);
PB.registerLoopAnalyses(LAM);
PB.crossRegisterProxies(LAM, FAM, CGAM, MAM);
ModulePassManager MPM;
MPM.addPass(ThinLTOBitcodeWriterPass(OutStream, nullptr));
MPM.run(*M.M, MAM);
} else {
std::unique_ptr<ModuleSummaryIndex> Index;
if (M.LTOInfo && M.LTOInfo->HasSummary) {
ProfileSummaryInfo PSI(M);
Index = std::make_unique<ModuleSummaryIndex>(
buildModuleSummaryIndex(M, nullptr, &PSI));
}
WriteBitcodeToFile(M.getModule(), OutStream, Index.get());
}
}

void TestRunner::writeOutput(StringRef Message) {
std::error_code EC;
raw_fd_ostream Out(OutputFilename, EC,
Expand All @@ -106,11 +69,6 @@ void TestRunner::writeOutput(StringRef Message) {
exit(1);
}

// Requesting bitcode emission with mir is nonsense, so just ignore it.
if (EmitBitcode && !Program->isMIR())
writeBitcode(*Program, Out);
else
Program->print(Out, /*AnnotationWriter=*/nullptr);

Program->writeOutput(Out, EmitBitcode);
errs() << Message << OutputFilename << '\n';
}
5 changes: 4 additions & 1 deletion llvm/tools/llvm-reduce/TestRunner.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,10 @@ class TestRunner {
/// Returns the most reduced version of the original testcase
ReducerWorkItem &getProgram() const { return *Program; }

void setProgram(std::unique_ptr<ReducerWorkItem> P);
void setProgram(std::unique_ptr<ReducerWorkItem> &&P) {
assert(P && "Setting null program?");
Program = std::move(P);
}

const TargetMachine *getTargetMachine() const { return TM.get(); }

Expand Down
77 changes: 16 additions & 61 deletions llvm/tools/llvm-reduce/deltas/Delta.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@

#include "Delta.h"
#include "ReducerWorkItem.h"
#include "TestRunner.h"
#include "Utils.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/Analysis/ModuleSummaryAnalysis.h"
Expand All @@ -27,7 +28,6 @@
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/MemoryBufferRef.h"
#include "llvm/Support/ThreadPool.h"
#include "llvm/Support/ToolOutputFile.h"
#include <fstream>
#include <set>

Expand All @@ -45,11 +45,6 @@ static cl::opt<unsigned int> StartingGranularityLevel(
cl::desc("Number of times to divide chunks prior to first test"),
cl::cat(LLVMReduceOptions));

static cl::opt<bool> TmpFilesAsBitcode(
"write-tmp-files-as-bitcode",
cl::desc("Always write temporary files as bitcode instead of textual IR"),
cl::init(false), cl::cat(LLVMReduceOptions));

#ifdef LLVM_ENABLE_THREADS
static cl::opt<unsigned> NumJobs(
"j",
Expand All @@ -60,45 +55,6 @@ static cl::opt<unsigned> NumJobs(
unsigned NumJobs = 1;
#endif

void writeBitcode(const ReducerWorkItem &M, raw_ostream &OutStream);

void readBitcode(ReducerWorkItem &M, MemoryBufferRef Data, LLVMContext &Ctx,
StringRef ToolName);

bool isReduced(const ReducerWorkItem &M, const TestRunner &Test) {
const bool UseBitcode = Test.inputIsBitcode() || TmpFilesAsBitcode;

SmallString<128> CurrentFilepath;

// Write ReducerWorkItem to tmp file
int FD;
std::error_code EC = sys::fs::createTemporaryFile(
"llvm-reduce", M.isMIR() ? "mir" : (UseBitcode ? "bc" : "ll"), FD,
CurrentFilepath,
UseBitcode && !M.isMIR() ? sys::fs::OF_None : sys::fs::OF_Text);
if (EC) {
errs() << "Error making unique filename: " << EC.message() << "!\n";
exit(1);
}

ToolOutputFile Out(CurrentFilepath, FD);

if (TmpFilesAsBitcode)
writeBitcode(M, Out.os());
else
M.print(Out.os(), /*AnnotationWriter=*/nullptr);

Out.os().close();
if (Out.os().has_error()) {
errs() << "Error emitting bitcode to file '" << CurrentFilepath
<< "': " << Out.os().error().message();
exit(1);
}

// Current Chunks aren't interesting
return Test.run(CurrentFilepath);
}

/// Splits Chunks in half and prints them.
/// If unable to split (when chunk size is 1) returns false.
static bool increaseGranularity(std::vector<Chunk> &Chunks) {
Expand Down Expand Up @@ -157,7 +113,7 @@ CheckChunk(const Chunk ChunkToCheckForUninterestingness,
ExtractChunksFromModule(O, *Clone);

// Some reductions may result in invalid IR. Skip such reductions.
if (verifyReducerWorkItem(*Clone, &errs())) {
if (Clone->verify(&errs())) {
if (AbortOnInvalidReduction) {
errs() << "Invalid reduction, aborting.\n";
Clone->print(errs());
Expand All @@ -178,7 +134,7 @@ CheckChunk(const Chunk ChunkToCheckForUninterestingness,
errs() << "\n";
}

if (!isReduced(*Clone, Test)) {
if (!Clone->isReduced(Test)) {
// Program became non-reduced, so this chunk appears to be interesting.
if (Verbose)
errs() << "\n";
Expand All @@ -196,15 +152,15 @@ static SmallString<0> ProcessChunkFromSerializedBitcode(
LLVMContext Ctx;
auto CloneMMM = std::make_unique<ReducerWorkItem>();
MemoryBufferRef Data(OriginalBC, "<bc file>");
readBitcode(*CloneMMM, Data, Ctx, Test.getToolName());
CloneMMM->readBitcode(Data, Ctx, Test.getToolName());

SmallString<0> Result;
if (std::unique_ptr<ReducerWorkItem> ChunkResult =
CheckChunk(ChunkToCheckForUninterestingness, std::move(CloneMMM),
Test, ExtractChunksFromModule, UninterestingChunks,
ChunksStillConsideredInteresting)) {
raw_svector_ostream BCOS(Result);
writeBitcode(*ChunkResult, BCOS);
ChunkResult->writeBitcode(BCOS);
// Communicate that the task reduced a chunk.
AnyReduced = true;
}
Expand All @@ -227,7 +183,7 @@ static void waitAndDiscardResultsBarrier(SharedTaskQueue &TaskQueue) {
/// reduction pass where no change must be made to the module.
void llvm::runDeltaPass(TestRunner &Test, ReductionFunc ExtractChunksFromModule,
StringRef Message) {
assert(!verifyReducerWorkItem(Test.getProgram(), &errs()) &&
assert(!Test.getProgram().verify(&errs()) &&
"input module is broken before making changes");
errs() << "*** " << Message << "...\n";

Expand All @@ -241,17 +197,17 @@ void llvm::runDeltaPass(TestRunner &Test, ReductionFunc ExtractChunksFromModule,
ExtractChunksFromModule(Counter, Test.getProgram());
Targets = Counter.count();

assert(!verifyReducerWorkItem(Test.getProgram(), &errs()) &&
assert(!Test.getProgram().verify(&errs()) &&
"input module is broken after counting chunks");
assert(isReduced(Test.getProgram(), Test) &&
assert(Test.getProgram().isReduced(Test) &&
"input module no longer interesting after counting chunks");

#ifndef NDEBUG
// Make sure that the number of chunks does not change as we reduce.
std::vector<Chunk> NoChunks = {{0, INT_MAX}};
Oracle NoChunksCounter(NoChunks);
std::unique_ptr<ReducerWorkItem> Clone =
cloneReducerWorkItem(Test.getProgram(), Test.getTargetMachine());
Test.getProgram().clone(Test.getTargetMachine());
ExtractChunksFromModule(NoChunksCounter, *Clone);
assert(Targets == NoChunksCounter.count() &&
"number of chunks changes when reducing");
Expand Down Expand Up @@ -288,7 +244,7 @@ void llvm::runDeltaPass(TestRunner &Test, ReductionFunc ExtractChunksFromModule,
SmallString<0> OriginalBC;
if (NumJobs > 1) {
raw_svector_ostream BCOS(OriginalBC);
writeBitcode(Test.getProgram(), BCOS);
Test.getProgram().writeBitcode(BCOS);
}

SharedTaskQueue TaskQueue;
Expand Down Expand Up @@ -351,8 +307,8 @@ void llvm::runDeltaPass(TestRunner &Test, ReductionFunc ExtractChunksFromModule,

Result = std::make_unique<ReducerWorkItem>();
MemoryBufferRef Data(StringRef(Res), "<bc file>");
readBitcode(*Result, Data, Test.getProgram().M->getContext(),
Test.getToolName());
Result->readBitcode(Data, Test.getProgram().M->getContext(),
Test.getToolName());
break;
}

Expand All @@ -366,11 +322,10 @@ void llvm::runDeltaPass(TestRunner &Test, ReductionFunc ExtractChunksFromModule,
// Forward I to the last chunk processed in parallel.
I += NumChunksProcessed - 1;
} else {
Result = CheckChunk(
*I,
cloneReducerWorkItem(Test.getProgram(), Test.getTargetMachine()),
Test, ExtractChunksFromModule, UninterestingChunks,
ChunksStillConsideredInteresting);
Result =
CheckChunk(*I, Test.getProgram().clone(Test.getTargetMachine()),
Test, ExtractChunksFromModule, UninterestingChunks,
ChunksStillConsideredInteresting);
}

if (!Result)
Expand Down
6 changes: 5 additions & 1 deletion llvm/tools/llvm-reduce/deltas/Delta.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,18 @@
#ifndef LLVM_TOOLS_LLVM_REDUCE_DELTAS_DELTA_H
#define LLVM_TOOLS_LLVM_REDUCE_DELTAS_DELTA_H

#include "TestRunner.h"
#include "ReducerWorkItem.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/ScopeExit.h"
#include "llvm/Support/raw_ostream.h"
#include <functional>
#include <utility>
#include <vector>

namespace llvm {

class TestRunner;

struct Chunk {
int Begin;
int End;
Expand Down
22 changes: 1 addition & 21 deletions llvm/tools/llvm-reduce/llvm-reduce.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -103,8 +103,6 @@ static cl::opt<int>

static codegen::RegisterCodeGenFlags CGF;

bool isReduced(const ReducerWorkItem &M, const TestRunner &Test);

/// Turn off crash debugging features
///
/// Crash is expected, so disable crash reports and symbolization to reduce
Expand Down Expand Up @@ -139,24 +137,6 @@ static std::pair<StringRef, bool> determineOutputType(bool IsMIR,
return {OutputFilename, OutputBitcode};
}

void readBitcode(ReducerWorkItem &M, MemoryBufferRef Data, LLVMContext &Ctx,
StringRef ToolName) {
Expected<BitcodeFileContents> IF = llvm::getBitcodeFileContents(Data);
if (!IF) {
WithColor::error(errs(), ToolName) << IF.takeError();
exit(1);
}
BitcodeModule BM = IF->Mods[0];
Expected<BitcodeLTOInfo> LI = BM.getLTOInfo();
Expected<std::unique_ptr<Module>> MOrErr = BM.parseModule(Ctx);
if (!LI || !MOrErr) {
WithColor::error(errs(), ToolName) << IF.takeError();
exit(1);
}
M.LTOInfo = std::make_unique<BitcodeLTOInfo>(*LI);
M.M = std::move(MOrErr.get());
}

int main(int Argc, char **Argv) {
InitLLVM X(Argc, Argv);
const StringRef ToolName(Argv[0]);
Expand Down Expand Up @@ -219,7 +199,7 @@ int main(int Argc, char **Argv) {
// test, rather than evaluating the source IR directly. This is for the
// convenience of lit tests; the stripped out comments may have broken the
// interestingness checks.
if (!isReduced(Tester.getProgram(), Tester)) {
if (!Tester.getProgram().isReduced(Tester)) {
errs() << "\nInput isn't interesting! Verify interesting-ness test\n";
return 1;
}
Expand Down