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_const_reduction_opportunity_finder.h"
16
17 #include "source/opt/instruction.h"
18 #include "source/reduce/change_operand_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 OperandToConstReductionOpportunityFinder::GetAvailableOpportunities(
25 opt::IRContext* context, uint32_t target_function) const {
26 std::vector<std::unique_ptr<ReductionOpportunity>> result;
27 assert(result.empty());
28
29 // We first loop over all constants. This means that all the reduction
30 // opportunities to replace an operand with a particular constant will be
31 // contiguous, and in particular it means that multiple, incompatible
32 // reduction opportunities that try to replace the same operand with distinct
33 // constants are likely to be discontiguous. This is good because the
34 // reducer works in the spirit of delta debugging and tries applying large
35 // contiguous blocks of opportunities early on, and we want to avoid having a
36 // large block of incompatible opportunities if possible.
37 for (const auto& constant : context->GetConstants()) {
38 for (auto* function : GetTargetFunctions(context, target_function)) {
39 for (auto& block : *function) {
40 for (auto& inst : block) {
41 // We iterate through the operands using an explicit index (rather
42 // than using a lambda) so that we use said index in the construction
43 // of a ChangeOperandReductionOpportunity
44 for (uint32_t index = 0; index < inst.NumOperands(); index++) {
45 const auto& operand = inst.GetOperand(index);
46 if (spvIsInIdType(operand.type)) {
47 const auto id = operand.words[0];
48 auto def = context->get_def_use_mgr()->GetDef(id);
49 if (spvOpcodeIsConstant(def->opcode())) {
50 // The argument is already a constant.
51 continue;
52 }
53 if (def->opcode() == SpvOpFunction) {
54 // The argument refers to a function, e.g. the function called
55 // by OpFunctionCall; avoid replacing this with a constant of
56 // the function's return type.
57 continue;
58 }
59 auto type_id = def->type_id();
60 if (type_id) {
61 if (constant->type_id() == type_id) {
62 result.push_back(
63 MakeUnique<ChangeOperandReductionOpportunity>(
64 &inst, index, constant->result_id()));
65 }
66 }
67 }
68 }
69 }
70 }
71 }
72 }
73 return result;
74 }
75
GetName() const76 std::string OperandToConstReductionOpportunityFinder::GetName() const {
77 return "OperandToConstReductionOpportunityFinder";
78 }
79
80 } // namespace reduce
81 } // namespace spvtools
82