SPIRV-Tools/source/fuzz/overflow_id_source.h
Alastair Donaldson fcb22ecf0f
spirv-fuzz: Report fresh ids in transformations (#3856)
Adds a virtual method, GetFreshIds(), to Transformation. Every
transformation uses this to indicate which ids in its protobuf message
are fresh ids. This means that when replaying a sequence of
transformations the replayer can obtain a smallest id that is not in
use by the module already and that will not be used by any
transformation by necessity. Ids greater than or equal to this id
can be used as overflow ids.

Fixes #3851.
2020-09-29 22:12:49 +01:00

112 lines
3.3 KiB
C++

// 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_OVERFLOW_ID_SOURCE_H_
#define SOURCE_FUZZ_OVERFLOW_ID_SOURCE_H_
#include <cstdint>
#include <unordered_set>
namespace spvtools {
namespace fuzz {
// An implementation of this interface can be used to provide fresh ids on
// demand when applying a transformation.
//
// During fuzzing this should never be required: a fuzzer pass should determine
// all the fresh ids it requires to apply a transformation.
//
// However, during shrinking we can have the situation where, after removing
// an early transformation, a later transformation needs more ids.
//
// As an example, suppose a SPIR-V function originally has this form:
//
// main() {
// stmt1;
// stmt2;
// stmt3;
// stmt4;
// }
//
// Now suppose two *outlining* transformations are applied. The first
// transformation, T1, outlines "stmt1; stmt2;" into a function foo, giving us:
//
// foo() {
// stmt1;
// stmt2;
// }
//
// main() {
// foo();
// stmt3;
// stmt4;
// }
//
// The second transformation, T2, outlines "foo(); stmt3;" from main into a
// function bar, giving us:
//
// foo() {
// stmt1;
// stmt2;
// }
//
// bar() {
// foo();
// stmt3;
// }
//
// main() {
// bar();
// stmt4;
// }
//
// Suppose that T2 used a set of fresh ids, FRESH, in order to perform its
// outlining.
//
// Now suppose that during shrinking we remove T1, but still want to apply T2.
// The fresh ids used by T2 - FRESH - are sufficient to outline "foo(); stmt3;".
// However, because we did not apply T1, "foo();" does not exist and instead the
// task of T2 is to outline "stmt1; stmt2; stmt3;". The set FRESH contains
// *some* of the fresh ids required to do this (those for "stmt3;"), but not all
// of them (those for "stmt1; stmt2;" are missing).
//
// A source of overflow ids can be used to allow the shrinker to proceed
// nevertheless.
//
// It is desirable to use overflow ids only when needed. In our worked example,
// T2 should still use the ids from FRESH when handling "stmt3;", because later
// transformations might refer to those ids and will become inapplicable if
// overflow ids are used instead.
class OverflowIdSource {
public:
virtual ~OverflowIdSource();
// Returns true if and only if this source is capable of providing overflow
// ids.
virtual bool HasOverflowIds() const = 0;
// Precondition: HasOverflowIds() must hold. Returns the next available
// overflow id.
virtual uint32_t GetNextOverflowId() = 0;
// Returns the set of overflow ids from this source that have been previously
// issued via calls to GetNextOverflowId().
virtual const std::unordered_set<uint32_t>& GetIssuedOverflowIds() const = 0;
};
} // namespace fuzz
} // namespace spvtools
#endif // SOURCE_FUZZ_OVERFLOW_ID_SOURCE_H_