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