• 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       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   std::unordered_set<uint32_t> GetFreshIds() const override;
60 
61   protobufs::Transformation ToMessage() const override;
62 
63   // Helper method that, given composite type |composite_type_inst|, returns the
64   // type of the sub-object at index |index_id|, which is required to be in-
65   // bounds.
66   static opt::Instruction* FollowCompositeIndex(
67       opt::IRContext* ir_context, const opt::Instruction& composite_type_inst,
68       uint32_t index_id);
69 
70   // Returns id of the back-edge block, given the corresponding
71   // |loop_header_block_id|. |loop_header_block_id| must be the id of a loop
72   // header block. Returns 0 if the loop has no back-edge block.
73   static uint32_t GetBackEdgeBlockId(opt::IRContext* ir_context,
74                                      uint32_t loop_header_block_id);
75 
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  private:
97   // Should only be called if |message_.is_livesafe| holds.  Attempts to make
98   // the function livesafe (see FactFunctionIsLivesafe for a definition).
99   // Returns false if this is not possible, due to |message_| or |ir_context|
100   // not containing sufficient ingredients (such as types and fresh ids) to add
101   // the instrumentation necessary to make the function livesafe.
102   bool TryToMakeFunctionLivesafe(
103       opt::IRContext* ir_context,
104       const TransformationContext& transformation_context) const;
105 
106   // A helper for TryToMakeFunctionLivesafe that tries to add loop-limiting
107   // logic.
108   bool TryToAddLoopLimiters(opt::IRContext* ir_context,
109                             opt::Function* added_function) const;
110 
111   // A helper for TryToMakeFunctionLivesafe that tries to replace OpKill and
112   // OpUnreachable instructions into return instructions.
113   bool TryToTurnKillOrUnreachableIntoReturn(
114       opt::IRContext* ir_context, opt::Function* added_function,
115       opt::Instruction* kill_or_unreachable_inst) const;
116 
117   // A helper for TryToMakeFunctionLivesafe that tries to clamp access chain
118   // indices so that they are guaranteed to be in-bounds.
119   bool TryToClampAccessChainIndices(opt::IRContext* ir_context,
120                                     opt::Instruction* access_chain_inst) const;
121 
122   protobufs::TransformationAddFunction message_;
123 };
124 
125 }  // namespace fuzz
126 }  // namespace spvtools
127 
128 #endif  // SOURCE_FUZZ_TRANSFORMATION_ADD_FUNCTION_H_
129