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