1 // Copyright (c) 2020 Google LLC
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
7 // http://www.apache.org/licenses/LICENSE-2.0
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.
15 #include "fuzzer_pass_interchange_signedness_of_integer_operands.h"
17 #include "source/fuzz/fuzzer_util.h"
18 #include "source/fuzz/id_use_descriptor.h"
19 #include "source/fuzz/transformation_record_synonymous_constants.h"
20 #include "source/fuzz/transformation_replace_id_with_synonym.h"
25 FuzzerPassInterchangeSignednessOfIntegerOperands::
26 FuzzerPassInterchangeSignednessOfIntegerOperands(
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
) {}
35 void FuzzerPassInterchangeSignednessOfIntegerOperands::Apply() {
36 assert(!GetFuzzerContext()->IsWgslCompatible() &&
37 "Cannot interchange signedness in WGSL");
39 // Make vector keeping track of all the uses we want to replace.
40 // This is a vector of pairs, where the first element is an id use descriptor
41 // identifying the use of a constant id and the second is the id that should
42 // be used to replace it.
43 std::vector
<std::pair
<protobufs::IdUseDescriptor
, uint32_t>> uses_to_replace
;
45 for (auto constant
: GetIRContext()->GetConstants()) {
46 uint32_t constant_id
= constant
->result_id();
48 // We want to record the synonymity of an integer constant with another
49 // constant with opposite signedness, and this can only be done if they are
51 if (GetTransformationContext()->GetFactManager()->IdIsIrrelevant(
57 FindOrCreateToggledIntegerConstant(constant
->result_id());
59 // Not an integer constant
63 assert(!GetTransformationContext()->GetFactManager()->IdIsIrrelevant(
65 "FindOrCreateToggledConstant can't produce an irrelevant id");
67 // Record synonymous constants
69 TransformationRecordSynonymousConstants(constant_id
, toggled_id
));
71 // Find all the uses of the constant and, for each, probabilistically
72 // decide whether to replace it.
73 GetIRContext()->get_def_use_mgr()->ForEachUse(
75 [this, toggled_id
, &uses_to_replace
](opt::Instruction
* use_inst
,
76 uint32_t use_index
) -> void {
77 if (GetFuzzerContext()->ChoosePercentage(
79 ->GetChanceOfInterchangingSignednessOfIntegerOperands())) {
80 MaybeAddUseToReplace(use_inst
, use_index
, toggled_id
,
86 // Replace the ids if it is allowed.
87 for (auto use_to_replace
: uses_to_replace
) {
88 MaybeApplyTransformation(TransformationReplaceIdWithSynonym(
89 use_to_replace
.first
, use_to_replace
.second
));
93 uint32_t FuzzerPassInterchangeSignednessOfIntegerOperands::
94 FindOrCreateToggledIntegerConstant(uint32_t id
) {
95 // |id| must not be a specialization constant because we do not know the value
96 // of specialization constants.
97 if (opt::IsSpecConstantInst(
98 GetIRContext()->get_def_use_mgr()->GetDef(id
)->opcode())) {
102 auto constant
= GetIRContext()->get_constant_mgr()->FindDeclaredConstant(id
);
104 // This pass only toggles integer constants.
105 if (!constant
->AsIntConstant() &&
106 (!constant
->AsVectorConstant() ||
107 !constant
->AsVectorConstant()->component_type()->AsInteger())) {
111 if (auto integer
= constant
->AsIntConstant()) {
112 auto type
= integer
->type()->AsInteger();
114 // Find or create and return the toggled constant.
115 return FindOrCreateIntegerConstant(std::vector
<uint32_t>(integer
->words()),
116 type
->width(), !type
->IsSigned(), false);
119 // The constant is an integer vector.
121 // Find the component type.
122 auto component_type
=
123 constant
->AsVectorConstant()->component_type()->AsInteger();
125 // Find or create the toggled component type.
126 uint32_t toggled_component_type
= FindOrCreateIntegerType(
127 component_type
->width(), !component_type
->IsSigned());
129 // Get the information about the toggled components. We need to extract this
130 // information now because the analyses might be invalidated, which would make
131 // the constant and component_type variables invalid.
132 std::vector
<std::vector
<uint32_t>> component_words
;
134 for (auto component
: constant
->AsVectorConstant()->GetComponents()) {
135 component_words
.push_back(component
->AsIntConstant()->words());
137 uint32_t width
= component_type
->width();
138 bool is_signed
= !component_type
->IsSigned();
140 std::vector
<uint32_t> toggled_components
;
142 // Find or create the toggled components.
143 for (auto words
: component_words
) {
144 toggled_components
.push_back(
145 FindOrCreateIntegerConstant(words
, width
, is_signed
, false));
148 // Find or create the required toggled vector type.
149 uint32_t toggled_type
= FindOrCreateVectorType(
150 toggled_component_type
, (uint32_t)toggled_components
.size());
152 // Find or create and return the toggled vector constant.
153 return FindOrCreateCompositeConstant(toggled_components
, toggled_type
, false);
157 } // namespace spvtools