1 // Copyright (c) 2018 Google LLC
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //     http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #ifndef SOURCE_REDUCE_REDUCER_H_
16 #define SOURCE_REDUCE_REDUCER_H_
17 
18 #include <functional>
19 #include <string>
20 
21 #include "source/reduce/reduction_pass.h"
22 #include "spirv-tools/libspirv.hpp"
23 
24 namespace spvtools {
25 namespace reduce {
26 
27 // This class manages the process of applying a reduction -- parameterized by a
28 // number of reduction passes and an interestingness test, to a SPIR-V binary.
29 class Reducer {
30  public:
31   // Possible statuses that can result from running a reduction.
32   enum ReductionResultStatus {
33     kInitialStateNotInteresting,
34     kReachedStepLimit,
35     kComplete,
36     kInitialStateInvalid,
37 
38     // Returned when the fail-on-validation-error option is set and a
39     // reduction step yields a state that fails validation.
40     kStateInvalid,
41   };
42 
43   // The type for a function that will take a binary and return true if and
44   // only if the binary is deemed interesting. (The function also takes an
45   // integer argument that will be incremented each time the function is
46   // called; this is for debugging purposes).
47   //
48   // The notion of "interesting" depends on what properties of the binary or
49   // tools that process the binary we are trying to maintain during reduction.
50   using InterestingnessFunction =
51       std::function<bool(const std::vector<uint32_t>&, uint32_t)>;
52 
53   // Constructs an instance with the given target |target_env|, which is used to
54   // decode the binary to be reduced later.
55   //
56   // The constructed instance will have an empty message consumer, which just
57   // ignores all messages from the library. Use SetMessageConsumer() to supply
58   // one if messages are of concern.
59   //
60   // The constructed instance also needs to have an interestingness function
61   // set and some reduction passes added to it in order to be useful.
62   explicit Reducer(spv_target_env target_env);
63 
64   // Disables copy/move constructor/assignment operations.
65   Reducer(const Reducer&) = delete;
66   Reducer(Reducer&&) = delete;
67   Reducer& operator=(const Reducer&) = delete;
68   Reducer& operator=(Reducer&&) = delete;
69 
70   // Destructs this instance.
71   ~Reducer();
72 
73   // Sets the message consumer to the given |consumer|. The |consumer| will be
74   // invoked once for each message communicated from the library.
75   void SetMessageConsumer(MessageConsumer consumer);
76 
77   // Sets the function that will be used to decide whether a reduced binary
78   // turned out to be interesting.
79   void SetInterestingnessFunction(
80       InterestingnessFunction interestingness_function);
81 
82   // Adds all default reduction passes.
83   void AddDefaultReductionPasses();
84 
85   // Adds a reduction pass based on the given finder to the sequence of passes
86   // that will be iterated over.
87   void AddReductionPass(std::unique_ptr<ReductionOpportunityFinder> finder);
88 
89   // Adds a cleanup reduction pass based on the given finder to the sequence of
90   // passes that will run after other passes.
91   void AddCleanupReductionPass(
92       std::unique_ptr<ReductionOpportunityFinder> finder);
93 
94   // Reduces the given SPIR-V module |binary_out|.
95   // The reduced binary ends up in |binary_out|.
96   // A status is returned.
97   ReductionResultStatus Run(const std::vector<uint32_t>& binary_in,
98                             std::vector<uint32_t>* binary_out,
99                             spv_const_reducer_options options,
100                             spv_validator_options validator_options);
101 
102  private:
103   static bool ReachedStepLimit(uint32_t current_step,
104                                spv_const_reducer_options options);
105 
106   ReductionResultStatus RunPasses(
107       std::vector<std::unique_ptr<ReductionPass>>* passes,
108       spv_const_reducer_options options,
109       spv_validator_options validator_options, const SpirvTools& tools,
110       std::vector<uint32_t>* current_binary, uint32_t* reductions_applied);
111 
112   const spv_target_env target_env_;
113   MessageConsumer consumer_;
114   InterestingnessFunction interestingness_function_;
115   std::vector<std::unique_ptr<ReductionPass>> passes_;
116   std::vector<std::unique_ptr<ReductionPass>> cleanup_passes_;
117 };
118 
119 }  // namespace reduce
120 }  // namespace spvtools
121 
122 #endif  // SOURCE_REDUCE_REDUCER_H_
123