aboutsummaryrefslogtreecommitdiff
path: root/tools/llvm-reduce
diff options
context:
space:
mode:
Diffstat (limited to 'tools/llvm-reduce')
-rw-r--r--tools/llvm-reduce/CMakeLists.txt26
-rw-r--r--tools/llvm-reduce/DeltaManager.h36
-rw-r--r--tools/llvm-reduce/LLVMBuild.txt24
-rw-r--r--tools/llvm-reduce/TestRunner.cpp42
-rw-r--r--tools/llvm-reduce/TestRunner.h46
-rw-r--r--tools/llvm-reduce/deltas/Delta.cpp162
-rw-r--r--tools/llvm-reduce/deltas/Delta.h76
-rw-r--r--tools/llvm-reduce/deltas/ReduceArguments.cpp125
-rw-r--r--tools/llvm-reduce/deltas/ReduceArguments.h21
-rw-r--r--tools/llvm-reduce/deltas/ReduceBasicBlocks.cpp146
-rw-r--r--tools/llvm-reduce/deltas/ReduceBasicBlocks.h20
-rw-r--r--tools/llvm-reduce/deltas/ReduceFunctions.cpp77
-rw-r--r--tools/llvm-reduce/deltas/ReduceFunctions.h20
-rw-r--r--tools/llvm-reduce/deltas/ReduceGlobalVars.cpp74
-rw-r--r--tools/llvm-reduce/deltas/ReduceGlobalVars.h20
-rw-r--r--tools/llvm-reduce/deltas/ReduceInstructions.cpp65
-rw-r--r--tools/llvm-reduce/deltas/ReduceInstructions.h20
-rw-r--r--tools/llvm-reduce/deltas/ReduceMetadata.cpp138
-rw-r--r--tools/llvm-reduce/deltas/ReduceMetadata.h18
-rw-r--r--tools/llvm-reduce/llvm-reduce.cpp114
20 files changed, 1270 insertions, 0 deletions
diff --git a/tools/llvm-reduce/CMakeLists.txt b/tools/llvm-reduce/CMakeLists.txt
new file mode 100644
index 000000000000..48de0ffa78a1
--- /dev/null
+++ b/tools/llvm-reduce/CMakeLists.txt
@@ -0,0 +1,26 @@
+set(LLVM_LINK_COMPONENTS
+ AllTargetsAsmParsers
+ AllTargetsCodeGens
+ AllTargetsDescs
+ AllTargetsInfos
+ Core
+ IRReader
+ Support
+ Target
+ TransformUtils
+ )
+
+add_llvm_tool(llvm-reduce
+ llvm-reduce.cpp
+ TestRunner.cpp
+ deltas/Delta.cpp
+ deltas/ReduceFunctions.cpp
+ deltas/ReduceGlobalVars.cpp
+ deltas/ReduceMetadata.cpp
+ deltas/ReduceArguments.cpp
+ deltas/ReduceBasicBlocks.cpp
+ deltas/ReduceInstructions.cpp
+
+ DEPENDS
+ intrinsics_gen
+ )
diff --git a/tools/llvm-reduce/DeltaManager.h b/tools/llvm-reduce/DeltaManager.h
new file mode 100644
index 000000000000..2309c3adf4e6
--- /dev/null
+++ b/tools/llvm-reduce/DeltaManager.h
@@ -0,0 +1,36 @@
+//===- DeltaManager.h - Runs Delta Passes to reduce Input -----------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file calls each specialized Delta pass in order to reduce the input IR
+// file.
+//
+//===----------------------------------------------------------------------===//
+
+#include "TestRunner.h"
+#include "deltas/Delta.h"
+#include "deltas/ReduceArguments.h"
+#include "deltas/ReduceBasicBlocks.h"
+#include "deltas/ReduceFunctions.h"
+#include "deltas/ReduceGlobalVars.h"
+#include "deltas/ReduceMetadata.h"
+#include "deltas/ReduceInstructions.h"
+
+namespace llvm {
+
+// TODO: Add CLI option to run only specified Passes (for unit tests)
+inline void runDeltaPasses(TestRunner &Tester) {
+ reduceFunctionsDeltaPass(Tester);
+ reduceBasicBlocksDeltaPass(Tester);
+ reduceGlobalsDeltaPass(Tester);
+ reduceMetadataDeltaPass(Tester);
+ reduceArgumentsDeltaPass(Tester);
+ reduceInstructionsDeltaPass(Tester);
+ // TODO: Implement the remaining Delta Passes
+}
+
+} // namespace llvm
diff --git a/tools/llvm-reduce/LLVMBuild.txt b/tools/llvm-reduce/LLVMBuild.txt
new file mode 100644
index 000000000000..7928f0503283
--- /dev/null
+++ b/tools/llvm-reduce/LLVMBuild.txt
@@ -0,0 +1,24 @@
+;===- ./tools/llvm-reduce/LLVMBuild.txt ------------------------*- Conf -*--===;
+;
+; Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+; See https://llvm.org/LICENSE.txt for license information.
+; SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+;
+;===------------------------------------------------------------------------===;
+;
+; This is an LLVMBuild description file for the components in this subdirectory.
+;
+; For more information on the LLVMBuild system, please see:
+;
+; http://llvm.org/docs/LLVMBuild.html
+;
+;===------------------------------------------------------------------------===;
+
+[component_0]
+type = Tool
+name = llvm-reduce
+parent = Tools
+required_libraries =
+ BitReader
+ IRReader
+ all-targets
diff --git a/tools/llvm-reduce/TestRunner.cpp b/tools/llvm-reduce/TestRunner.cpp
new file mode 100644
index 000000000000..d0e195d5697c
--- /dev/null
+++ b/tools/llvm-reduce/TestRunner.cpp
@@ -0,0 +1,42 @@
+//===-- TestRunner.cpp ----------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "TestRunner.h"
+
+using namespace llvm;
+
+TestRunner::TestRunner(StringRef TestName, const std::vector<std::string> &TestArgs)
+ : TestName(TestName), TestArgs(TestArgs) {
+}
+
+/// Runs the interestingness test, passes file to be tested as first argument
+/// and other specified test arguments after that.
+int TestRunner::run(StringRef Filename) {
+ std::vector<StringRef> ProgramArgs;
+ ProgramArgs.push_back(TestName);
+
+ for (const auto &Arg : TestArgs)
+ ProgramArgs.push_back(Arg);
+
+ ProgramArgs.push_back(Filename);
+
+ std::string ErrMsg;
+ int Result = sys::ExecuteAndWait(
+ TestName, ProgramArgs, /*Env=*/None, /*Redirects=*/None,
+ /*SecondsToWait=*/0, /*MemoryLimit=*/0, &ErrMsg);
+
+ if (Result < 0) {
+ Error E = make_error<StringError>("Error running interesting-ness test: " +
+ ErrMsg,
+ inconvertibleErrorCode());
+ errs() << toString(std::move(E));
+ exit(1);
+ }
+
+ return !Result;
+}
diff --git a/tools/llvm-reduce/TestRunner.h b/tools/llvm-reduce/TestRunner.h
new file mode 100644
index 000000000000..2270d6bd90b2
--- /dev/null
+++ b/tools/llvm-reduce/TestRunner.h
@@ -0,0 +1,46 @@
+//===-- tools/llvm-reduce/TestRunner.h ---------------------------*- C++ -*-===/
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_TOOLS_LLVMREDUCE_TESTRUNNER_H
+#define LLVM_TOOLS_LLVMREDUCE_TESTRUNNER_H
+
+#include "llvm/ADT/SmallString.h"
+#include "llvm/IR/Module.h"
+#include "llvm/Support/Error.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/Path.h"
+#include "llvm/Support/Program.h"
+#include <vector>
+
+namespace llvm {
+
+// This class contains all the info necessary for running the provided
+// interesting-ness test, as well as the most reduced module and its
+// respective filename.
+class TestRunner {
+public:
+ TestRunner(StringRef TestName, const std::vector<std::string> &TestArgs);
+
+ /// Runs the interesting-ness test for the specified file
+ /// @returns 0 if test was successful, 1 if otherwise
+ int run(StringRef Filename);
+
+ /// Returns the most reduced version of the original testcase
+ Module *getProgram() const { return Program.get(); }
+
+ void setProgram(std::unique_ptr<Module> P) { Program = std::move(P); }
+
+private:
+ StringRef TestName;
+ const std::vector<std::string> &TestArgs;
+ std::unique_ptr<Module> Program;
+};
+
+} // namespace llvm
+
+#endif
diff --git a/tools/llvm-reduce/deltas/Delta.cpp b/tools/llvm-reduce/deltas/Delta.cpp
new file mode 100644
index 000000000000..0642241ddebd
--- /dev/null
+++ b/tools/llvm-reduce/deltas/Delta.cpp
@@ -0,0 +1,162 @@
+//===- Delta.cpp - Delta Debugging Algorithm Implementation ---------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file contains the implementation for the Delta Debugging Algorithm:
+// it splits a given set of Targets (i.e. Functions, Instructions, BBs, etc.)
+// into chunks and tries to reduce the number chunks that are interesting.
+//
+//===----------------------------------------------------------------------===//
+
+#include "Delta.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/Support/ToolOutputFile.h"
+#include "llvm/Transforms/Utils/Cloning.h"
+#include <fstream>
+#include <set>
+
+using namespace llvm;
+
+bool IsReduced(Module &M, TestRunner &Test, SmallString<128> &CurrentFilepath) {
+ // Write Module to tmp file
+ int FD;
+ std::error_code EC =
+ sys::fs::createTemporaryFile("llvm-reduce", "ll", FD, CurrentFilepath);
+ if (EC) {
+ errs() << "Error making unique filename: " << EC.message() << "!\n";
+ exit(1);
+ }
+
+ ToolOutputFile Out(CurrentFilepath, FD);
+ M.print(Out.os(), /*AnnotationWriter=*/nullptr);
+ Out.os().close();
+ if (Out.os().has_error()) {
+ errs() << "Error emitting bitcode to file '" << CurrentFilepath << "'!\n";
+ exit(1);
+ }
+
+ // Current Chunks aren't interesting
+ return Test.run(CurrentFilepath);
+}
+
+/// Counts the amount of lines for a given file
+static int getLines(StringRef Filepath) {
+ int Lines = 0;
+ std::string CurrLine;
+ std::ifstream FileStream(Filepath);
+
+ while (std::getline(FileStream, CurrLine))
+ ++Lines;
+
+ return Lines;
+}
+
+/// 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) {
+ errs() << "Increasing granularity...";
+ std::vector<Chunk> NewChunks;
+ bool SplitOne = false;
+
+ for (auto &C : Chunks) {
+ if (C.end - C.begin == 0)
+ NewChunks.push_back(C);
+ else {
+ int Half = (C.begin + C.end) / 2;
+ NewChunks.push_back({C.begin, Half});
+ NewChunks.push_back({Half + 1, C.end});
+ SplitOne = true;
+ }
+ }
+ if (SplitOne) {
+ Chunks = NewChunks;
+ errs() << "Success! New Chunks:\n";
+ for (auto C : Chunks) {
+ errs() << '\t';
+ C.print();
+ errs() << '\n';
+ }
+ }
+ return SplitOne;
+}
+
+/// Runs the Delta Debugging algorithm, splits the code into chunks and
+/// reduces the amount of chunks that are considered interesting by the
+/// given test.
+void llvm::runDeltaPass(
+ TestRunner &Test, int Targets,
+ std::function<void(const std::vector<Chunk> &, Module *)>
+ ExtractChunksFromModule) {
+ assert(Targets >= 0);
+ if (!Targets) {
+ errs() << "\nNothing to reduce\n";
+ return;
+ }
+
+ if (Module *Program = Test.getProgram()) {
+ SmallString<128> CurrentFilepath;
+ if (!IsReduced(*Program, Test, CurrentFilepath)) {
+ errs() << "\nInput isn't interesting! Verify interesting-ness test\n";
+ exit(1);
+ }
+ }
+
+ std::vector<Chunk> Chunks = {{1, Targets}};
+ std::set<Chunk> UninterestingChunks;
+ std::unique_ptr<Module> ReducedProgram;
+
+ if (!increaseGranularity(Chunks)) {
+ errs() << "\nAlready at minimum size. Cannot reduce anymore.\n";
+ return;
+ }
+
+ do {
+ UninterestingChunks = {};
+ for (int I = Chunks.size() - 1; I >= 0; --I) {
+ std::vector<Chunk> CurrentChunks;
+
+ for (auto C : Chunks)
+ if (!UninterestingChunks.count(C) && C != Chunks[I])
+ CurrentChunks.push_back(C);
+
+ if (CurrentChunks.empty())
+ continue;
+
+ // Clone module before hacking it up..
+ std::unique_ptr<Module> Clone = CloneModule(*Test.getProgram());
+ // Generate Module with only Targets inside Current Chunks
+ ExtractChunksFromModule(CurrentChunks, Clone.get());
+
+ errs() << "Ignoring: ";
+ Chunks[I].print();
+ for (auto C : UninterestingChunks)
+ C.print();
+
+
+
+ SmallString<128> CurrentFilepath;
+ if (!IsReduced(*Clone, Test, CurrentFilepath)) {
+ errs() << "\n";
+ continue;
+ }
+
+ UninterestingChunks.insert(Chunks[I]);
+ ReducedProgram = std::move(Clone);
+ errs() << " **** SUCCESS | lines: " << getLines(CurrentFilepath) << "\n";
+ }
+ // Delete uninteresting chunks
+ erase_if(Chunks, [&UninterestingChunks](const Chunk &C) {
+ return UninterestingChunks.count(C);
+ });
+
+ } while (!UninterestingChunks.empty() || increaseGranularity(Chunks));
+
+ // If we reduced the testcase replace it
+ if (ReducedProgram)
+ Test.setProgram(std::move(ReducedProgram));
+ errs() << "Couldn't increase anymore.\n";
+}
diff --git a/tools/llvm-reduce/deltas/Delta.h b/tools/llvm-reduce/deltas/Delta.h
new file mode 100644
index 000000000000..dbb18e4bd07f
--- /dev/null
+++ b/tools/llvm-reduce/deltas/Delta.h
@@ -0,0 +1,76 @@
+//===- Delta.h - Delta Debugging Algorithm Implementation -----------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file contains the implementation for the Delta Debugging Algorithm:
+// it splits a given set of Targets (i.e. Functions, Instructions, BBs, etc.)
+// into chunks and tries to reduce the number chunks that are interesting.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_TOOLS_LLVMREDUCE_LLVMREDUCE_DELTA_H
+#define LLVM_TOOLS_LLVMREDUCE_LLVMREDUCE_DELTA_H
+
+#include "TestRunner.h"
+#include <vector>
+#include <utility>
+#include <functional>
+
+namespace llvm {
+
+struct Chunk {
+ int begin;
+ int end;
+
+ /// Helper function to verify if a given Target-index is inside the Chunk
+ bool contains(int Index) const { return Index >= begin && Index <= end; }
+
+ void print() const {
+ errs() << "[" << begin;
+ if (end - begin != 0)
+ errs() << "," << end;
+ errs() << "]";
+ }
+
+ /// Operator when populating CurrentChunks in Generic Delta Pass
+ friend bool operator!=(const Chunk &C1, const Chunk &C2) {
+ return C1.begin != C2.begin || C1.end != C2.end;
+ }
+
+ /// Operator used for sets
+ friend bool operator<(const Chunk &C1, const Chunk &C2) {
+ return std::tie(C1.begin, C1.end) < std::tie(C2.begin, C2.end);
+ }
+};
+
+/// This function implements the Delta Debugging algorithm, it receives a
+/// number of Targets (e.g. Functions, Instructions, Basic Blocks, etc.) and
+/// splits them in half; these chunks of targets are then tested while ignoring
+/// one chunk, if a chunk is proven to be uninteresting (i.e. fails the test)
+/// it is removed from consideration. The algorithm will attempt to split the
+/// Chunks in half and start the process again until it can't split chunks
+/// anymore.
+///
+/// This function is intended to be called by each specialized delta pass (e.g.
+/// RemoveFunctions) and receives three key parameters:
+/// * Test: The main TestRunner instance which is used to run the provided
+/// interesting-ness test, as well as to store and access the reduced Program.
+/// * Targets: The amount of Targets that are going to be reduced by the
+/// algorithm, for example, the RemoveGlobalVars pass would send the amount of
+/// initialized GVs.
+/// * ExtractChunksFromModule: A function used to tailor the main program so it
+/// only contains Targets that are inside Chunks of the given iteration.
+/// Note: This function is implemented by each specialized Delta pass
+///
+/// Other implementations of the Delta Debugging algorithm can also be found in
+/// the CReduce, Delta, and Lithium projects.
+void runDeltaPass(TestRunner &Test, int Targets,
+ std::function<void(const std::vector<Chunk> &, Module *)>
+ ExtractChunksFromModule);
+} // namespace llvm
+
+#endif
diff --git a/tools/llvm-reduce/deltas/ReduceArguments.cpp b/tools/llvm-reduce/deltas/ReduceArguments.cpp
new file mode 100644
index 000000000000..f5f14b83f42c
--- /dev/null
+++ b/tools/llvm-reduce/deltas/ReduceArguments.cpp
@@ -0,0 +1,125 @@
+//===- ReduceArguments.cpp - Specialized Delta Pass -----------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements a function which calls the Generic Delta pass in order
+// to reduce uninteresting Arguments from defined functions.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ReduceArguments.h"
+#include "Delta.h"
+#include "llvm/ADT/SmallVector.h"
+#include <set>
+#include <vector>
+
+using namespace llvm;
+
+/// Goes over OldF calls and replaces them with a call to NewF
+static void replaceFunctionCalls(Function &OldF, Function &NewF,
+ const std::set<int> &ArgIndexesToKeep) {
+ const auto &Users = OldF.users();
+ for (auto I = Users.begin(), E = Users.end(); I != E; )
+ if (auto *CI = dyn_cast<CallInst>(*I++)) {
+ SmallVector<Value *, 8> Args;
+ for (auto ArgI = CI->arg_begin(), E = CI->arg_end(); ArgI != E; ++ArgI)
+ if (ArgIndexesToKeep.count(ArgI - CI->arg_begin()))
+ Args.push_back(*ArgI);
+
+ CallInst *NewCI = CallInst::Create(&NewF, Args);
+ NewCI->setCallingConv(NewF.getCallingConv());
+ if (!CI->use_empty())
+ CI->replaceAllUsesWith(NewCI);
+ ReplaceInstWithInst(CI, NewCI);
+ }
+}
+
+/// Removes out-of-chunk arguments from functions, and modifies their calls
+/// accordingly. It also removes allocations of out-of-chunk arguments.
+static void extractArgumentsFromModule(std::vector<Chunk> ChunksToKeep,
+ Module *Program) {
+ int I = 0, ArgCount = 0;
+ std::set<Argument *> ArgsToKeep;
+ std::vector<Function *> Funcs;
+ // Get inside-chunk arguments, as well as their parent function
+ for (auto &F : *Program)
+ if (!F.isDeclaration()) {
+ Funcs.push_back(&F);
+ for (auto &A : F.args())
+ if (I < (int)ChunksToKeep.size()) {
+ if (ChunksToKeep[I].contains(++ArgCount))
+ ArgsToKeep.insert(&A);
+ if (ChunksToKeep[I].end == ArgCount)
+ ++I;
+ }
+ }
+
+ for (auto *F : Funcs) {
+ ValueToValueMapTy VMap;
+ std::vector<Instruction *> InstToDelete;
+ for (auto &A : F->args())
+ if (!ArgsToKeep.count(&A)) {
+ // By adding undesired arguments to the VMap, CloneFunction will remove
+ // them from the resulting Function
+ VMap[&A] = UndefValue::get(A.getType());
+ for (auto *U : A.users())
+ if (auto *I = dyn_cast<Instruction>(*&U))
+ InstToDelete.push_back(I);
+ }
+ // Delete any instruction that uses the argument
+ for (auto *I : InstToDelete) {
+ I->replaceAllUsesWith(UndefValue::get(I->getType()));
+ I->eraseFromParent();
+ }
+
+ // No arguments to reduce
+ if (VMap.empty())
+ continue;
+
+ std::set<int> ArgIndexesToKeep;
+ int ArgI = 0;
+ for (auto &Arg : F->args())
+ if (ArgsToKeep.count(&Arg))
+ ArgIndexesToKeep.insert(++ArgI);
+
+ auto *ClonedFunc = CloneFunction(F, VMap);
+ // In order to preserve function order, we move Clone after old Function
+ ClonedFunc->removeFromParent();
+ Program->getFunctionList().insertAfter(F->getIterator(), ClonedFunc);
+
+ replaceFunctionCalls(*F, *ClonedFunc, ArgIndexesToKeep);
+ // Rename Cloned Function to Old's name
+ std::string FName = F->getName();
+ F->eraseFromParent();
+ ClonedFunc->setName(FName);
+ }
+}
+
+/// Counts the amount of arguments in non-declaration functions and prints their
+/// respective name, index, and parent function name
+static int countArguments(Module *Program) {
+ // TODO: Silence index with --quiet flag
+ outs() << "----------------------------\n";
+ outs() << "Param Index Reference:\n";
+ int ArgsCount = 0;
+ for (auto &F : *Program)
+ if (!F.isDeclaration() && F.arg_size()) {
+ outs() << " " << F.getName() << "\n";
+ for (auto &A : F.args())
+ outs() << "\t" << ++ArgsCount << ": " << A.getName() << "\n";
+
+ outs() << "----------------------------\n";
+ }
+
+ return ArgsCount;
+}
+
+void llvm::reduceArgumentsDeltaPass(TestRunner &Test) {
+ outs() << "*** Reducing Arguments...\n";
+ int ArgCount = countArguments(Test.getProgram());
+ runDeltaPass(Test, ArgCount, extractArgumentsFromModule);
+}
diff --git a/tools/llvm-reduce/deltas/ReduceArguments.h b/tools/llvm-reduce/deltas/ReduceArguments.h
new file mode 100644
index 000000000000..d9682b44f74d
--- /dev/null
+++ b/tools/llvm-reduce/deltas/ReduceArguments.h
@@ -0,0 +1,21 @@
+//===- ReduceArguments.h - Specialized Delta Pass -------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements a function which calls the Generic Delta pass in order
+// to reduce uninteresting Arguments from defined functions.
+//
+//===----------------------------------------------------------------------===//
+
+#include "Delta.h"
+#include "llvm/IR/Argument.h"
+#include "llvm/Transforms/Utils/BasicBlockUtils.h"
+#include "llvm/Transforms/Utils/Cloning.h"
+
+namespace llvm {
+void reduceArgumentsDeltaPass(TestRunner &Test);
+} // namespace llvm
diff --git a/tools/llvm-reduce/deltas/ReduceBasicBlocks.cpp b/tools/llvm-reduce/deltas/ReduceBasicBlocks.cpp
new file mode 100644
index 000000000000..03c3962d2fd9
--- /dev/null
+++ b/tools/llvm-reduce/deltas/ReduceBasicBlocks.cpp
@@ -0,0 +1,146 @@
+//===- ReduceArguments.cpp - Specialized Delta Pass -----------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements a function which calls the Generic Delta pass in order
+// to reduce uninteresting Arguments from defined functions.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ReduceBasicBlocks.h"
+#include "llvm/IR/BasicBlock.h"
+#include "llvm/IR/Instruction.h"
+#include "llvm/IR/Instructions.h"
+#include "llvm/IR/LLVMContext.h"
+#include "llvm/IR/Value.h"
+#include "llvm/Support/Casting.h"
+#include "llvm/Support/raw_ostream.h"
+#include <vector>
+
+using namespace llvm;
+
+/// Replaces BB Terminator with one that only contains Chunk BBs
+static void replaceBranchTerminator(BasicBlock &BB,
+ std::set<BasicBlock *> BBsToKeep) {
+ auto Term = BB.getTerminator();
+ std::vector<BasicBlock *> ChunkSucessors;
+ for (auto Succ : successors(&BB))
+ if (BBsToKeep.count(Succ))
+ ChunkSucessors.push_back(Succ);
+
+ // BB only references Chunk BBs
+ if (ChunkSucessors.size() == Term->getNumSuccessors())
+ return;
+
+ bool IsBranch = isa<BranchInst>(Term);
+ Value *Address = nullptr;
+ if (auto IndBI = dyn_cast<IndirectBrInst>(Term))
+ Address = IndBI->getAddress();
+
+ Term->eraseFromParent();
+
+ if (ChunkSucessors.empty()) {
+ ReturnInst::Create(BB.getContext(), nullptr, &BB);
+ return;
+ }
+
+ if (IsBranch)
+ BranchInst::Create(ChunkSucessors[0], &BB);
+
+ if (Address) {
+ auto NewIndBI =
+ IndirectBrInst::Create(Address, ChunkSucessors.size(), &BB);
+ for (auto Dest : ChunkSucessors)
+ NewIndBI->addDestination(Dest);
+ }
+}
+
+/// Removes uninteresting BBs from switch, if the default case ends up being
+/// uninteresting, the switch is replaced with a void return (since it has to be
+/// replace with something)
+static void removeUninterestingBBsFromSwitch(SwitchInst &SwInst,
+ std::set<BasicBlock *> BBsToKeep) {
+ if (!BBsToKeep.count(SwInst.getDefaultDest())) {
+ ReturnInst::Create(SwInst.getContext(), nullptr, SwInst.getParent());
+ SwInst.eraseFromParent();
+ } else
+ for (int I = 0, E = SwInst.getNumCases(); I != E; ++I) {
+ auto Case = SwInst.case_begin() + I;
+ if (!BBsToKeep.count(Case->getCaseSuccessor())) {
+ SwInst.removeCase(Case);
+ --I;
+ --E;
+ }
+ }
+}
+
+/// Removes out-of-chunk arguments from functions, and modifies their calls
+/// accordingly. It also removes allocations of out-of-chunk arguments.
+static void extractBasicBlocksFromModule(std::vector<Chunk> ChunksToKeep,
+ Module *Program) {
+ int I = 0, BBCount = 0;
+ std::set<BasicBlock *> BBsToKeep;
+
+ for (auto &F : *Program)
+ for (auto &BB : F)
+ if (I < (int)ChunksToKeep.size()) {
+ if (ChunksToKeep[I].contains(++BBCount))
+ BBsToKeep.insert(&BB);
+ if (ChunksToKeep[I].end == BBCount)
+ ++I;
+ }
+
+ std::vector<BasicBlock *> BBsToDelete;
+ for (auto &F : *Program)
+ for (auto &BB : F) {
+ if (!BBsToKeep.count(&BB)) {
+ BBsToDelete.push_back(&BB);
+ // Remove out-of-chunk BB from successor phi nodes
+ for (auto *Succ : successors(&BB))
+ Succ->removePredecessor(&BB);
+ }
+ }
+
+ // Replace terminators that reference out-of-chunk BBs
+ for (auto &F : *Program)
+ for (auto &BB : F) {
+ if (auto *SwInst = dyn_cast<SwitchInst>(BB.getTerminator()))
+ removeUninterestingBBsFromSwitch(*SwInst, BBsToKeep);
+ else
+ replaceBranchTerminator(BB, BBsToKeep);
+ }
+
+ // Replace out-of-chunk switch uses
+ for (auto &BB : BBsToDelete) {
+ // Instructions might be referenced in other BBs
+ for (auto &I : *BB)
+ I.replaceAllUsesWith(UndefValue::get(I.getType()));
+ BB->eraseFromParent();
+ }
+}
+
+/// Counts the amount of basic blocks and prints their name & respective index
+static int countBasicBlocks(Module *Program) {
+ // TODO: Silence index with --quiet flag
+ outs() << "----------------------------\n";
+ int BBCount = 0;
+ for (auto &F : *Program)
+ for (auto &BB : F) {
+ if (BB.hasName())
+ outs() << "\t" << ++BBCount << ": " << BB.getName() << "\n";
+ else
+ outs() << "\t" << ++BBCount << ": Unnamed\n";
+ }
+
+ return BBCount;
+}
+
+void llvm::reduceBasicBlocksDeltaPass(TestRunner &Test) {
+ outs() << "*** Reducing Basic Blocks...\n";
+ int BBCount = countBasicBlocks(Test.getProgram());
+ runDeltaPass(Test, BBCount, extractBasicBlocksFromModule);
+}
diff --git a/tools/llvm-reduce/deltas/ReduceBasicBlocks.h b/tools/llvm-reduce/deltas/ReduceBasicBlocks.h
new file mode 100644
index 000000000000..cf76a0abbcd7
--- /dev/null
+++ b/tools/llvm-reduce/deltas/ReduceBasicBlocks.h
@@ -0,0 +1,20 @@
+//===- ReduceArguments.h - Specialized Delta Pass -------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements a function which calls the Generic Delta pass in order
+// to reduce uninteresting Arguments from defined functions.
+//
+//===----------------------------------------------------------------------===//
+
+#include "Delta.h"
+#include "llvm/Transforms/Utils/BasicBlockUtils.h"
+#include "llvm/Transforms/Utils/Cloning.h"
+
+namespace llvm {
+void reduceBasicBlocksDeltaPass(TestRunner &Test);
+} // namespace llvm
diff --git a/tools/llvm-reduce/deltas/ReduceFunctions.cpp b/tools/llvm-reduce/deltas/ReduceFunctions.cpp
new file mode 100644
index 000000000000..3382f35a945a
--- /dev/null
+++ b/tools/llvm-reduce/deltas/ReduceFunctions.cpp
@@ -0,0 +1,77 @@
+//===- ReduceFunctions.cpp - Specialized Delta Pass -----------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements a function which calls the Generic Delta pass in order
+// to reduce functions (and any instruction that calls it) in the provided
+// Module.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ReduceFunctions.h"
+#include "Delta.h"
+#include "llvm/ADT/SetVector.h"
+#include <set>
+
+using namespace llvm;
+
+/// Removes all the Defined Functions (as well as their calls)
+/// that aren't inside any of the desired Chunks.
+static void extractFunctionsFromModule(const std::vector<Chunk> &ChunksToKeep,
+ Module *Program) {
+ // Get functions inside desired chunks
+ std::set<Function *> FuncsToKeep;
+ int I = 0, FunctionCount = 0;
+ for (auto &F : *Program)
+ if (I < (int)ChunksToKeep.size()) {
+ if (ChunksToKeep[I].contains(++FunctionCount))
+ FuncsToKeep.insert(&F);
+ if (FunctionCount == ChunksToKeep[I].end)
+ ++I;
+ }
+
+ // Delete out-of-chunk functions, and replace their calls with undef
+ std::vector<Function *> FuncsToRemove;
+ SetVector<CallInst *> CallsToRemove;
+ for (auto &F : *Program)
+ if (!FuncsToKeep.count(&F)) {
+ for (auto U : F.users())
+ if (auto *Call = dyn_cast<CallInst>(U)) {
+ Call->replaceAllUsesWith(UndefValue::get(Call->getType()));
+ CallsToRemove.insert(Call);
+ }
+ F.replaceAllUsesWith(UndefValue::get(F.getType()));
+ FuncsToRemove.push_back(&F);
+ }
+
+ for (auto *C : CallsToRemove)
+ C->eraseFromParent();
+
+ for (auto *F : FuncsToRemove)
+ F->eraseFromParent();
+}
+
+/// Counts the amount of non-declaration functions and prints their
+/// respective name & index
+static int countFunctions(Module *Program) {
+ // TODO: Silence index with --quiet flag
+ errs() << "----------------------------\n";
+ errs() << "Function Index Reference:\n";
+ int FunctionCount = 0;
+ for (auto &F : *Program)
+ errs() << "\t" << ++FunctionCount << ": " << F.getName() << "\n";
+
+ errs() << "----------------------------\n";
+ return FunctionCount;
+}
+
+void llvm::reduceFunctionsDeltaPass(TestRunner &Test) {
+ errs() << "*** Reducing Functions...\n";
+ int Functions = countFunctions(Test.getProgram());
+ runDeltaPass(Test, Functions, extractFunctionsFromModule);
+ errs() << "----------------------------\n";
+}
diff --git a/tools/llvm-reduce/deltas/ReduceFunctions.h b/tools/llvm-reduce/deltas/ReduceFunctions.h
new file mode 100644
index 000000000000..7c2cd3f33e9f
--- /dev/null
+++ b/tools/llvm-reduce/deltas/ReduceFunctions.h
@@ -0,0 +1,20 @@
+//===- ReduceFunctions.h - Specialized Delta Pass -------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements a function which calls the Generic Delta pass in order
+// to reduce functions (and any instruction that calls it) in the provided
+// Module.
+//
+//===----------------------------------------------------------------------===//
+
+#include "Delta.h"
+#include "llvm/Transforms/Utils/Cloning.h"
+
+namespace llvm {
+void reduceFunctionsDeltaPass(TestRunner &Test);
+} // namespace llvm
diff --git a/tools/llvm-reduce/deltas/ReduceGlobalVars.cpp b/tools/llvm-reduce/deltas/ReduceGlobalVars.cpp
new file mode 100644
index 000000000000..5732208ee0a9
--- /dev/null
+++ b/tools/llvm-reduce/deltas/ReduceGlobalVars.cpp
@@ -0,0 +1,74 @@
+//===- ReduceGlobalVars.cpp - Specialized Delta Pass ----------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements a function which calls the Generic Delta pass in order
+// to reduce initialized Global Variables in the provided Module.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ReduceGlobalVars.h"
+#include <set>
+
+using namespace llvm;
+
+/// Removes all the Initialized GVs that aren't inside the desired Chunks.
+static void extractGVsFromModule(std::vector<Chunk> ChunksToKeep,
+ Module *Program) {
+ // Get GVs inside desired chunks
+ std::set<GlobalVariable *> GVsToKeep;
+ int I = 0, GVCount = 0;
+ for (auto &GV : Program->globals())
+ if (GV.hasInitializer() && I < (int)ChunksToKeep.size()) {
+ if (ChunksToKeep[I].contains(++GVCount))
+ GVsToKeep.insert(&GV);
+ if (GVCount == ChunksToKeep[I].end)
+ ++I;
+ }
+
+ // Delete out-of-chunk GVs and their uses
+ std::vector<GlobalVariable *> ToRemove;
+ std::vector<Instruction *> InstToRemove;
+ for (auto &GV : Program->globals())
+ if (GV.hasInitializer() && !GVsToKeep.count(&GV)) {
+ for (auto U : GV.users())
+ if (auto *Inst = dyn_cast<Instruction>(U))
+ InstToRemove.push_back(Inst);
+
+ GV.replaceAllUsesWith(UndefValue::get(GV.getType()));
+ ToRemove.push_back(&GV);
+ }
+
+ // Delete Instruction uses of unwanted GVs
+ for (auto *Inst : InstToRemove) {
+ Inst->replaceAllUsesWith(UndefValue::get(Inst->getType()));
+ Inst->eraseFromParent();
+ }
+
+ for (auto *GV : ToRemove)
+ GV->eraseFromParent();
+}
+
+/// Counts the amount of initialized GVs and displays their
+/// respective name & index
+static int countGVs(Module *Program) {
+ // TODO: Silence index with --quiet flag
+ outs() << "----------------------------\n";
+ outs() << "GlobalVariable Index Reference:\n";
+ int GVCount = 0;
+ for (auto &GV : Program->globals())
+ if (GV.hasInitializer())
+ outs() << "\t" << ++GVCount << ": " << GV.getName() << "\n";
+ outs() << "----------------------------\n";
+ return GVCount;
+}
+
+void llvm::reduceGlobalsDeltaPass(TestRunner &Test) {
+ outs() << "*** Reducing GVs...\n";
+ int GVCount = countGVs(Test.getProgram());
+ runDeltaPass(Test, GVCount, extractGVsFromModule);
+}
diff --git a/tools/llvm-reduce/deltas/ReduceGlobalVars.h b/tools/llvm-reduce/deltas/ReduceGlobalVars.h
new file mode 100644
index 000000000000..d4a870aded58
--- /dev/null
+++ b/tools/llvm-reduce/deltas/ReduceGlobalVars.h
@@ -0,0 +1,20 @@
+//===- ReduceGlobalVars.h - Specialized Delta Pass ------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements a function which calls the Generic Delta pass in order
+// to reduce initialized Global Variables in the provided Module.
+//
+//===----------------------------------------------------------------------===//
+
+#include "Delta.h"
+#include "llvm/IR/Value.h"
+#include "llvm/Transforms/Utils/Cloning.h"
+
+namespace llvm {
+void reduceGlobalsDeltaPass(TestRunner &Test);
+} // namespace llvm
diff --git a/tools/llvm-reduce/deltas/ReduceInstructions.cpp b/tools/llvm-reduce/deltas/ReduceInstructions.cpp
new file mode 100644
index 000000000000..b3497ad2dc02
--- /dev/null
+++ b/tools/llvm-reduce/deltas/ReduceInstructions.cpp
@@ -0,0 +1,65 @@
+//===- ReduceArguments.cpp - Specialized Delta Pass -----------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements a function which calls the Generic Delta pass in order
+// to reduce uninteresting Arguments from defined functions.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ReduceInstructions.h"
+
+using namespace llvm;
+
+/// Removes out-of-chunk arguments from functions, and modifies their calls
+/// accordingly. It also removes allocations of out-of-chunk arguments.
+static void extractInstrFromModule(std::vector<Chunk> ChunksToKeep,
+ Module *Program) {
+ int I = 0, InstCount = 0;
+ std::set<Instruction *> InstToKeep;
+
+ for (auto &F : *Program)
+ for (auto &BB : F)
+ for (auto &Inst : BB)
+ if (I < (int)ChunksToKeep.size()) {
+ if (ChunksToKeep[I].contains(++InstCount))
+ InstToKeep.insert(&Inst);
+ if (ChunksToKeep[I].end == InstCount)
+ ++I;
+ }
+
+ std::vector<Instruction *> InstToDelete;
+ for (auto &F : *Program)
+ for (auto &BB : F)
+ for (auto &Inst : BB)
+ if (!InstToKeep.count(&Inst)) {
+ Inst.replaceAllUsesWith(UndefValue::get(Inst.getType()));
+ InstToDelete.push_back(&Inst);
+ }
+
+ for (auto &I : InstToDelete)
+ I->eraseFromParent();
+}
+
+/// Counts the amount of basic blocks and prints their name & respective index
+static unsigned countInstructions(Module *Program) {
+ // TODO: Silence index with --quiet flag
+ outs() << "----------------------------\n";
+ int InstCount = 0;
+ for (auto &F : *Program)
+ for (auto &BB : F)
+ InstCount += BB.getInstList().size();
+ outs() << "Number of instructions: " << InstCount << "\n";
+
+ return InstCount;
+}
+
+void llvm::reduceInstructionsDeltaPass(TestRunner &Test) {
+ outs() << "*** Reducing Insructions...\n";
+ unsigned InstCount = countInstructions(Test.getProgram());
+ runDeltaPass(Test, InstCount, extractInstrFromModule);
+}
diff --git a/tools/llvm-reduce/deltas/ReduceInstructions.h b/tools/llvm-reduce/deltas/ReduceInstructions.h
new file mode 100644
index 000000000000..a9266acd051a
--- /dev/null
+++ b/tools/llvm-reduce/deltas/ReduceInstructions.h
@@ -0,0 +1,20 @@
+//===- ReduceArguments.h - Specialized Delta Pass -------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements a function which calls the Generic Delta pass in order
+// to reduce uninteresting Arguments from defined functions.
+//
+//===----------------------------------------------------------------------===//
+
+#include "Delta.h"
+#include "llvm/Transforms/Utils/BasicBlockUtils.h"
+#include "llvm/Transforms/Utils/Cloning.h"
+
+namespace llvm {
+void reduceInstructionsDeltaPass(TestRunner &Test);
+} // namespace llvm
diff --git a/tools/llvm-reduce/deltas/ReduceMetadata.cpp b/tools/llvm-reduce/deltas/ReduceMetadata.cpp
new file mode 100644
index 000000000000..4ea223546efa
--- /dev/null
+++ b/tools/llvm-reduce/deltas/ReduceMetadata.cpp
@@ -0,0 +1,138 @@
+//===- ReduceMetadata.cpp - Specialized Delta Pass ------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements two functions used by the Generic Delta Debugging
+// Algorithm, which are used to reduce Metadata nodes.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ReduceMetadata.h"
+#include "Delta.h"
+#include "llvm/ADT/SmallVector.h"
+#include <set>
+#include <vector>
+
+using namespace llvm;
+
+/// Adds all Unnamed Metadata Nodes that are inside desired Chunks to set
+template <class T>
+static void getChunkMetadataNodes(T &MDUser, int &I,
+ const std::vector<Chunk> &ChunksToKeep,
+ std::set<MDNode *> &SeenNodes,
+ std::set<MDNode *> &NodesToKeep) {
+ SmallVector<std::pair<unsigned, MDNode *>, 4> MDs;
+ MDUser.getAllMetadata(MDs);
+ for (auto &MD : MDs) {
+ SeenNodes.insert(MD.second);
+ if (I < (int)ChunksToKeep.size()) {
+ if (ChunksToKeep[I].contains(SeenNodes.size()))
+ NodesToKeep.insert(MD.second);
+ if (ChunksToKeep[I].end == (int)SeenNodes.size())
+ ++I;
+ }
+ }
+}
+
+/// Erases out-of-chunk unnamed metadata nodes from its user
+template <class T>
+static void eraseMetadataIfOutsideChunk(T &MDUser,
+ const std::set<MDNode *> &NodesToKeep) {
+ SmallVector<std::pair<unsigned, MDNode *>, 4> MDs;
+ MDUser.getAllMetadata(MDs);
+ for (int I = 0, E = MDs.size(); I != E; ++I)
+ if (!NodesToKeep.count(MDs[I].second))
+ MDUser.setMetadata(I, NULL);
+}
+
+/// Removes all the Named and Unnamed Metadata Nodes, as well as any debug
+/// functions that aren't inside the desired Chunks.
+static void extractMetadataFromModule(const std::vector<Chunk> &ChunksToKeep,
+ Module *Program) {
+ std::set<MDNode *> SeenNodes;
+ std::set<MDNode *> NodesToKeep;
+ int I = 0;
+
+ // Add chunk MDNodes used by GVs, Functions, and Instructions to set
+ for (auto &GV : Program->globals())
+ getChunkMetadataNodes(GV, I, ChunksToKeep, SeenNodes, NodesToKeep);
+
+ for (auto &F : *Program) {
+ getChunkMetadataNodes(F, I, ChunksToKeep, SeenNodes, NodesToKeep);
+ for (auto &BB : F)
+ for (auto &Inst : BB)
+ getChunkMetadataNodes(Inst, I, ChunksToKeep, SeenNodes, NodesToKeep);
+ }
+
+ // Once more, go over metadata nodes, but deleting the ones outside chunks
+ for (auto &GV : Program->globals())
+ eraseMetadataIfOutsideChunk(GV, NodesToKeep);
+
+ for (auto &F : *Program) {
+ eraseMetadataIfOutsideChunk(F, NodesToKeep);
+ for (auto &BB : F)
+ for (auto &Inst : BB)
+ eraseMetadataIfOutsideChunk(Inst, NodesToKeep);
+ }
+
+
+ // Get out-of-chunk Named metadata nodes
+ unsigned MetadataCount = SeenNodes.size();
+ std::vector<NamedMDNode *> NamedNodesToDelete;
+ for (auto &MD : Program->named_metadata()) {
+ if (I < (int)ChunksToKeep.size()) {
+ if (!ChunksToKeep[I].contains(++MetadataCount))
+ NamedNodesToDelete.push_back(&MD);
+ if (ChunksToKeep[I].end == (int)SeenNodes.size())
+ ++I;
+ } else
+ NamedNodesToDelete.push_back(&MD);
+ }
+
+ for (auto *NN : NamedNodesToDelete) {
+ for (int I = 0, E = NN->getNumOperands(); I != E; ++I)
+ NN->setOperand(I, NULL);
+ NN->eraseFromParent();
+ }
+}
+
+// Gets unnamed metadata nodes used by a given instruction/GV/function and adds
+// them to the set of seen nodes
+template <class T>
+static void addMetadataToSet(T &MDUser, std::set<MDNode *> &UnnamedNodes) {
+ SmallVector<std::pair<unsigned, MDNode *>, 4> MDs;
+ MDUser.getAllMetadata(MDs);
+ for (auto &MD : MDs)
+ UnnamedNodes.insert(MD.second);
+}
+
+/// Returns the amount of Named and Unnamed Metadata Nodes
+static int countMetadataTargets(Module *Program) {
+ std::set<MDNode *> UnnamedNodes;
+ int NamedMetadataNodes = Program->named_metadata_size();
+
+ // Get metadata nodes used by globals
+ for (auto &GV : Program->globals())
+ addMetadataToSet(GV, UnnamedNodes);
+
+ // Do the same for nodes used by functions & instructions
+ for (auto &F : *Program) {
+ addMetadataToSet(F, UnnamedNodes);
+ for (auto &BB : F)
+ for (auto &I : BB)
+ addMetadataToSet(I, UnnamedNodes);
+ }
+
+ return UnnamedNodes.size() + NamedMetadataNodes;
+}
+
+void llvm::reduceMetadataDeltaPass(TestRunner &Test) {
+ outs() << "*** Reducing Metadata...\n";
+ int MDCount = countMetadataTargets(Test.getProgram());
+ runDeltaPass(Test, MDCount, extractMetadataFromModule);
+ outs() << "----------------------------\n";
+}
diff --git a/tools/llvm-reduce/deltas/ReduceMetadata.h b/tools/llvm-reduce/deltas/ReduceMetadata.h
new file mode 100644
index 000000000000..275b44c2aa7d
--- /dev/null
+++ b/tools/llvm-reduce/deltas/ReduceMetadata.h
@@ -0,0 +1,18 @@
+//===- ReduceMetadata.h - Specialized Delta Pass ------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements two functions used by the Generic Delta Debugging
+// Algorithm, which are used to reduce Metadata nodes.
+//
+//===----------------------------------------------------------------------===//
+
+#include "TestRunner.h"
+
+namespace llvm {
+void reduceMetadataDeltaPass(TestRunner &Test);
+} // namespace llvm
diff --git a/tools/llvm-reduce/llvm-reduce.cpp b/tools/llvm-reduce/llvm-reduce.cpp
new file mode 100644
index 000000000000..83dcf980a786
--- /dev/null
+++ b/tools/llvm-reduce/llvm-reduce.cpp
@@ -0,0 +1,114 @@
+//===- llvm-reduce.cpp - The LLVM Delta Reduction utility -----------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This program tries to reduce an IR test case for a given interesting-ness
+// test. It runs multiple delta debugging passes in order to minimize the input
+// file. It's worth noting that this is a part of the bugpoint redesign
+// proposal, and thus a *temporary* tool that will eventually be integrated
+// into the bugpoint tool itself.
+//
+//===----------------------------------------------------------------------===//
+
+#include "DeltaManager.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/IR/LLVMContext.h"
+#include "llvm/IR/Verifier.h"
+#include "llvm/IRReader/IRReader.h"
+#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/InitLLVM.h"
+#include "llvm/Support/SourceMgr.h"
+#include "llvm/Support/raw_ostream.h"
+#include <system_error>
+#include <vector>
+
+using namespace llvm;
+
+static cl::opt<bool> Help("h", cl::desc("Alias for -help"), cl::Hidden);
+static cl::opt<bool> Version("v", cl::desc("Alias for -version"), cl::Hidden);
+
+static cl::opt<std::string> InputFilename(cl::Positional, cl::Required,
+ cl::desc("<input llvm ll/bc file>"));
+
+static cl::opt<std::string>
+ TestFilename("test", cl::Required,
+ cl::desc("Name of the interesting-ness test to be run"));
+
+static cl::list<std::string>
+ TestArguments("test-arg", cl::ZeroOrMore,
+ cl::desc("Arguments passed onto the interesting-ness test"));
+
+static cl::opt<std::string>
+ OutputFilename("output",
+ cl::desc("Specify the output file. default: reduced.ll"));
+static cl::alias OutputFileAlias("o", cl::desc("Alias for -output"),
+ cl::aliasopt(OutputFilename));
+
+static cl::opt<bool>
+ ReplaceInput("in-place",
+ cl::desc("WARNING: This option will replace your input file"
+ "with the reduced version!"));
+
+// Parses IR into a Module and verifies it
+static std::unique_ptr<Module> parseInputFile(StringRef Filename,
+ LLVMContext &Ctxt) {
+ SMDiagnostic Err;
+ std::unique_ptr<Module> Result = parseIRFile(Filename, Err, Ctxt);
+ if (!Result) {
+ Err.print("llvm-reduce", errs());
+ return Result;
+ }
+
+ if (verifyModule(*Result, &errs())) {
+ errs() << "Error: " << Filename << " - input module is broken!\n";
+ return std::unique_ptr<Module>();
+ }
+
+ return Result;
+}
+
+int main(int argc, char **argv) {
+ InitLLVM X(argc, argv);
+
+ cl::ParseCommandLineOptions(argc, argv, "LLVM automatic testcase reducer.\n");
+
+ LLVMContext Context;
+ std::unique_ptr<Module> OriginalProgram =
+ parseInputFile(InputFilename, Context);
+
+ // Initialize test environment
+ TestRunner Tester(TestFilename, TestArguments);
+ Tester.setProgram(std::move(OriginalProgram));
+
+ // Try to reduce code
+ runDeltaPasses(Tester);
+
+ if (!Tester.getProgram()) {
+ errs() << "\nCouldnt reduce input :/\n";
+ } else {
+ // Print reduced file to STDOUT
+ if (OutputFilename == "-")
+ Tester.getProgram()->print(outs(), nullptr);
+ else {
+ if (ReplaceInput) // In-place
+ OutputFilename = InputFilename.c_str();
+ else if (OutputFilename.empty())
+ OutputFilename = "reduced.ll";
+
+ std::error_code EC;
+ raw_fd_ostream Out(OutputFilename, EC);
+ if (EC) {
+ errs() << "Error opening output file: " << EC.message() << "!\n";
+ exit(1);
+ }
+ Tester.getProgram()->print(Out, /*AnnotationWriter=*/nullptr);
+ errs() << "\nDone reducing! Reduced testcase: " << OutputFilename << "\n";
+ }
+ }
+
+ return 0;
+}