1 // Copyright (c) 2020 André Perez Maselco
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 "source/fuzz/transformation_expand_vector_reduction.h"
17 #include "source/fuzz/fuzzer_util.h"
18 #include "source/fuzz/instruction_descriptor.h"
23 TransformationExpandVectorReduction::TransformationExpandVectorReduction(
24 protobufs::TransformationExpandVectorReduction message
)
25 : message_(std::move(message
)) {}
27 TransformationExpandVectorReduction::TransformationExpandVectorReduction(
28 const uint32_t instruction_result_id
,
29 const std::vector
<uint32_t>& fresh_ids
) {
30 message_
.set_instruction_result_id(instruction_result_id
);
31 *message_
.mutable_fresh_ids() =
32 google::protobuf::RepeatedField
<google::protobuf::uint32
>(
33 fresh_ids
.begin(), fresh_ids
.end());
36 bool TransformationExpandVectorReduction::IsApplicable(
37 opt::IRContext
* ir_context
, const TransformationContext
& /*unused*/) const {
39 ir_context
->get_def_use_mgr()->GetDef(message_
.instruction_result_id());
41 // |instruction| must be defined.
46 // |instruction| must be OpAny or OpAll.
47 if (instruction
->opcode() != spv::Op::OpAny
&&
48 instruction
->opcode() != spv::Op::OpAll
) {
52 // |message_.fresh_ids.size| must have the exact number of fresh ids required
53 // to apply the transformation.
54 if (static_cast<uint32_t>(message_
.fresh_ids().size()) !=
55 GetRequiredFreshIdCount(ir_context
, instruction
)) {
59 std::set
<uint32_t> ids_used_by_this_transformation
;
60 for (uint32_t fresh_id
: message_
.fresh_ids()) {
61 // All ids in |message_.fresh_ids| must be fresh.
62 if (!fuzzerutil::IsFreshId(ir_context
, fresh_id
)) {
66 // All fresh ids need to be distinct.
67 if (!CheckIdIsFreshAndNotUsedByThisTransformation(
68 fresh_id
, ir_context
, &ids_used_by_this_transformation
)) {
76 void TransformationExpandVectorReduction::Apply(
77 opt::IRContext
* ir_context
,
78 TransformationContext
* transformation_context
) const {
80 ir_context
->get_def_use_mgr()->GetDef(message_
.instruction_result_id());
81 auto* vector
= ir_context
->get_def_use_mgr()->GetDef(
82 instruction
->GetSingleWordInOperand(0));
83 uint32_t vector_component_count
= ir_context
->get_type_mgr()
84 ->GetType(vector
->type_id())
89 auto fresh_id
= message_
.fresh_ids().begin();
91 // |vector_components| are the ids of the extracted components from |vector|.
92 std::vector
<uint32_t> vector_components
;
94 for (uint32_t i
= 0; i
< vector_component_count
; i
++) {
95 // Extracts the i-th |vector| component.
96 auto vector_component
=
97 opt::Instruction(ir_context
, spv::Op::OpCompositeExtract
,
98 instruction
->type_id(), *fresh_id
++,
99 {{SPV_OPERAND_TYPE_ID
, {vector
->result_id()}},
100 {SPV_OPERAND_TYPE_LITERAL_INTEGER
, {i
}}});
101 instruction
->InsertBefore(MakeUnique
<opt::Instruction
>(vector_component
));
102 fuzzerutil::UpdateModuleIdBound(ir_context
, vector_component
.result_id());
103 vector_components
.push_back(vector_component
.result_id());
106 // The first two |vector| components are used in the first logical operation.
107 auto logical_instruction
= opt::Instruction(
109 instruction
->opcode() == spv::Op::OpAny
? spv::Op::OpLogicalOr
110 : spv::Op::OpLogicalAnd
,
111 instruction
->type_id(), *fresh_id
++,
112 {{SPV_OPERAND_TYPE_ID
, {vector_components
[0]}},
113 {SPV_OPERAND_TYPE_ID
, {vector_components
[1]}}});
114 instruction
->InsertBefore(MakeUnique
<opt::Instruction
>(logical_instruction
));
115 fuzzerutil::UpdateModuleIdBound(ir_context
, logical_instruction
.result_id());
117 // Evaluates the remaining components.
118 for (uint32_t i
= 2; i
< vector_components
.size(); i
++) {
119 logical_instruction
= opt::Instruction(
120 ir_context
, logical_instruction
.opcode(), instruction
->type_id(),
122 {{SPV_OPERAND_TYPE_ID
, {vector_components
[i
]}},
123 {SPV_OPERAND_TYPE_ID
, {logical_instruction
.result_id()}}});
124 instruction
->InsertBefore(
125 MakeUnique
<opt::Instruction
>(logical_instruction
));
126 fuzzerutil::UpdateModuleIdBound(ir_context
,
127 logical_instruction
.result_id());
130 ir_context
->InvalidateAnalysesExceptFor(opt::IRContext::kAnalysisNone
);
132 // If it's possible to make a synonym of |instruction|, then add the fact that
133 // the last |logical_instruction| is a synonym of |instruction|.
134 if (fuzzerutil::CanMakeSynonymOf(ir_context
, *transformation_context
,
136 transformation_context
->GetFactManager()->AddFactDataSynonym(
137 MakeDataDescriptor(logical_instruction
.result_id(), {}),
138 MakeDataDescriptor(instruction
->result_id(), {}));
142 protobufs::Transformation
TransformationExpandVectorReduction::ToMessage()
144 protobufs::Transformation result
;
145 *result
.mutable_expand_vector_reduction() = message_
;
149 uint32_t TransformationExpandVectorReduction::GetRequiredFreshIdCount(
150 opt::IRContext
* ir_context
, opt::Instruction
* instruction
) {
151 // For each vector component, 1 OpCompositeExtract and 1 OpLogical* (except
152 // for the first component) instructions will be inserted.
153 return 2 * ir_context
->get_type_mgr()
154 ->GetType(ir_context
->get_def_use_mgr()
155 ->GetDef(instruction
->GetSingleWordInOperand(0))
162 std::unordered_set
<uint32_t> TransformationExpandVectorReduction::GetFreshIds()
164 std::unordered_set
<uint32_t> result
;
165 for (auto id
: message_
.fresh_ids()) {
172 } // namespace spvtools