1 // Copyright (c) 2020 André Perez Maselco
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_INLINE_FUNCTION_H_
16 #define SOURCE_FUZZ_TRANSFORMATION_INLINE_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 TransformationInlineFunction : public Transformation {
27  public:
28   explicit TransformationInlineFunction(
29       const protobufs::TransformationInlineFunction& message);
30 
31   TransformationInlineFunction(
32       uint32_t function_call_id,
33       const std::map<uint32_t, uint32_t>& result_id_map);
34 
35   // - |message_.result_id_map| must map the instructions of the called function
36   //   to fresh ids, unless overflow ids are available.
37   // - |message_.function_call_id| must be an OpFunctionCall instruction.
38   //   It must not have an early return and must not use OpUnreachable or
39   //   OpKill. This is to guard against making the module invalid when the
40   //   caller is inside a continue construct.
41   //   TODO(https://github.com/KhronosGroup/SPIRV-Tools/issues/3735):
42   //     Allow functions that use OpKill or OpUnreachable to be inlined if the
43   //     function call is not part of a continue construct.
44   bool IsApplicable(
45       opt::IRContext* ir_context,
46       const TransformationContext& transformation_context) const override;
47 
48   // Replaces the OpFunctionCall instruction, identified by
49   // |message_.function_call_id|, with a copy of the function's body.
50   // |message_.result_id_map| is used to provide fresh ids for duplicate
51   // instructions.
52   void Apply(opt::IRContext* ir_context,
53              TransformationContext* transformation_context) const override;
54 
55   std::unordered_set<uint32_t> GetFreshIds() const override;
56 
57   protobufs::Transformation ToMessage() const override;
58 
59   // Returns true if |function_call_instruction| is defined, is an
60   // OpFunctionCall instruction, has no uses if its return type is void, has no
61   // early returns and has no uses of OpKill or OpUnreachable.
62   static bool IsSuitableForInlining(
63       opt::IRContext* ir_context, opt::Instruction* function_call_instruction);
64 
65  private:
66   protobufs::TransformationInlineFunction message_;
67 
68   // Inline |instruction_to_be_inlined| by setting its ids to the corresponding
69   // ids in |result_id_map|.
70   void AdaptInlinedInstruction(
71       const std::map<uint32_t, uint32_t>& result_id_map,
72       opt::IRContext* ir_context, opt::Instruction* instruction) const;
73 };
74 
75 }  // namespace fuzz
76 }  // namespace spvtools
77 
78 #endif  // SOURCE_FUZZ_TRANSFORMATION_INLINE_FUNCTION_H_
79