• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2019 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 #include "source/fuzz/fuzzer_pass_adjust_memory_operands_masks.h"
16 
17 #include "source/fuzz/instruction_descriptor.h"
18 #include "source/fuzz/transformation_set_memory_operands_mask.h"
19 
20 namespace spvtools {
21 namespace fuzz {
22 
FuzzerPassAdjustMemoryOperandsMasks(opt::IRContext * ir_context,TransformationContext * transformation_context,FuzzerContext * fuzzer_context,protobufs::TransformationSequence * transformations)23 FuzzerPassAdjustMemoryOperandsMasks::FuzzerPassAdjustMemoryOperandsMasks(
24     opt::IRContext* ir_context, TransformationContext* transformation_context,
25     FuzzerContext* fuzzer_context,
26     protobufs::TransformationSequence* transformations)
27     : FuzzerPass(ir_context, transformation_context, fuzzer_context,
28                  transformations) {}
29 
Apply()30 void FuzzerPassAdjustMemoryOperandsMasks::Apply() {
31   // Consider every block in every function.
32   for (auto& function : *GetIRContext()->module()) {
33     for (auto& block : function) {
34       // Consider every instruction in this block, using an explicit iterator so
35       // that when we find an instruction of interest we can search backwards to
36       // create an id descriptor for it.
37       for (auto inst_it = block.cbegin(); inst_it != block.cend(); ++inst_it) {
38         if (!TransformationSetMemoryOperandsMask::IsMemoryAccess(*inst_it)) {
39           // We are only interested in memory access instructions.
40           continue;
41         }
42 
43         std::vector<uint32_t> indices_of_available_masks_to_adjust;
44         // All memory instructions have at least one memory operands mask.
45         indices_of_available_masks_to_adjust.push_back(0);
46         // From SPIR-V 1.4 onwards, OpCopyMemory and OpCopyMemorySized have a
47         // second mask.
48         switch (inst_it->opcode()) {
49           case SpvOpCopyMemory:
50           case SpvOpCopyMemorySized:
51             if (TransformationSetMemoryOperandsMask::
52                     MultipleMemoryOperandMasksAreSupported(GetIRContext())) {
53               indices_of_available_masks_to_adjust.push_back(1);
54             }
55             break;
56           default:
57             break;
58         }
59 
60         // Consider the available masks
61         for (auto mask_index : indices_of_available_masks_to_adjust) {
62           // Randomly decide whether to adjust this mask.
63           if (!GetFuzzerContext()->ChoosePercentage(
64                   GetFuzzerContext()
65                       ->GetChanceOfAdjustingMemoryOperandsMask())) {
66             continue;
67           }
68           // Get the existing mask, using None if there was no mask present at
69           // all.
70           auto existing_mask_in_operand_index =
71               TransformationSetMemoryOperandsMask::GetInOperandIndexForMask(
72                   *inst_it, mask_index);
73           auto existing_mask =
74               existing_mask_in_operand_index < inst_it->NumInOperands()
75                   ? inst_it->GetSingleWordInOperand(
76                         existing_mask_in_operand_index)
77                   : static_cast<uint32_t>(SpvMemoryAccessMaskNone);
78 
79           // There are two things we can do to a mask:
80           // - add Volatile if not already present
81           // - toggle Nontemporal
82           // The following ensures that we do at least one of these
83           bool add_volatile = !(existing_mask & SpvMemoryAccessVolatileMask) &&
84                               GetFuzzerContext()->ChooseEven();
85           bool toggle_nontemporal =
86               !add_volatile || GetFuzzerContext()->ChooseEven();
87 
88           // These bitwise operations use '|' to add Volatile if desired, and
89           // '^' to toggle Nontemporal if desired.
90           uint32_t new_mask =
91               (existing_mask | (add_volatile ? SpvMemoryAccessVolatileMask
92                                              : SpvMemoryAccessMaskNone)) ^
93               (toggle_nontemporal ? SpvMemoryAccessNontemporalMask
94                                   : SpvMemoryAccessMaskNone);
95 
96           TransformationSetMemoryOperandsMask transformation(
97               MakeInstructionDescriptor(block, inst_it), new_mask, mask_index);
98           ApplyTransformation(transformation);
99         }
100       }
101     }
102   }
103 }
104 
105 }  // namespace fuzz
106 }  // namespace spvtools
107