1 // Copyright (c) 2018 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/reduce/operand_to_undef_reduction_opportunity_finder.h"
16
17 #include "source/opt/instruction.h"
18 #include "source/reduce/change_operand_to_undef_reduction_opportunity.h"
19
20 namespace spvtools {
21 namespace reduce {
22
23 std::vector<std::unique_ptr<ReductionOpportunity>>
GetAvailableOpportunities(opt::IRContext * context,uint32_t target_function) const24 OperandToUndefReductionOpportunityFinder::GetAvailableOpportunities(
25 opt::IRContext* context, uint32_t target_function) const {
26 std::vector<std::unique_ptr<ReductionOpportunity>> result;
27
28 for (auto* function : GetTargetFunctions(context, target_function)) {
29 for (auto& block : *function) {
30 for (auto& inst : block) {
31 // Skip instructions that result in a pointer type.
32 auto type_id = inst.type_id();
33 if (type_id) {
34 auto type_id_def = context->get_def_use_mgr()->GetDef(type_id);
35 if (type_id_def->opcode() == SpvOpTypePointer) {
36 continue;
37 }
38 }
39
40 // We iterate through the operands using an explicit index (rather
41 // than using a lambda) so that we use said index in the construction
42 // of a ChangeOperandToUndefReductionOpportunity
43 for (uint32_t index = 0; index < inst.NumOperands(); index++) {
44 const auto& operand = inst.GetOperand(index);
45
46 if (spvIsInIdType(operand.type)) {
47 const auto operand_id = operand.words[0];
48 auto operand_id_def =
49 context->get_def_use_mgr()->GetDef(operand_id);
50
51 // Skip constant and undef operands.
52 // We always want the reducer to make the module "smaller", which
53 // ensures termination.
54 // Therefore, we assume: id > undef id > constant id.
55 if (spvOpcodeIsConstantOrUndef(operand_id_def->opcode())) {
56 continue;
57 }
58
59 // Don't replace function operands with undef.
60 if (operand_id_def->opcode() == SpvOpFunction) {
61 continue;
62 }
63
64 // Only consider operands that have a type.
65 auto operand_type_id = operand_id_def->type_id();
66 if (operand_type_id) {
67 auto operand_type_id_def =
68 context->get_def_use_mgr()->GetDef(operand_type_id);
69
70 // Skip pointer operands.
71 if (operand_type_id_def->opcode() == SpvOpTypePointer) {
72 continue;
73 }
74
75 result.push_back(
76 MakeUnique<ChangeOperandToUndefReductionOpportunity>(
77 context, &inst, index));
78 }
79 }
80 }
81 }
82 }
83 }
84 return result;
85 }
86
GetName() const87 std::string OperandToUndefReductionOpportunityFinder::GetName() const {
88 return "OperandToUndefReductionOpportunityFinder";
89 }
90
91 } // namespace reduce
92 } // namespace spvtools
93