mirror of
https://github.com/KhronosGroup/SPIRV-Tools
synced 2024-11-22 19:50:05 +00:00
521223b70a
This change allows the generator to (optionally and at random) make the functions of a module "livesafe" during donation. This involves introducing a loop limiter variable to each function and gating the number of total loop iterations for the function using that variable. It also involves eliminating OpKill and OpUnreachable instructions (changing them to OpReturn/OpReturnValue), and clamping access chain indices so that they are always in-bounds.
125 lines
5.5 KiB
C++
125 lines
5.5 KiB
C++
// Copyright (c) 2019 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_TRANSFORMATION_ADD_FUNCTION_H_
|
|
#define SOURCE_FUZZ_TRANSFORMATION_ADD_FUNCTION_H_
|
|
|
|
#include "source/fuzz/fact_manager.h"
|
|
#include "source/fuzz/protobufs/spirvfuzz_protobufs.h"
|
|
#include "source/fuzz/transformation.h"
|
|
#include "source/opt/ir_context.h"
|
|
|
|
namespace spvtools {
|
|
namespace fuzz {
|
|
|
|
class TransformationAddFunction : public Transformation {
|
|
public:
|
|
explicit TransformationAddFunction(
|
|
const protobufs::TransformationAddFunction& message);
|
|
|
|
// Creates a transformation to add a non live-safe function.
|
|
explicit TransformationAddFunction(
|
|
const std::vector<protobufs::Instruction>& instructions);
|
|
|
|
// Creates a transformation to add a live-safe function.
|
|
TransformationAddFunction(
|
|
const std::vector<protobufs::Instruction>& instructions,
|
|
uint32_t loop_limiter_variable_id, uint32_t loop_limit_constant_id,
|
|
const std::vector<protobufs::LoopLimiterInfo>& loop_limiters,
|
|
uint32_t kill_unreachable_return_value_id,
|
|
const std::vector<protobufs::AccessChainClampingInfo>&
|
|
access_chain_clampers);
|
|
|
|
// - |message_.instruction| must correspond to a sufficiently well-formed
|
|
// sequence of instructions that a function can be created from them
|
|
// - If |message_.is_livesafe| holds then |message_| must contain suitable
|
|
// ingredients to make the function livesafe, and the function must only
|
|
// invoke other livesafe functions
|
|
// - Adding the created function to the module must lead to a valid module.
|
|
bool IsApplicable(opt::IRContext* context,
|
|
const FactManager& fact_manager) const override;
|
|
|
|
// Adds the function defined by |message_.instruction| to the module, making
|
|
// it livesafe if |message_.is_livesafe| holds.
|
|
void Apply(opt::IRContext* context, FactManager* fact_manager) const override;
|
|
|
|
protobufs::Transformation ToMessage() const override;
|
|
|
|
// Helper method that returns the bound for indexing into a composite of type
|
|
// |composite_type_inst|, i.e. the number of fields of a struct, the size of
|
|
// an array, the number of components of a vector, or the number of columns of
|
|
// a matrix.
|
|
static uint32_t GetBoundForCompositeIndex(
|
|
opt::IRContext* context, const opt::Instruction& composite_type_inst);
|
|
|
|
// Helper method that, given composite type |composite_type_inst|, returns the
|
|
// type of the sub-object at index |index_id|, which is required to be in-
|
|
// bounds.
|
|
static opt::Instruction* FollowCompositeIndex(
|
|
opt::IRContext* context, const opt::Instruction& composite_type_inst,
|
|
uint32_t index_id);
|
|
|
|
private:
|
|
// Attempts to create a function from the series of instructions in
|
|
// |message_.instruction| and add it to |context|.
|
|
//
|
|
// Returns false if adding the function is not possible due to the messages
|
|
// not respecting the basic structure of a function, e.g. if there is no
|
|
// OpFunction instruction or no blocks; in this case |context| is left in an
|
|
// indeterminate state.
|
|
//
|
|
// Otherwise returns true. Whether |context| is valid after addition of the
|
|
// function depends on the contents of |message_.instruction|.
|
|
//
|
|
// Intended usage:
|
|
// - Perform a dry run of this method on a clone of a module, and use
|
|
// the validator to check whether the resulting module is valid. Working
|
|
// on a clone means it does not matter if the function fails to be cleanly
|
|
// added, or leads to an invalid module.
|
|
// - If the dry run succeeds, run the method on the real module of interest,
|
|
// to add the function.
|
|
bool TryToAddFunction(opt::IRContext* context) const;
|
|
|
|
// Should only be called if |message_.is_livesafe| holds. Attempts to make
|
|
// the function livesafe (see FactFunctionIsLivesafe for a definition).
|
|
// Returns false if this is not possible, due to |message_| or |context| not
|
|
// containing sufficient ingredients (such as types and fresh ids) to add
|
|
// the instrumentation necessary to make the function livesafe.
|
|
bool TryToMakeFunctionLivesafe(opt::IRContext* context,
|
|
const FactManager& fact_manager) const;
|
|
|
|
// A helper for TryToMakeFunctionLivesafe that tries to add loop-limiting
|
|
// logic.
|
|
bool TryToAddLoopLimiters(opt::IRContext* context,
|
|
opt::Function* added_function) const;
|
|
|
|
// A helper for TryToMakeFunctionLivesafe that tries to replace OpKill and
|
|
// OpUnreachable instructions into return instructions.
|
|
bool TryToTurnKillOrUnreachableIntoReturn(
|
|
opt::IRContext* context, opt::Function* added_function,
|
|
opt::Instruction* kill_or_unreachable_inst) const;
|
|
|
|
// A helper for TryToMakeFunctionLivesafe that tries to clamp access chain
|
|
// indices so that they are guaranteed to be in-bounds.
|
|
bool TryToClampAccessChainIndices(opt::IRContext* context,
|
|
opt::Instruction* access_chain_inst) const;
|
|
|
|
protobufs::TransformationAddFunction message_;
|
|
};
|
|
|
|
} // namespace fuzz
|
|
} // namespace spvtools
|
|
|
|
#endif // SOURCE_FUZZ_TRANSFORMATION_ADD_FUNCTION_H_
|