1 // Copyright (c) 2018 Google Inc.
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/remove_unused_instruction_reduction_opportunity_finder.h"
16
17 #include "source/opcode.h"
18 #include "source/opt/instruction.h"
19 #include "source/reduce/remove_instruction_reduction_opportunity.h"
20
21 namespace spvtools {
22 namespace reduce {
23
24 RemoveUnusedInstructionReductionOpportunityFinder::
RemoveUnusedInstructionReductionOpportunityFinder(bool remove_constants_and_undefs)25 RemoveUnusedInstructionReductionOpportunityFinder(
26 bool remove_constants_and_undefs)
27 : remove_constants_and_undefs_(remove_constants_and_undefs) {}
28
29 std::vector<std::unique_ptr<ReductionOpportunity>>
GetAvailableOpportunities(opt::IRContext * context,uint32_t target_function) const30 RemoveUnusedInstructionReductionOpportunityFinder::GetAvailableOpportunities(
31 opt::IRContext* context, uint32_t target_function) const {
32 std::vector<std::unique_ptr<ReductionOpportunity>> result;
33
34 if (!target_function) {
35 // We are not restricting reduction to a specific function, so we consider
36 // unused instructions defined outside functions.
37
38 for (auto& inst : context->module()->debugs1()) {
39 if (context->get_def_use_mgr()->NumUses(&inst) > 0) {
40 continue;
41 }
42 result.push_back(
43 MakeUnique<RemoveInstructionReductionOpportunity>(&inst));
44 }
45
46 for (auto& inst : context->module()->debugs2()) {
47 if (context->get_def_use_mgr()->NumUses(&inst) > 0) {
48 continue;
49 }
50 result.push_back(
51 MakeUnique<RemoveInstructionReductionOpportunity>(&inst));
52 }
53
54 for (auto& inst : context->module()->debugs3()) {
55 if (context->get_def_use_mgr()->NumUses(&inst) > 0) {
56 continue;
57 }
58 result.push_back(
59 MakeUnique<RemoveInstructionReductionOpportunity>(&inst));
60 }
61
62 for (auto& inst : context->module()->ext_inst_debuginfo()) {
63 if (context->get_def_use_mgr()->NumUses(&inst) > 0) {
64 continue;
65 }
66 result.push_back(
67 MakeUnique<RemoveInstructionReductionOpportunity>(&inst));
68 }
69
70 for (auto& inst : context->module()->types_values()) {
71 if (!remove_constants_and_undefs_ &&
72 spvOpcodeIsConstantOrUndef(inst.opcode())) {
73 continue;
74 }
75 if (!OnlyReferencedByIntimateDecorationOrEntryPointInterface(context,
76 inst)) {
77 continue;
78 }
79 result.push_back(
80 MakeUnique<RemoveInstructionReductionOpportunity>(&inst));
81 }
82
83 for (auto& inst : context->module()->annotations()) {
84 if (context->get_def_use_mgr()->NumUsers(&inst) > 0) {
85 continue;
86 }
87 if (!IsIndependentlyRemovableDecoration(inst)) {
88 continue;
89 }
90 result.push_back(
91 MakeUnique<RemoveInstructionReductionOpportunity>(&inst));
92 }
93 }
94
95 for (auto* function : GetTargetFunctions(context, target_function)) {
96 for (auto& block : *function) {
97 for (auto& inst : block) {
98 if (context->get_def_use_mgr()->NumUses(&inst) > 0) {
99 continue;
100 }
101 if (!remove_constants_and_undefs_ &&
102 spvOpcodeIsConstantOrUndef(inst.opcode())) {
103 continue;
104 }
105 if (spvOpcodeIsBlockTerminator(inst.opcode()) ||
106 inst.opcode() == SpvOpSelectionMerge ||
107 inst.opcode() == SpvOpLoopMerge) {
108 // In this reduction pass we do not want to affect static
109 // control flow.
110 continue;
111 }
112 // Given that we're in a block, we should only get here if
113 // the instruction is not directly related to control flow;
114 // i.e., it's some straightforward instruction with an
115 // unused result, like an arithmetic operation or function
116 // call.
117 result.push_back(
118 MakeUnique<RemoveInstructionReductionOpportunity>(&inst));
119 }
120 }
121 }
122 return result;
123 }
124
GetName() const125 std::string RemoveUnusedInstructionReductionOpportunityFinder::GetName() const {
126 return "RemoveUnusedInstructionReductionOpportunityFinder";
127 }
128
129 bool RemoveUnusedInstructionReductionOpportunityFinder::
OnlyReferencedByIntimateDecorationOrEntryPointInterface(opt::IRContext * context,const opt::Instruction & inst) const130 OnlyReferencedByIntimateDecorationOrEntryPointInterface(
131 opt::IRContext* context, const opt::Instruction& inst) const {
132 return context->get_def_use_mgr()->WhileEachUse(
133 &inst, [this](opt::Instruction* user, uint32_t use_index) -> bool {
134 return (user->IsDecoration() &&
135 !IsIndependentlyRemovableDecoration(*user)) ||
136 (user->opcode() == SpvOpEntryPoint && use_index > 2);
137 });
138 }
139
140 bool RemoveUnusedInstructionReductionOpportunityFinder::
IsIndependentlyRemovableDecoration(const opt::Instruction & inst) const141 IsIndependentlyRemovableDecoration(const opt::Instruction& inst) const {
142 uint32_t decoration;
143 switch (inst.opcode()) {
144 case SpvOpDecorate:
145 case SpvOpDecorateId:
146 case SpvOpDecorateString:
147 decoration = inst.GetSingleWordInOperand(1u);
148 break;
149 case SpvOpMemberDecorate:
150 case SpvOpMemberDecorateString:
151 decoration = inst.GetSingleWordInOperand(2u);
152 break;
153 default:
154 // The instruction is not a decoration. It is legitimate for this to be
155 // reached: it allows the method to be invoked on arbitrary instructions.
156 return false;
157 }
158
159 // We conservatively only remove specific decorations that we believe will
160 // not change the shader interface, will not make the shader invalid, will
161 // actually be found in practice, etc.
162
163 switch (decoration) {
164 case SpvDecorationRelaxedPrecision:
165 case SpvDecorationNoSignedWrap:
166 case SpvDecorationNoContraction:
167 case SpvDecorationNoUnsignedWrap:
168 case SpvDecorationUserSemantic:
169 return true;
170 default:
171 return false;
172 }
173 }
174
175 } // namespace reduce
176 } // namespace spvtools
177