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 @@ -16,9 +16,10 @@ #define LLVM_TOOLS_LLVMREDUCE_LLVMREDUCE_DELTA_H #include "TestRunner.h" -#include -#include +#include "llvm/ADT/ScopeExit.h" #include +#include +#include namespace llvm { @@ -47,6 +48,39 @@ } }; +/// Provides opaque interface for querying into ChunksToKeep without having to +/// actually understand what is going on. +class Oracle { + /// Out of all the features that we promised to be, + /// how many have we already processed? 1-based! + int Index = 1; + + /// The actual workhorse, contains the knowledge whether or not + /// some particular feature should be preserved this time. + ArrayRef ChunksToKeep; + +public: + explicit Oracle(ArrayRef ChunksToKeep_) + : ChunksToKeep(ChunksToKeep_) {} + + /// Should be called for each feature on which we are operating. + /// Name is self-explanatory - if returns true, then it should be preserved. + bool shouldKeep() { + if (ChunksToKeep.empty()) + return false; // All further features are to be discarded. + + // Does the current (front) chunk contain such a feature? + bool ShouldKeep = ChunksToKeep.front().contains(Index); + auto _ = make_scope_exit([&]() { ++Index; }); // Next time - next feature. + + // Is this the last feature in the chunk? + if (ChunksToKeep.front().end == Index) + ChunksToKeep = ChunksToKeep.drop_front(); // Onto next chunk. + + return ShouldKeep; + } +}; + /// 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 diff --git a/llvm/tools/llvm-reduce/deltas/ReduceArguments.cpp b/llvm/tools/llvm-reduce/deltas/ReduceArguments.cpp --- a/llvm/tools/llvm-reduce/deltas/ReduceArguments.cpp +++ b/llvm/tools/llvm-reduce/deltas/ReduceArguments.cpp @@ -42,7 +42,8 @@ /// accordingly. It also removes allocations of out-of-chunk arguments. static void extractArgumentsFromModule(std::vector ChunksToKeep, Module *Program) { - int I = 0, ArgCount = 0; + Oracle O(ChunksToKeep); + std::set ArgsToKeep; std::vector Funcs; // Get inside-chunk arguments, as well as their parent function @@ -50,12 +51,8 @@ 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; - } + if (O.shouldKeep()) + ArgsToKeep.insert(&A); } for (auto *F : Funcs) { diff --git a/llvm/tools/llvm-reduce/deltas/ReduceBasicBlocks.cpp b/llvm/tools/llvm-reduce/deltas/ReduceBasicBlocks.cpp --- a/llvm/tools/llvm-reduce/deltas/ReduceBasicBlocks.cpp +++ b/llvm/tools/llvm-reduce/deltas/ReduceBasicBlocks.cpp @@ -82,17 +82,14 @@ /// accordingly. It also removes allocations of out-of-chunk arguments. static void extractBasicBlocksFromModule(std::vector ChunksToKeep, Module *Program) { - int I = 0, BBCount = 0; + Oracle O(ChunksToKeep); + std::set 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; - } + if (O.shouldKeep()) + BBsToKeep.insert(&BB); std::vector BBsToDelete; for (auto &F : *Program) diff --git a/llvm/tools/llvm-reduce/deltas/ReduceFunctions.cpp b/llvm/tools/llvm-reduce/deltas/ReduceFunctions.cpp --- a/llvm/tools/llvm-reduce/deltas/ReduceFunctions.cpp +++ b/llvm/tools/llvm-reduce/deltas/ReduceFunctions.cpp @@ -24,16 +24,13 @@ /// that aren't inside any of the desired Chunks. static void extractFunctionsFromModule(const std::vector &ChunksToKeep, Module *Program) { + Oracle O(ChunksToKeep); + // Get functions inside desired chunks std::set 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; - } + if (O.shouldKeep()) + FuncsToKeep.insert(&F); // Delete out-of-chunk functions, and replace their calls with undef std::vector FuncsToRemove; diff --git a/llvm/tools/llvm-reduce/deltas/ReduceGlobalVars.cpp b/llvm/tools/llvm-reduce/deltas/ReduceGlobalVars.cpp --- a/llvm/tools/llvm-reduce/deltas/ReduceGlobalVars.cpp +++ b/llvm/tools/llvm-reduce/deltas/ReduceGlobalVars.cpp @@ -20,16 +20,13 @@ /// Removes all the Initialized GVs that aren't inside the desired Chunks. static void extractGVsFromModule(std::vector ChunksToKeep, Module *Program) { + Oracle O(ChunksToKeep); + // Get GVs inside desired chunks std::set 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; - } + if (GV.hasInitializer() && O.shouldKeep()) + GVsToKeep.insert(&GV); // Delete out-of-chunk GVs and their uses std::vector ToRemove; diff --git a/llvm/tools/llvm-reduce/deltas/ReduceInstructions.cpp b/llvm/tools/llvm-reduce/deltas/ReduceInstructions.cpp --- a/llvm/tools/llvm-reduce/deltas/ReduceInstructions.cpp +++ b/llvm/tools/llvm-reduce/deltas/ReduceInstructions.cpp @@ -19,18 +19,15 @@ /// accordingly. It also removes allocations of out-of-chunk arguments. static void extractInstrFromModule(std::vector ChunksToKeep, Module *Program) { - int I = 0, InstCount = 0; + Oracle O(ChunksToKeep); + std::set 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; - } + if (O.shouldKeep()) + InstToKeep.insert(&Inst); std::vector InstToDelete; for (auto &F : *Program) diff --git a/llvm/tools/llvm-reduce/deltas/ReduceMetadata.cpp b/llvm/tools/llvm-reduce/deltas/ReduceMetadata.cpp --- a/llvm/tools/llvm-reduce/deltas/ReduceMetadata.cpp +++ b/llvm/tools/llvm-reduce/deltas/ReduceMetadata.cpp @@ -21,20 +21,15 @@ /// Adds all Unnamed Metadata Nodes that are inside desired Chunks to set template -static void getChunkMetadataNodes(T &MDUser, int &I, - const std::vector &ChunksToKeep, +static void getChunkMetadataNodes(T &MDUser, Oracle &O, std::set &SeenNodes, std::set &NodesToKeep) { SmallVector, 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; - } + if (O.shouldKeep()) + NodesToKeep.insert(MD.second); } } @@ -53,19 +48,20 @@ /// functions that aren't inside the desired Chunks. static void extractMetadataFromModule(const std::vector &ChunksToKeep, Module *Program) { + Oracle O(ChunksToKeep); + std::set SeenNodes; std::set 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); + getChunkMetadataNodes(GV, O, SeenNodes, NodesToKeep); for (auto &F : *Program) { - getChunkMetadataNodes(F, I, ChunksToKeep, SeenNodes, NodesToKeep); + getChunkMetadataNodes(F, O, SeenNodes, NodesToKeep); for (auto &BB : F) for (auto &Inst : BB) - getChunkMetadataNodes(Inst, I, ChunksToKeep, SeenNodes, NodesToKeep); + getChunkMetadataNodes(Inst, O, SeenNodes, NodesToKeep); } // Once more, go over metadata nodes, but deleting the ones outside chunks @@ -81,17 +77,10 @@ // Get out-of-chunk Named metadata nodes - unsigned MetadataCount = SeenNodes.size(); std::vector 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 + for (auto &MD : Program->named_metadata()) + if (!O.shouldKeep()) NamedNodesToDelete.push_back(&MD); - } for (auto *NN : NamedNodesToDelete) { for (int I = 0, E = NN->getNumOperands(); I != E; ++I) diff --git a/llvm/tools/llvm-reduce/deltas/ReduceOperandBundles.cpp b/llvm/tools/llvm-reduce/deltas/ReduceOperandBundles.cpp --- a/llvm/tools/llvm-reduce/deltas/ReduceOperandBundles.cpp +++ b/llvm/tools/llvm-reduce/deltas/ReduceOperandBundles.cpp @@ -17,7 +17,6 @@ #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/STLExtras.h" -#include "llvm/ADT/ScopeExit.h" #include "llvm/ADT/Sequence.h" #include "llvm/ADT/iterator_range.h" #include "llvm/IR/InstVisitor.h" @@ -35,38 +34,6 @@ namespace { -/// Provides opaque interface for querying into ChunksToKeep without having to -/// actually understand what is going on. -struct Oracle { - /// Out of all the features that we promised to be, - /// how many have we already processed? 1-based! - int Index = 1; - - /// The actual workhorse, contains the knowledge whether or not - /// some particular feature should be preserved this time. - ArrayRef ChunksToKeep; - -public: - Oracle(ArrayRef ChunksToKeep_) : ChunksToKeep(ChunksToKeep_) {} - - /// Should be called for each feature on which we are operating. - /// Name is self-explanatory - if returns true, then it should be preserved. - bool shouldKeep() { - if (ChunksToKeep.empty()) - return false; // All further features are to be discarded. - - // Does the current (front) chunk contain such a feature? - bool ShouldKeep = ChunksToKeep.front().contains(Index); - auto _ = make_scope_exit([&]() { ++Index; }); // Next time - next feature. - - // Is this the last feature in the chunk? - if (ChunksToKeep.front().end == Index) - ChunksToKeep = ChunksToKeep.drop_front(); // Onto next chunk. - - return ShouldKeep; - } -}; - /// Given ChunksToKeep, produce a map of calls and indexes of operand bundles /// to be preserved for each call. class OperandBundleRemapper : public InstVisitor {