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 #include "source/fuzz/transformation_add_image_sample_unused_components.h"
16 
17 #include "source/fuzz/fuzzer_util.h"
18 #include "source/fuzz/instruction_descriptor.h"
19 
20 namespace spvtools {
21 namespace fuzz {
22 
23 TransformationAddImageSampleUnusedComponents::
TransformationAddImageSampleUnusedComponents(const spvtools::fuzz::protobufs::TransformationAddImageSampleUnusedComponents & message)24     TransformationAddImageSampleUnusedComponents(
25         const spvtools::fuzz::protobufs::
26             TransformationAddImageSampleUnusedComponents& message)
27     : message_(message) {}
28 
29 TransformationAddImageSampleUnusedComponents::
TransformationAddImageSampleUnusedComponents(uint32_t coordinate_with_unused_components_id,const protobufs::InstructionDescriptor & instruction_descriptor)30     TransformationAddImageSampleUnusedComponents(
31         uint32_t coordinate_with_unused_components_id,
32         const protobufs::InstructionDescriptor& instruction_descriptor) {
33   message_.set_coordinate_with_unused_components_id(
34       coordinate_with_unused_components_id);
35   *message_.mutable_instruction_descriptor() = instruction_descriptor;
36 }
37 
IsApplicable(opt::IRContext * ir_context,const TransformationContext &) const38 bool TransformationAddImageSampleUnusedComponents::IsApplicable(
39     opt::IRContext* ir_context, const TransformationContext& /*unused*/) const {
40   auto image_sample_instruction =
41       FindInstruction(message_.instruction_descriptor(), ir_context);
42 
43   // The image sample instruction must be defined.
44   if (image_sample_instruction == nullptr) {
45     return false;
46   }
47 
48   // The instruction must be an image sample instruction.
49   if (!spvOpcodeIsImageSample(image_sample_instruction->opcode())) {
50     return false;
51   }
52 
53   uint32_t coordinate_id = image_sample_instruction->GetSingleWordInOperand(1);
54   auto coordinate_instruction =
55       ir_context->get_def_use_mgr()->GetDef(coordinate_id);
56   auto coordinate_type =
57       ir_context->get_type_mgr()->GetType(coordinate_instruction->type_id());
58 
59   // It must be possible to add unused components.
60   if (coordinate_type->AsVector() &&
61       coordinate_type->AsVector()->element_count() == 4) {
62     return false;
63   }
64 
65   auto coordinate_with_unused_components_instruction =
66       ir_context->get_def_use_mgr()->GetDef(
67           message_.coordinate_with_unused_components_id());
68 
69   // The coordinate with unused components instruction must be defined.
70   if (coordinate_with_unused_components_instruction == nullptr) {
71     return false;
72   }
73 
74   // It must be an OpCompositeConstruct instruction such that it can be checked
75   // that the original components are present.
76   if (coordinate_with_unused_components_instruction->opcode() !=
77       SpvOpCompositeConstruct) {
78     return false;
79   }
80 
81   // The first constituent must be the original coordinate.
82   if (coordinate_with_unused_components_instruction->GetSingleWordInOperand(
83           0) != coordinate_id) {
84     return false;
85   }
86 
87   auto coordinate_with_unused_components_type =
88       ir_context->get_type_mgr()->GetType(
89           coordinate_with_unused_components_instruction->type_id());
90 
91   // |coordinate_with_unused_components_type| must be a vector.
92   if (!coordinate_with_unused_components_type->AsVector()) {
93     return false;
94   }
95 
96   return true;
97 }
98 
Apply(opt::IRContext * ir_context,TransformationContext *) const99 void TransformationAddImageSampleUnusedComponents::Apply(
100     opt::IRContext* ir_context, TransformationContext* /*unused*/) const {
101   // Sets the coordinate operand.
102   auto image_sample_instruction =
103       FindInstruction(message_.instruction_descriptor(), ir_context);
104   image_sample_instruction->SetInOperand(
105       1, {message_.coordinate_with_unused_components_id()});
106   ir_context->InvalidateAnalysesExceptFor(opt::IRContext::kAnalysisNone);
107 }
108 
109 protobufs::Transformation
ToMessage() const110 TransformationAddImageSampleUnusedComponents::ToMessage() const {
111   protobufs::Transformation result;
112   *result.mutable_add_image_sample_unused_components() = message_;
113   return result;
114 }
115 
116 std::unordered_set<uint32_t>
GetFreshIds() const117 TransformationAddImageSampleUnusedComponents::GetFreshIds() const {
118   return std::unordered_set<uint32_t>();
119 }
120 
121 }  // namespace fuzz
122 }  // namespace spvtools
123