diff --git a/llvm/test/Reduce/Inputs/remove-funcs.sh b/llvm/test/Reduce/Inputs/interestingness-test.sh rename from llvm/test/Reduce/Inputs/remove-funcs.sh rename to llvm/test/Reduce/Inputs/interestingness-test.sh diff --git a/llvm/test/Reduce/remove-funcs.ll b/llvm/test/Reduce/remove-funcs.ll --- a/llvm/test/Reduce/remove-funcs.ll +++ b/llvm/test/Reduce/remove-funcs.ll @@ -1,7 +1,7 @@ ; Test that llvm-reduce can remove uninteresting functions as well as ; their InstCalls. ; -; RUN: llvm-reduce --test %p/Inputs/remove-funcs.sh --test-arg %lli %s +; RUN: llvm-reduce --test %p/Inputs/interestingness-test.sh --test-arg %lli %s ; RUN: cat reduced.ll | FileCheck %s ; REQUIRES: plugins, shell diff --git a/llvm/test/Reduce/remove-global-vars.ll b/llvm/test/Reduce/remove-global-vars.ll new file mode 100644 --- /dev/null +++ b/llvm/test/Reduce/remove-global-vars.ll @@ -0,0 +1,55 @@ +; Test that llvm-reduce can remove uninteresting Global Variables as well as +; their uses (both direct and derived). +; +; RUN: llvm-reduce --test %p/Inputs/interestingness-test.sh --test-arg %lli %s +; RUN: cat reduced.ll | FileCheck %s +; REQUIRES: plugins, shell + +@uninteresting1 = global i32 0, align 4 +; CHECK: @interesting = global +@interesting = global i32 5, align 4 +; CHECK-NOT: global +@uninteresting2 = global i32 25, align 4 +@uninteresting3 = global i32 50, align 4 +@.str = private unnamed_addr constant [4 x i8] c"%i\0A\00", align 1 + +define void @func(i32* dereferenceable(4) %x) { +entry: + %x.addr = alloca i32*, align 8 + store i32* %x, i32** %x.addr, align 8 + %0 = load i32*, i32** %x.addr, align 8 + %1 = load i32, i32* %0, align 4 + %inc = add nsw i32 %1, 1 + store i32 %inc, i32* %0, align 4 + ret void +} + +define i32 @main() { +entry: + %retval = alloca i32, align 4 + store i32 0, i32* %retval, align 4 + ; CHECK-NOT: load i32, i32* @uninteresting2, align 4 + %0 = load i32, i32* @uninteresting2, align 4 + store i32 %0, i32* @interesting, align 4 + ; CHECK-NOT: load i32, i32* @uninteresting3, align 4 + %1 = load i32, i32* @uninteresting3, align 4 + %dec = add nsw i32 %1, -1 + ; CHECK-NOT: store i32 %dec, i32* @uninteresting3, align 4 + store i32 %dec, i32* @uninteresting3, align 4 + ; CHECK: load i32, i32* @interesting, align 4 + %2 = load i32, i32* @interesting, align 4 + ; CHECK-NOT: load i32, i32* @uninteresting2, align 4 + %3 = load i32, i32* @uninteresting2, align 4 + %add = add nsw i32 %2, %3 + ; CHECK-NOT: store i32 %add, i32* @uninteresting1, align 4 + store i32 %add, i32* @uninteresting1, align 4 + ; CHECK: store i32 10, i32* @interesting, align 4 + store i32 10, i32* @interesting, align 4 + ; CHECK-NOT: call void @func(i32* dereferenceable(4) @uninteresting1) + call void @func(i32* dereferenceable(4) @uninteresting1) + %4 = load i32, i32* @interesting, align 4 + %call = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @.str, i64 0, i64 0), i32 %4) + ret i32 0 +} + +declare i32 @printf(i8*, ...) 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 @@ -15,7 +15,9 @@ add_llvm_tool(llvm-reduce llvm-reduce.cpp TestRunner.cpp + deltas/Delta.cpp deltas/RemoveFunctions.cpp + deltas/RemoveGlobalVars.cpp DEPENDS intrinsics_gen diff --git a/llvm/tools/llvm-reduce/DeltaManager.h b/llvm/tools/llvm-reduce/DeltaManager.h --- a/llvm/tools/llvm-reduce/DeltaManager.h +++ b/llvm/tools/llvm-reduce/DeltaManager.h @@ -1,4 +1,4 @@ -//===- llvm-reduce.cpp - The LLVM Delta Reduction utility -----------------===// +//===- 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. @@ -6,21 +6,25 @@ // //===----------------------------------------------------------------------===// // -// This class calls each specialized Delta pass by passing it as a template to -// the generic Delta Pass. +// This file calls each specialized Delta pass in order to reduce the input IR +// file. // //===----------------------------------------------------------------------===// #include "TestRunner.h" #include "deltas/Delta.h" #include "deltas/RemoveFunctions.h" +#include "deltas/RemoveGlobalVars.h" namespace llvm { inline void runDeltaPasses(TestRunner &Tester) { + // TODO: Add option to only call certain delta passes outs() << "Reducing functions...\n"; - Delta::run(Tester); - // TODO: Implement the rest of the Delta Passes + removeFunctionsDeltaPass(Tester); + outs() << "Reducing GVs...\n"; + removeGlobalsDeltaPass(Tester); + // TODO: Implement the remaining Delta Passes } } // namespace llvm 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 @@ -1,4 +1,4 @@ -//===- llvm-reduce.cpp - The LLVM Delta Reduction utility -----------------===// +//===-- 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. 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 @@ -1,3 +1,11 @@ +//===-- 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; diff --git a/llvm/tools/llvm-reduce/deltas/Delta.h b/llvm/tools/llvm-reduce/deltas/Delta.h --- a/llvm/tools/llvm-reduce/deltas/Delta.h +++ b/llvm/tools/llvm-reduce/deltas/Delta.h @@ -1,4 +1,4 @@ -//===- llvm-reduce.cpp - The LLVM Delta Reduction utility -----------------===// +//===- 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. @@ -41,180 +41,33 @@ } }; -/// Writes IR code to the given Filepath -inline bool writeProgramToFile(StringRef Filepath, int FD, const Module &M) { - ToolOutputFile Out(Filepath, FD); - M.print(Out.os(), /*AnnotationWriter=*/nullptr); - Out.os().close(); - - if (!Out.os().has_error()) { - Out.keep(); - return false; - } - return true; -} - -/// Creates a temporary (and unique) file inside the tmp folder and outputs -/// the module inside it. -inline SmallString<128> createTmpFile(Module *M, StringRef TmpDir) { - SmallString<128> UniqueFilepath; - int UniqueFD; - - std::error_code EC = sys::fs::createUniqueFile(TmpDir + "/tmp-%%%.ll", - UniqueFD, UniqueFilepath); - if (EC) { - errs() << "Error making unique filename: " << EC.message() << "!\n"; - exit(1); - } - - if (writeProgramToFile(UniqueFilepath, UniqueFD, *M)) { - errs() << "Error emitting bitcode to file '" << UniqueFilepath << "'!\n"; - exit(1); - } - return UniqueFilepath; -} - -/// Prints the Chunk Indexes with the following format: [start, end], if -/// chunk is at minimum size (1), then it just displays [start]. -inline void printChunks(std::vector Chunks, bool Oneline = false) { - for (auto C : Chunks) { - if (!Oneline) - outs() << '\t'; - outs() << "[" << C.begin; - if (C.end - C.begin != 0) - outs() << "," << C.end; - outs() << "]"; - if (!Oneline) - outs() << '\n'; - } -} - -/// Counts the amount of lines for a given file -inline unsigned getLines(StringRef Filepath) { - unsigned 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. -inline bool increaseGranularity(std::vector &Chunks) { - outs() << "Increasing granularity..."; - std::vector 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; - outs() << "Success! New Chunks:\n"; - printChunks(Chunks); - } - return SplitOne; -} - namespace llvm { -/// This class implements the Delta Debugging algorithm, it receives a set 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. Otherwise, the algorithm will attempt to split -/// the Chunks in half and start the process again, until it can't split chunks +/// 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. /// -/// The class is intended to be called statically by the DeltaManager class -/// alongside a specialized delta pass (e.g. RemoveFunctions) passed as a -/// template. -/// This specialized pass implements two functions: -/// * getTargetCount, which returns the amount of targets (e.g. Functions) -/// there are in the Module. -/// * extractChunksFromModule, which clones the given Module and modifies it -/// so it only contains Chunk Targets. +/// 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 be found in the -/// CReduce, Delta, and Lithium projects. -template class Delta { -public: - /// Runs the Delta Debugging algorithm, splits the code into chunks and - /// reduces the amount of chunks that are considered interesting by the - /// given test. - static void run(TestRunner &Test) { - int TargetCount = P::getTargetCount(Test.getProgram()); - std::vector Chunks = {{1, TargetCount}}; - std::set UninterestingChunks; - std::unique_ptr ReducedProgram; - - if (Test.run(Test.getReducedFilepath())) - increaseGranularity(Chunks); - else { - outs() << "Error: input file isnt interesting\n"; - exit(1); - } - - do { - UninterestingChunks = {}; - for (int I = Chunks.size() - 1; I >= 0; --I) { - std::vector CurrentChunks; - - for (auto C : Chunks) - if (!UninterestingChunks.count(C) && C != Chunks[I]) - CurrentChunks.push_back(C); - - // Generate Module with only Targets inside Current Chunks - std::unique_ptr CurrentProgram = - P::extractChunksFromModule(CurrentChunks, Test.getProgram()); - // Write Module to tmp file - SmallString<128> CurrentFilepath = - createTmpFile(CurrentProgram.get(), Test.getTmpDir()); - - outs() << "Testing with: "; - printChunks(CurrentChunks, /*Oneline=*/true); - outs() << " | " << sys::path::filename(CurrentFilepath); - - // Current Chunks aren't interesting - if (!Test.run(CurrentFilepath)) { - outs() << "\n"; - continue; - } - // We only care about interesting chunks if they reduce the testcase - if (getLines(CurrentFilepath) < getLines(Test.getReducedFilepath())) { - UninterestingChunks.insert(Chunks[I]); - Test.setReducedFilepath(CurrentFilepath); - ReducedProgram = std::move(CurrentProgram); - outs() << " **** SUCCESS | lines: " << getLines(CurrentFilepath); - } - outs() << "\n"; - } - // Delete uninteresting chunks - auto It = Chunks.begin(), E = Chunks.end(); - while (It != E) { - if (UninterestingChunks.count(*It)) - It = Chunks.erase(It); - else - ++It; - } - } while (!UninterestingChunks.empty() || increaseGranularity(Chunks)); - - // If we reduced the testcase replace it - if (ReducedProgram) - Test.setProgram(std::move(ReducedProgram)); - outs() << "Couldn't increase anymore.\n"; - } -}; +/// 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(std::vector, Module *)> + ExtractChunksFromModule); } // namespace llvm diff --git a/llvm/tools/llvm-reduce/deltas/Delta.cpp b/llvm/tools/llvm-reduce/deltas/Delta.cpp new file mode 100644 --- /dev/null +++ b/llvm/tools/llvm-reduce/deltas/Delta.cpp @@ -0,0 +1,171 @@ +//===- 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" + +/// Writes IR code to the given Filepath +static bool writeProgramToFile(StringRef Filepath, int FD, const Module &M) { + ToolOutputFile Out(Filepath, FD); + M.print(Out.os(), /*AnnotationWriter=*/nullptr); + Out.os().close(); + + if (!Out.os().has_error()) { + Out.keep(); + return false; + } + return true; +} + +/// Creates a temporary (and unique) file inside the tmp folder and writes +/// the given module IR. +static SmallString<128> createTmpFile(Module *M, StringRef TmpDir) { + SmallString<128> UniqueFilepath; + int UniqueFD; + + std::error_code EC = sys::fs::createUniqueFile(TmpDir + "/tmp-%%%.ll", + UniqueFD, UniqueFilepath); + if (EC) { + errs() << "Error making unique filename: " << EC.message() << "!\n"; + exit(1); + } + + if (writeProgramToFile(UniqueFilepath, UniqueFD, *M)) { + errs() << "Error emitting bitcode to file '" << UniqueFilepath << "'!\n"; + exit(1); + } + return UniqueFilepath; +} + +/// Prints the Chunk Indexes with the following format: [start, end], if +/// chunk is at minimum size (1), then it just displays [start]. +static void printChunks(std::vector Chunks, bool Oneline = false) { + for (auto C : Chunks) { + if (!Oneline) + outs() << '\t'; + outs() << "[" << C.begin; + if (C.end - C.begin != 0) + outs() << "," << C.end; + outs() << "]"; + if (!Oneline) + outs() << '\n'; + } +} + +/// Counts the amount of lines for a given file +static unsigned getLines(StringRef Filepath) { + unsigned 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 &Chunks) { + outs() << "Increasing granularity..."; + std::vector 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; + outs() << "Success! New Chunks:\n"; + printChunks(Chunks); + } + return SplitOne; +} + +void llvm::runDeltaPass( + TestRunner &Test, int Targets, + std::function(std::vector, Module *)> + ExtractChunksFromModule) { + if (!Targets) + return; + + std::vector Chunks = {{1, Targets}}; + std::set UninterestingChunks; + std::unique_ptr ReducedProgram; + + if (!Test.run(Test.getReducedFilepath()) || !increaseGranularity(Chunks)) { + outs() << "\nCouldn't reduce\n"; + outs() << "----------------------------\n"; + return; + } + + do { + UninterestingChunks = {}; + for (int I = Chunks.size() - 1; I >= 0; --I) { + std::vector CurrentChunks; + + for (auto C : Chunks) + if (!UninterestingChunks.count(C) && C != Chunks[I]) + CurrentChunks.push_back(C); + + if (CurrentChunks.empty()) + break; + + // Generate Module with only Targets inside Current Chunks + std::unique_ptr CurrentProgram = + ExtractChunksFromModule(CurrentChunks, Test.getProgram()); + // Write Module to tmp file + SmallString<128> CurrentFilepath = + createTmpFile(CurrentProgram.get(), Test.getTmpDir()); + + outs() << "Testing with: "; + printChunks(CurrentChunks, /*Oneline=*/true); + outs() << " | " << sys::path::filename(CurrentFilepath); + + // Current Chunks aren't interesting + if (!Test.run(CurrentFilepath)) { + outs() << "\n"; + continue; + } + // We only care about interesting chunks if they reduce the testcase + if (getLines(CurrentFilepath) < getLines(Test.getReducedFilepath())) { + UninterestingChunks.insert(Chunks[I]); + Test.setReducedFilepath(CurrentFilepath); + ReducedProgram = std::move(CurrentProgram); + outs() << " **** SUCCESS | lines: " << getLines(CurrentFilepath); + } + outs() << "\n"; + } + // Delete uninteresting chunks + auto UnwantedChunks = Chunks.end(); + UnwantedChunks = std::remove_if(Chunks.begin(), Chunks.end(), + [UninterestingChunks](const Chunk &C) { + return UninterestingChunks.count(C); + }); + Chunks.erase(UnwantedChunks, Chunks.end()); + + } while (!UninterestingChunks.empty() || increaseGranularity(Chunks)); + + // If we reduced the testcase replace it + if (ReducedProgram) + Test.setProgram(std::move(ReducedProgram)); + outs() << "Couldn't increase anymore.\n"; + outs() << "----------------------------\n"; +} \ No newline at end of file diff --git a/llvm/tools/llvm-reduce/deltas/RemoveFunctions.h b/llvm/tools/llvm-reduce/deltas/RemoveFunctions.h --- a/llvm/tools/llvm-reduce/deltas/RemoveFunctions.h +++ b/llvm/tools/llvm-reduce/deltas/RemoveFunctions.h @@ -1,4 +1,4 @@ -//===- llvm-reduce.cpp - The LLVM Delta Reduction utility -----------------===// +//===- RemoveFunctions.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. @@ -6,8 +6,9 @@ // //===----------------------------------------------------------------------===// // -// This file is a Specialized Delta Pass, which removes the functions that are -// not in the provided function-chunks. +// 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. // //===----------------------------------------------------------------------===// @@ -15,14 +16,5 @@ #include "llvm/Transforms/Utils/Cloning.h" namespace llvm { - -class RemoveFunctions { -public: - /// Outputs the number of Functions in the given Module - static int getTargetCount(Module *Program); - /// Clones module and returns it with chunk functions only - static std::unique_ptr - extractChunksFromModule(std::vector ChunksToKeep, Module *Program); -}; - +void removeFunctionsDeltaPass(TestRunner &Test); } // namespace llvm diff --git a/llvm/tools/llvm-reduce/deltas/RemoveFunctions.cpp b/llvm/tools/llvm-reduce/deltas/RemoveFunctions.cpp --- a/llvm/tools/llvm-reduce/deltas/RemoveFunctions.cpp +++ b/llvm/tools/llvm-reduce/deltas/RemoveFunctions.cpp @@ -1,4 +1,4 @@ -//===- llvm-reduce.cpp - The LLVM Delta Reduction utility -----------------===// +//===- RemoveFunctions.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. @@ -6,33 +6,30 @@ // //===----------------------------------------------------------------------===// // -// This file is a Specialized Delta Pass, which removes the functions that are -// not in the provided function-chunks. +// 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 "RemoveFunctions.h" -using namespace llvm; - /// Removes all the Defined Functions (as well as their calls) /// that aren't inside any of the desired Chunks. /// @returns the Module stripped of out-of-chunk functions -std::unique_ptr -RemoveFunctions::extractChunksFromModule(std::vector ChunksToKeep, - Module *Program) { +static std::unique_ptr +extractFunctionsFromModule(std::vector ChunksToKeep, Module *Program) { std::unique_ptr Clone = CloneModule(*Program); // Get functions inside desired chunks std::set FuncsToKeep; int I = 0, FunctionCount = 1; for (auto &F : *Clone) { - if (!F.isDeclaration()) { + if (!F.isDeclaration() && I < ChunksToKeep.size()) { if (FunctionCount >= ChunksToKeep[I].begin && - FunctionCount <= ChunksToKeep[I].end) { + FunctionCount <= ChunksToKeep[I].end) FuncsToKeep.insert(&F); - } - if (FunctionCount >= ChunksToKeep[I].end) + if (FunctionCount == ChunksToKeep[I].end) ++I; ++FunctionCount; } @@ -68,11 +65,11 @@ } /// Counts the amount of non-declaration functions and prints their -/// respective index & name -int RemoveFunctions::getTargetCount(Module *Program) { +/// respective name & index +static int countFunctions(Module *Program) { // TODO: Silence index with --quiet flag outs() << "----------------------------\n"; - outs() << "Chunk Index Reference:\n"; + outs() << "Function Index Reference:\n"; int FunctionCount = 0; for (auto &F : *Program) if (!F.isDeclaration()) { @@ -82,3 +79,8 @@ outs() << "----------------------------\n"; return FunctionCount; } + +void llvm::removeFunctionsDeltaPass(TestRunner &Test) { + int FunctionCount = countFunctions(Test.getProgram()); + runDeltaPass(Test, FunctionCount, extractFunctionsFromModule); +} \ No newline at end of file diff --git a/llvm/tools/llvm-reduce/deltas/RemoveGlobalVars.h b/llvm/tools/llvm-reduce/deltas/RemoveGlobalVars.h new file mode 100644 --- /dev/null +++ b/llvm/tools/llvm-reduce/deltas/RemoveGlobalVars.h @@ -0,0 +1,20 @@ +//===- RemoveGlobalVars.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 removeGlobalsDeltaPass(TestRunner &Test); +} // namespace llvm diff --git a/llvm/tools/llvm-reduce/deltas/RemoveGlobalVars.cpp b/llvm/tools/llvm-reduce/deltas/RemoveGlobalVars.cpp new file mode 100644 --- /dev/null +++ b/llvm/tools/llvm-reduce/deltas/RemoveGlobalVars.cpp @@ -0,0 +1,68 @@ +//===- RemoveGlobalVars.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 "RemoveGlobalVars.h" + +/// Removes all the Initialized GVs that aren't inside the desired Chunks. +/// @returns the Module stripped of out-of-chunk GVs +static std::unique_ptr +extractGVsFromModule(std::vector ChunksToKeep, Module *Program) { + std::unique_ptr Clone = CloneModule(*Program); + + // Get GVs inside desired chunks + std::set GVsToKeep; + int I = 0, GVCount = 1; + for (auto &GV : Clone->globals()) { + if (GV.hasInitializer() && I < ChunksToKeep.size()) { + if (GVCount >= ChunksToKeep[I].begin && GVCount <= ChunksToKeep[I].end) + GVsToKeep.insert(&GV); + if (GVCount == ChunksToKeep[I].end) + ++I; + ++GVCount; + } + } + + // Delete out-of-chunk GVs + std::vector ToRemove; + for (auto &GV : Clone->globals()) { + if (GV.hasInitializer() && !GVsToKeep.count(&GV)) { + GV.replaceAllUsesWith(UndefValue::get(GV.getType())); + ToRemove.push_back(&GV); + } + } + for (auto *GV : ToRemove) + GV->eraseFromParent(); + + return Clone; +} + +/// 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()) { + ++GVCount; + outs() << "\t" << GVCount << ": " << GV.getName() << "\n"; + } + outs() << "----------------------------\n"; + return GVCount; +} + +void llvm::removeGlobalsDeltaPass(TestRunner &Test) { + int GVCount = countGVs(Test.getProgram()); + runDeltaPass(Test, GVCount, extractGVsFromModule); +} \ No newline at end of file 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 @@ -8,8 +8,9 @@ // // 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 *temporary* tool that will eventually -// be integrated into the bugpoint tool itself. +// 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. // //===----------------------------------------------------------------------===//