SPIRV-Tools/source/fuzz/overflow_id_source.h
Alastair Donaldson 9e26ae0455
spirv-fuzz: Overflow ids (#3734)
This change adds the notion of "overflow ids", which can be used
during shrinking to facilitate applying transformations that would
otherwise have become inapplicable due to earlier transformations
being removed.
2020-08-26 07:49:42 +01:00

107 lines
3.0 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>
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;
};
} // namespace fuzz
} // namespace spvtools
#endif // SOURCE_FUZZ_OVERFLOW_ID_SOURCE_H_