File: added_function_reducer.h

package info (click to toggle)
spirv-tools 2023.1-2
  • links: PTS, VCS
  • area: main
  • in suites: bookworm
  • size: 25,608 kB
  • sloc: cpp: 408,882; javascript: 5,890; python: 2,847; ansic: 403; sh: 385; ruby: 88; makefile: 17; lisp: 9
file content (193 lines) | stat: -rw-r--r-- 8,838 bytes parent folder | download | duplicates (18)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
// Copyright (c) 2020 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#ifndef SOURCE_FUZZ_ADDED_FUNCTION_REDUCER_H_
#define SOURCE_FUZZ_ADDED_FUNCTION_REDUCER_H_

#include <unordered_set>
#include <vector>

#include "source/fuzz/protobufs/spirvfuzz_protobufs.h"
#include "source/fuzz/shrinker.h"
#include "spirv-tools/libspirv.hpp"

namespace spvtools {
namespace fuzz {

// An auxiliary class used by Shrinker, this class takes care of using
// spirv-reduce to reduce the body of a function encoded in an AddFunction
// transformation, in case a smaller, simpler function can be added instead.
class AddedFunctionReducer {
 public:
  // Possible statuses that can result from running the shrinker.
  enum class AddedFunctionReducerResultStatus {
    kComplete,
    kReductionFailed,
  };

  struct AddedFunctionReducerResult {
    AddedFunctionReducerResultStatus status;
    std::vector<uint32_t> transformed_binary;
    protobufs::TransformationSequence applied_transformations;
    uint32_t num_reduction_attempts;
  };

  AddedFunctionReducer(
      spv_target_env target_env, MessageConsumer consumer,
      const std::vector<uint32_t>& binary_in,
      const protobufs::FactSequence& initial_facts,
      const protobufs::TransformationSequence& transformation_sequence_in,
      uint32_t index_of_add_function_transformation,
      const Shrinker::InterestingnessFunction&
          shrinker_interestingness_function,
      bool validate_during_replay, spv_validator_options validator_options,
      uint32_t shrinker_step_limit, uint32_t num_existing_shrink_attempts);

  // Disables copy/move constructor/assignment operations.
  AddedFunctionReducer(const AddedFunctionReducer&) = delete;
  AddedFunctionReducer(AddedFunctionReducer&&) = delete;
  AddedFunctionReducer& operator=(const AddedFunctionReducer&) = delete;
  AddedFunctionReducer& operator=(AddedFunctionReducer&&) = delete;

  ~AddedFunctionReducer();

  // Invokes spirv-reduce on the function in the AddFunction transformation
  // identified by |index_of_add_function_transformation|.  Returns a sequence
  // of transformations identical to |transformation_sequence_in|, except that
  // the AddFunction transformation at |index_of_add_function_transformation|
  // might have been simplified.  The binary associated with applying the
  // resulting sequence of transformations to |binary_in| is also returned, as
  // well as the number of reduction steps that spirv-reduce made.
  //
  // On failure, an empty transformation sequence and binary are returned,
  // with a placeholder value of 0 for the number of reduction attempts.
  AddedFunctionReducerResult Run();

 private:
  // Yields, via |binary_out|, the binary obtained by applying transformations
  // [0, |index_of_added_function_| - 1] from |transformations_in_| to
  // |binary_in_|, and then adding the raw function encoded in
  // |transformations_in_[index_of_added_function_]| (without adapting that
  // function to make it livesafe).  This function has |added_function_id_| as
  // its result id.
  //
  // The ids associated with all global variables in |binary_out| that had the
  // "irrelevant pointee value" fact are also returned via
  // |irrelevant_pointee_global_variables|.
  //
  // The point of this function is that spirv-reduce can subsequently be applied
  // to function |added_function_id_| in |binary_out|.  By construction,
  // |added_function_id_| should originally manipulate globals for which
  // "irrelevant pointee value" facts hold.  The set
  // |irrelevant_pointee_global_variables| can be used to force spirv-reduce
  // to preserve this, to avoid the reduced function ending up manipulating
  // other global variables of the SPIR-V module, potentially changing their
  // value and thus changing the semantics of the module.
  void ReplayPrefixAndAddFunction(
      std::vector<uint32_t>* binary_out,
      std::unordered_set<uint32_t>* irrelevant_pointee_global_variables) const;

  // This is the interestingness function that will be used by spirv-reduce
  // when shrinking the added function.
  //
  // For |binary_under_reduction| to be deemed interesting, the following
  // conditions must hold:
  // - The function with id |added_function_id_| in |binary_under_reduction|
  //   must only reference global variables in
  //   |irrelevant_pointee_global_variables|.  This avoids the reduced function
  //   changing the semantics of the original SPIR-V module.
  // - It must be possible to successfully replay the transformations in
  //   |transformation_sequence_in_|, adapted so that the function added by the
  //   transformation at |index_of_add_function_transformation_| is replaced by
  //   the function with id |added_function_id_| in |binary_under_reduction|,
  //   to |binary_in| (starting with initial facts |initial_facts_|).
  // - All the transformations in this sequence must be successfully applied
  //   during replay.
  // - The resulting binary must be interesting according to
  //   |shrinker_interestingness_function_|.
  bool InterestingnessFunctionForReducingAddedFunction(
      const std::vector<uint32_t>& binary_under_reduction,
      const std::unordered_set<uint32_t>& irrelevant_pointee_global_variables);

  // Starting with |binary_in_| and |initial_facts_|, the transformations in
  // |transformation_sequence_in_| are replayed.  However, the transformation
  // at index |index_of_add_function_transformation_| of
  // |transformation_sequence_in_| -- which is guaranteed to be an AddFunction
  // transformation -- is adapted so that the function to be added is replaced
  // with the function in |binary_under_reduction| with id |added_function_id_|.
  //
  // The binary resulting from this replay is returned via |binary_out|, and the
  // adapted transformation sequence via |transformation_sequence_out|.
  void ReplayAdaptedTransformations(
      const std::vector<uint32_t>& binary_under_reduction,
      std::vector<uint32_t>* binary_out,
      protobufs::TransformationSequence* transformation_sequence_out) const;

  // Returns the id of the function to be added by the AddFunction
  // transformation at
  // |transformation_sequence_in_[index_of_add_function_transformation_]|.
  uint32_t GetAddedFunctionId() const;

  // Target environment.
  const spv_target_env target_env_;

  // Message consumer.
  MessageConsumer consumer_;

  // The initial binary to which transformations are applied -- i.e., the
  // binary to which spirv-fuzz originally applied transformations.
  const std::vector<uint32_t>& binary_in_;

  // Initial facts about |binary_in_|.
  const protobufs::FactSequence& initial_facts_;

  // A set of transformations that can be successfully applied to |binary_in_|.
  const protobufs::TransformationSequence& transformation_sequence_in_;

  // An index into |transformation_sequence_in_| referring to an AddFunction
  // transformation.  This is the transformation to be simplified using
  // spirv-reduce.
  const uint32_t index_of_add_function_transformation_;

  // The interestingness function that has been provided to guide the
  // overall shrinking process.  The AddFunction transformation being simplified
  // by this class should still -- when applied in conjunction with the other
  // transformations in |transformation_sequence_in_| -- lead to a binary that
  // is deemed interesting by this function.
  const Shrinker::InterestingnessFunction& shrinker_interestingness_function_;

  // Determines whether to check for validity during the replaying of
  // transformations.
  const bool validate_during_replay_;

  // Options to control validation.
  spv_validator_options validator_options_;

  // The step limit associated with the overall shrinking process.
  const uint32_t shrinker_step_limit_;

  // The number of shrink attempts that had been applied prior to invoking this
  // AddedFunctionReducer instance.
  const uint32_t num_existing_shrink_attempts_;

  // Tracks the number of attempts that spirv-reduce has invoked its
  // interestingness function, which it does once at the start of reduction,
  // and then once more each time it makes a reduction step.
  uint32_t num_reducer_interestingness_function_invocations_;
};

}  // namespace fuzz
}  // namespace spvtools

#endif  // SOURCE_FUZZ_ADDED_FUNCTION_REDUCER_H_