• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2019 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_FUZZ_TRANSFORMATION_ADD_FUNCTION_H_
16 #define SOURCE_FUZZ_TRANSFORMATION_ADD_FUNCTION_H_
17 
18 #include "source/fuzz/protobufs/spirvfuzz_protobufs.h"
19 #include "source/fuzz/transformation.h"
20 #include "source/fuzz/transformation_context.h"
21 #include "source/opt/ir_context.h"
22 
23 namespace spvtools {
24 namespace fuzz {
25 
26 class TransformationAddFunction : public Transformation {
27  public:
28   explicit TransformationAddFunction(
29       const protobufs::TransformationAddFunction& message);
30 
31   // Creates a transformation to add a non live-safe function.
32   explicit TransformationAddFunction(
33       const std::vector<protobufs::Instruction>& instructions);
34 
35   // Creates a transformation to add a live-safe function.
36   TransformationAddFunction(
37       const std::vector<protobufs::Instruction>& instructions,
38       uint32_t loop_limiter_variable_id, uint32_t loop_limit_constant_id,
39       const std::vector<protobufs::LoopLimiterInfo>& loop_limiters,
40       uint32_t kill_unreachable_return_value_id,
41       const std::vector<protobufs::AccessChainClampingInfo>&
42           access_chain_clampers);
43 
44   // - |message_.instruction| must correspond to a sufficiently well-formed
45   //   sequence of instructions that a function can be created from them
46   // - If |message_.is_livesafe| holds then |message_| must contain suitable
47   //   ingredients to make the function livesafe, and the function must only
48   //   invoke other livesafe functions
49   // - Adding the created function to the module must lead to a valid module.
50   bool IsApplicable(
51       opt::IRContext* ir_context,
52       const TransformationContext& transformation_context) const override;
53 
54   // Adds the function defined by |message_.instruction| to the module, making
55   // it livesafe if |message_.is_livesafe| holds.
56   void Apply(opt::IRContext* ir_context,
57              TransformationContext* transformation_context) const override;
58 
59   protobufs::Transformation ToMessage() const override;
60 
61   // Helper method that returns the bound for indexing into a composite of type
62   // |composite_type_inst|, i.e. the number of fields of a struct, the size of
63   // an array, the number of components of a vector, or the number of columns of
64   // a matrix.
65   static uint32_t GetBoundForCompositeIndex(
66       opt::IRContext* ir_context, const opt::Instruction& composite_type_inst);
67 
68   // Helper method that, given composite type |composite_type_inst|, returns the
69   // type of the sub-object at index |index_id|, which is required to be in-
70   // bounds.
71   static opt::Instruction* FollowCompositeIndex(
72       opt::IRContext* ir_context, const opt::Instruction& composite_type_inst,
73       uint32_t index_id);
74 
75  private:
76   // Attempts to create a function from the series of instructions in
77   // |message_.instruction| and add it to |ir_context|.
78   //
79   // Returns false if adding the function is not possible due to the messages
80   // not respecting the basic structure of a function, e.g. if there is no
81   // OpFunction instruction or no blocks; in this case |ir_context| is left in
82   // an indeterminate state.
83   //
84   // Otherwise returns true.  Whether |ir_context| is valid after addition of
85   // the function depends on the contents of |message_.instruction|.
86   //
87   // Intended usage:
88   // - Perform a dry run of this method on a clone of a module, and use
89   //   the validator to check whether the resulting module is valid.  Working
90   //   on a clone means it does not matter if the function fails to be cleanly
91   //   added, or leads to an invalid module.
92   // - If the dry run succeeds, run the method on the real module of interest,
93   //   to add the function.
94   bool TryToAddFunction(opt::IRContext* ir_context) const;
95 
96   // Should only be called if |message_.is_livesafe| holds.  Attempts to make
97   // the function livesafe (see FactFunctionIsLivesafe for a definition).
98   // Returns false if this is not possible, due to |message_| or |ir_context|
99   // not containing sufficient ingredients (such as types and fresh ids) to add
100   // the instrumentation necessary to make the function livesafe.
101   bool TryToMakeFunctionLivesafe(
102       opt::IRContext* ir_context,
103       const TransformationContext& transformation_context) const;
104 
105   // A helper for TryToMakeFunctionLivesafe that tries to add loop-limiting
106   // logic.
107   bool TryToAddLoopLimiters(opt::IRContext* ir_context,
108                             opt::Function* added_function) const;
109 
110   // A helper for TryToMakeFunctionLivesafe that tries to replace OpKill and
111   // OpUnreachable instructions into return instructions.
112   bool TryToTurnKillOrUnreachableIntoReturn(
113       opt::IRContext* ir_context, opt::Function* added_function,
114       opt::Instruction* kill_or_unreachable_inst) const;
115 
116   // A helper for TryToMakeFunctionLivesafe that tries to clamp access chain
117   // indices so that they are guaranteed to be in-bounds.
118   bool TryToClampAccessChainIndices(opt::IRContext* ir_context,
119                                     opt::Instruction* access_chain_inst) const;
120 
121   protobufs::TransformationAddFunction message_;
122 };
123 
124 }  // namespace fuzz
125 }  // namespace spvtools
126 
127 #endif  // SOURCE_FUZZ_TRANSFORMATION_ADD_FUNCTION_H_
128