• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/fuzzer_pass_add_image_sample_unused_components.h"
16 
17 #include "source/fuzz/fuzzer_util.h"
18 #include "source/fuzz/instruction_descriptor.h"
19 #include "source/fuzz/transformation_add_image_sample_unused_components.h"
20 #include "source/fuzz/transformation_composite_construct.h"
21 
22 namespace spvtools {
23 namespace fuzz {
24 
25 FuzzerPassAddImageSampleUnusedComponents::
FuzzerPassAddImageSampleUnusedComponents(opt::IRContext * ir_context,TransformationContext * transformation_context,FuzzerContext * fuzzer_context,protobufs::TransformationSequence * transformations)26     FuzzerPassAddImageSampleUnusedComponents(
27         opt::IRContext* ir_context,
28         TransformationContext* transformation_context,
29         FuzzerContext* fuzzer_context,
30         protobufs::TransformationSequence* transformations)
31     : FuzzerPass(ir_context, transformation_context, fuzzer_context,
32                  transformations) {}
33 
Apply()34 void FuzzerPassAddImageSampleUnusedComponents::Apply() {
35   // SPIR-V module to help understand the transformation.
36   //
37   //       OpCapability Shader
38   //  %1 = OpExtInstImport "GLSL.std.450"
39   //       OpMemoryModel Logical GLSL450
40   //       OpEntryPoint Fragment %15 "main" %12 %14
41   //       OpExecutionMode %15 OriginUpperLeft
42   //
43   // ; Decorations
44   //        OpDecorate %12 Location 0 ; Input color variable location
45   //        OpDecorate %13 DescriptorSet 0 ; Image coordinate variable
46   //        descriptor set OpDecorate %13 Binding 0 ; Image coordinate
47   //        variable binding OpDecorate %14 Location 0 ; Fragment color
48   //        variable location
49   //
50   // ; Types
51   //  %2 = OpTypeVoid
52   //  %3 = OpTypeFunction %2
53   //  %4 = OpTypeFloat 32
54   //  %5 = OpTypeVector %4 2
55   //  %6 = OpTypeVector %4 4
56   //  %7 = OpTypeImage %4 2D 0 0 0 1 Rgba32f
57   //  %8 = OpTypeSampledImage %7
58   //  %9 = OpTypePointer Input %5
59   // %10 = OpTypePointer UniformConstant %8
60   // %11 = OpTypePointer Output %6
61   //
62   // ; Variables
63   // %12 = OpVariable %9 Input ; Input image coordinate variable
64   // %13 = OpVariable %10 UniformConstant ; Image variable
65   // %14 = OpVariable %11 Output ; Fragment color variable
66   //
67   // ; main function
68   // %15 = OpFunction %2 None %3
69   // %16 = OpLabel
70   // %17 = OpLoad %5 %12
71   // %18 = OpLoad %8 %13
72   // %19 = OpImageSampleImplicitLod %6 %18 %17
73   //       OpStore %14 %19
74   //       OpReturn
75   //       OpFunctionEnd
76 
77   GetIRContext()->module()->ForEachInst([this](opt::Instruction* instruction) {
78     // |instruction| %19 = OpImageSampleImplicitLod %6 %18 %17
79     if (!spvOpcodeIsImageSample(instruction->opcode())) {
80       return;
81     }
82 
83     if (!GetFuzzerContext()->ChoosePercentage(
84             GetFuzzerContext()
85                 ->GetChanceOfAddingImageSampleUnusedComponents())) {
86       return;
87     }
88 
89     // Gets image sample coordinate information.
90     // |coordinate_instruction| %17 = OpLoad %5 %12
91     uint32_t coordinate_id = instruction->GetSingleWordInOperand(1);
92     auto coordinate_instruction =
93         GetIRContext()->get_def_use_mgr()->GetDef(coordinate_id);
94     auto coordinate_type = GetIRContext()->get_type_mgr()->GetType(
95         coordinate_instruction->type_id());
96 
97     // If the coordinate is a 4-dimensional vector, then no unused components
98     // may be added.
99     if (coordinate_type->AsVector() &&
100         coordinate_type->AsVector()->element_count() == 4) {
101       return;
102     }
103 
104     // If the coordinate is a scalar, then at most 3 unused components may be
105     // added. If the coordinate is a vector, then the maximum number of unused
106     // components depends on the vector size.
107     // For the sample module, the coordinate type instruction is %5 =
108     // OpTypeVector %4 2, thus |max_unused_component_count| = 4 - 2 = 2.
109     uint32_t max_unused_component_count =
110         coordinate_type->AsInteger() || coordinate_type->AsFloat()
111             ? 3
112             : 4 - coordinate_type->AsVector()->element_count();
113 
114     // |unused_component_count| may be 1 or 2.
115     uint32_t unused_component_count =
116         GetFuzzerContext()->GetRandomUnusedComponentCountForImageSample(
117             max_unused_component_count);
118 
119     // Gets a type for the zero-unused components.
120     uint32_t zero_constant_type_id;
121     switch (unused_component_count) {
122       case 1:
123         // If the coordinate is an integer or float, then the unused components
124         // type is the same as the coordinate. If the coordinate is a vector,
125         // then the unused components type is the same as the vector components
126         // type.
127         zero_constant_type_id =
128             coordinate_type->AsInteger() || coordinate_type->AsFloat()
129                 ? coordinate_instruction->type_id()
130                 : GetIRContext()->get_type_mgr()->GetId(
131                       coordinate_type->AsVector()->element_type());
132         break;
133       case 2:
134       case 3:
135         // If the coordinate is an integer or float, then the unused components
136         // type is the same as the coordinate. If the coordinate is a vector,
137         // then the unused components type is the same as the coordinate
138         // components type.
139         // |zero_constant_type_id| %5 = OpTypeVector %4 2
140         zero_constant_type_id =
141             coordinate_type->AsInteger() || coordinate_type->AsFloat()
142                 ? FindOrCreateVectorType(coordinate_instruction->type_id(),
143                                          unused_component_count)
144                 : FindOrCreateVectorType(
145                       GetIRContext()->get_type_mgr()->GetId(
146                           coordinate_type->AsVector()->element_type()),
147                       unused_component_count);
148         break;
149       default:
150         assert(false && "Should be unreachable.");
151         zero_constant_type_id = 0;
152         break;
153     }
154 
155     // Gets |coordinate_type| again because the module may have changed due to
156     // the use of FindOrCreateVectorType above.
157     coordinate_type = GetIRContext()->get_type_mgr()->GetType(
158         coordinate_instruction->type_id());
159 
160     // If the new vector type with unused components does not exist, then create
161     // it. |coordinate_with_unused_components_type_id| %6 = OpTypeVector %4 4
162     uint32_t coordinate_with_unused_components_type_id =
163         coordinate_type->AsInteger() || coordinate_type->AsFloat()
164             ? FindOrCreateVectorType(coordinate_instruction->type_id(),
165                                      1 + unused_component_count)
166             : FindOrCreateVectorType(
167                   GetIRContext()->get_type_mgr()->GetId(
168                       coordinate_type->AsVector()->element_type()),
169                   coordinate_type->AsVector()->element_count() +
170                       unused_component_count);
171 
172     // Inserts an OpCompositeConstruct instruction which
173     // represents the coordinate with unused components.
174     // |coordinate_with_unused_components_id|
175     // %22 = OpCompositeConstruct %6 %17 %21
176     uint32_t coordinate_with_unused_components_id =
177         GetFuzzerContext()->GetFreshId();
178     ApplyTransformation(TransformationCompositeConstruct(
179         coordinate_with_unused_components_type_id,
180         {coordinate_instruction->result_id(),
181          // FindOrCreateZeroConstant
182          // %20 = OpConstant %4 0
183          // %21 = OpConstantComposite %5 %20 %20
184          FindOrCreateZeroConstant(zero_constant_type_id, true)},
185         MakeInstructionDescriptor(GetIRContext(), instruction),
186         coordinate_with_unused_components_id));
187 
188     // Tries to add unused components to the image sample coordinate.
189     // %19 = OpImageSampleImplicitLod %6 %18 %22
190     ApplyTransformation(TransformationAddImageSampleUnusedComponents(
191         coordinate_with_unused_components_id,
192         MakeInstructionDescriptor(GetIRContext(), instruction)));
193   });
194 }
195 
196 }  // namespace fuzz
197 }  // namespace spvtools
198