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
24namespace spvtools {
25namespace 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.
29class 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