xref: /llvm-project/llvm/tools/llvm-reduce/deltas/Delta.h (revision 7ca94a841c7c557191f278ab68f8358e5b9f6cee)
13a25b21cSMatt Arsenault //===- Delta.h - Delta Debugging Algorithm Implementation -------*- C++ -*-===//
2ddc64eb9SDiego Trevino Ferrer //
3ddc64eb9SDiego Trevino Ferrer // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4ddc64eb9SDiego Trevino Ferrer // See https://llvm.org/LICENSE.txt for license information.
5ddc64eb9SDiego Trevino Ferrer // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6ddc64eb9SDiego Trevino Ferrer //
7ddc64eb9SDiego Trevino Ferrer //===----------------------------------------------------------------------===//
8ddc64eb9SDiego Trevino Ferrer //
9ddc64eb9SDiego Trevino Ferrer // This file contains the implementation for the Delta Debugging Algorithm:
10ddc64eb9SDiego Trevino Ferrer // it splits a given set of Targets (i.e. Functions, Instructions, BBs, etc.)
11ddc64eb9SDiego Trevino Ferrer // into chunks and tries to reduce the number chunks that are interesting.
12ddc64eb9SDiego Trevino Ferrer //
13ddc64eb9SDiego Trevino Ferrer //===----------------------------------------------------------------------===//
14ddc64eb9SDiego Trevino Ferrer 
1556fa1b4fSSamuel #ifndef LLVM_TOOLS_LLVM_REDUCE_DELTAS_DELTA_H
1656fa1b4fSSamuel #define LLVM_TOOLS_LLVM_REDUCE_DELTAS_DELTA_H
17ddc64eb9SDiego Trevino Ferrer 
18*592536a9SMatt Arsenault #include "ReducerWorkItem.h"
19*592536a9SMatt Arsenault #include "llvm/ADT/ArrayRef.h"
20*592536a9SMatt Arsenault #include "llvm/Support/raw_ostream.h"
21aac114caSDavid Blaikie #include <functional>
22a39c7ab9SRoman Lebedev #include <utility>
23ddc64eb9SDiego Trevino Ferrer 
24345fbfd7SDavid Blaikie namespace llvm {
25ddc64eb9SDiego Trevino Ferrer 
26*592536a9SMatt Arsenault class TestRunner;
27*592536a9SMatt Arsenault 
28ddc64eb9SDiego Trevino Ferrer struct Chunk {
2956fa1b4fSSamuel   int Begin;
3056fa1b4fSSamuel   int End;
31ddc64eb9SDiego Trevino Ferrer 
32ddc64eb9SDiego Trevino Ferrer   /// Helper function to verify if a given Target-index is inside the Chunk
containsChunk3356fa1b4fSSamuel   bool contains(int Index) const { return Index >= Begin && Index <= End; }
34ddc64eb9SDiego Trevino Ferrer 
printChunk35ddc64eb9SDiego Trevino Ferrer   void print() const {
36ea48d251SMatt Arsenault     errs() << '[' << Begin;
3756fa1b4fSSamuel     if (End - Begin != 0)
38ea48d251SMatt Arsenault       errs() << ',' << End;
39ea48d251SMatt Arsenault     errs() << ']';
40ddc64eb9SDiego Trevino Ferrer   }
41ddc64eb9SDiego Trevino Ferrer 
42ddc64eb9SDiego Trevino Ferrer   /// Operator when populating CurrentChunks in Generic Delta Pass
43ddc64eb9SDiego Trevino Ferrer   friend bool operator!=(const Chunk &C1, const Chunk &C2) {
4456fa1b4fSSamuel     return C1.Begin != C2.Begin || C1.End != C2.End;
45ddc64eb9SDiego Trevino Ferrer   }
46ddc64eb9SDiego Trevino Ferrer 
4789b73916SMatt Arsenault   friend bool operator==(const Chunk &C1, const Chunk &C2) {
4889b73916SMatt Arsenault     return C1.Begin == C2.Begin && C1.End == C2.End;
4989b73916SMatt Arsenault   }
5089b73916SMatt Arsenault 
51ddc64eb9SDiego Trevino Ferrer   /// Operator used for sets
52ddc64eb9SDiego Trevino Ferrer   friend bool operator<(const Chunk &C1, const Chunk &C2) {
5356fa1b4fSSamuel     return std::tie(C1.Begin, C1.End) < std::tie(C2.Begin, C2.End);
54ddc64eb9SDiego Trevino Ferrer   }
55ddc64eb9SDiego Trevino Ferrer };
56ddc64eb9SDiego Trevino Ferrer 
5789b73916SMatt Arsenault template<>
5889b73916SMatt Arsenault struct DenseMapInfo<Chunk> {
5989b73916SMatt Arsenault   static inline Chunk getEmptyKey() {
6089b73916SMatt Arsenault     return {DenseMapInfo<int>::getEmptyKey(),
6189b73916SMatt Arsenault             DenseMapInfo<int>::getEmptyKey()};
6289b73916SMatt Arsenault   }
6389b73916SMatt Arsenault 
6489b73916SMatt Arsenault   static inline Chunk getTombstoneKey() {
6589b73916SMatt Arsenault     return {DenseMapInfo<int>::getTombstoneKey(),
6689b73916SMatt Arsenault             DenseMapInfo<int>::getTombstoneKey()};
6789b73916SMatt Arsenault   }
6889b73916SMatt Arsenault 
6989b73916SMatt Arsenault   static unsigned getHashValue(const Chunk Val) {
7089b73916SMatt Arsenault     std::pair<int, int> PairVal = std::make_pair(Val.Begin, Val.End);
7189b73916SMatt Arsenault     return DenseMapInfo<std::pair<int, int>>::getHashValue(PairVal);
7289b73916SMatt Arsenault   }
7389b73916SMatt Arsenault 
7489b73916SMatt Arsenault   static bool isEqual(const Chunk LHS, const Chunk RHS) {
7589b73916SMatt Arsenault     return LHS == RHS;
7689b73916SMatt Arsenault   }
7789b73916SMatt Arsenault };
7889b73916SMatt Arsenault 
7989b73916SMatt Arsenault 
80a39c7ab9SRoman Lebedev /// Provides opaque interface for querying into ChunksToKeep without having to
81a39c7ab9SRoman Lebedev /// actually understand what is going on.
82a39c7ab9SRoman Lebedev class Oracle {
83a39c7ab9SRoman Lebedev   /// Out of all the features that we promised to be,
846f288bd7SArthur Eubanks   /// how many have we already processed?
856f288bd7SArthur Eubanks   int Index = 0;
86a39c7ab9SRoman Lebedev 
87a39c7ab9SRoman Lebedev   /// The actual workhorse, contains the knowledge whether or not
88a39c7ab9SRoman Lebedev   /// some particular feature should be preserved this time.
89a39c7ab9SRoman Lebedev   ArrayRef<Chunk> ChunksToKeep;
90a39c7ab9SRoman Lebedev 
91a39c7ab9SRoman Lebedev public:
9256fa1b4fSSamuel   explicit Oracle(ArrayRef<Chunk> ChunksToKeep) : ChunksToKeep(ChunksToKeep) {}
93a39c7ab9SRoman Lebedev 
94a39c7ab9SRoman Lebedev   /// Should be called for each feature on which we are operating.
95a39c7ab9SRoman Lebedev   /// Name is self-explanatory - if returns true, then it should be preserved.
96a39c7ab9SRoman Lebedev   bool shouldKeep() {
976f288bd7SArthur Eubanks     if (ChunksToKeep.empty()) {
986f288bd7SArthur Eubanks       ++Index;
99a39c7ab9SRoman Lebedev       return false; // All further features are to be discarded.
1006f288bd7SArthur Eubanks     }
101a39c7ab9SRoman Lebedev 
102a39c7ab9SRoman Lebedev     // Does the current (front) chunk contain such a feature?
103a39c7ab9SRoman Lebedev     bool ShouldKeep = ChunksToKeep.front().contains(Index);
104a39c7ab9SRoman Lebedev 
105a39c7ab9SRoman Lebedev     // Is this the last feature in the chunk?
10656fa1b4fSSamuel     if (ChunksToKeep.front().End == Index)
107a39c7ab9SRoman Lebedev       ChunksToKeep = ChunksToKeep.drop_front(); // Onto next chunk.
108a39c7ab9SRoman Lebedev 
1096f288bd7SArthur Eubanks     ++Index;
1106f288bd7SArthur Eubanks 
111a39c7ab9SRoman Lebedev     return ShouldKeep;
112a39c7ab9SRoman Lebedev   }
1136f288bd7SArthur Eubanks 
1146f288bd7SArthur Eubanks   int count() { return Index; }
115a39c7ab9SRoman Lebedev };
116a39c7ab9SRoman Lebedev 
1177c2db666SMatt Arsenault using ReductionFunc = function_ref<void(Oracle &, ReducerWorkItem &)>;
1187c2db666SMatt Arsenault 
119ddc64eb9SDiego Trevino Ferrer /// This function implements the Delta Debugging algorithm, it receives a
120ddc64eb9SDiego Trevino Ferrer /// number of Targets (e.g. Functions, Instructions, Basic Blocks, etc.) and
121ddc64eb9SDiego Trevino Ferrer /// splits them in half; these chunks of targets are then tested while ignoring
122ddc64eb9SDiego Trevino Ferrer /// one chunk, if a chunk is proven to be uninteresting (i.e. fails the test)
123ddc64eb9SDiego Trevino Ferrer /// it is removed from consideration. The algorithm will attempt to split the
124ddc64eb9SDiego Trevino Ferrer /// Chunks in half and start the process again until it can't split chunks
125ddc64eb9SDiego Trevino Ferrer /// anymore.
126ddc64eb9SDiego Trevino Ferrer ///
127ddc64eb9SDiego Trevino Ferrer /// This function is intended to be called by each specialized delta pass (e.g.
128ddc64eb9SDiego Trevino Ferrer /// RemoveFunctions) and receives three key parameters:
129ddc64eb9SDiego Trevino Ferrer /// * Test: The main TestRunner instance which is used to run the provided
130ddc64eb9SDiego Trevino Ferrer /// interesting-ness test, as well as to store and access the reduced Program.
131ddc64eb9SDiego Trevino Ferrer /// * ExtractChunksFromModule: A function used to tailor the main program so it
132ddc64eb9SDiego Trevino Ferrer /// only contains Targets that are inside Chunks of the given iteration.
133ddc64eb9SDiego Trevino Ferrer /// Note: This function is implemented by each specialized Delta pass
134ddc64eb9SDiego Trevino Ferrer ///
135ddc64eb9SDiego Trevino Ferrer /// Other implementations of the Delta Debugging algorithm can also be found in
136ddc64eb9SDiego Trevino Ferrer /// the CReduce, Delta, and Lithium projects.
1372592ccdeSArthur Eubanks void runDeltaPass(TestRunner &Test, ReductionFunc ExtractChunksFromModule,
1382592ccdeSArthur Eubanks                   StringRef Message);
139ddc64eb9SDiego Trevino Ferrer } // namespace llvm
140ddc64eb9SDiego Trevino Ferrer 
141ddc64eb9SDiego Trevino Ferrer #endif
142