1 // Copyright (c) 2020 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_OPPHI_SYNONYM_H_
16 #define SOURCE_FUZZ_TRANSFORMATION_ADD_OPPHI_SYNONYM_H_
17 
18 #include "source/fuzz/transformation.h"
19 
20 namespace spvtools {
21 namespace fuzz {
22 class TransformationAddOpPhiSynonym : public Transformation {
23  public:
24   explicit TransformationAddOpPhiSynonym(
25       const protobufs::TransformationAddOpPhiSynonym& message);
26 
27   TransformationAddOpPhiSynonym(
28       uint32_t block_id, const std::map<uint32_t, uint32_t>& preds_to_ids,
29       uint32_t fresh_id);
30 
31   // - |message_.block_id| is the label of a block with at least one
32   //   predecessor.
33   // - |message_.block_id| must not be a dead block.
34   // - |message_.pred_to_id| contains a mapping from each of the predecessors of
35   //   the block to an id that is available at the end of the predecessor.
36   // - All the ids corresponding to a predecessor in |message_.pred_to_id|:
37   //    - have been recorded as synonymous and all have the same type.
38   //      TODO(https://github.com/KhronosGroup/SPIRV-Tools/issues/3726): if a
39   //       predecessor is a dead block, any id of the right type could be used,
40   //       even if it is not synonym with the others.
41   //    - have one of the following types: Bool, Integer, Float, Vector, Matrix,
42   //      Array, Struct. Pointer types are also allowed if the VariablePointers
43   //      capability is enabled and the storage class is Workgroup or
44   //      StorageBuffer.
45   // - |message_.fresh_id| is a fresh id.
46   bool IsApplicable(
47       opt::IRContext* ir_context,
48       const TransformationContext& transformation_context) const override;
49 
50   // Given a block with n predecessors, with n >= 1, and n corresponding
51   // synonymous ids of the same type, each available to use at the end of the
52   // corresponding predecessor, adds an OpPhi instruction at the beginning of
53   // the block of the form:
54   //   %fresh_id = OpPhi %type %id_1 %pred_1 %id_2 %pred_2 ... %id_n %pred_n
55   // This instruction is then marked as synonymous with the ids.
56   void Apply(opt::IRContext* ir_context,
57              TransformationContext* transformation_context) const override;
58 
59   // Returns true if |type_id| is the id of a type in the module, which is one
60   // of the following: Bool, Integer, Float, Vector, Matrix, Array, Struct.
61   // Pointer types are also allowed if the VariablePointers capability is
62   // enabled and the storage class is Workgroup or StorageBuffer.
63   static bool CheckTypeIsAllowed(opt::IRContext* ir_context, uint32_t type_id);
64 
65   std::unordered_set<uint32_t> GetFreshIds() const override;
66 
67   protobufs::Transformation ToMessage() const override;
68 
69  private:
70   protobufs::TransformationAddOpPhiSynonym message_;
71 };
72 }  // namespace fuzz
73 }  // namespace spvtools
74 
75 #endif  // SOURCE_FUZZ_TRANSFORMATION_ADD_OPPHI_SYNONYM_H_
76