1 // Copyright (c) 2020 Vasyl Teliman
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_SYNONYM_H_
16 #define SOURCE_FUZZ_TRANSFORMATION_ADD_SYNONYM_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 TransformationAddSynonym : public Transformation {
27  public:
28   explicit TransformationAddSynonym(
29       protobufs::TransformationAddSynonym message);
30 
31   TransformationAddSynonym(
32       uint32_t result_id,
33       protobufs::TransformationAddSynonym::SynonymType synonym_type,
34       uint32_t synonym_fresh_id,
35       const protobufs::InstructionDescriptor& insert_before);
36 
37   // - |result_id| must be a valid result id of some instruction in the module.
38   // - |result_id| may not be an irrelevant id.
39   // - |synonym_type| is a type of the synonymous instruction that will be
40   //   created.
41   // - |synonym_fresh_id| is a fresh id.
42   // - |insert_before| must be a valid instruction descriptor and we must be
43   //   able to insert a new synonymous instruction before |insert_before|.
44   // - |result_id| must be available before |insert_before|.
45   bool IsApplicable(
46       opt::IRContext* ir_context,
47       const TransformationContext& transformation_context) const override;
48 
49   // Creates a new synonymous instruction according to the |synonym_type| with
50   // result id |synonym_fresh_id|.
51   // Inserts that instruction before |insert_before| and creates a fact
52   // that the |synonym_fresh_id| and the |result_id| are synonymous.
53   void Apply(opt::IRContext* ir_context,
54              TransformationContext* transformation_context) const override;
55 
56   std::unordered_set<uint32_t> GetFreshIds() const override;
57 
58   protobufs::Transformation ToMessage() const override;
59 
60   // Returns true if we can create a synonym of |inst| according to the
61   // |synonym_type|.
62   static bool IsInstructionValid(
63       opt::IRContext* ir_context,
64       const TransformationContext& transformation_context,
65       opt::Instruction* inst,
66       protobufs::TransformationAddSynonym::SynonymType synonym_type);
67 
68   // Returns true if |synonym_type| requires an additional constant instruction
69   // to be present in the module.
70   static bool IsAdditionalConstantRequired(
71       protobufs::TransformationAddSynonym::SynonymType synonym_type);
72 
73  private:
74   // Returns a new instruction which is synonymous to |message_.result_id|.
75   std::unique_ptr<opt::Instruction> MakeSynonymousInstruction(
76       opt::IRContext* ir_context,
77       const TransformationContext& transformation_context) const;
78 
79   // Returns a result id of a constant instruction that is required to be
80   // present in some synonym types (e.g. returns a result id of a zero constant
81   // for ADD_ZERO synonym type). Returns 0 if no such instruction is present in
82   // the module. This method should only be called when
83   // IsAdditionalConstantRequired returns true.
84   uint32_t MaybeGetConstantId(
85       opt::IRContext* ir_context,
86       const TransformationContext& transformation_context) const;
87 
88   protobufs::TransformationAddSynonym message_;
89 };
90 
91 }  // namespace fuzz
92 }  // namespace spvtools
93 
94 #endif  // SOURCE_FUZZ_TRANSFORMATION_ADD_SYNONYM_H_
95